AidlMapLayer for OsmAnd-Telegram in progress

This commit is contained in:
Alex Sytnyk 2018-07-26 21:36:20 +03:00
parent 8410f16bf5
commit 17d682d73d
8 changed files with 273 additions and 96 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

View file

@ -826,6 +826,7 @@ public class OsmandAidlApi {
for (AMapPoint point : layer.getPoints()) { for (AMapPoint point : layer.getPoints()) {
existingLayer.putPoint(point); existingLayer.putPoint(point);
} }
existingLayer.copyZoomBounds(layer);
refreshMap(); refreshMap();
return true; return true;
} else { } else {

View file

@ -16,6 +16,14 @@ public class AMapLayer implements Parcelable {
private float zOrder = 5.5f; private float zOrder = 5.5f;
private Map<String, AMapPoint> points = new ConcurrentHashMap<>(); private Map<String, AMapPoint> points = new ConcurrentHashMap<>();
private boolean imagePoints = false;
private int circlePointMinZoom = 0;
private int circlePointMaxZoom = 6;
private int smallPointMinZoom = 7;
private int smallPointMaxZoom = 13;
private int bigPointMinZoom = 14;
private int bigPointMaxZoom = 22;
public AMapLayer(String id, String name, float zOrder, List<AMapPoint> pointList) { public AMapLayer(String id, String name, float zOrder, List<AMapPoint> pointList) {
this.id = id; this.id = id;
this.name = name; this.name = name;
@ -74,11 +82,74 @@ public class AMapLayer implements Parcelable {
points.remove(pointId); points.remove(pointId);
} }
public boolean isImagePoints() {
return imagePoints;
}
public void setImagePoints(boolean imagePoints) {
this.imagePoints = imagePoints;
}
public void copyZoomBounds(AMapLayer layer) {
circlePointMinZoom = layer.circlePointMinZoom;
circlePointMaxZoom = layer.circlePointMaxZoom;
smallPointMinZoom = layer.smallPointMinZoom;
smallPointMaxZoom = layer.smallPointMaxZoom;
bigPointMinZoom = layer.bigPointMinZoom;
bigPointMaxZoom = layer.bigPointMaxZoom;
}
public void setCirclePointZoomBounds(int min, int max) {
circlePointMinZoom = min;
circlePointMaxZoom = max;
}
public void setSmallPointZoomBounds(int min, int max) {
smallPointMinZoom = min;
smallPointMaxZoom = max;
}
public void setBigPointZoomBounds(int min, int max) {
bigPointMinZoom = min;
bigPointMaxZoom = max;
}
public int getCirclePointMinZoom() {
return circlePointMinZoom;
}
public int getCirclePointMaxZoom() {
return circlePointMaxZoom;
}
public int getSmallPointMinZoom() {
return smallPointMinZoom;
}
public int getSmallPointMaxZoom() {
return smallPointMaxZoom;
}
public int getBigPointMinZoom() {
return bigPointMinZoom;
}
public int getBigPointMaxZoom() {
return bigPointMaxZoom;
}
public void writeToParcel(Parcel out, int flags) { public void writeToParcel(Parcel out, int flags) {
out.writeString(id); out.writeString(id);
out.writeString(name); out.writeString(name);
out.writeFloat(zOrder); out.writeFloat(zOrder);
out.writeTypedList(new ArrayList<>(points.values())); out.writeTypedList(new ArrayList<>(points.values()));
out.writeByte((byte) (imagePoints ? 1 : 0));
out.writeInt(circlePointMinZoom);
out.writeInt(circlePointMaxZoom);
out.writeInt(smallPointMinZoom);
out.writeInt(smallPointMaxZoom);
out.writeInt(bigPointMinZoom);
out.writeInt(bigPointMaxZoom);
} }
private void readFromParcel(Parcel in) { private void readFromParcel(Parcel in) {
@ -90,6 +161,13 @@ public class AMapLayer implements Parcelable {
for (AMapPoint p : pointList) { for (AMapPoint p : pointList) {
this.points.put(p.getId(), p); this.points.put(p.getId(), p);
} }
imagePoints = in.readByte() == 1;
circlePointMinZoom = in.readInt();
circlePointMaxZoom = in.readInt();
smallPointMinZoom = in.readInt();
smallPointMaxZoom = in.readInt();
bigPointMinZoom = in.readInt();
bigPointMaxZoom = in.readInt();
} }
public int describeContents() { public int describeContents() {

View file

@ -11,7 +11,6 @@ import java.util.List;
import java.util.Map; import java.util.Map;
public class AMapPoint implements Parcelable { public class AMapPoint implements Parcelable {
public static final int POINT_IMAGE_SIZE_PX = 160;
public static final String POINT_IMAGE_URI_PARAM = "point_image_uri_param"; public static final String POINT_IMAGE_URI_PARAM = "point_image_uri_param";
private String id; private String id;

View file

@ -1,10 +1,14 @@
package net.osmand.plus.views; package net.osmand.plus.views;
import android.content.res.Resources;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.BitmapFactory; import android.graphics.BitmapFactory;
import android.graphics.Canvas; import android.graphics.Canvas;
import android.graphics.Paint; import android.graphics.Paint;
import android.graphics.PointF; import android.graphics.PointF;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.Rect;
import android.net.Uri; import android.net.Uri;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
@ -26,29 +30,45 @@ import net.osmand.plus.widgets.tools.CropCircleTransformation;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import static net.osmand.aidl.maplayer.point.AMapPoint.POINT_IMAGE_SIZE_PX;
public class AidlMapLayer extends OsmandMapLayer implements IContextMenuProvider, MapTextLayer.MapTextProvider<AMapPoint> { public class AidlMapLayer extends OsmandMapLayer implements IContextMenuProvider, MapTextLayer.MapTextProvider<AMapPoint> {
private static int POINT_OUTER_COLOR = 0x88555555;
private static final int POINT_OUTER_COLOR = 0x88555555;
private static final float START_ZOOM = 7;
private final MapActivity map; private final MapActivity map;
private AMapLayer aidlLayer;
private OsmandMapTileView view; private OsmandMapTileView view;
private AMapLayer aidlLayer;
private Paint pointInnerCircle; private Paint pointInnerCircle;
private Paint pointOuter; private Paint pointOuterCircle;
private Paint bitmapPaint; private Paint bitmapPaint;
private final static float startZoom = 7;
private Bitmap circle;
private Bitmap smallIconBg;
private Bitmap bigIconBg;
private Bitmap placeholder;
private int smallIconSize;
private int bigIconSize;
private PointType pointsType;
private MapTextLayer mapTextLayer; private MapTextLayer mapTextLayer;
private Map<String, Bitmap> pointImages = new ConcurrentHashMap<>(); private Map<String, Bitmap> pointImages = new ConcurrentHashMap<>();
private Set<String> imageRequests = new HashSet<>();
private List<AMapPoint> displayedPoints = new ArrayList<>();
public AidlMapLayer(MapActivity map, AMapLayer aidlLayer) { public AidlMapLayer(MapActivity map, AMapLayer aidlLayer) {
this.map = map; this.map = map;
this.aidlLayer = aidlLayer; this.aidlLayer = aidlLayer;
@ -58,88 +78,120 @@ public class AidlMapLayer extends OsmandMapLayer implements IContextMenuProvider
public void initLayer(OsmandMapTileView view) { public void initLayer(OsmandMapTileView view) {
this.view = view; this.view = view;
Resources res = view.getResources();
boolean night = map.getMyApplication().getDaynightHelper().isNightMode();
pointInnerCircle = new Paint(); pointInnerCircle = new Paint();
pointInnerCircle.setColor(view.getApplication().getResources().getColor(R.color.poi_background)); pointInnerCircle.setColor(res.getColor(R.color.poi_background));
pointInnerCircle.setStyle(Paint.Style.FILL); pointInnerCircle.setStyle(Paint.Style.FILL);
pointInnerCircle.setAntiAlias(true); pointInnerCircle.setAntiAlias(true);
pointOuter = new Paint(); pointOuterCircle = new Paint();
pointOuter.setColor(POINT_OUTER_COLOR); pointOuterCircle.setColor(POINT_OUTER_COLOR);
pointOuter.setAntiAlias(true); pointOuterCircle.setStyle(Paint.Style.FILL_AND_STROKE);
pointOuter.setStyle(Paint.Style.FILL_AND_STROKE); pointOuterCircle.setAntiAlias(true);
bitmapPaint = new Paint(); bitmapPaint = new Paint();
bitmapPaint.setAntiAlias(true); bitmapPaint.setAntiAlias(true);
bitmapPaint.setDither(true); bitmapPaint.setDither(true);
bitmapPaint.setFilterBitmap(true); bitmapPaint.setFilterBitmap(true);
circle = BitmapFactory.decodeResource(res, R.drawable.map_white_shield_small);
smallIconBg = BitmapFactory.decodeResource(res, night
? R.drawable.map_pin_user_location_small_night : R.drawable.map_pin_user_location_small_day);
bigIconBg = BitmapFactory.decodeResource(res, night
? R.drawable.map_pin_user_location_night : R.drawable.map_pin_user_location_day);
placeholder = BitmapFactory.decodeResource(res, R.drawable.img_user_picture);
smallIconSize = AndroidUtils.dpToPx(map, 20);
bigIconSize = AndroidUtils.dpToPx(map, 40);
mapTextLayer = view.getLayerByClass(MapTextLayer.class); mapTextLayer = view.getLayerByClass(MapTextLayer.class);
} }
private int getRadiusPoi(RotatedTileBox tb) {
int r;
final double zoom = tb.getZoom();
if (zoom < startZoom) {
r = 0;
} else if (zoom <= 11) {
r = 10;
} else if (zoom <= 14) {
r = 12;
} else {
r = 14;
}
return (int) (r * tb.getDensity());
}
private boolean hasBitmap(AMapPoint point) {
String imageUriStr = point.getParams().get(AMapPoint.POINT_IMAGE_URI_PARAM);
return !TextUtils.isEmpty(imageUriStr) && pointImages.containsKey(imageUriStr);
}
@Override @Override
public void onDraw(Canvas canvas, RotatedTileBox tileBox, DrawSettings settings) { public void onDraw(Canvas canvas, RotatedTileBox tileBox, DrawSettings settings) {
} }
@Override @Override
public void onPrepareBufferImage(Canvas canvas, RotatedTileBox tileBox, DrawSettings settings) { public void onPrepareBufferImage(Canvas canvas, RotatedTileBox tileBox, DrawSettings settings) {
float density = (float) Math.ceil(tileBox.getDensity()); pointsType = getPointsType(tileBox.getZoom());
final int radius = getRadiusPoi(tileBox); if (pointsType == PointType.NONE) {
final int maxRadius = (int) (Math.max(radius, POINT_IMAGE_SIZE_PX) + density); mapTextLayer.putData(this, Collections.emptyList());
return;
}
displayedPoints.clear();
imageRequests.clear();
canvas.rotate(-tileBox.getRotate(), tileBox.getCenterPixelX(), tileBox.getCenterPixelY()); canvas.rotate(-tileBox.getRotate(), tileBox.getCenterPixelX(), tileBox.getCenterPixelY());
Set<String> imageRequests = new HashSet<>(); for (AMapPoint point : aidlLayer.getPoints()) {
List<AMapPoint> points = aidlLayer.getPoints();
for (AMapPoint point : points) {
ALatLon l = point.getLocation(); ALatLon l = point.getLocation();
if (l != null) { if (l != null) {
int x = (int) tileBox.getPixXFromLatLon(l.getLatitude(), l.getLongitude()); int x = (int) tileBox.getPixXFromLatLon(l.getLatitude(), l.getLongitude());
int y = (int) tileBox.getPixYFromLatLon(l.getLatitude(), l.getLongitude()); int y = (int) tileBox.getPixYFromLatLon(l.getLatitude(), l.getLongitude());
if (tileBox.containsPoint(x, y, maxRadius)) { if (tileBox.containsPoint(x, y, bigIconSize)) {
boolean hasBitmap = false; Bitmap image = null;
Map<String, String> params = point.getParams(); if (pointsType != PointType.STANDARD) {
String imageUriStr = params.get(AMapPoint.POINT_IMAGE_URI_PARAM); String imageUri = point.getParams().get(AMapPoint.POINT_IMAGE_URI_PARAM);
if (!TextUtils.isEmpty(imageUriStr)) { if (!TextUtils.isEmpty(imageUri)) {
Bitmap bitmap = pointImages.get(imageUriStr); image = pointImages.get(imageUri);
if (bitmap == null) { if (image == null) {
imageRequests.add(imageUriStr); imageRequests.add(imageUri);
} else { }
hasBitmap = true;
canvas.drawBitmap(bitmap, x - bitmap.getHeight() / 2, y - bitmap.getWidth() / 2, bitmapPaint);
} }
} }
if (!hasBitmap) { displayedPoints.add(point);
pointInnerCircle.setColor(point.getColor()); drawPoint(canvas, x, y, tileBox, point, image);
pointOuter.setColor(POINT_OUTER_COLOR);
canvas.drawCircle(x, y, radius + density, pointOuter);
canvas.drawCircle(x, y, radius - density, pointInnerCircle);
}
} }
} }
} }
if (imageRequests.size() > 0) { if (imageRequests.size() > 0) {
executeTaskInBackground(new PointImageReaderTask(this), imageRequests.toArray(new String[imageRequests.size()])); executeTaskInBackground(new PointImageReaderTask(this), imageRequests.toArray(new String[imageRequests.size()]));
} }
mapTextLayer.putData(this, points); mapTextLayer.putData(this, displayedPoints);
}
private void drawPoint(Canvas canvas, int x, int y, RotatedTileBox tb, AMapPoint point, Bitmap image) {
if (pointsType == PointType.STANDARD) {
int radius = getRadiusPoi(tb);
float density = tb.getDensity();
pointInnerCircle.setColor(point.getColor());
canvas.drawCircle(x, y, radius + density, pointOuterCircle);
canvas.drawCircle(x, y, radius - density, pointInnerCircle);
} else if (pointsType == PointType.CIRCLE) {
bitmapPaint.setColorFilter(new PorterDuffColorFilter(point.getColor(), PorterDuff.Mode.MULTIPLY));
canvas.drawBitmap(circle, x - circle.getWidth() / 2, y - circle.getHeight() / 2, bitmapPaint);
} else if (pointsType == PointType.SMALL_ICON) {
drawImagePoint(canvas, x, y, smallIconBg.getHeight() / 2, smallIconBg, y, smallIconSize / 2, image);
} else if (pointsType == PointType.BIG_ICON) {
// FIXME: y offset
float bgVerticalOffset = bigIconBg.getHeight() * 0.9f;
float imageCenterY = y - bgVerticalOffset + bigIconBg.getHeight() / 2;
drawImagePoint(canvas, x, y, bgVerticalOffset, bigIconBg, (int) imageCenterY, bigIconSize / 2, image);
}
}
private void drawImagePoint(Canvas canvas,
int bgCenterX,
int bgCenterY,
float bgVerticalOffset,
Bitmap bg,
int imageCenterY,
int imageOffset,
Bitmap image) {
bitmapPaint.setColorFilter(null);
canvas.drawBitmap(bg, bgCenterX - bg.getWidth() / 2, bgCenterY - bgVerticalOffset, bitmapPaint);
if (image == null) {
image = placeholder;
}
Rect rect = new Rect();
rect.left = bgCenterX - imageOffset;
rect.top = imageCenterY - imageOffset;
rect.right = bgCenterX + imageOffset;
rect.bottom = imageCenterY + imageOffset;
canvas.drawBitmap(image, null, rect, bitmapPaint);
} }
@Override @Override
@ -151,12 +203,6 @@ public class AidlMapLayer extends OsmandMapLayer implements IContextMenuProvider
return false; return false;
} }
public void refresh() {
if (view != null) {
view.refreshMap();
}
}
@Override @Override
public boolean disableSingleTap() { public boolean disableSingleTap() {
return false; return false;
@ -207,12 +253,90 @@ public class AidlMapLayer extends OsmandMapLayer implements IContextMenuProvider
return aidlLayer.getPoint(id); return aidlLayer.getPoint(id);
} }
@Override
public LatLon getTextLocation(AMapPoint o) {
ALatLon loc = o.getLocation();
if (loc != null) {
return new LatLon(loc.getLatitude(), loc.getLongitude());
}
return null;
}
@Override
public int getTextShift(AMapPoint o, RotatedTileBox rb) {
if (pointsType == PointType.STANDARD) {
return (int) (getRadiusPoi(rb) * 1.5);
} else if (pointsType == PointType.CIRCLE) {
return (int) (circle.getHeight() * 0.6);
} else if (pointsType == PointType.SMALL_ICON) {
return smallIconBg.getHeight() / 2;
} else if (pointsType == PointType.BIG_ICON) {
return bigIconBg.getHeight() / 6;
}
return 0;
}
@Override
public String getText(AMapPoint o) {
return o.getShortName();
}
@Override
public boolean isTextVisible() {
return true;
}
@Override
public boolean isFakeBoldText() {
return true;
}
public void refresh() {
if (view != null) {
view.refreshMap();
}
}
private PointType getPointsType(int zoom) {
if (!aidlLayer.isImagePoints()) {
return zoom >= START_ZOOM ? PointType.STANDARD : PointType.NONE;
}
if (zoom >= aidlLayer.getCirclePointMinZoom() && zoom <= aidlLayer.getCirclePointMaxZoom()) {
return PointType.CIRCLE;
} else if (zoom >= aidlLayer.getSmallPointMinZoom() && zoom <= aidlLayer.getSmallPointMaxZoom()) {
return PointType.SMALL_ICON;
} else if (zoom >= aidlLayer.getBigPointMinZoom() && zoom <= aidlLayer.getBigPointMaxZoom()) {
return PointType.BIG_ICON;
}
return PointType.NONE;
}
private int getRadiusPoi(RotatedTileBox tb) {
int r;
final double zoom = tb.getZoom();
if (zoom < START_ZOOM) {
r = 0;
} else if (zoom <= 11) {
r = 10;
} else if (zoom <= 14) {
r = 12;
} else {
r = 14;
}
return (int) (r * tb.getDensity());
}
private boolean hasBitmap(AMapPoint point) {
String imageUriStr = point.getParams().get(AMapPoint.POINT_IMAGE_URI_PARAM);
return !TextUtils.isEmpty(imageUriStr) && pointImages.containsKey(imageUriStr);
}
private void getFromPoint(RotatedTileBox tb, PointF point, List<? super AMapPoint> points) { private void getFromPoint(RotatedTileBox tb, PointF point, List<? super AMapPoint> points) {
if (view != null) { if (view != null) {
int ex = (int) point.x; int ex = (int) point.x;
int ey = (int) point.y; int ey = (int) point.y;
final int rp = getRadiusPoi(tb); final int rp = getRadiusPoi(tb);
final int bitmapRadius = (int) ((POINT_IMAGE_SIZE_PX / tb.getDensity()) * 3 / 2); final int bitmapRadius = (int) ((bigIconSize / tb.getDensity()) * 3 / 2);
int compare; int compare;
int radius = rp * 3 / 2; int radius = rp * 3 / 2;
for (AMapPoint p : aidlLayer.getPoints()) { for (AMapPoint p : aidlLayer.getPoints()) {
@ -229,37 +353,12 @@ public class AidlMapLayer extends OsmandMapLayer implements IContextMenuProvider
} }
} }
@Override private enum PointType {
public LatLon getTextLocation(AMapPoint o) { STANDARD,
ALatLon loc = o.getLocation(); CIRCLE,
if (loc != null) { SMALL_ICON,
return new LatLon(loc.getLatitude(), loc.getLongitude()); BIG_ICON,
} NONE
return null;
}
@Override
public int getTextShift(AMapPoint o, RotatedTileBox rb) {
int radius = getRadiusPoi(rb);
if (hasBitmap(o)) {
return (int) (POINT_IMAGE_SIZE_PX * 0.6);
}
return (int) (radius * 1.5);
}
@Override
public String getText(AMapPoint o) {
return o.getShortName();
}
@Override
public boolean isTextVisible() {
return true;
}
@Override
public boolean isFakeBoldText() {
return true;
} }
private static class PointImageReaderTask extends AsyncTask<String, Void, Boolean> { private static class PointImageReaderTask extends AsyncTask<String, Void, Boolean> {
@ -285,8 +384,8 @@ public class AidlMapLayer extends OsmandMapLayer implements IContextMenuProvider
Bitmap bitmap = BitmapFactory.decodeStream(ims); Bitmap bitmap = BitmapFactory.decodeStream(ims);
if (bitmap != null) { if (bitmap != null) {
bitmap = circleTransformation.transform(bitmap); bitmap = circleTransformation.transform(bitmap);
if (bitmap.getWidth() != POINT_IMAGE_SIZE_PX || bitmap.getHeight() != POINT_IMAGE_SIZE_PX) { if (bitmap.getWidth() != layer.bigIconSize || bitmap.getHeight() != layer.bigIconSize) {
bitmap = AndroidUtils.scaleBitmap(bitmap, POINT_IMAGE_SIZE_PX, POINT_IMAGE_SIZE_PX, false); bitmap = AndroidUtils.scaleBitmap(bitmap, layer.bigIconSize, layer.bigIconSize, false);
} }
layer.pointImages.put(imageUriStr, bitmap); layer.pointImages.put(imageUriStr, bitmap);
res = true; res = true;