From 0d89b958ce1bf59cf58dfd2dcdd560001ffb9605 Mon Sep 17 00:00:00 2001 From: crimean Date: Thu, 14 Jun 2018 21:01:10 +0300 Subject: [PATCH] Telegram - show images on map --- OsmAnd-telegram/AndroidManifest.xml | 11 ++ OsmAnd-telegram/res/xml/paths.xml | 24 ++++ .../osmand/aidl/maplayer/point/AMapPoint.java | 17 ++- .../src/net/osmand/telegram/MainActivity.kt | 4 + .../telegram/helpers/OsmandAidlHelper.kt | 9 +- .../telegram/helpers/ShowLocationHelper.kt | 18 ++- .../osmand/telegram/helpers/TelegramHelper.kt | 61 +++++++++- .../net/osmand/telegram/utils/AndroidUtils.kt | 13 +- .../src/net/osmand/telegram/utils/UiUtils.kt | 2 +- OsmAnd/src/net/osmand/AndroidUtils.java | 24 +++- .../osmand/aidl/maplayer/point/AMapPoint.java | 17 ++- .../net/osmand/plus/views/AidlMapLayer.java | 115 +++++++++++++++--- 12 files changed, 285 insertions(+), 30 deletions(-) create mode 100644 OsmAnd-telegram/res/xml/paths.xml diff --git a/OsmAnd-telegram/AndroidManifest.xml b/OsmAnd-telegram/AndroidManifest.xml index 558d4b38df..39a133866b 100644 --- a/OsmAnd-telegram/AndroidManifest.xml +++ b/OsmAnd-telegram/AndroidManifest.xml @@ -42,6 +42,17 @@ + + + + + \ No newline at end of file diff --git a/OsmAnd-telegram/res/xml/paths.xml b/OsmAnd-telegram/res/xml/paths.xml new file mode 100644 index 0000000000..e7904b975d --- /dev/null +++ b/OsmAnd-telegram/res/xml/paths.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/OsmAnd-telegram/src/net/osmand/aidl/maplayer/point/AMapPoint.java b/OsmAnd-telegram/src/net/osmand/aidl/maplayer/point/AMapPoint.java index 1d0d2e01e8..622e67d00b 100644 --- a/OsmAnd-telegram/src/net/osmand/aidl/maplayer/point/AMapPoint.java +++ b/OsmAnd-telegram/src/net/osmand/aidl/maplayer/point/AMapPoint.java @@ -6,9 +6,14 @@ import android.os.Parcelable; import net.osmand.aidl.map.ALatLon; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; 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"; + private String id; private String shortName; private String fullName; @@ -16,9 +21,10 @@ public class AMapPoint implements Parcelable { private int color; private ALatLon location; private List details = new ArrayList<>(); + private Map params = new HashMap<>(); public AMapPoint(String id, String shortName, String fullName, String typeName, int color, - ALatLon location, List details) { + ALatLon location, List details, Map params) { this.id = id; this.shortName = shortName; this.fullName = fullName; @@ -28,6 +34,9 @@ public class AMapPoint implements Parcelable { if (details != null) { this.details.addAll(details); } + if (params != null) { + this.params.putAll(params); + } } public AMapPoint(Parcel in) { @@ -73,6 +82,10 @@ public class AMapPoint implements Parcelable { return details; } + public Map getParams() { + return params; + } + public void writeToParcel(Parcel out, int flags) { out.writeString(id); out.writeString(shortName); @@ -81,6 +94,7 @@ public class AMapPoint implements Parcelable { out.writeInt(color); out.writeParcelable(location, flags); out.writeStringList(details); + out.writeMap(params); } private void readFromParcel(Parcel in) { @@ -91,6 +105,7 @@ public class AMapPoint implements Parcelable { color = in.readInt(); location = in.readParcelable(ALatLon.class.getClassLoader()); in.readStringList(details); + in.readMap(params, HashMap.class.getClassLoader()); } public int describeContents() { diff --git a/OsmAnd-telegram/src/net/osmand/telegram/MainActivity.kt b/OsmAnd-telegram/src/net/osmand/telegram/MainActivity.kt index 60b9af5ec6..a3236a22fd 100644 --- a/OsmAnd-telegram/src/net/osmand/telegram/MainActivity.kt +++ b/OsmAnd-telegram/src/net/osmand/telegram/MainActivity.kt @@ -172,6 +172,10 @@ class MainActivity : AppCompatActivity(), TelegramListener { } } + override fun onTelegramUserChanged(user: TdApi.User) { + + } + override fun onTelegramError(code: Int, message: String) { runOnUi { Toast.makeText(this@MainActivity, "$code - $message", Toast.LENGTH_LONG).show() diff --git a/OsmAnd-telegram/src/net/osmand/telegram/helpers/OsmandAidlHelper.kt b/OsmAnd-telegram/src/net/osmand/telegram/helpers/OsmandAidlHelper.kt index 1e2dddc467..ff7869b5df 100644 --- a/OsmAnd-telegram/src/net/osmand/telegram/helpers/OsmandAidlHelper.kt +++ b/OsmAnd-telegram/src/net/osmand/telegram/helpers/OsmandAidlHelper.kt @@ -8,7 +8,6 @@ import android.content.ServiceConnection import android.net.Uri import android.os.IBinder import android.os.RemoteException -import android.widget.Toast import net.osmand.aidl.IOsmAndAidlInterface import net.osmand.aidl.favorite.AFavorite import net.osmand.aidl.favorite.AddFavoriteParams @@ -537,10 +536,10 @@ class OsmandAidlHelper(private val app: Application) { * @param details - list of details. Displayed under context menu. */ fun addMapPoint(layerId: String, pointId: String, shortName: String, fullName: String, - typeName: String, color: Int, location: ALatLon, details: List?): Boolean { + typeName: String, color: Int, location: ALatLon, details: List?, params: Map?): Boolean { if (mIOsmAndAidlInterface != null) { try { - val point = AMapPoint(pointId, shortName, fullName, typeName, color, location, details) + val point = AMapPoint(pointId, shortName, fullName, typeName, color, location, details, params) return mIOsmAndAidlInterface!!.addMapPoint(AddMapPointParams(layerId, point)) } catch (e: RemoteException) { e.printStackTrace() @@ -563,10 +562,10 @@ class OsmandAidlHelper(private val app: Application) { * @param details - list of details. Displayed under context menu. */ fun updateMapPoint(layerId: String, pointId: String, shortName: String, fullName: String, - typeName: String, color: Int, location: ALatLon, details: List?): Boolean { + typeName: String, color: Int, location: ALatLon, details: List?, params: Map?): Boolean { if (mIOsmAndAidlInterface != null) { try { - val point = AMapPoint(pointId, shortName, fullName, typeName, color, location, details) + val point = AMapPoint(pointId, shortName, fullName, typeName, color, location, details, params) return mIOsmAndAidlInterface!!.updateMapPoint(UpdateMapPointParams(layerId, point)) } catch (e: RemoteException) { e.printStackTrace() diff --git a/OsmAnd-telegram/src/net/osmand/telegram/helpers/ShowLocationHelper.kt b/OsmAnd-telegram/src/net/osmand/telegram/helpers/ShowLocationHelper.kt index 4f88d1906f..07cc5a1423 100644 --- a/OsmAnd-telegram/src/net/osmand/telegram/helpers/ShowLocationHelper.kt +++ b/OsmAnd-telegram/src/net/osmand/telegram/helpers/ShowLocationHelper.kt @@ -1,9 +1,15 @@ package net.osmand.telegram.helpers +import android.content.Intent import android.graphics.Color +import android.net.Uri +import android.text.TextUtils import net.osmand.aidl.map.ALatLon +import net.osmand.aidl.maplayer.point.AMapPoint import net.osmand.telegram.TelegramApplication +import net.osmand.telegram.utils.AndroidUtils import org.drinkless.td.libcore.telegram.TdApi +import java.io.File class ShowLocationHelper(private val app: TelegramApplication) { @@ -26,6 +32,7 @@ class ShowLocationHelper(private val app: TelegramApplication) { val content = message.content if (content is TdApi.MessageLocation) { var userName = "" + var photoUri: Uri? = null val user = telegramHelper.getUser(message.senderUserId) if (user != null) { userName = "${user.firstName} ${user.lastName}".trim() @@ -35,13 +42,22 @@ class ShowLocationHelper(private val app: TelegramApplication) { if (userName.isEmpty()) { userName = user.phoneNumber } + val photoPath = telegramHelper.getUserPhotoPath(user) + if (!TextUtils.isEmpty(photoPath)) { + photoUri = AndroidUtils.getUriForFile(app, File(photoPath)) + app.grantUriPermission("net.osmand.plus", photoUri, Intent.FLAG_GRANT_READ_URI_PERMISSION) + } } if (userName.isEmpty()) { userName = message.senderUserId.toString() } setupMapLayer() + val params = mutableMapOf() + if (photoUri != null) { + params[AMapPoint.POINT_IMAGE_URI_PARAM] = photoUri.toString() + } osmandHelper.addMapPoint(MAP_LAYER_ID, "${chatTitle}_${message.senderUserId}", userName, userName, - chatTitle, Color.RED, ALatLon(content.location.latitude, content.location.longitude), null) + chatTitle, Color.RED, ALatLon(content.location.latitude, content.location.longitude), null, params) } } else if (osmandHelper.isOsmandBound()) { osmandHelper.connectOsmand() diff --git a/OsmAnd-telegram/src/net/osmand/telegram/helpers/TelegramHelper.kt b/OsmAnd-telegram/src/net/osmand/telegram/helpers/TelegramHelper.kt index ee0292447e..e8fe5a737f 100644 --- a/OsmAnd-telegram/src/net/osmand/telegram/helpers/TelegramHelper.kt +++ b/OsmAnd-telegram/src/net/osmand/telegram/helpers/TelegramHelper.kt @@ -42,6 +42,7 @@ class TelegramHelper private constructor() { private val chatLiveMessages = ConcurrentHashMap() private val downloadChatFilesMap = ConcurrentHashMap() + private val downloadUserFilesMap = ConcurrentHashMap() private val usersLiveMessages = ConcurrentHashMap() @@ -140,6 +141,7 @@ class TelegramHelper private constructor() { fun onTelegramChatsRead() fun onTelegramChatsChanged() fun onTelegramChatChanged(chat: TdApi.Chat) + fun onTelegramUserChanged(user: TdApi.User) fun onTelegramError(code: Int, message: String) fun onSendLiveLicationError(code: Int, message: String) } @@ -215,6 +217,54 @@ class TelegramHelper private constructor() { return client != null && haveAuthorization } + fun getUserPhotoPath(user: TdApi.User):String? { + return if (hasLocalUserPhoto(user)) { + user.profilePhoto?.small?.local?.path + } else { + if (hasRemoteUserPhoto(user)) { + requestUserPhoto(user) + } + null + } + } + + private fun hasLocalUserPhoto(user: TdApi.User): Boolean { + val localPhoto = user.profilePhoto?.small?.local + return if (localPhoto != null) { + localPhoto.canBeDownloaded && localPhoto.isDownloadingCompleted && localPhoto.path.isNotEmpty() + } else { + false + } + } + + private fun hasRemoteUserPhoto(user: TdApi.User): Boolean { + val remotePhoto = user.profilePhoto?.small?.remote + return remotePhoto?.id?.isNotEmpty() ?: false + } + + private fun requestUserPhoto(user: TdApi.User) { + val remotePhoto = user.profilePhoto?.small?.remote + if (remotePhoto != null && remotePhoto.id.isNotEmpty()) { + downloadUserFilesMap[remotePhoto.id] = user + client!!.send(TdApi.GetRemoteFile(remotePhoto.id, null)) { obj -> + when (obj.constructor) { + TdApi.Error.CONSTRUCTOR -> { + val error = obj as TdApi.Error + val code = error.code + if (code != IGNORED_ERROR_CODE) { + listener?.onTelegramError(code, error.message) + } + } + TdApi.File.CONSTRUCTOR -> { + val file = obj as TdApi.File + client!!.send(TdApi.DownloadFile(file.id, 10), defaultHandler) + } + else -> listener?.onTelegramError(-1, "Receive wrong response from TDLib: $obj") + } + } + } + } + private fun requestChats(reload: Boolean = false) { synchronized(chatList) { if (reload) { @@ -776,8 +826,17 @@ class TelegramHelper private constructor() { if (chat != null) { synchronized(chat) { chat.photo?.small = updateFile.file - listener?.onTelegramChatChanged(chat) } + listener?.onTelegramChatChanged(chat) + return + } + val user = downloadUserFilesMap.remove(remoteId) + if (user != null) { + synchronized(user) { + user.profilePhoto?.small = updateFile.file + } + listener?.onTelegramUserChanged(user) + return } } } diff --git a/OsmAnd-telegram/src/net/osmand/telegram/utils/AndroidUtils.kt b/OsmAnd-telegram/src/net/osmand/telegram/utils/AndroidUtils.kt index c7f1a6cfdd..6f089c80a9 100644 --- a/OsmAnd-telegram/src/net/osmand/telegram/utils/AndroidUtils.kt +++ b/OsmAnd-telegram/src/net/osmand/telegram/utils/AndroidUtils.kt @@ -5,14 +5,17 @@ import android.app.Activity import android.content.Context import android.content.pm.PackageManager import android.content.res.Configuration +import android.net.Uri +import android.os.Build import android.support.annotation.AttrRes import android.support.annotation.ColorInt import android.support.v4.app.ActivityCompat -import android.support.v4.content.ContextCompat +import android.support.v4.content.FileProvider import android.util.TypedValue import android.util.TypedValue.COMPLEX_UNIT_DIP import android.view.View import android.view.inputmethod.InputMethodManager +import java.io.File object AndroidUtils { @@ -61,4 +64,12 @@ object AndroidUtils { ta.recycle() return color } + + fun getUriForFile(context: Context, file: File): Uri { + return if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { + Uri.fromFile(file) + } else { + FileProvider.getUriForFile(context, "net.osmand.telegram.fileprovider", file) + } + } } diff --git a/OsmAnd-telegram/src/net/osmand/telegram/utils/UiUtils.kt b/OsmAnd-telegram/src/net/osmand/telegram/utils/UiUtils.kt index f131c0ff21..d2dd82c16a 100644 --- a/OsmAnd-telegram/src/net/osmand/telegram/utils/UiUtils.kt +++ b/OsmAnd-telegram/src/net/osmand/telegram/utils/UiUtils.kt @@ -93,7 +93,7 @@ class UiUtils(private val app: TelegramApplication) { return getDrawable(id, if (light) R.color.icon_color_light else 0) } - fun createCircleBitmap(source: Bitmap, recycleSource: Boolean = false): Bitmap { + private fun createCircleBitmap(source: Bitmap, recycleSource: Boolean = false): Bitmap { val size = Math.min(source.width, source.height) val width = (source.width - size) / 2 diff --git a/OsmAnd/src/net/osmand/AndroidUtils.java b/OsmAnd/src/net/osmand/AndroidUtils.java index 444b52b88b..e2a4a94acf 100644 --- a/OsmAnd/src/net/osmand/AndroidUtils.java +++ b/OsmAnd/src/net/osmand/AndroidUtils.java @@ -7,7 +7,9 @@ import android.content.Context; import android.content.res.ColorStateList; import android.content.res.Configuration; import android.content.res.Resources; +import android.graphics.Bitmap; import android.graphics.Canvas; +import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.PointF; import android.graphics.drawable.ClipDrawable; @@ -99,6 +101,20 @@ public class AndroidUtils { } + public static Bitmap scaleBitmap(Bitmap bm, int newWidth, int newHeight, boolean keepOriginalBitmap) { + int width = bm.getWidth(); + int height = bm.getHeight(); + float scaleWidth = ((float) newWidth) / width; + float scaleHeight = ((float) newHeight) / height; + Matrix matrix = new Matrix(); + matrix.postScale(scaleWidth, scaleHeight); + Bitmap resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, false); + if (!keepOriginalBitmap) { + bm.recycle(); + } + return resizedBitmap; + } + public static ColorStateList createBottomNavColorStateList(Context ctx, boolean nightMode) { return AndroidUtils.createCheckedColorStateList(ctx, nightMode, R.color.icon_color, R.color.wikivoyage_active_light, @@ -130,7 +146,7 @@ public class AndroidUtils { while (i < text.length() && i != -1) { ImageSpan span = new ImageSpan(icon) { public void draw(Canvas canvas, CharSequence text, int start, int end, - float x, int top, int y, int bottom, Paint paint) { + float x, int top, int y, int bottom, Paint paint) { Drawable drawable = getDrawable(); canvas.save(); int transY = bottom - drawable.getBounds().bottom; @@ -168,13 +184,13 @@ public class AndroidUtils { public static String formatDate(Context ctx, long time) { return DateFormat.getDateFormat(ctx).format(new Date(time)); } - + public static String formatDateTime(Context ctx, long time) { Date d = new Date(time); return DateFormat.getDateFormat(ctx).format(d) + " " + DateFormat.getTimeFormat(ctx).format(d); } - + public static String formatTime(Context ctx, long time) { return DateFormat.getTimeFormat(ctx).format(new Date(time)); } @@ -197,7 +213,7 @@ public class AndroidUtils { ViewParent viewParent = view.getParent(); while (viewParent != null && viewParent instanceof View) { - View parentView = (View)viewParent; + View parentView = (View) viewParent; if (parentView.getId() == id) return parentView; diff --git a/OsmAnd/src/net/osmand/aidl/maplayer/point/AMapPoint.java b/OsmAnd/src/net/osmand/aidl/maplayer/point/AMapPoint.java index 1d0d2e01e8..622e67d00b 100644 --- a/OsmAnd/src/net/osmand/aidl/maplayer/point/AMapPoint.java +++ b/OsmAnd/src/net/osmand/aidl/maplayer/point/AMapPoint.java @@ -6,9 +6,14 @@ import android.os.Parcelable; import net.osmand.aidl.map.ALatLon; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; 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"; + private String id; private String shortName; private String fullName; @@ -16,9 +21,10 @@ public class AMapPoint implements Parcelable { private int color; private ALatLon location; private List details = new ArrayList<>(); + private Map params = new HashMap<>(); public AMapPoint(String id, String shortName, String fullName, String typeName, int color, - ALatLon location, List details) { + ALatLon location, List details, Map params) { this.id = id; this.shortName = shortName; this.fullName = fullName; @@ -28,6 +34,9 @@ public class AMapPoint implements Parcelable { if (details != null) { this.details.addAll(details); } + if (params != null) { + this.params.putAll(params); + } } public AMapPoint(Parcel in) { @@ -73,6 +82,10 @@ public class AMapPoint implements Parcelable { return details; } + public Map getParams() { + return params; + } + public void writeToParcel(Parcel out, int flags) { out.writeString(id); out.writeString(shortName); @@ -81,6 +94,7 @@ public class AMapPoint implements Parcelable { out.writeInt(color); out.writeParcelable(location, flags); out.writeStringList(details); + out.writeMap(params); } private void readFromParcel(Parcel in) { @@ -91,6 +105,7 @@ public class AMapPoint implements Parcelable { color = in.readInt(); location = in.readParcelable(ALatLon.class.getClassLoader()); in.readStringList(details); + in.readMap(params, HashMap.class.getClassLoader()); } public int describeContents() { diff --git a/OsmAnd/src/net/osmand/plus/views/AidlMapLayer.java b/OsmAnd/src/net/osmand/plus/views/AidlMapLayer.java index 3fad81cd11..04a08e0d75 100644 --- a/OsmAnd/src/net/osmand/plus/views/AidlMapLayer.java +++ b/OsmAnd/src/net/osmand/plus/views/AidlMapLayer.java @@ -1,13 +1,16 @@ package net.osmand.plus.views; -import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.PointF; -import android.util.DisplayMetrics; -import android.view.WindowManager; +import android.net.Uri; +import android.os.AsyncTask; +import android.text.TextUtils; +import net.osmand.AndroidUtils; import net.osmand.aidl.map.ALatLon; import net.osmand.aidl.maplayer.AMapLayer; import net.osmand.aidl.maplayer.point.AMapPoint; @@ -17,8 +20,18 @@ import net.osmand.data.RotatedTileBox; import net.osmand.plus.R; import net.osmand.plus.activities.MapActivity; import net.osmand.plus.views.ContextMenuLayer.IContextMenuProvider; +import net.osmand.plus.widgets.tools.CropCircleTransformation; +import java.io.IOException; +import java.io.InputStream; +import java.lang.ref.WeakReference; +import java.util.HashSet; import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import static net.osmand.aidl.maplayer.point.AMapPoint.POINT_IMAGE_SIZE_PX; public class AidlMapLayer extends OsmandMapLayer implements IContextMenuProvider { private static int POINT_OUTER_COLOR = 0x88555555; @@ -29,9 +42,12 @@ public class AidlMapLayer extends OsmandMapLayer implements IContextMenuProvider private OsmandMapTileView view; private Paint pointInnerCircle; private Paint pointOuter; + private Paint bitmapPaint; private final static float startZoom = 7; private Paint paintTextIcon; + private Map pointImages = new ConcurrentHashMap<>(); + public AidlMapLayer(MapActivity map, AMapLayer aidlLayer) { this.map = map; this.aidlLayer = aidlLayer; @@ -40,9 +56,6 @@ public class AidlMapLayer extends OsmandMapLayer implements IContextMenuProvider @Override public void initLayer(OsmandMapTileView view) { this.view = view; - DisplayMetrics dm = new DisplayMetrics(); - WindowManager wmgr = (WindowManager) view.getContext().getSystemService(Context.WINDOW_SERVICE); - wmgr.getDefaultDisplay().getMetrics(dm); pointInnerCircle = new Paint(); pointInnerCircle.setColor(view.getApplication().getResources().getColor(R.color.poi_background)); @@ -60,6 +73,11 @@ public class AidlMapLayer extends OsmandMapLayer implements IContextMenuProvider pointOuter.setColor(POINT_OUTER_COLOR); pointOuter.setAntiAlias(true); pointOuter.setStyle(Paint.Style.FILL_AND_STROKE); + + bitmapPaint = new Paint(); + bitmapPaint.setAntiAlias(true); + bitmapPaint.setDither(true); + bitmapPaint.setFilterBitmap(true); } private int getRadiusPoi(RotatedTileBox tb) { @@ -78,24 +96,48 @@ public class AidlMapLayer extends OsmandMapLayer implements IContextMenuProvider } @Override - public void onDraw(Canvas canvas, RotatedTileBox tileBox, DrawSettings nightMode) { - final int r = getRadiusPoi(tileBox); + public void onDraw(Canvas canvas, RotatedTileBox tileBox, DrawSettings settings) { + } + + @Override + public void onPrepareBufferImage(Canvas canvas, RotatedTileBox tileBox, DrawSettings settings) { + float density = (float) Math.ceil(tileBox.getDensity()); + final int radius = getRadiusPoi(tileBox); + final int maxRadius = (int) (Math.max(radius, POINT_IMAGE_SIZE_PX) + density); canvas.rotate(-tileBox.getRotate(), tileBox.getCenterPixelX(), tileBox.getCenterPixelY()); + paintTextIcon.setTextSize(radius * 3 / 2); + + Set imageRequests = new HashSet<>(); List points = aidlLayer.getPoints(); for (AMapPoint point : points) { ALatLon l = point.getLocation(); if (l != null) { int x = (int) tileBox.getPixXFromLatLon(l.getLatitude(), l.getLongitude()); int y = (int) tileBox.getPixYFromLatLon(l.getLatitude(), l.getLongitude()); - pointInnerCircle.setColor(point.getColor()); - pointOuter.setColor(POINT_OUTER_COLOR); - paintTextIcon.setColor(PAINT_TEXT_ICON_COLOR); - canvas.drawCircle(x, y, r + (float)Math.ceil(tileBox.getDensity()), pointOuter); - canvas.drawCircle(x, y, r - (float)Math.ceil(tileBox.getDensity()), pointInnerCircle); - paintTextIcon.setTextSize(r * 3 / 2); - canvas.drawText(point.getShortName(), x, y + r * 2.5f, paintTextIcon); + if (tileBox.containsPoint(x, y, maxRadius)) { + Map params = point.getParams(); + String imageUriStr = params.get(AMapPoint.POINT_IMAGE_URI_PARAM); + if (!TextUtils.isEmpty(imageUriStr)) { + Bitmap bitmap = pointImages.get(imageUriStr); + if (bitmap == null) { + imageRequests.add(imageUriStr); + } else { + canvas.drawBitmap(bitmap, x - bitmap.getHeight() / 2, y - bitmap.getWidth() / 2, bitmapPaint); + canvas.drawText(point.getShortName(), x, y + maxRadius * 0.9f, paintTextIcon); + } + } else { + pointInnerCircle.setColor(point.getColor()); + pointOuter.setColor(POINT_OUTER_COLOR); + canvas.drawCircle(x, y, radius + density, pointOuter); + canvas.drawCircle(x, y, radius - density, pointInnerCircle); + canvas.drawText(point.getShortName(), x, y + radius * 2.5f, paintTextIcon); + } + } } } + if (imageRequests.size() > 0) { + executeTaskInBackground(new PointImageReaderTask(this), imageRequests.toArray(new String[imageRequests.size()])); + } } @Override @@ -178,4 +220,47 @@ public class AidlMapLayer extends OsmandMapLayer implements IContextMenuProvider } } } + + private static class PointImageReaderTask extends AsyncTask { + + private WeakReference layerRef; + private CropCircleTransformation circleTransformation = new CropCircleTransformation(); + + PointImageReaderTask(AidlMapLayer layer) { + this.layerRef = new WeakReference<>(layer); + } + + @Override + protected Void doInBackground(String... imageUriStrs) { + for (String imageUriStr : imageUriStrs) { + Uri fileUri = Uri.parse(imageUriStr); + try { + AidlMapLayer layer = layerRef.get(); + if (layer != null) { + try { + InputStream ims = layer.map.getContentResolver().openInputStream(fileUri); + if (ims != null) { + Bitmap bitmap = BitmapFactory.decodeStream(ims); + if (bitmap != null) { + bitmap = circleTransformation.transform(bitmap); + if (bitmap.getWidth() != POINT_IMAGE_SIZE_PX || bitmap.getHeight() != POINT_IMAGE_SIZE_PX) { + bitmap = AndroidUtils.scaleBitmap(bitmap, POINT_IMAGE_SIZE_PX, POINT_IMAGE_SIZE_PX, false); + } + layer.pointImages.put(imageUriStr, bitmap); + } + ims.close(); + } + } catch (IOException e) { + // ignore + } + } else { + break; + } + } catch (Throwable e) { + // ignore + } + } + return null; + } + } }