display loaded tile

This commit is contained in:
simon 2020-08-31 11:35:00 +03:00
parent db49b925ca
commit 3f9b0f03d4
12 changed files with 4108 additions and 39 deletions

View file

@ -91,8 +91,10 @@ public class ServerActivity extends AppCompatActivity {
}
private void deInitServer() {
server.closeAllConnections();
server.stop();
if (server != null){
server.closeAllConnections();
server.stop();
}
initialized = false;
}

View file

@ -2,13 +2,26 @@ package net.osmand.plus.server;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.Log;
import android.webkit.MimeTypeMap;
import androidx.core.util.Pair;
import com.google.gson.Gson;
import fi.iki.elonen.NanoHTTPD;
import net.osmand.data.FavouritePoint;
import net.osmand.data.GeometryTile;
import net.osmand.data.QuadPointDouble;
import net.osmand.data.QuadRect;
import net.osmand.map.ITileSource;
import net.osmand.map.TileSourceManager;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.resources.ResourceManager;
import net.osmand.plus.server.map.LayersDraw;
import net.osmand.plus.server.map.MapTileMiniLayer;
import net.osmand.plus.server.map.OsmandMapMiniLayer;
import net.osmand.plus.server.map.OsmandMapTileMiniView;
import java.io.*;
import java.nio.charset.Charset;
@ -16,9 +29,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import fi.iki.elonen.NanoHTTPD;
import net.osmand.plus.activities.MapActivity;
import static fi.iki.elonen.NanoHTTPD.newFixedLengthResponse;
public class ApiRouter {
@ -47,22 +57,74 @@ public class ApiRouter {
};
endpoints.put(favorites.uri,favorites);
ApiEndpoint tile = new ApiEndpoint();
final ApiEndpoint tile = new ApiEndpoint();
tile.uri = "/tile";
tile.apiCall = new ApiEndpoint.ApiCall(){
@Override
public NanoHTTPD.Response call(NanoHTTPD.IHTTPSession session) {
Bitmap bitmap = mapActivity.getMapView().currentCanvas;
//androidContext.getApplicationContext().get
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] byteArray = stream.toByteArray();
ByteArrayInputStream str = new ByteArrayInputStream(byteArray);
return newFixedLengthResponse(
NanoHTTPD.Response.Status.OK,
"image/png",
str,
str.available());
try{
ITileSource map = TileSourceManager.getMapillaryVectorSource();
Bitmap bitmap = Bitmap.createBitmap(512,512,Bitmap.Config.ARGB_8888);//mapActivity.getMapView().currentCanvas;
//OsmandMapTileView tileView = new OsmandMapTileView(mapActivity,300,300);
OsmandMapTileMiniView tileView = new OsmandMapTileMiniView(androidContext,512,512);
Canvas canvas = new Canvas(bitmap);
LayersDraw.createLayers(androidContext,canvas, tileView);
Paint p = new Paint();
p.setStyle(Paint.Style.FILL_AND_STROKE);
p.setColor(Color.BLACK);
//canvas.drawBitmap(bitmap ,0, 0, null);
boolean nightMode = androidContext.getDaynightHelper().isNightMode();
OsmandMapMiniLayer.DrawSettings drawSettings = new OsmandMapMiniLayer.DrawSettings(nightMode, false);
tileView.refreshMapInternal(drawSettings);
tileView.refreshMap();
MapTileMiniLayer mapTileLayer = new MapTileMiniLayer(true);
//mapView.addLayer(mapTileLayer, 0.0f);
//mapTileLayer.drawTileMap(canvas,tileView.getCurrentRotatedTileBox());
tileView.drawOverMap(canvas,tileView.getCurrentRotatedTileBox(),drawSettings);
//androidContext.getApplicationContext().get
ByteArrayOutputStream stream = new ByteArrayOutputStream();
//bitmap = tileView.currentCanvas;
final QuadRect tilesRect = tileView.getCurrentRotatedTileBox().getTileBounds();
int left = (int) Math.floor(tilesRect.left);
int top = (int) Math.floor(tilesRect.top);
int width = (int) Math.ceil(tilesRect.right - left);
int height = (int) Math.ceil(tilesRect.bottom - top);
int dzoom = 1;
int div = (int) Math.pow(2.0, dzoom);
ResourceManager mgr = androidContext.getResourceManager();
int tileX = (left ) / div;
int tileY = (top) / div;
String tileId = mgr.calculateTileId(map, tileX, tileY, 14);
//androidContext.getResourceManager().
// getMapTileDownloader().
//String imgTileId = mgr.calculateTileId(map, tileX / div, tileY / div, nzoom - kzoom);
Map<String, Pair<QuadPointDouble, GeometryTile>> tiles = new HashMap<>();
//bitmap = null;
boolean first = true;
//while (bitmap == null){
// bitmap = androidContext.getResourceManager().getBitmapTilesCache().getTileForMapAsync(
// tileId,map,tileX,tileY,14,first
// );
// first = false;
//}
canvas.drawLine(0,0,canvas.getWidth(),canvas.getHeight(), p);
//bitmap = tileView.currentCanvas;
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] byteArray = stream.toByteArray();
ByteArrayInputStream str = new ByteArrayInputStream(byteArray);
return newFixedLengthResponse(
NanoHTTPD.Response.Status.OK,
"image/png",
str,
str.available());
}
catch (Exception e){
e.printStackTrace();
}
return ErrorResponses.response500;
}
};
endpoints.put(tile.uri,tile);

View file

@ -1,55 +1,67 @@
package net.osmand.plus.server.map;
import net.osmand.StateChangedListener;
import android.graphics.Canvas;
import net.osmand.data.RotatedTileBox;
import net.osmand.map.ITileSource;
import net.osmand.map.TileSourceManager;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.OsmandPlugin;
import net.osmand.plus.measurementtool.MeasurementToolLayer;
import net.osmand.plus.render.MapVectorLayer;
import net.osmand.plus.routing.RoutingHelper;
import net.osmand.plus.views.MapTileLayer;
import net.osmand.plus.views.OsmandMapTileView;
import net.osmand.plus.views.layers.*;
import net.osmand.plus.views.layers.FavouritesLayer;
import net.osmand.plus.views.layers.GPXLayer;
import net.osmand.plus.views.layers.MapTextLayer;
import net.osmand.plus.views.layers.RouteLayer;
public class LayersDraw {
public static void createLayers(OsmandApplication app, final OsmandMapTileView mapView) {
public static void createLayers(OsmandApplication app, Canvas canvas, final OsmandMapTileMiniView mapView) {
RoutingHelper routingHelper = app.getRoutingHelper();
// first create to make accessible
MapTextLayer mapTextLayer = new MapTextLayer();
// 5.95 all labels
mapView.addLayer(mapTextLayer, 5.95f);
//mapView.addLayer(mapTextLayer, 5.95f);
// 8. context menu layer
//ContextMenuLayer contextMenuLayer = new ContextMenuLayer(activity);
//ContextMenuLayer contextMenuLayer = new ContextMenuLayer(app);
//mapView.addLayer(contextMenuLayer, 8);
// mapView.addLayer(underlayLayer, -0.5f);
MapTileLayer mapTileLayer = new MapTileLayer(true);
RotatedTileBox currentTileBlock = mapView.getCurrentRotatedTileBox();
MapTileMiniLayer mapTileLayer = new MapTileMiniLayer(true);
mapView.addLayer(mapTileLayer, 0.0f);
mapView.setMainLayer(mapTileLayer);
ITileSource map = TileSourceManager.getMapillaryVectorSource();
mapTileLayer.setMap(map);
mapTileLayer.drawTileMap(canvas,currentTileBlock);
//mapView.setMainLayer(mapTileLayer);
// 0.5 layer
MapVectorLayer mapVectorLayer = new MapVectorLayer(mapTileLayer, false);
MapVectorMiniLayer mapVectorLayer = new MapVectorMiniLayer(mapTileLayer, false);
mapView.addLayer(mapVectorLayer, 0.5f);
mapVectorLayer.onPrepareBufferImage(canvas,
currentTileBlock,
new OsmandMapMiniLayer.DrawSettings(false));
//DownloadedRegionsLayer downloadedRegionsLayer = new DownloadedRegionsLayer(activity);
//mapView.addLayer(downloadedRegionsLayer, 0.5f);
// 0.9 gpx layer
GPXLayer gpxLayer = new GPXLayer();
mapView.addLayer(gpxLayer, 0.9f);
//mapView.addLayer(gpxLayer, 0.9f);
// 1. route layer
RouteLayer routeLayer = new RouteLayer(routingHelper);
mapView.addLayer(routeLayer, 1);
//mapView.addLayer(routeLayer, 1);
// 2. osm bugs layer
// 3. poi layer
//POIMapLayer poiMapLayer = new POIMapLayer(activity);
//mapView.addLayer(poiMapLayer, 3);
POIMapLayerMini poiMapLayer = new POIMapLayerMini(app);
mapView.addLayer(poiMapLayer, 3);
poiMapLayer.onPrepareBufferImage(canvas, currentTileBlock,
new OsmandMapMiniLayer.DrawSettings(false));
// 4. favorites layer
FavouritesLayer mFavouritesLayer = new FavouritesLayer();
mapView.addLayer(mFavouritesLayer, 4);
//mapView.addLayer(mFavouritesLayer, 4);
// 4.6 measurement tool layer
MeasurementToolLayer measurementToolLayer = new MeasurementToolLayer();
mapView.addLayer(measurementToolLayer, 4.6f);
//MeasurementToolLayer measurementToolLayer = new MeasurementToolLayer();
//mapView.addLayer(measurementToolLayer, 4.6f);
// 5. transport layer
//TransportStopsLayer transportStopsLayer = new TransportStopsLayer(activity);
//mapView.addLayer(transportStopsLayer, 5);
@ -61,8 +73,11 @@ public class LayersDraw {
//PointNavigationLayer navigationLayer = new PointNavigationLayer(activity);
//mapView.addLayer(navigationLayer, 7);
// 7.3 map markers layer
//MapMarkersLayer mapMarkersLayer = new MapMarkersLayer(activity);
//MapMarkersMiniLayer mapMarkersLayer = new MapMarkersMiniLayer(app);
//mapView.addLayer(mapMarkersLayer, 7.3f);
//MyCustomLayer layer = new MyCustomLayer();
//mapView.addLayer(layer,2);
// 7.5 Impassible roads
//ImpassableRoadsLayer impassableRoadsLayer = new ImpassableRoadsLayer(activity);
//mapView.addLayer(impassableRoadsLayer, 7.5f);
@ -92,6 +107,11 @@ public class LayersDraw {
// };
// app.getSettings().MAP_TRANSPARENCY.addListener(transparencyListener);
//OsmandPlugin.createLayers(mapView, activity);
//app.getAppCustomization().createLayers(mapView, activity);
//app.getAidlApi().registerMapLayers(activity);
//return OsmandPlugin.createLayers(mapView, app);
//app.getAppCustomization().createLayers(mapView, activity);
//app.getAidlApi().registerMapLayers(activity);

View file

@ -0,0 +1,646 @@
package net.osmand.plus.server.map;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.graphics.PointF;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.Rect;
import android.os.Handler;
import android.os.Message;
import android.text.TextPaint;
import android.text.TextUtils;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import com.google.android.material.snackbar.Snackbar;
import net.osmand.GPXUtilities.TrkSegment;
import net.osmand.Location;
import net.osmand.data.Amenity;
import net.osmand.data.LatLon;
import net.osmand.data.PointDescription;
import net.osmand.data.QuadPoint;
import net.osmand.data.RotatedTileBox;
import net.osmand.plus.MapMarkersHelper;
import net.osmand.plus.MapMarkersHelper.MapMarker;
import net.osmand.plus.OsmAndConstants;
import net.osmand.plus.OsmAndFormatter;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.plus.R;
import net.osmand.plus.TargetPointsHelper.TargetPoint;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.base.MapViewTrackingUtilities;
import net.osmand.plus.views.OsmandMapLayer;
import net.osmand.plus.views.OsmandMapTileView;
import net.osmand.plus.views.Renderable;
import net.osmand.plus.views.layers.ContextMenuLayer;
import net.osmand.plus.views.layers.ContextMenuLayer.ApplyMovedObjectCallback;
import net.osmand.plus.views.layers.ContextMenuLayer.IContextMenuProvider;
import net.osmand.plus.views.layers.ContextMenuLayer.IContextMenuProviderSelection;
import net.osmand.plus.views.layers.geometry.GeometryWay;
import net.osmand.plus.views.mapwidgets.MapMarkersWidgetsFactory;
import net.osmand.util.MapUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class MapMarkersMiniLayer extends OsmandMapMiniLayer implements IContextMenuProvider,
IContextMenuProviderSelection, ContextMenuLayer.IMoveObjectProvider {
private static final long USE_FINGER_LOCATION_DELAY = 1000;
private static final int MAP_REFRESH_MESSAGE = OsmAndConstants.UI_HANDLER_MAP_VIEW + 6;
protected static final int DIST_TO_SHOW = 80;
private OsmandApplication application;
private OsmandMapTileMiniView view;
private MapMarkersWidgetsMiniFactory widgetsFactory;
private Paint bitmapPaint;
private Bitmap markerBitmapBlue;
private Bitmap markerBitmapGreen;
private Bitmap markerBitmapOrange;
private Bitmap markerBitmapRed;
private Bitmap markerBitmapYellow;
private Bitmap markerBitmapTeal;
private Bitmap markerBitmapPurple;
private Paint bitmapPaintDestBlue;
private Paint bitmapPaintDestGreen;
private Paint bitmapPaintDestOrange;
private Paint bitmapPaintDestRed;
private Paint bitmapPaintDestYellow;
private Paint bitmapPaintDestTeal;
private Paint bitmapPaintDestPurple;
private Bitmap arrowLight;
private Bitmap arrowToDestination;
private Bitmap arrowShadow;
private float[] calculations = new float[2];
private final TextPaint textPaint = new TextPaint();
private final RenderingLineAttributes lineAttrs = new RenderingLineAttributes("measureDistanceLine");
private final RenderingLineAttributes textAttrs = new RenderingLineAttributes("rulerLineFont");
private final RenderingLineAttributes planRouteAttrs = new RenderingLineAttributes("markerPlanRouteline");
private TrkSegment route;
private float textSize;
private int verticalOffset;
private List<Float> tx = new ArrayList<>();
private List<Float> ty = new ArrayList<>();
private Path linePath = new Path();
private LatLon fingerLocation;
private boolean hasMoved;
private boolean moving;
private boolean useFingerLocation;
private GestureDetector longTapDetector;
private Handler handler;
private ContextMenuLayer contextMenuLayer;
private boolean inPlanRouteMode;
private boolean defaultAppMode = true;
private List<Amenity> amenities = new ArrayList<>();
public MapMarkersMiniLayer(OsmandApplication app) {
this.application = app;
}
public MapMarkersWidgetsMiniFactory getWidgetsFactory() {
return widgetsFactory;
}
public boolean isInPlanRouteMode() {
return inPlanRouteMode;
}
public void setInPlanRouteMode(boolean inPlanRouteMode) {
this.inPlanRouteMode = inPlanRouteMode;
}
public void setDefaultAppMode(boolean defaultAppMode) {
this.defaultAppMode = defaultAppMode;
}
private void initUI() {
bitmapPaint = new Paint();
bitmapPaint.setAntiAlias(true);
bitmapPaint.setFilterBitmap(true);
markerBitmapBlue = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_marker_blue);
markerBitmapGreen = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_marker_green);
markerBitmapOrange = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_marker_orange);
markerBitmapRed = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_marker_red);
markerBitmapYellow = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_marker_yellow);
markerBitmapTeal = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_marker_teal);
markerBitmapPurple = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_marker_purple);
arrowLight = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_marker_direction_arrow_p1_light);
arrowToDestination = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_marker_direction_arrow_p2_color);
arrowShadow = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_marker_direction_arrow_p3_shadow);
bitmapPaintDestBlue = createPaintDest(R.color.marker_blue);
bitmapPaintDestGreen = createPaintDest(R.color.marker_green);
bitmapPaintDestOrange = createPaintDest(R.color.marker_orange);
bitmapPaintDestRed = createPaintDest(R.color.marker_red);
bitmapPaintDestYellow = createPaintDest(R.color.marker_yellow);
bitmapPaintDestTeal = createPaintDest(R.color.marker_teal);
bitmapPaintDestPurple = createPaintDest(R.color.marker_purple);
widgetsFactory = new MapMarkersWidgetsMiniFactory(application);
//contextMenuLayer = view.getLayerByClass(ContextMenuLayer.class);
textSize = application.getResources().getDimensionPixelSize(R.dimen.guide_line_text_size);
verticalOffset = application.getResources().getDimensionPixelSize(R.dimen.guide_line_vertical_offset);
}
private Paint createPaintDest(int colorId) {
Paint paint = new Paint();
paint.setDither(true);
paint.setAntiAlias(true);
paint.setFilterBitmap(true);
int color = ContextCompat.getColor(application, colorId);
paint.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN));
return paint;
}
private Paint getMarkerDestPaint(int colorIndex) {
switch (colorIndex) {
case 0:
return bitmapPaintDestBlue;
case 1:
return bitmapPaintDestGreen;
case 2:
return bitmapPaintDestOrange;
case 3:
return bitmapPaintDestRed;
case 4:
return bitmapPaintDestYellow;
case 5:
return bitmapPaintDestTeal;
case 6:
return bitmapPaintDestPurple;
default:
return bitmapPaintDestBlue;
}
}
private Bitmap getMapMarkerBitmap(int colorIndex) {
switch (colorIndex) {
case 0:
return markerBitmapBlue;
case 1:
return markerBitmapGreen;
case 2:
return markerBitmapOrange;
case 3:
return markerBitmapRed;
case 4:
return markerBitmapYellow;
case 5:
return markerBitmapTeal;
case 6:
return markerBitmapPurple;
default:
return markerBitmapBlue;
}
}
public void setRoute(TrkSegment route) {
this.route = route;
}
@Override
public void initLayer(OsmandMapTileMiniView view) {
this.view = view;
//handler = new Handler();
initUI();
// longTapDetector = new GestureDetector(view.getContext(), new GestureDetector.SimpleOnGestureListener() {
// @Override
// public void onLongPress(MotionEvent e) {
// cancelFingerAction();
// }
// });
}
@Override
public void onPrepareBufferImage(Canvas canvas, RotatedTileBox tileBox, DrawSettings nightMode) {
OsmandApplication app = application;
OsmandSettings settings = app.getSettings();
if (!settings.SHOW_MAP_MARKERS.get()) {
return;
}
Location myLoc;
if (useFingerLocation && fingerLocation != null) {
myLoc = new Location("");
myLoc.setLatitude(fingerLocation.getLatitude());
myLoc.setLongitude(fingerLocation.getLongitude());
} else {
myLoc = app.getLocationProvider().getLastStaleKnownLocation();
}
MapMarkersHelper markersHelper = app.getMapMarkersHelper();
List<MapMarker> activeMapMarkers = markersHelper.getMapMarkers();
int displayedWidgets = settings.DISPLAYED_MARKERS_WIDGETS_COUNT.get();
if (route != null && route.points.size() > 0) {
planRouteAttrs.updatePaints(app, nightMode, tileBox);
new Renderable.StandardTrack(new ArrayList<>(route.points), 17.2).
drawSegment(view.getZoom(), defaultAppMode ? planRouteAttrs.paint : planRouteAttrs.paint2, canvas, tileBox);
}
if (settings.SHOW_LINES_TO_FIRST_MARKERS.get() && myLoc != null) {
textAttrs.paint.setTextSize(textSize);
textAttrs.paint2.setTextSize(textSize);
lineAttrs.updatePaints(app, nightMode, tileBox);
textAttrs.updatePaints(app, nightMode, tileBox);
textAttrs.paint.setStyle(Paint.Style.FILL);
textPaint.set(textAttrs.paint);
boolean drawMarkerName = settings.DISPLAYED_MARKERS_WIDGETS_COUNT.get() == 1;
float locX;
float locY;
if (app.getMapViewTrackingUtilities().isMapLinkedToLocation()
&& !MapViewTrackingUtilities.isSmallSpeedForAnimation(myLoc)
&& !app.getMapViewTrackingUtilities().isMovingToMyLocation()) {
locX = tileBox.getPixXFromLatLon(tileBox.getLatitude(), tileBox.getLongitude());
locY = tileBox.getPixYFromLatLon(tileBox.getLatitude(), tileBox.getLongitude());
} else {
locX = tileBox.getPixXFromLatLon(myLoc.getLatitude(), myLoc.getLongitude());
locY = tileBox.getPixYFromLatLon(myLoc.getLatitude(), myLoc.getLongitude());
}
int[] colors = MapMarker.getColors(application);
for (int i = 0; i < activeMapMarkers.size() && i < displayedWidgets; i++) {
MapMarker marker = activeMapMarkers.get(i);
float markerX = tileBox.getPixXFromLatLon(marker.getLatitude(), marker.getLongitude());
float markerY = tileBox.getPixYFromLatLon(marker.getLatitude(), marker.getLongitude());
linePath.reset();
tx.clear();
ty.clear();
tx.add(locX);
ty.add(locY);
tx.add(markerX);
ty.add(markerY);
GeometryWay.calculatePath(tileBox, tx, ty, linePath);
PathMeasure pm = new PathMeasure(linePath, false);
float[] pos = new float[2];
pm.getPosTan(pm.getLength() / 2, pos, null);
float dist = (float) MapUtils.getDistance(myLoc.getLatitude(), myLoc.getLongitude(), marker.getLatitude(), marker.getLongitude());
String distSt = OsmAndFormatter.getFormattedDistance(dist, view.getApplication());
String text = distSt + (drawMarkerName ? "" + marker.getName(application) : "");
text = TextUtils.ellipsize(text, textPaint, pm.getLength(), TextUtils.TruncateAt.END).toString();
Rect bounds = new Rect();
textAttrs.paint.getTextBounds(text, 0, text.length(), bounds);
float hOffset = pm.getLength() / 2 - bounds.width() / 2;
lineAttrs.paint.setColor(colors[marker.colorIndex]);
canvas.rotate(-tileBox.getRotate(), tileBox.getCenterPixelX(), tileBox.getCenterPixelY());
canvas.drawPath(linePath, lineAttrs.paint);
if (locX >= markerX) {
canvas.rotate(180, pos[0], pos[1]);
canvas.drawTextOnPath(text, linePath, hOffset, bounds.height() + verticalOffset, textAttrs.paint2);
canvas.drawTextOnPath(text, linePath, hOffset, bounds.height() + verticalOffset, textAttrs.paint);
canvas.rotate(-180, pos[0], pos[1]);
} else {
canvas.drawTextOnPath(text, linePath, hOffset, -verticalOffset, textAttrs.paint2);
canvas.drawTextOnPath(text, linePath, hOffset, -verticalOffset, textAttrs.paint);
}
canvas.rotate(tileBox.getRotate(), tileBox.getCenterPixelX(), tileBox.getCenterPixelY());
}
}
}
@Override
public void onDraw(Canvas canvas, RotatedTileBox tileBox, DrawSettings nightMode) {
//widgetsFactory.updateInfo(useFingerLocation ? fingerLocation : null, tileBox.getZoom());
OsmandSettings settings = application.getSettings();
if (tileBox.getZoom() < 3 || !settings.SHOW_MAP_MARKERS.get()) {
return;
}
int displayedWidgets = settings.DISPLAYED_MARKERS_WIDGETS_COUNT.get();
MapMarkersHelper markersHelper = application.getMapMarkersHelper();
for (MapMarker marker : markersHelper.getMapMarkers()) {
if (isLocationVisible(tileBox, marker) && !overlappedByWaypoint(marker)
&& !isInMotion(marker) && !isSynced(marker)) {
Bitmap bmp = getMapMarkerBitmap(marker.colorIndex);
int marginX = bmp.getWidth() / 6;
int marginY = bmp.getHeight();
int locationX = tileBox.getPixXFromLonNoRot(marker.getLongitude());
int locationY = tileBox.getPixYFromLatNoRot(marker.getLatitude());
canvas.rotate(-tileBox.getRotate(), locationX, locationY);
canvas.drawBitmap(bmp, locationX - marginX, locationY - marginY, bitmapPaint);
canvas.rotate(tileBox.getRotate(), locationX, locationY);
}
}
if (settings.SHOW_ARROWS_TO_FIRST_MARKERS.get()) {
LatLon loc = tileBox.getCenterLatLon();
int i = 0;
for (MapMarker marker : markersHelper.getMapMarkers()) {
if (!isLocationVisible(tileBox, marker) && !isInMotion(marker)) {
canvas.save();
net.osmand.Location.distanceBetween(loc.getLatitude(), loc.getLongitude(),
marker.getLatitude(), marker.getLongitude(), calculations);
float bearing = calculations[1] - 90;
float radiusBearing = DIST_TO_SHOW * tileBox.getDensity();
final QuadPoint cp = tileBox.getCenterPixelPoint();
canvas.rotate(bearing, cp.x, cp.y);
canvas.translate(-24 * tileBox.getDensity() + radiusBearing, -22 * tileBox.getDensity());
canvas.drawBitmap(arrowShadow, cp.x, cp.y, bitmapPaint);
canvas.drawBitmap(arrowToDestination, cp.x, cp.y, getMarkerDestPaint(marker.colorIndex));
canvas.drawBitmap(arrowLight, cp.x, cp.y, bitmapPaint);
canvas.restore();
}
i++;
if (i > displayedWidgets - 1) {
break;
}
}
}
// if (contextMenuLayer.getMoveableObject() instanceof MapMarker) {
// MapMarker objectInMotion = (MapMarker) contextMenuLayer.getMoveableObject();
// PointF pf = contextMenuLayer.getMovableCenterPoint(tileBox);
// Bitmap bitmap = getMapMarkerBitmap(objectInMotion.colorIndex);
// int marginX = bitmap.getWidth() / 6;
// int marginY = bitmap.getHeight();
// float locationX = pf.x;
// float locationY = pf.y;
// canvas.rotate(-tileBox.getRotate(), locationX, locationY);
// canvas.drawBitmap(bitmap, locationX - marginX, locationY - marginY, bitmapPaint);
//
// }
}
private boolean isSynced(@NonNull MapMarker marker) {
return marker.wptPt != null || marker.favouritePoint != null;
}
private boolean isInMotion(@NonNull MapMarker marker) {
return marker.equals(contextMenuLayer.getMoveableObject());
}
public boolean isLocationVisible(RotatedTileBox tb, MapMarker marker) {
//noinspection SimplifiableIfStatement
if (marker == null || tb == null) {
return false;
}
return containsLatLon(tb, marker.getLatitude(), marker.getLongitude());
}
public boolean containsLatLon(RotatedTileBox tb, double lat, double lon) {
double widgetHeight = 0;
if (widgetsFactory.isTopBarVisible()) {
widgetHeight = widgetsFactory.getTopBarHeight();
}
double tx = tb.getPixXFromLatLon(lat, lon);
double ty = tb.getPixYFromLatLon(lat, lon);
return tx >= 0 && tx <= tb.getPixWidth() && ty >= widgetHeight && ty <= tb.getPixHeight();
}
public boolean overlappedByWaypoint(MapMarker marker) {
List<TargetPoint> targetPoints = application.getTargetPointsHelper().getAllPoints();
for (TargetPoint t : targetPoints) {
if (t.point.equals(marker.point)) {
return true;
}
}
return false;
}
@Override
public void destroyLayer() {
}
@Override
public boolean onTouchEvent(MotionEvent event, RotatedTileBox tileBox) {
if (!longTapDetector.onTouchEvent(event)) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
float x = event.getX();
float y = event.getY();
fingerLocation = tileBox.getLatLonFromPixel(x, y);
hasMoved = false;
moving = true;
break;
case MotionEvent.ACTION_MOVE:
if (!hasMoved) {
if (!handler.hasMessages(MAP_REFRESH_MESSAGE)) {
Message msg = Message.obtain(handler, new Runnable() {
@Override
public void run() {
handler.removeMessages(MAP_REFRESH_MESSAGE);
if (moving) {
if (!useFingerLocation) {
useFingerLocation = true;
}
}
}
});
msg.what = MAP_REFRESH_MESSAGE;
handler.sendMessageDelayed(msg, USE_FINGER_LOCATION_DELAY);
}
hasMoved = true;
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
cancelFingerAction();
break;
}
}
return super.onTouchEvent(event, tileBox);
}
private void cancelFingerAction() {
handler.removeMessages(MAP_REFRESH_MESSAGE);
useFingerLocation = false;
moving = false;
fingerLocation = null;
}
@Override
public boolean drawInScreenPixels() {
return false;
}
@Override
public boolean disableSingleTap() {
return inPlanRouteMode;
}
@Override
public boolean disableLongPressOnMap() {
return inPlanRouteMode;
}
@Override
public boolean isObjectClickable(Object o) {
return false;
}
@Override
public boolean runExclusiveAction(Object o, boolean unknownLocation) {
OsmandSettings settings = application.getSettings();
if (unknownLocation
|| o == null
|| !(o instanceof MapMarker)
|| !settings.SELECT_MARKER_ON_SINGLE_TAP.get()
|| !settings.SHOW_MAP_MARKERS.get()) {
return false;
}
final MapMarkersHelper helper = application.getMapMarkersHelper();
final MapMarker old = helper.getMapMarkers().get(0);
helper.moveMarkerToTop((MapMarker) o);
String title = application.getString(R.string.marker_activated, helper.getMapMarkers().get(0).getName(application));
return true;
}
@Override
public void collectObjectsFromPoint(PointF point, RotatedTileBox tileBox, List<Object> o, boolean unknownLocation) {
if (tileBox.getZoom() < 3 || !application.getSettings().SHOW_MAP_MARKERS.get()) {
return;
}
amenities.clear();
OsmandApplication app = application;
int r = getDefaultRadiusPoi(tileBox);
boolean selectMarkerOnSingleTap = app.getSettings().SELECT_MARKER_ON_SINGLE_TAP.get();
for (MapMarker marker : app.getMapMarkersHelper().getMapMarkers()) {
if ((!unknownLocation && selectMarkerOnSingleTap) || !isSynced(marker)) {
LatLon latLon = marker.point;
if (latLon != null) {
int x = (int) tileBox.getPixXFromLatLon(latLon.getLatitude(), latLon.getLongitude());
int y = (int) tileBox.getPixYFromLatLon(latLon.getLatitude(), latLon.getLongitude());
if (calculateBelongs((int) point.x, (int) point.y, x, y, r)) {
if (!unknownLocation && selectMarkerOnSingleTap) {
o.add(marker);
} else {
if (isMarkerOnFavorite(marker) && app.getSettings().SHOW_FAVORITES.get()
|| isMarkerOnWaypoint(marker) && app.getSettings().SHOW_WPT.get()) {
continue;
}
Amenity mapObj = getMapObjectByMarker(marker);
if (mapObj != null) {
amenities.add(mapObj);
o.add(mapObj);
} else {
o.add(marker);
}
}
}
}
}
}
}
private boolean isMarkerOnWaypoint(@NonNull MapMarker marker) {
return marker.point != null && application.getSelectedGpxHelper().getVisibleWayPointByLatLon(marker.point) != null;
}
private boolean isMarkerOnFavorite(@NonNull MapMarker marker) {
return marker.point != null && application.getFavorites().getVisibleFavByLatLon(marker.point) != null;
}
@Nullable
public Amenity getMapObjectByMarker(@NonNull MapMarker marker) {
if (marker.mapObjectName != null && marker.point != null) {
String mapObjName = marker.mapObjectName.split("_")[0];
return findAmenity(application, -1, Collections.singletonList(mapObjName), marker.point, 15);
}
return null;
}
private boolean calculateBelongs(int ex, int ey, int objx, int objy, int radius) {
return Math.abs(objx - ex) <= radius * 1.5 && (ey - objy) <= radius * 1.5 && (objy - ey) <= 2.5 * radius;
}
@Override
public LatLon getObjectLocation(Object o) {
if (o instanceof MapMarker) {
return ((MapMarker) o).point;
} else if (o instanceof Amenity && amenities.contains(o)) {
return ((Amenity) o).getLocation();
}
return null;
}
@Override
public PointDescription getObjectName(Object o) {
// if (o instanceof MapMarker) {
// return ((MapMarker) o).getPointDescription(view.getContext());
// }
return null;
}
@Override
public int getOrder(Object o) {
return 0;
}
@Override
public void setSelectedObject(Object o) {
}
@Override
public void clearSelectedObject() {
}
@Override
public boolean isObjectMovable(Object o) {
return o instanceof MapMarker;
}
@Override
public void applyNewObjectPosition(@NonNull Object o, @NonNull LatLon position,
@Nullable ApplyMovedObjectCallback callback) {
boolean result = false;
MapMarker newObject = null;
if (o instanceof MapMarker) {
MapMarkersHelper markersHelper = application.getMapMarkersHelper();
MapMarker marker = (MapMarker) o;
PointDescription originalDescription = marker.getOriginalPointDescription();
if (originalDescription.isLocation()) {
originalDescription.setName(PointDescription.getSearchAddressStr(application));
}
markersHelper.moveMapMarker(marker, position);
int index = markersHelper.getMapMarkers().indexOf(marker);
if (index != -1) {
newObject = markersHelper.getMapMarkers().get(index);
}
result = true;
}
if (callback != null) {
callback.onApplyMovedObject(result, newObject == null ? o : newObject);
}
}
}

View file

@ -0,0 +1,306 @@
package net.osmand.plus.server.map;
import android.view.View;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import net.osmand.Location;
import net.osmand.data.LatLon;
import net.osmand.data.PointDescription;
import net.osmand.plus.*;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.helpers.AndroidUiHelper;
import net.osmand.plus.mapmarkers.MapMarkersDialogFragment;
import net.osmand.plus.views.AnimateDraggingMapThread;
import net.osmand.plus.views.DirectionDrawable;
import net.osmand.plus.views.OsmandMapLayer;
import net.osmand.plus.views.OsmandMapTileView;
import net.osmand.plus.views.mapwidgets.widgets.TextInfoWidget;
import net.osmand.util.Algorithms;
import net.osmand.util.MapUtils;
import java.util.List;
public class MapMarkersWidgetsMiniFactory {
public static final int MIN_DIST_OK_VISIBLE = 40; // meters
public static final int MIN_DIST_2ND_ROW_SHOW = 150; // meters
private static OsmandApplication app;
private MapMarkersHelper helper;
private int screenOrientation;
private boolean portraitMode;
private LatLon loc;
private boolean cachedTopBarVisibility;
public MapMarkersWidgetsMiniFactory(final OsmandApplication application) {
this.app = application;
helper = app.getMapMarkersHelper();
screenOrientation = app.getUIUtilities().getScreenOrientation();
//portraitMode = AndroidUiHelper.isOrientationPortrait(map);
updateVisibility(false);
}
private void removeMarker(int index) {
if (helper.getMapMarkers().size() > index) {
helper.moveMapMarkerToHistory(helper.getMapMarkers().get(index));
}
}
private void showMarkerOnMap(int index) {
// if (helper.getMapMarkers().size() > index) {
// MapMarkersHelper.MapMarker marker = helper.getMapMarkers().get(index);
// AnimateDraggingMapThread thread = app.getMapView().getAnimatedDraggingThread();
// LatLon pointToNavigate = marker.point;
// if (pointToNavigate != null) {
// int fZoom = map.getMapView().getZoom() < 15 ? 15 : map.getMapView().getZoom();
// thread.startMoving(pointToNavigate.getLatitude(), pointToNavigate.getLongitude(), fZoom, true);
// }
// //MapMarkerDialogHelper.showMarkerOnMap(map, marker);
// }
}
public boolean updateVisibility(boolean visible) {
return visible;
}
public int getTopBarHeight() {
return 0;
}
public boolean isTopBarVisible() {
return false;
}
public void updateInfo(LatLon customLocation, int zoom) {
if (customLocation != null) {
loc = customLocation;
} else {
Location l = app.getLocationProvider().getLastStaleKnownLocation();
if (l != null) {
loc = new LatLon(l.getLatitude(), l.getLongitude());
} else {
}
}
List<MapMarkersHelper.MapMarker> markers = helper.getMapMarkers();
if (zoom < 3 || markers.size() == 0
|| !app.getSettings().MARKERS_DISTANCE_INDICATION_ENABLED.get()
|| !app.getSettings().MAP_MARKERS_MODE.get().isToolbar()
|| app.getRoutingHelper().isFollowingMode()
|| app.getRoutingHelper().isRoutePlanningMode()) {
updateVisibility(false);
return;
}
Float heading = app.getMapViewTrackingUtilities().getHeading();
MapMarkersHelper.MapMarker marker = markers.get(0);
if (markers.size() > 1 && app.getSettings().DISPLAYED_MARKERS_WIDGETS_COUNT.get() == 2) {
marker = markers.get(1);
if (loc != null && customLocation == null) {
for (int i = 1; i < markers.size(); i++) {
MapMarkersHelper.MapMarker m = markers.get(i);
m.dist = (int) (MapUtils.getDistance(m.getLatitude(), m.getLongitude(),
loc.getLatitude(), loc.getLongitude()));
if (m.dist < MIN_DIST_2ND_ROW_SHOW && marker.dist > m.dist) {
marker = m;
}
}
}
} else {
}
updateVisibility(true);
}
private void updateUI(LatLon loc, Float heading, MapMarkersHelper.MapMarker marker, ImageView arrowImg,
TextView distText, ImageButton okButton, TextView addressText,
boolean firstLine, boolean customLocation) {
float[] mes = new float[2];
if (loc != null && marker.point != null) {
Location.distanceBetween(marker.getLatitude(), marker.getLongitude(), loc.getLatitude(), loc.getLongitude(), mes);
}
if (customLocation) {
heading = 0f;
}
boolean newImage = false;
DirectionDrawable dd;
if (!(arrowImg.getDrawable() instanceof DirectionDrawable)) {
newImage = true;
dd = new DirectionDrawable(app, arrowImg.getWidth(), arrowImg.getHeight());
} else {
dd = (DirectionDrawable) arrowImg.getDrawable();
}
dd.setImage(R.drawable.ic_arrow_marker_diretion, MapMarkersHelper.MapMarker.getColorId(marker.colorIndex));
if (heading != null && loc != null) {
dd.setAngle(mes[1] - heading + 180 + screenOrientation);
}
if (newImage) {
arrowImg.setImageDrawable(dd);
}
arrowImg.invalidate();
int dist = (int) mes[0];
String txt;
if (loc != null) {
txt = OsmAndFormatter.getFormattedDistance(dist, app);
} else {
txt = "";
}
if (txt != null) {
distText.setText(txt);
}
AndroidUiHelper.updateVisibility(okButton, !customLocation && loc != null && dist < MIN_DIST_OK_VISIBLE);
String descr;
PointDescription pd = marker.getPointDescription(app);
if (Algorithms.isEmpty(pd.getName())) {
descr = pd.getTypeName();
} else {
descr = pd.getName();
}
if (!firstLine && !isLandscapeLayout()) {
descr = "" + descr;
}
addressText.setText(descr);
}
public TextInfoWidget createMapMarkerControl(final MapActivity map, final boolean firstMarker) {
return new net.osmand.plus.views.mapwidgets.MapMarkersWidgetsFactory.DistanceToMapMarkerControl(map, firstMarker) {
@Override
public LatLon getLatLon() {
return loc;
}
@Override
protected void click(OsmandMapTileView view) {
showMarkerOnMap(firstMarker ? 0 : 1);
}
};
}
public boolean isLandscapeLayout() {
return !portraitMode;
}
public abstract static class DistanceToMapMarkerControl extends TextInfoWidget {
private boolean firstMarker;
private final OsmandMapTileView view;
private MapActivity map;
private MapMarkersHelper helper;
private float[] calculations = new float[1];
private int cachedMeters;
private int cachedMarkerColorIndex = -1;
private Boolean cachedNightMode = null;
public DistanceToMapMarkerControl(MapActivity map, boolean firstMarker) {
super(map);
this.map = map;
this.firstMarker = firstMarker;
this.view = map.getMapView();
helper = app.getMapMarkersHelper();
setText(null, null);
setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
click(view);
}
});
}
protected abstract void click(OsmandMapTileView view);
public abstract LatLon getLatLon();
@Override
public boolean updateInfo(OsmandMapLayer.DrawSettings drawSettings) {
MapMarkersHelper.MapMarker marker = getMarker();
if (marker == null
|| app.getRoutingHelper().isRoutePlanningMode()
|| app.getRoutingHelper().isFollowingMode()) {
cachedMeters = 0;
setText(null, null);
return false;
}
boolean res = false;
int d = getDistance();
if (isUpdateNeeded() || cachedMeters != d) {
cachedMeters = d;
String ds = OsmAndFormatter.getFormattedDistance(cachedMeters, app);
int ls = ds.lastIndexOf(' ');
if (ls == -1) {
setText(ds, null);
} else {
setText(ds.substring(0, ls), ds.substring(ls + 1));
}
res = true;
}
if (marker.colorIndex != -1) {
if (marker.colorIndex != cachedMarkerColorIndex
|| cachedNightMode == null || cachedNightMode != isNight()) {
setImageDrawable(app.getUIUtilities()
.getLayeredIcon(isNight() ? R.drawable.widget_marker_night : R.drawable.widget_marker_day,
R.drawable.widget_marker_triangle, 0,
MapMarkersHelper.MapMarker.getColorId(marker.colorIndex)));
cachedMarkerColorIndex = marker.colorIndex;
cachedNightMode = isNight();
res = true;
}
}
return res;
}
@Override
public boolean isMetricSystemDepended() {
return true;
}
public LatLon getPointToNavigate() {
MapMarkersHelper.MapMarker marker = getMarker();
if (marker != null) {
return marker.point;
}
return null;
}
private MapMarkersHelper.MapMarker getMarker() {
List<MapMarkersHelper.MapMarker> markers = helper.getMapMarkers();
if (firstMarker) {
if (markers.size() > 0) {
return markers.get(0);
}
} else {
if (markers.size() > 1) {
return markers.get(1);
}
}
return null;
}
public int getDistance() {
int d = 0;
LatLon l = getPointToNavigate();
if (l != null) {
LatLon loc = getLatLon();
if (loc == null) {
Location.distanceBetween(view.getLatitude(), view.getLongitude(), l.getLatitude(), l.getLongitude(), calculations);
} else {
Location.distanceBetween(loc.getLatitude(), loc.getLongitude(), l.getLatitude(), l.getLongitude(), calculations);
}
d = (int) calculations[0];
}
return d;
}
}
}

View file

@ -0,0 +1,223 @@
package net.osmand.plus.server.map;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.text.TextUtils;
import gnu.trove.set.hash.TIntHashSet;
import net.osmand.data.LatLon;
import net.osmand.data.RotatedTileBox;
import net.osmand.plus.R;
import net.osmand.plus.views.OsmandMapLayer;
import net.osmand.plus.views.OsmandMapTileView;
import java.util.*;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.Paint.Style;
import android.text.TextUtils;
import net.osmand.data.LatLon;
import net.osmand.data.RotatedTileBox;
import java.util.Collection;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeMap;
import gnu.trove.set.hash.TIntHashSet;
import net.osmand.plus.R;
import net.osmand.plus.views.OsmandMapLayer;
import net.osmand.plus.views.OsmandMapTileView;
public class MapTextMiniLayer extends OsmandMapLayer {
private static final int TEXT_WRAP = 15;
private static final int TEXT_LINES = 3;
private static final int TEXT_SIZE = 13;
private Map<OsmandMapLayer, Collection<?>> textObjects = new LinkedHashMap<>();
private Paint paintTextIcon;
private OsmandMapTileView view;
public interface MapTextProvider<T> {
LatLon getTextLocation(T o);
int getTextShift(T o, RotatedTileBox rb);
String getText(T o);
boolean isTextVisible();
boolean isFakeBoldText();
}
public void putData(OsmandMapLayer ml, Collection<?> objects) {
if (objects == null || objects.isEmpty()) {
textObjects.remove(ml);
} else {
if (ml instanceof net.osmand.plus.views.layers.MapTextLayer.MapTextProvider) {
textObjects.put(ml, objects);
} else {
throw new IllegalArgumentException();
}
}
}
@SuppressWarnings("unchecked")
@Override
public void onPrepareBufferImage(Canvas canvas, RotatedTileBox tileBox, DrawSettings settings) {
TIntHashSet set = new TIntHashSet();
for (OsmandMapLayer l : textObjects.keySet()) {
net.osmand.plus.views.layers.MapTextLayer.MapTextProvider provider = (net.osmand.plus.views.layers.MapTextLayer.MapTextProvider) l;
if (!view.isLayerVisible(l) || !provider.isTextVisible()) {
continue;
}
updateTextSize();
paintTextIcon.setFakeBoldText(provider.isFakeBoldText());
for (Object o : textObjects.get(l)) {
LatLon loc = provider.getTextLocation(o);
String name = provider.getText(o);
if (loc == null || TextUtils.isEmpty(name)) {
continue;
}
int x = (int) tileBox.getPixXFromLatLon(loc.getLatitude(), loc.getLongitude());
int y = (int) tileBox.getPixYFromLatLon(loc.getLatitude(), loc.getLongitude());
int tx = tileBox.getPixXFromLonNoRot(loc.getLongitude());
int ty = tileBox.getPixYFromLatNoRot(loc.getLatitude());
int lines = 0;
while (lines < TEXT_LINES) {
if (set.contains(division(tx, ty, 0, lines)) || set.contains(division(tx, ty, -1, lines))
|| set.contains(division(tx, ty, +1, lines))) {
break;
}
lines++;
}
if (lines != 0) {
int r = provider.getTextShift(o, tileBox);
drawWrappedText(canvas, name, paintTextIcon.getTextSize(), x,
y + r + 2 + paintTextIcon.getTextSize() / 2, lines);
while (lines > 0) {
set.add(division(tx, ty, 1, lines - 1));
set.add(division(tx, ty, -1, lines - 1));
set.add(division(tx, ty, 0, lines - 1));
lines--;
}
}
}
}
}
private int division(int x, int y, int sx, int sy) {
// make numbers positive
return ((((x + 10000) >> 4) + sx) << 16) | (((y + 10000) >> 4) + sy);
}
private void drawWrappedText(Canvas cv, String text, float textSize, float x, float y, int lines) {
boolean nightMode = view.getApplication().getDaynightHelper().isNightMode();
if (text.length() > TEXT_WRAP) {
int start = 0;
int end = text.length();
int lastSpace = -1;
int line = 0;
int pos = 0;
int limit = 0;
while (pos < end && (line < lines)) {
lastSpace = -1;
limit += TEXT_WRAP;
while (pos < limit && pos < end) {
if (Character.isWhitespace(text.charAt(pos))) {
lastSpace = pos;
}
pos++;
}
if (lastSpace == -1 || (pos == end)) {
drawShadowText(cv, text.substring(start, pos), x, y + line * (textSize + 2), nightMode);
start = pos;
} else {
String subtext = text.substring(start, lastSpace);
if (line + 1 == lines) {
subtext += "..";
}
drawShadowText(cv, subtext, x, y + line * (textSize + 2), nightMode);
start = lastSpace + 1;
limit += (start - pos) - 1;
}
line++;
}
} else {
drawShadowText(cv, text, x, y, nightMode);
}
}
private void drawShadowText(Canvas cv, String text, float centerX, float centerY, boolean nightMode) {
Resources r = view.getApplication().getResources();
paintTextIcon.setStyle(Paint.Style.STROKE);
paintTextIcon.setColor(nightMode
? r.getColor(R.color.widgettext_shadow_night)
: r.getColor(R.color.widgettext_shadow_day));
paintTextIcon.setStrokeWidth(2);
cv.drawText(text, centerX, centerY, paintTextIcon);
// reset
paintTextIcon.setStrokeWidth(2);
paintTextIcon.setStyle(Paint.Style.FILL);
paintTextIcon.setColor(nightMode
? r.getColor(R.color.widgettext_night)
: r.getColor(R.color.widgettext_day));
cv.drawText(text, centerX, centerY, paintTextIcon);
}
@Override
public void initLayer(OsmandMapTileView v) {
this.view = v;
paintTextIcon = new Paint();
updateTextSize();
paintTextIcon.setTextAlign(Paint.Align.CENTER);
paintTextIcon.setAntiAlias(true);
Map<OsmandMapLayer, Collection<?>> textObjectsLoc = new TreeMap<>(new Comparator<OsmandMapLayer>() {
@Override
public int compare(OsmandMapLayer lhs, OsmandMapLayer rhs) {
if (view != null) {
float z1 = view.getZorder(lhs);
float z2 = view.getZorder(rhs);
return Float.compare(z1, z2);
}
return 0;
}
});
textObjectsLoc.putAll(this.textObjects);
this.textObjects = textObjectsLoc;
}
@Override
public void onDraw(Canvas canvas, RotatedTileBox tileBox, DrawSettings settings) {
}
@Override
public void destroyLayer() {
}
@Override
public boolean drawInScreenPixels() {
return true;
}
private void updateTextSize() {
float scale = view.getApplication().getSettings().TEXT_SCALE.get();
float textSize = scale * TEXT_SIZE * view.getDensity();
if (paintTextIcon.getTextSize() != textSize) {
paintTextIcon.setTextSize(textSize);
}
}
}

View file

@ -0,0 +1,276 @@
package net.osmand.plus.server.map;
import android.annotation.SuppressLint;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Build;
import android.widget.Toast;
import net.osmand.data.QuadRect;
import net.osmand.data.RotatedTileBox;
import net.osmand.map.ITileSource;
import net.osmand.map.TileSourceManager;
import net.osmand.map.TileSourceManager.TileSourceTemplate;
import net.osmand.plus.OsmandPlugin;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.plus.R;
import net.osmand.plus.mapillary.MapillaryPlugin;
import net.osmand.plus.rastermaps.OsmandRasterMapsPlugin;
import net.osmand.plus.resources.ResourceManager;
import net.osmand.plus.views.BaseMapLayer;
import net.osmand.plus.views.MapTileAdapter;
import net.osmand.plus.views.OsmandMapTileView;
import net.osmand.plus.views.YandexTrafficAdapter;
import net.osmand.util.MapUtils;
public class MapTileMiniLayer extends OsmandMapMiniLayer {
protected static final int emptyTileDivisor = 16;
public static final int OVERZOOM_IN = 2;
protected final boolean mainMap;
protected ITileSource map = null;
protected Paint paintBitmap;
protected RectF bitmapToDraw = new RectF();
protected Rect bitmapToZoom = new Rect();
protected ResourceManager resourceManager;
protected OsmandSettings settings;
private boolean visible = true;
private boolean useSampling;
public MapTileMiniLayer(boolean mainMap) {
this.mainMap = mainMap;
}
@Override
public boolean drawInScreenPixels() {
return false;
}
@Override
public void initLayer(OsmandMapTileMiniView view) {
settings = view.getSettings();
resourceManager = view.getApplication().getResourceManager();
useSampling = Build.VERSION.SDK_INT < 28;
paintBitmap = new Paint();
paintBitmap.setFilterBitmap(true);
}
public void setAlpha(int alpha) {
if (paintBitmap != null) {
paintBitmap.setAlpha(alpha);
}
}
public void setMapTileAdapter(MapTileAdapter mapTileAdapter) {
}
public void setMapForMapTileAdapter(ITileSource map, MapTileAdapter mapTileAdapter) {
}
public void setMap(ITileSource map) {
MapTileAdapter target = null;
if (map instanceof TileSourceTemplate) {
if (TileSourceManager.RULE_YANDEX_TRAFFIC.equals(((TileSourceTemplate) map).getRule())) {
map = null;
target = new YandexTrafficAdapter();
}
}
this.map = map;
setMapTileAdapter(target);
}
public MapTileAdapter getMapTileAdapter() {
return null;
}
@SuppressLint("WrongCall")
@Override
public void onPrepareBufferImage(Canvas canvas, RotatedTileBox tileBox,
DrawSettings drawSettings) {
drawTileMap(canvas, tileBox);
}
@Override
public void onDraw(Canvas canvas, RotatedTileBox tileBox, DrawSettings drawSettings) {
}
public void drawTileMap(Canvas canvas, RotatedTileBox tileBox) {
ITileSource map = this.map;
if (map == null) {
return;
}
ResourceManager mgr = resourceManager;
int nzoom = tileBox.getZoom();
final QuadRect tilesRect = tileBox.getTileBounds();
// recalculate for ellipsoid coordinates
float ellipticTileCorrection = 0;
if (map.isEllipticYTile()) {
ellipticTileCorrection = (float) (MapUtils.getTileEllipsoidNumberY(nzoom, tileBox.getLatitude()) - tileBox.getCenterTileY());
}
int left = (int) Math.floor(tilesRect.left);
int top = (int) Math.floor(tilesRect.top + ellipticTileCorrection);
int width = (int) Math.ceil(tilesRect.right - left);
int height = (int) Math.ceil(tilesRect.bottom + ellipticTileCorrection - top);
boolean useInternet = (OsmandPlugin.getEnabledPlugin(OsmandRasterMapsPlugin.class) != null || OsmandPlugin.getEnabledPlugin(MapillaryPlugin.class) != null)
&& settings.isInternetConnectionAvailable() && map.couldBeDownloadedFromInternet();
int maxLevel = map.getMaximumZoomSupported();
int tileSize = map.getTileSize();
boolean oneTileShown = false;
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
int leftPlusI = left + i;
int topPlusJ = top + j;
int x1 = tileBox.getPixXFromTileXNoRot(leftPlusI);
int x2 = tileBox.getPixXFromTileXNoRot(leftPlusI + 1);
int y1 = tileBox.getPixYFromTileYNoRot(topPlusJ - ellipticTileCorrection);
int y2 = tileBox.getPixYFromTileYNoRot(topPlusJ + 1 - ellipticTileCorrection);
bitmapToDraw.set(x1, y1, x2 , y2);
final int tileX = leftPlusI;
final int tileY = topPlusJ;
Bitmap bmp = null;
String ordImgTile = mgr.calculateTileId(map, tileX, tileY, nzoom);
// asking tile image async
boolean imgExist = mgr.tileExistOnFileSystem(ordImgTile, map, tileX, tileY, nzoom);
boolean originalWillBeLoaded = useInternet && nzoom <= maxLevel;
if (imgExist || originalWillBeLoaded) {
bmp = mgr.getBitmapTilesCache().getTileForMapAsync(ordImgTile, map, tileX, tileY, nzoom, useInternet);
}
if (bmp == null) {
int div = 1;
boolean readFromCache = originalWillBeLoaded || imgExist;
boolean loadIfExists = !readFromCache;
// asking if there is small version of the map (in cache)
int allowedScale = Math.min(OVERZOOM_IN + Math.max(0, nzoom - map.getMaximumZoomSupported()), 8);
int kzoom = 1;
for (; kzoom <= allowedScale; kzoom++) {
div *= 2;
String imgTileId = mgr.calculateTileId(map, tileX / div, tileY / div, nzoom - kzoom);
if (readFromCache) {
bmp = mgr.getBitmapTilesCache().get(imgTileId);
if (bmp != null) {
break;
}
} else if (loadIfExists) {
if (mgr.tileExistOnFileSystem(imgTileId, map, tileX / div, tileY / div, nzoom - kzoom)
|| (useInternet && nzoom - kzoom <= maxLevel)) {
bmp = mgr.getBitmapTilesCache().getTileForMapAsync(imgTileId, map, tileX / div, tileY / div, nzoom
- kzoom, useInternet);
break;
}
}
}
if (bmp != null) {
if (bmp.getWidth() != tileSize && bmp.getWidth() > 0) {
tileSize = bmp.getWidth();
}
int xZoom = (tileX % div) * tileSize / div;
int yZoom = (tileY % div) * tileSize / div;
// nice scale
boolean useSampling = this.useSampling && kzoom > 3;
bitmapToZoom.set(Math.max(xZoom, 0), Math.max(yZoom, 0),
Math.min(xZoom + tileSize / div, tileSize),
Math.min(yZoom + tileSize / div, tileSize));
if (!useSampling) {
canvas.drawBitmap(bmp, bitmapToZoom, bitmapToDraw, paintBitmap);
} else {
int margin = 1;
int scaledSize = tileSize / div;
float innerMargin = 0.5f;
RectF src = new RectF(0, 0, scaledSize, scaledSize);
if (bitmapToZoom.left >= margin) {
bitmapToZoom.left -= margin;
src.left = innerMargin;
src.right += margin;
}
if (bitmapToZoom.top >= margin) {
bitmapToZoom.top -= margin;
src.top = innerMargin;
src.bottom += margin;
}
if (bitmapToZoom.right + margin <= tileSize) {
bitmapToZoom.right += margin;
src.right += margin - innerMargin;
}
if (bitmapToZoom.bottom + margin <= tileSize) {
bitmapToZoom.bottom += margin;
src.bottom += margin - innerMargin;
}
Matrix m = new Matrix();
RectF dest = new RectF(0, 0, tileSize, tileSize);
m.setRectToRect(src, dest, Matrix.ScaleToFit.FILL);
Bitmap sampled = Bitmap.createBitmap(bmp,
bitmapToZoom.left, bitmapToZoom.top,
bitmapToZoom.width(), bitmapToZoom.height(), m, true);
bitmapToZoom.set(0, 0, tileSize, tileSize);
// very expensive that's why put in the cache
mgr.getBitmapTilesCache().put(ordImgTile, sampled);
canvas.drawBitmap(sampled, bitmapToZoom, bitmapToDraw, paintBitmap);
}
}
} else {
bitmapToZoom.set(0, 0, tileSize, tileSize);
canvas.drawBitmap(bmp, bitmapToZoom, bitmapToDraw, paintBitmap);
}
if (bmp != null) {
oneTileShown = true;
}
}
}
}
public int getMaximumShownMapZoom() {
return map == null ? 20 : map.getMaximumZoomSupported() + OVERZOOM_IN;
}
public int getMinimumShownMapZoom() {
return map == null ? 1 : map.getMinimumZoomSupported();
}
@Override
public void destroyLayer() {
setMapTileAdapter(null);
}
public boolean isVisible() {
return visible;
}
public void setVisible(boolean visible) {
this.visible = visible;
}
public ITileSource getMap() {
return map;
}
}

View file

@ -0,0 +1,232 @@
package net.osmand.plus.server.map;
import android.graphics.*;
import net.osmand.core.android.MapRendererView;
import net.osmand.core.jni.MapLayerConfiguration;
import net.osmand.core.jni.PointI;
import net.osmand.data.LatLon;
import net.osmand.data.QuadPointDouble;
import net.osmand.data.RotatedTileBox;
import net.osmand.plus.render.MapRenderRepositories;
import net.osmand.plus.resources.ResourceManager;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.plus.views.*;
import net.osmand.plus.views.corenative.NativeCoreContext;
import net.osmand.util.Algorithms;
import net.osmand.util.MapUtils;
import net.osmand.core.android.MapRendererView;
import net.osmand.core.android.TileSourceProxyProvider;
import net.osmand.core.jni.MapLayerConfiguration;
import net.osmand.core.jni.PointI;
import net.osmand.data.LatLon;
import net.osmand.data.QuadPointDouble;
import net.osmand.data.RotatedTileBox;
import net.osmand.map.ITileSource;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.plus.resources.ResourceManager;
import net.osmand.plus.views.BaseMapLayer;
import net.osmand.plus.views.MapTileLayer;
import net.osmand.plus.views.OsmandMapTileView;
import net.osmand.plus.views.corenative.NativeCoreContext;
import net.osmand.util.Algorithms;
import net.osmand.util.MapUtils;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.RectF;
public class MapVectorMiniLayer extends OsmandMapMiniLayer {
public static final int DEFAULT_MAX_ZOOM = 21;
public static final int DEFAULT_MIN_ZOOM = 1;
private int alpha = 255;
protected int warningToSwitchMapShown = 0;
public int getAlpha() {
return alpha;
}
private OsmandMapTileMiniView view;
private ResourceManager resourceManager;
private Paint paintImg;
private RectF destImage = new RectF();
private final MapTileMiniLayer tileLayer;
private boolean visible = false;
private boolean oldRender = false;
private String cachedUnderlay;
private Integer cachedMapTransparency;
private String cachedOverlay;
private Integer cachedOverlayTransparency;
public MapVectorMiniLayer(MapTileMiniLayer tileLayer, boolean oldRender) {
this.tileLayer = tileLayer;
this.oldRender = oldRender;
}
@Override
public void destroyLayer() {
}
@Override
public boolean drawInScreenPixels() {
return false;
}
@Override
public void initLayer(OsmandMapTileMiniView view) {
this.view = view;
resourceManager = view.getApplication().getResourceManager();
paintImg = new Paint();
paintImg.setFilterBitmap(true);
paintImg.setAlpha(getAlpha());
}
public boolean isVectorDataVisible() {
return visible && view.getZoom() >= view.getSettings().LEVEL_TO_SWITCH_VECTOR_RASTER.get();
}
public boolean isVisible() {
return visible;
}
public void setVisible(boolean visible) {
this.visible = visible;
if (!visible) {
resourceManager.getRenderer().clearCache();
}
}
@Override
public void onDraw(Canvas canvas, RotatedTileBox tilesRect, DrawSettings drawSettings) {
}
@Override
public void onPrepareBufferImage(Canvas canvas, RotatedTileBox tilesRect, DrawSettings drawSettings) {
// if (!visible) {
// return;
// }
// if (!isVectorDataVisible() && tileLayer != null) {
// tileLayer.drawTileMap(canvas, tilesRect);
// resourceManager.getRenderer().interruptLoadingMap();
// } else {
final MapRendererView mapRenderer = view.getMapRenderer();
if (mapRenderer != null && !oldRender) {
NativeCoreContext.getMapRendererContext().setNightMode(drawSettings.isNightMode());
OsmandSettings st = view.getApplication().getSettings();
/* TODO: Commented to avoid crash (looks like IMapTiledDataProvider.Request parameter does not pass correctly or cannot be resolved while calling obtainImage method)
if (!Algorithms.objectEquals(st.MAP_UNDERLAY.get(), cachedUnderlay)) {
cachedUnderlay = st.MAP_UNDERLAY.get();
ITileSource tileSource = st.getTileSourceByName(cachedUnderlay, false);
if (tileSource != null) {
TileSourceProxyProvider prov = new TileSourceProxyProvider(view.getApplication(), tileSource);
mapRenderer.setMapLayerProvider(-1, prov.instantiateProxy(true));
prov.swigReleaseOwnership();
// mapRenderer.setMapLayerProvider(-1,
// net.osmand.core.jni.OnlineTileSources.getBuiltIn().createProviderFor("Mapnik (OsmAnd)"));
} else {
mapRenderer.resetMapLayerProvider(-1);
}
}
*/
if (!Algorithms.objectEquals(st.MAP_TRANSPARENCY.get(), cachedMapTransparency)) {
cachedMapTransparency = st.MAP_TRANSPARENCY.get();
MapLayerConfiguration mapLayerConfiguration = new MapLayerConfiguration();
mapLayerConfiguration.setOpacityFactor(((float) cachedMapTransparency) / 255.0f);
mapRenderer.setMapLayerConfiguration(0, mapLayerConfiguration);
}
/* TODO: Commented to avoid crash (looks like IMapTiledDataProvider.Request parameter does not pass correctly or cannot be resolved while calling obtainImage method)
if (!Algorithms.objectEquals(st.MAP_OVERLAY.get(), cachedOverlay)) {
cachedOverlay = st.MAP_OVERLAY.get();
ITileSource tileSource = st.getTileSourceByName(cachedOverlay, false);
if (tileSource != null) {
TileSourceProxyProvider prov = new TileSourceProxyProvider(view.getApplication(), tileSource);
mapRenderer.setMapLayerProvider(1, prov.instantiateProxy(true));
prov.swigReleaseOwnership();
// mapRenderer.setMapLayerProvider(1,
// net.osmand.core.jni.OnlineTileSources.getBuiltIn().createProviderFor("Mapnik (OsmAnd)"));
} else {
mapRenderer.resetMapLayerProvider(1);
}
}
if (!Algorithms.objectEquals(st.MAP_OVERLAY_TRANSPARENCY.get(), cachedOverlayTransparency)) {
cachedOverlayTransparency = st.MAP_OVERLAY_TRANSPARENCY.get();
MapLayerConfiguration mapLayerConfiguration = new MapLayerConfiguration();
mapLayerConfiguration.setOpacityFactor(((float) cachedOverlayTransparency) / 255.0f);
mapRenderer.setMapLayerConfiguration(1, mapLayerConfiguration);
}
*/
// opengl renderer
LatLon ll = tilesRect.getLatLonFromPixel(tilesRect.getPixWidth() / 2, tilesRect.getPixHeight() / 2);
mapRenderer.setTarget(new PointI(MapUtils.get31TileNumberX(ll.getLongitude()), MapUtils.get31TileNumberY(ll
.getLatitude())));
mapRenderer.setAzimuth(-tilesRect.getRotate());
mapRenderer.setZoom((float) (tilesRect.getZoom() + tilesRect.getZoomAnimation() + tilesRect
.getZoomFloatPart()));
float zoomMagnifier = st.MAP_DENSITY.get();
mapRenderer.setVisualZoomShift(zoomMagnifier - 1.0f);
} else {
//if (!view.isZooming()) {
final OsmandMapLayer.DrawSettings drawSettings1 =
new OsmandMapLayer.DrawSettings(drawSettings.isNightMode(), true);
if (resourceManager.updateRenderedMapNeeded(tilesRect, drawSettings1)) {
// pixRect.set(-view.getWidth(), -view.getHeight() / 2, 2 * view.getWidth(), 3 *
// view.getHeight() / 2);
final RotatedTileBox copy = tilesRect.copy();
copy.increasePixelDimensions(copy.getPixWidth() / 3, copy.getPixHeight() / 4);
resourceManager.updateRendererMap(copy, null);
}
MapRenderRepositories renderer = resourceManager.getRenderer();
RotatedTileBox currentTileBlock = tilesRect;
resourceManager.getRenderer().loadMap(currentTileBlock, resourceManager.getMapTileDownloader());
drawRenderedMap(canvas, renderer.getBitmap(), renderer.getBitmapLocation(), tilesRect);
drawRenderedMap(canvas, renderer.getPrevBitmap(), renderer.getPrevBmpLocation(), tilesRect);
}
}
private boolean drawRenderedMap(Canvas canvas, Bitmap bmp, RotatedTileBox bmpLoc, RotatedTileBox currentViewport) {
boolean shown = false;
if (bmp != null && bmpLoc != null) {
float rot = -bmpLoc.getRotate();
canvas.rotate(rot, currentViewport.getCenterPixelX(), currentViewport.getCenterPixelY());
final RotatedTileBox calc = currentViewport.copy();
calc.setRotate(bmpLoc.getRotate());
QuadPointDouble lt = bmpLoc.getLeftTopTile(bmpLoc.getZoom());
QuadPointDouble rb = bmpLoc.getRightBottomTile(bmpLoc.getZoom());
final float x1 = calc.getPixXFromTile(lt.x, lt.y, bmpLoc.getZoom());
final float x2 = calc.getPixXFromTile(rb.x, rb.y, bmpLoc.getZoom());
final float y1 = calc.getPixYFromTile(lt.x, lt.y, bmpLoc.getZoom());
final float y2 = calc.getPixYFromTile(rb.x, rb.y, bmpLoc.getZoom());
// LatLon lt = bmpLoc.getLeftTopLatLon();
// LatLon rb = bmpLoc.getRightBottomLatLon();
// final float x1 = calc.getPixXFromLatLon(lt.getLatitude(), lt.getLongitude());
// final float x2 = calc.getPixXFromLatLon(rb.getLatitude(), rb.getLongitude());
// final float y1 = calc.getPixYFromLatLon(lt.getLatitude(), lt.getLongitude());
// final float y2 = calc.getPixYFromLatLon(rb.getLatitude(), rb.getLongitude());
destImage.set(x1, y1, x2, y2);
if (!bmp.isRecycled()) {
canvas.drawBitmap(bmp, null, destImage, paintImg);
shown = true;
}
canvas.rotate(-rot, currentViewport.getCenterPixelX(), currentViewport.getCenterPixelY());
}
return shown;
}
@Override
public boolean onLongPressEvent(PointF point, RotatedTileBox tileBox) {
return false;
}
@Override
public boolean onSingleTap(PointF point, RotatedTileBox tileBox) {
return false;
}
}

View file

@ -0,0 +1,35 @@
package net.osmand.plus.server.map;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import net.osmand.data.RotatedTileBox;
public class MyCustomLayer extends OsmandMapMiniLayer{
protected Paint paintBitmap;
@Override
public void initLayer(OsmandMapTileMiniView view) {
paintBitmap = new Paint();
paintBitmap.setFilterBitmap(true);
paintBitmap.setColor(Color.BLACK);
}
@Override
public void onDraw(Canvas canvas, RotatedTileBox tileBox, DrawSettings settings) {
//canvas.drawCircle(canvas.getWidth()/2,canvas.getHeight()/2,40,paintBitmap);
}
@Override
public void destroyLayer() {
}
@Override
public boolean drawInScreenPixels() {
return false;
}
}

View file

@ -0,0 +1,482 @@
package net.osmand.plus.server.map;
import android.content.Context;
import android.graphics.*;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.view.MotionEvent;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import net.osmand.binary.BinaryMapIndexReader;
import net.osmand.data.*;
import net.osmand.osm.PoiCategory;
import net.osmand.plus.ContextMenuAdapter;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.render.OsmandRenderer;
import net.osmand.plus.views.OsmandMapTileView;
import net.osmand.render.RenderingRuleSearchRequest;
import net.osmand.render.RenderingRulesStorage;
import net.osmand.util.MapUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
public abstract class OsmandMapMiniLayer {
protected List<LatLon> fullObjectsLatLon;
protected List<LatLon> smallObjectsLatLon;
public enum MapGestureType {
DOUBLE_TAP_ZOOM_IN,
DOUBLE_TAP_ZOOM_CHANGE,
TWO_POINTERS_ZOOM_OUT
}
public boolean isMapGestureAllowed(MapGestureType type) {
return true;
}
public abstract void initLayer(OsmandMapTileMiniView view);
public abstract void onDraw(Canvas canvas, RotatedTileBox tileBox, DrawSettings settings);
public void onPrepareBufferImage(Canvas canvas, RotatedTileBox tileBox, DrawSettings settings) {
}
public abstract void destroyLayer();
public void onRetainNonConfigurationInstance(Map<String, Object> map) {
}
public void populateObjectContextMenu(LatLon latLon, Object o, ContextMenuAdapter adapter, MapActivity mapActivity) {
}
public boolean onSingleTap(PointF point, RotatedTileBox tileBox) {
return false;
}
public boolean onLongPressEvent(PointF point, RotatedTileBox tileBox) {
return false;
}
public boolean onTouchEvent(MotionEvent event, RotatedTileBox tileBox) {
return false;
}
public <Params> void executeTaskInBackground(AsyncTask<Params, ?, ?> task, Params... params) {
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
}
public boolean isPresentInFullObjects(LatLon latLon) {
if (fullObjectsLatLon == null) {
return true;
} else if (latLon != null) {
return fullObjectsLatLon.contains(latLon);
}
return false;
}
public boolean isPresentInSmallObjects(LatLon latLon) {
if (smallObjectsLatLon != null && latLon != null) {
return smallObjectsLatLon.contains(latLon);
}
return false;
}
/**
* This method returns whether canvas should be rotated as
* map rotated before {@link #onDraw(android.graphics.Canvas, net.osmand.data.RotatedTileBox, DrawSettings)}.
* If the layer draws simply layer over screen (not over map)
* it should return true.
*/
public abstract boolean drawInScreenPixels();
public static class DrawSettings {
private final boolean nightMode;
private final boolean updateVectorRendering;
public DrawSettings(boolean nightMode) {
this(nightMode, false);
}
public DrawSettings(boolean nightMode, boolean updateVectorRendering) {
this.nightMode = nightMode;
this.updateVectorRendering = updateVectorRendering;
}
public boolean isUpdateVectorRendering() {
return updateVectorRendering;
}
public boolean isNightMode() {
return nightMode;
}
}
@NonNull
public static QuadTree<QuadRect> initBoundIntersections(RotatedTileBox tileBox) {
QuadRect bounds = new QuadRect(0, 0, tileBox.getPixWidth(), tileBox.getPixHeight());
bounds.inset(-bounds.width() / 4, -bounds.height() / 4);
return new QuadTree<>(bounds, 4, 0.6f);
}
public static boolean intersects(QuadTree<QuadRect> boundIntersections, float x, float y, float width, float height) {
List<QuadRect> result = new ArrayList<>();
QuadRect visibleRect = calculateRect(x, y, width, height);
boundIntersections.queryInBox(new QuadRect(visibleRect.left, visibleRect.top, visibleRect.right, visibleRect.bottom), result);
for (QuadRect r : result) {
if (QuadRect.intersects(r, visibleRect)) {
return true;
}
}
boundIntersections.insert(visibleRect,
new QuadRect(visibleRect.left, visibleRect.top, visibleRect.right, visibleRect.bottom));
return false;
}
public QuadRect getCorrectedQuadRect(QuadRect latlonRect) {
double topLatitude = latlonRect.top;
double leftLongitude = latlonRect.left;
double bottomLatitude = latlonRect.bottom;
double rightLongitude = latlonRect.right;
// double lat = 0;
// double lon = 0;
// this is buggy lat/lon should be 0 but in that case
// it needs to be fixed in case there is no route points in the view bbox
double lat = topLatitude - bottomLatitude + 0.1;
double lon = rightLongitude - leftLongitude + 0.1;
return new QuadRect(leftLongitude - lon, topLatitude + lat, rightLongitude + lon, bottomLatitude - lat);
}
public static QuadRect calculateRect(float x, float y, float width, float height) {
QuadRect rf;
double left = x - width / 2.0d;
double top = y - height / 2.0d;
double right = left + width;
double bottom = top + height;
rf = new QuadRect(left, top, right, bottom);
return rf;
}
public Amenity findAmenity(OsmandApplication app, long id, List<String> names, LatLon latLon, int radius) {
QuadRect rect = MapUtils.calculateLatLonBbox(latLon.getLatitude(), latLon.getLongitude(), radius);
List<Amenity> amenities = app.getResourceManager().searchAmenities(
new BinaryMapIndexReader.SearchPoiTypeFilter() {
@Override
public boolean accept(PoiCategory type, String subcategory) {
return true;
}
@Override
public boolean isEmpty() {
return false;
}
}, rect.top, rect.left, rect.bottom, rect.right, -1, null);
Amenity res = null;
for (Amenity amenity : amenities) {
Long amenityId = amenity.getId() >> 1;
if (amenityId == id && !amenity.isClosed()) {
res = amenity;
break;
}
}
if (res == null && names != null && names.size() > 0) {
for (Amenity amenity : amenities) {
for (String name : names) {
if (name.equals(amenity.getName()) && !amenity.isClosed()) {
res = amenity;
break;
}
}
if (res != null) {
break;
}
}
}
return res;
}
public int getDefaultRadiusPoi(RotatedTileBox tb) {
int r;
final double zoom = tb.getZoom();
if (zoom <= 15) {
r = 10;
} else if (zoom <= 16) {
r = 14;
} else if (zoom <= 17) {
r = 16;
} else {
r = 18;
}
return (int) (r * tb.getDensity());
}
protected int getIconSize(Context ctx) {
return ctx.getResources().getDimensionPixelSize(R.dimen.favorites_icon_outline_size);
}
public Rect getIconDestinationRect(float x, float y, int width, int height, float scale) {
int scaledWidth = width;
int scaledHeight = height;
if (scale != 1.0f) {
scaledWidth = (int) (width * scale);
scaledHeight = (int) (height * scale);
}
Rect rect = new Rect(0, 0, scaledWidth, scaledHeight);
rect.offset((int) x - scaledWidth / 2, (int) y - scaledHeight / 2);
return rect;
}
public int getScaledTouchRadius(OsmandApplication app, int radiusPoi) {
float textScale = app.getSettings().TEXT_SCALE.get();
if (textScale < 1.0f) {
textScale = 1.0f;
}
return (int) textScale * radiusPoi;
}
public void setMapButtonIcon(ImageView imageView, Drawable icon) {
int btnSizePx = imageView.getLayoutParams().height;
int iconSizePx = imageView.getContext().getResources().getDimensionPixelSize(R.dimen.map_widget_icon);
int iconPadding = (btnSizePx - iconSizePx) / 2;
imageView.setPadding(iconPadding, iconPadding, iconPadding, iconPadding);
imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
imageView.setImageDrawable(icon);
}
public abstract class MapLayerData<T> {
public int ZOOM_THRESHOLD = 1;
public RotatedTileBox queriedBox;
protected T results;
protected Task currentTask;
protected Task pendingTask;
public RotatedTileBox getQueriedBox() {
return queriedBox;
}
public T getResults() {
return results;
}
public boolean queriedBoxContains(final RotatedTileBox queriedData, final RotatedTileBox newBox) {
return queriedData != null && queriedData.containsTileBox(newBox) && Math.abs(queriedData.getZoom() - newBox.getZoom()) <= ZOOM_THRESHOLD;
}
public void queryNewData(RotatedTileBox tileBox) {
if (!queriedBoxContains(queriedBox, tileBox)) {
Task ct = currentTask;
if (ct == null || !queriedBoxContains(ct.getDataBox(), tileBox)) {
RotatedTileBox original = tileBox.copy();
RotatedTileBox extended = original.copy();
extended.increasePixelDimensions(tileBox.getPixWidth() / 2, tileBox.getPixHeight() / 2);
Task task = new Task(original, extended);
if (currentTask == null) {
executeTaskInBackground(task);
} else {
pendingTask = task;
}
}
}
}
public void layerOnPreExecute() {
}
public void layerOnPostExecute() {
}
public boolean isInterrupted() {
return pendingTask != null;
}
protected abstract T calculateResult(RotatedTileBox tileBox);
public class Task extends AsyncTask<Object, Object, T> {
private RotatedTileBox dataBox;
private RotatedTileBox requestedBox;
public Task(RotatedTileBox requestedBox, RotatedTileBox dataBox) {
this.requestedBox = requestedBox;
this.dataBox = dataBox;
}
public RotatedTileBox getOriginalBox() {
return requestedBox;
}
public RotatedTileBox getDataBox() {
return dataBox;
}
@Override
protected T doInBackground(Object... params) {
if (queriedBoxContains(queriedBox, dataBox)) {
return null;
}
return calculateResult(dataBox);
}
@Override
protected void onPreExecute() {
currentTask = this;
layerOnPreExecute();
}
@Override
protected void onPostExecute(T result) {
if (result != null) {
queriedBox = dataBox;
results = result;
}
currentTask = null;
if (pendingTask != null) {
executeTaskInBackground(pendingTask);
pendingTask = null;
} else {
layerOnPostExecute();
}
}
}
public void clearCache() {
results = null;
queriedBox = null;
}
}
public static class RenderingLineAttributes {
protected int cachedHash;
public Paint paint;
public Paint customColorPaint;
public int customColor = 0;
public int defaultWidth = 0;
public int defaultColor = 0;
public boolean isPaint2;
public Paint paint2;
public int defaultWidth2 = 0;
public boolean isPaint3;
public Paint paint3;
public int defaultWidth3 = 0;
public Paint shadowPaint;
public boolean isShadowPaint;
public int defaultShadowWidthExtent = 2;
public Paint paint_1;
public boolean isPaint_1;
public int defaultWidth_1 = 0;
private String renderingAttribute;
public RenderingLineAttributes(String renderingAttribute) {
this.renderingAttribute = renderingAttribute;
paint = initPaint();
customColorPaint = new Paint(paint);
paint2 = initPaint();
paint3 = initPaint();
paint_1 = initPaint();
shadowPaint = initPaint();
}
private Paint initPaint() {
Paint paint = new Paint();
paint.setStyle(Paint.Style.STROKE);
paint.setAntiAlias(true);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStrokeJoin(Paint.Join.ROUND);
return paint;
}
public boolean updatePaints(OsmandApplication app, DrawSettings settings, RotatedTileBox tileBox) {
OsmandRenderer renderer = app.getResourceManager().getRenderer().getRenderer();
RenderingRulesStorage rrs = app.getRendererRegistry().getCurrentSelectedRenderer();
final boolean isNight = settings != null && settings.isNightMode();
int hsh = calculateHash(rrs, isNight, tileBox.getDensity());
if (hsh != cachedHash) {
cachedHash = hsh;
if (rrs != null) {
RenderingRuleSearchRequest req = new RenderingRuleSearchRequest(rrs);
req.setBooleanFilter(rrs.PROPS.R_NIGHT_MODE, isNight);
if (req.searchRenderingAttribute(renderingAttribute)) {
OsmandRenderer.RenderingContext rc = new OsmandRenderer.RenderingContext(app);
rc.setDensityValue((float) tileBox.getDensity());
// cachedColor = req.getIntPropertyValue(rrs.PROPS.R_COLOR);
renderer.updatePaint(req, paint, 0, false, rc);
isPaint2 = renderer.updatePaint(req, paint2, 1, false, rc);
if (paint2.getStrokeWidth() == 0 && defaultWidth2 != 0) {
paint2.setStrokeWidth(defaultWidth2);
}
isPaint3 = renderer.updatePaint(req, paint3, 2, false, rc);
if (paint3.getStrokeWidth() == 0 && defaultWidth3 != 0) {
paint3.setStrokeWidth(defaultWidth3);
}
isPaint_1 = renderer.updatePaint(req, paint_1, -1, false, rc);
if (paint_1.getStrokeWidth() == 0 && defaultWidth_1 != 0) {
paint_1.setStrokeWidth(defaultWidth_1);
}
isShadowPaint = req.isSpecified(rrs.PROPS.R_SHADOW_RADIUS);
if (isShadowPaint) {
ColorFilter cf = new PorterDuffColorFilter(
req.getIntPropertyValue(rrs.PROPS.R_SHADOW_COLOR), PorterDuff.Mode.SRC_IN);
shadowPaint.setColorFilter(cf);
shadowPaint.setStrokeWidth(paint.getStrokeWidth() + defaultShadowWidthExtent
* rc.getComplexValue(req, rrs.PROPS.R_SHADOW_RADIUS));
}
} else {
System.err.println("Rendering attribute route is not found !");
}
updateDefaultColor(paint, defaultColor);
if (paint.getStrokeWidth() == 0 && defaultWidth != 0) {
paint.setStrokeWidth(defaultWidth);
}
customColorPaint = new Paint(paint);
}
return true;
}
return false;
}
private void updateDefaultColor(Paint paint, int defaultColor) {
if ((paint.getColor() == 0 || paint.getColor() == Color.BLACK) && defaultColor != 0) {
paint.setColor(defaultColor);
}
}
private int calculateHash(Object... o) {
return Arrays.hashCode(o);
}
public void drawPath(Canvas canvas, Path path) {
if (isPaint_1) {
canvas.drawPath(path, paint_1);
}
if (isShadowPaint) {
canvas.drawPath(path, shadowPaint);
}
if (customColor != 0) {
customColorPaint.setColor(customColor);
canvas.drawPath(path, customColorPaint);
} else {
canvas.drawPath(path, paint);
}
if (isPaint2) {
canvas.drawPath(path, paint2);
}
if (isPaint3) {
canvas.drawPath(path, paint3);
}
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,471 @@
package net.osmand.plus.server.map;
import android.app.Dialog;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.PointF;
import android.graphics.drawable.Drawable;
import android.text.util.Linkify;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;
import androidx.appcompat.widget.Toolbar;
import androidx.core.content.ContextCompat;
import net.osmand.AndroidUtils;
import net.osmand.PlatformUtil;
import net.osmand.ResultMatcher;
import net.osmand.ValueHolder;
import net.osmand.data.*;
import net.osmand.osm.PoiType;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.OsmandPlugin;
import net.osmand.plus.R;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.base.PointImageDrawable;
import net.osmand.plus.helpers.WaypointHelper;
import net.osmand.plus.poi.PoiUIFilter;
import net.osmand.plus.render.RenderingIcons;
import net.osmand.plus.routing.IRouteInformationListener;
import net.osmand.plus.routing.RoutingHelper;
import net.osmand.plus.views.OsmandMapLayer;
import net.osmand.plus.views.OsmandMapTileView;
import net.osmand.plus.views.layers.ContextMenuLayer;
import net.osmand.plus.views.layers.MapTextLayer;
import net.osmand.util.Algorithms;
import java.util.*;
import static net.osmand.AndroidUtils.dpToPx;
import android.app.Dialog;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.PointF;
import android.graphics.drawable.Drawable;
import android.text.util.Linkify;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.ScrollView;
import android.widget.TextView;
import androidx.appcompat.widget.Toolbar;
import androidx.core.content.ContextCompat;
import net.osmand.AndroidUtils;
import net.osmand.PlatformUtil;
import net.osmand.ResultMatcher;
import net.osmand.ValueHolder;
import net.osmand.data.Amenity;
import net.osmand.data.LatLon;
import net.osmand.data.PointDescription;
import net.osmand.data.QuadRect;
import net.osmand.data.QuadTree;
import net.osmand.data.RotatedTileBox;
import net.osmand.osm.PoiType;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.OsmandPlugin;
import net.osmand.plus.R;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.base.PointImageDrawable;
import net.osmand.plus.helpers.WaypointHelper;
import net.osmand.plus.poi.PoiUIFilter;
import net.osmand.plus.render.RenderingIcons;
import net.osmand.plus.routing.IRouteInformationListener;
import net.osmand.plus.routing.RoutingHelper;
import net.osmand.plus.views.OsmandMapLayer;
import net.osmand.plus.views.OsmandMapTileView;
import net.osmand.plus.views.layers.MapTextLayer.MapTextProvider;
import net.osmand.util.Algorithms;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import static net.osmand.AndroidUtils.dpToPx;
public class POIMapLayerMini extends OsmandMapMiniLayer implements ContextMenuLayer.IContextMenuProvider,
MapTextLayer.MapTextProvider<Amenity>, IRouteInformationListener {
private static final int startZoom = 9;
public static final org.apache.commons.logging.Log log = PlatformUtil.getLog(net.osmand.plus.views.layers.POIMapLayer.class);
private OsmandMapTileMiniView view;
private RoutingHelper routingHelper;
private Set<PoiUIFilter> filters = new TreeSet<>();
private MapTextLayer mapTextLayer;
/// cache for displayed POI
// Work with cache (for map copied from AmenityIndexRepositoryOdb)
private MapLayerData<List<Amenity>> data;
private OsmandApplication app;
public POIMapLayerMini(final OsmandApplication app) {
routingHelper = app.getRoutingHelper();
routingHelper.addListener(this);
this.app = app;
data = new OsmandMapMiniLayer.MapLayerData<List<Amenity>>() {
Set<PoiUIFilter> calculatedFilters;
{
ZOOM_THRESHOLD = 0;
}
@Override
public boolean isInterrupted() {
return super.isInterrupted();
}
@Override
public void layerOnPreExecute() {
calculatedFilters = new TreeSet<>(filters);
}
@Override
public void layerOnPostExecute() {
}
@Override
protected List<Amenity> calculateResult(RotatedTileBox tileBox) {
QuadRect latLonBounds = tileBox.getLatLonBounds();
if (calculatedFilters.isEmpty() || latLonBounds == null) {
return new ArrayList<>();
}
int z = (int) Math.floor(tileBox.getZoom() + Math.log(view.getSettings().MAP_DENSITY.get()) / Math.log(2));
List<Amenity> res = new ArrayList<>();
PoiUIFilter.combineStandardPoiFilters(calculatedFilters, app);
for (PoiUIFilter filter : calculatedFilters) {
res.addAll(filter.searchAmenities(latLonBounds.top, latLonBounds.left,
latLonBounds.bottom, latLonBounds.right, z, new ResultMatcher<Amenity>() {
@Override
public boolean publish(Amenity object) {
return true;
}
@Override
public boolean isCancelled() {
return isInterrupted();
}
}));
}
Collections.sort(res, new Comparator<Amenity>() {
@Override
public int compare(Amenity lhs, Amenity rhs) {
return lhs.getId() < rhs.getId() ? -1 : (lhs.getId().longValue() == rhs.getId().longValue() ? 0 : 1);
}
});
return res;
}
};
}
public void getAmenityFromPoint(RotatedTileBox tb, PointF point, List<? super Amenity> am) {
List<Amenity> objects = data.getResults();
if (objects != null) {
int ex = (int) point.x;
int ey = (int) point.y;
int compare = getScaledTouchRadius(view.getApplication(), getRadiusPoi(tb));
int radius = compare * 3 / 2;
try {
for (int i = 0; i < objects.size(); i++) {
Amenity n = objects.get(i);
int x = (int) tb.getPixXFromLatLon(n.getLocation().getLatitude(), n.getLocation().getLongitude());
int y = (int) tb.getPixYFromLatLon(n.getLocation().getLatitude(), n.getLocation().getLongitude());
if (Math.abs(x - ex) <= compare && Math.abs(y - ey) <= compare) {
compare = radius;
am.add(n);
}
}
} catch (IndexOutOfBoundsException e) {
// that's really rare case, but is much efficient than introduce synchronized block
}
}
}
@Override
public void initLayer(OsmandMapTileMiniView view) {
this.view = view;
//mapTextLayer = view.getLayerByClass(MapTextLayer.class);
}
public int getRadiusPoi(RotatedTileBox tb) {
int r;
final double zoom = tb.getZoom();
if (zoom < startZoom) {
r = 0;
} else if (zoom <= 15) {
r = 10;
} else if (zoom <= 16) {
r = 14;
} else if (zoom <= 17) {
r = 16;
} else {
r = 18;
}
return (int) (r * view.getScaleCoefficient());
}
@Override
public void onPrepareBufferImage(Canvas canvas, RotatedTileBox tileBox, DrawSettings settings) {
Set<PoiUIFilter> selectedPoiFilters = app.getPoiFilters().getSelectedPoiFilters();
if (this.filters != selectedPoiFilters) {
this.filters = selectedPoiFilters;
data.clearCache();
}
List<Amenity> objects = Collections.emptyList();
List<Amenity> fullObjects = new ArrayList<>();
List<LatLon> fullObjectsLatLon = new ArrayList<>();
List<LatLon> smallObjectsLatLon = new ArrayList<>();
//if (!filters.isEmpty()) {
if (tileBox.getZoom() >= startZoom) {
data.queryNewData(tileBox);
objects = data.getResults();
if (objects != null) {
float textScale = app.getSettings().TEXT_SCALE.get();
float iconSize = getIconSize(app) * 1.5f * textScale;
QuadTree<QuadRect> boundIntersections = initBoundIntersections(tileBox);
WaypointHelper wph = app.getWaypointHelper();
PointImageDrawable pointImageDrawable = PointImageDrawable.getOrCreate(app,
ContextCompat.getColor(app, R.color.osmand_orange), true);
pointImageDrawable.setAlpha(0.8f);
for (Amenity o : objects) {
float x = tileBox.getPixXFromLatLon(o.getLocation().getLatitude(), o.getLocation()
.getLongitude());
float y = tileBox.getPixYFromLatLon(o.getLocation().getLatitude(), o.getLocation()
.getLongitude());
if (tileBox.containsPoint(x, y, iconSize)) {
if (intersects(boundIntersections, x, y, iconSize, iconSize) ||
(app.getSettings().SHOW_NEARBY_POI.get() && wph.isRouteCalculated() && !wph.isAmenityNoPassed(o))) {
pointImageDrawable.drawSmallPoint(canvas, x, y, textScale);
smallObjectsLatLon.add(new LatLon(o.getLocation().getLatitude(),
o.getLocation().getLongitude()));
} else {
fullObjects.add(o);
fullObjectsLatLon.add(new LatLon(o.getLocation().getLatitude(),
o.getLocation().getLongitude()));
}
}
}
for (Amenity o : fullObjects) {
int x = (int) tileBox.getPixXFromLatLon(o.getLocation().getLatitude(), o.getLocation()
.getLongitude());
int y = (int) tileBox.getPixYFromLatLon(o.getLocation().getLatitude(), o.getLocation()
.getLongitude());
if (tileBox.containsPoint(x, y, iconSize)) {
String id = null;
PoiType st = o.getType().getPoiTypeByKeyName(o.getSubType());
if (st != null) {
if (RenderingIcons.containsSmallIcon(st.getIconKeyName())) {
id = st.getIconKeyName();
} else if (RenderingIcons.containsSmallIcon(st.getOsmTag() + "_" + st.getOsmValue())) {
id = st.getOsmTag() + "_" + st.getOsmValue();
}
}
if (id != null) {
pointImageDrawable = PointImageDrawable.getOrCreate(app,
ContextCompat.getColor(app, R.color.osmand_orange), true,
RenderingIcons.getResId(id));
pointImageDrawable.setAlpha(0.8f);
pointImageDrawable.drawPoint(canvas, x, y, textScale, false);
}
}
}
this.fullObjectsLatLon = fullObjectsLatLon;
this.smallObjectsLatLon = smallObjectsLatLon;
}
}
//}
//mapTextLayer.putData(this, objects);
}
@Override
public void onDraw(Canvas canvas, RotatedTileBox tileBox, DrawSettings settings) {
}
@Override
public void destroyLayer() {
routingHelper.removeListener(this);
}
@Override
public boolean drawInScreenPixels() {
return true;
}
public static void showDescriptionDialog(Context ctx, OsmandApplication app, String text, String title) {
showText(ctx, app, text, title);
}
static int getResIdFromAttribute(final Context ctx, final int attr) {
if (attr == 0) {
return 0;
}
final TypedValue typedvalueattr = new TypedValue();
ctx.getTheme().resolveAttribute(attr, typedvalueattr, true);
return typedvalueattr.resourceId;
}
private static void showText(final Context ctx, final OsmandApplication app, final String text, String title) {
final Dialog dialog = new Dialog(ctx,
app.getSettings().isLightContent() ? R.style.OsmandLightTheme : R.style.OsmandDarkTheme);
LinearLayout ll = new LinearLayout(ctx);
ll.setOrientation(LinearLayout.VERTICAL);
final Toolbar topBar = new Toolbar(ctx);
topBar.setClickable(true);
Drawable icBack = app.getUIUtilities().getIcon(AndroidUtils.getNavigationIconResId(ctx));
topBar.setNavigationIcon(icBack);
topBar.setNavigationContentDescription(R.string.access_shared_string_navigate_up);
topBar.setTitle(title);
topBar.setBackgroundColor(ContextCompat.getColor(ctx, getResIdFromAttribute(ctx, R.attr.pstsTabBackground)));
topBar.setTitleTextColor(ContextCompat.getColor(ctx, getResIdFromAttribute(ctx, R.attr.pstsTextColor)));
topBar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View v) {
dialog.dismiss();
}
});
final TextView textView = new TextView(ctx);
LinearLayout.LayoutParams llTextParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
int textMargin = dpToPx(app, 10f);
boolean light = app.getSettings().isLightContent();
textView.setLayoutParams(llTextParams);
textView.setPadding(textMargin, textMargin, textMargin, textMargin);
textView.setTextSize(16);
textView.setTextColor(ContextCompat.getColor(app, light ? R.color.text_color_primary_light : R.color.text_color_primary_dark));
textView.setAutoLinkMask(Linkify.ALL);
textView.setLinksClickable(true);
textView.setText(text);
ScrollView scrollView = new ScrollView(ctx);
ll.addView(topBar);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 0);
lp.weight = 1;
ll.addView(scrollView, lp);
scrollView.addView(textView);
dialog.setContentView(ll);
dialog.setCancelable(true);
dialog.show();
}
@Override
public PointDescription getObjectName(Object o) {
if (o instanceof Amenity) {
Amenity amenity = (Amenity) o;
String preferredLang = app.getSettings().MAP_PREFERRED_LOCALE.get();
boolean transliterateNames = app.getSettings().MAP_TRANSLITERATE_NAMES.get();
if (amenity.getType().isWiki()) {
if (Algorithms.isEmpty(preferredLang)) {
preferredLang = app.getLanguage();
}
preferredLang = OsmandPlugin.onGetMapObjectsLocale(amenity, preferredLang);
}
return new PointDescription(PointDescription.POINT_TYPE_POI,
amenity.getName(preferredLang, transliterateNames));
}
return null;
}
@Override
public boolean disableSingleTap() {
return false;
}
@Override
public boolean disableLongPressOnMap() {
return false;
}
@Override
public void collectObjectsFromPoint(PointF point, RotatedTileBox tileBox, List<Object> objects, boolean unknownLocation) {
if (tileBox.getZoom() >= startZoom) {
getAmenityFromPoint(tileBox, point, objects);
}
}
@Override
public LatLon getObjectLocation(Object o) {
if (o instanceof Amenity) {
return ((Amenity) o).getLocation();
}
return null;
}
@Override
public boolean isObjectClickable(Object o) {
return o instanceof Amenity;
}
@Override
public boolean runExclusiveAction(Object o, boolean unknownLocation) {
return false;
}
@Override
public LatLon getTextLocation(Amenity o) {
return o.getLocation();
}
@Override
public int getTextShift(Amenity amenity, RotatedTileBox rb) {
int radiusPoi = getRadiusPoi(rb);
if (isPresentInFullObjects(amenity.getLocation())) {
radiusPoi += (getIconSize(app) - app.getResources().getDimensionPixelSize(R.dimen.favorites_icon_size_small)) / 2;
}
return radiusPoi;
}
@Override
public String getText(Amenity o) {
return o.getName(view.getSettings().MAP_PREFERRED_LOCALE.get(),
view.getSettings().MAP_TRANSLITERATE_NAMES.get());
}
@Override
public boolean isTextVisible() {
return app.getSettings().SHOW_POI_LABEL.get();
}
@Override
public boolean isFakeBoldText() {
return false;
}
@Override
public void newRouteIsCalculated(boolean newRoute, ValueHolder<Boolean> showToast) {
}
@Override
public void routeWasCancelled() {
}
@Override
public void routeWasFinished() {
}
}