From f2019314a66b936df8be90221db4412382753eca Mon Sep 17 00:00:00 2001 From: Alexey Kulish Date: Fri, 5 Feb 2016 16:09:45 +0300 Subject: [PATCH 01/18] Map markers storage --- .../src/net/osmand/data/PointDescription.java | 1 + .../src/net/osmand/plus/OsmandSettings.java | 368 ++++++++++++++---- 2 files changed, 300 insertions(+), 69 deletions(-) diff --git a/OsmAnd/src/net/osmand/data/PointDescription.java b/OsmAnd/src/net/osmand/data/PointDescription.java index d0c3b2eb79..4bd1cc441a 100644 --- a/OsmAnd/src/net/osmand/data/PointDescription.java +++ b/OsmAnd/src/net/osmand/data/PointDescription.java @@ -38,6 +38,7 @@ public class PointDescription { public static final String POINT_TYPE_MY_LOCATION = "my_location"; public static final String POINT_TYPE_ALARM = "alarm"; public static final String POINT_TYPE_TARGET = "destination"; + public static final String POINT_TYPE_MAP_MARKER = "map_marker"; public static final String POINT_TYPE_OSM_BUG = "bug"; public static final String POINT_TYPE_WORLD_REGION = "world_region"; public static final String POINT_TYPE_GPX_ITEM = "gpx_item"; diff --git a/OsmAnd/src/net/osmand/plus/OsmandSettings.java b/OsmAnd/src/net/osmand/plus/OsmandSettings.java index 29d93817db..7df5f81a9c 100644 --- a/OsmAnd/src/net/osmand/plus/OsmandSettings.java +++ b/OsmAnd/src/net/osmand/plus/OsmandSettings.java @@ -1472,8 +1472,19 @@ public class OsmandSettings { public final static String START_POINT_LAT = "start_point_lat"; //$NON-NLS-1$ public final static String START_POINT_LON = "start_point_lon"; //$NON-NLS-1$ public final static String START_POINT_DESCRIPTION = "start_point_description"; //$NON-NLS-1$ + public final static String INTERMEDIATE_POINTS = "intermediate_points"; //$NON-NLS-1$ public final static String INTERMEDIATE_POINTS_DESCRIPTION = "intermediate_points_description"; //$NON-NLS-1$ + private IntermediatePointsStorage intermediatePointsStorage = new IntermediatePointsStorage(); + + public final static String MAP_MARKERS_POINT = "map_markers_point"; //$NON-NLS-1$ + public final static String MAP_MARKERS_COLOR = "map_markers_color"; //$NON-NLS-1$ + public final static String MAP_MARKERS_DESCRIPTION = "map_markers_description"; //$NON-NLS-1$ + public final static String MAP_MARKERS_HISTORY_POINT = "map_markers_history_point"; //$NON-NLS-1$ + public final static String MAP_MARKERS_HISTORY_COLOR = "map_markers_history_color"; //$NON-NLS-1$ + public final static String MAP_MARKERS_HISTORY_DESCRIPTION = "map_markers_history_description"; //$NON-NLS-1$ + private MapMarkersStorage mapMarkersStorage = new MapMarkersStorage(); + private MapMarkersHistoryStorage mapMarkersHistoryStorage = new MapMarkersHistoryStorage(); public LatLon getPointToNavigate() { float lat = settingsAPI.getFloat(globalPreferences,POINT_NAVIGATE_LAT, 0); @@ -1521,92 +1532,311 @@ public class OsmandSettings { public final CommonPreference USE_INTERMEDIATE_POINTS_NAVIGATION = new BooleanPreference("use_intermediate_points_navigation", false).makeGlobal().cache(); + + private class IntermediatePointsStorage extends MapPointsStorage { + + public IntermediatePointsStorage() { + pointsKey = INTERMEDIATE_POINTS; + descriptionsKey = INTERMEDIATE_POINTS_DESCRIPTION; + } + } + + private class MapMarkersHistoryStorage extends MapMarkersStorage { + + public MapMarkersHistoryStorage() { + pointsKey = MAP_MARKERS_HISTORY_POINT; + descriptionsKey = MAP_MARKERS_HISTORY_DESCRIPTION; + colorsKey = MAP_MARKERS_HISTORY_COLOR; + } + } + + private class MapMarkersStorage extends MapPointsStorage { + + protected String colorsKey; + + public MapMarkersStorage() { + pointsKey = MAP_MARKERS_POINT; + descriptionsKey = MAP_MARKERS_DESCRIPTION; + colorsKey = MAP_MARKERS_COLOR; + } + + public List getColors(int sz) { + List list = new ArrayList<>(); + String ip = settingsAPI.getString(globalPreferences, colorsKey, ""); + if (ip.trim().length() > 0) { + StringTokenizer tok = new StringTokenizer(ip, ","); + while (tok.hasMoreTokens()) { + String colorStr = tok.nextToken(); + list.add(Integer.parseInt(colorStr)); + } + } + return list; + } + + public boolean insertPoint(double latitude, double longitude, + PointDescription historyDescription, int color, int index) { + List ps = getPoints(); + List ds = getPointDescriptions(ps.size()); + List cs = getColors(ps.size()); + ps.add(index, new LatLon(latitude, longitude)); + ds.add(index, PointDescription.serializeToString(historyDescription)); + cs.add(index, color); + if (historyDescription != null && !historyDescription.isSearchingAddress(ctx)) { + SearchHistoryHelper.getInstance(ctx).addNewItemToHistory(latitude, longitude, historyDescription); + } + return savePoints(ps, ds, cs); + } + + public boolean updatePoint(double latitude, double longitude, + PointDescription historyDescription, int color) { + List ps = getPoints(); + List ds = getPointDescriptions(ps.size()); + List cs = getColors(ps.size()); + int i = ps.indexOf(new LatLon(latitude, longitude)); + ds.set(i, PointDescription.serializeToString(historyDescription)); + cs.set(i, color); + if (historyDescription != null && !historyDescription.isSearchingAddress(ctx)) { + SearchHistoryHelper.getInstance(ctx).addNewItemToHistory(latitude, longitude, historyDescription); + } + return savePoints(ps, ds, cs); + } + + @Override + public boolean deletePoint(int index) { + List ps = getPoints(); + List ds = getPointDescriptions(ps.size()); + List cs = getColors(ps.size()); + ps.remove(index); + ds.remove(index); + cs.remove(index); + return savePoints(ps, ds, cs); + } + + public boolean savePoints(List ps, List ds, List cs) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < ps.size(); i++) { + if (i > 0) { + sb.append(","); + } + sb.append(((float) ps.get(i).getLatitude() + "")).append(",").append(((float) ps.get(i).getLongitude() + "")); + } + StringBuilder tb = new StringBuilder(); + for (int i = 0; i < ds.size(); i++) { + if (i > 0) { + tb.append("--"); + } + if (ds.get(i) == null) { + tb.append(""); + } else { + tb.append(ds.get(i)); + } + } + StringBuilder cb = new StringBuilder(); + for (int i = 0; i < cs.size(); i++) { + if (i > 0) { + cb.append(","); + } + cb.append(Integer.toString(cs.get(i))); + } + return settingsAPI.edit(globalPreferences) + .putString(pointsKey, sb.toString()) + .putString(descriptionsKey, tb.toString()) + .putString(colorsKey, cb.toString()) + .commit(); + } + + @Override + public boolean insertPoint(double latitude, double longitude, PointDescription historyDescription, int index) { + return false; + } + + @Override + public boolean updatePoint(double latitude, double longitude, PointDescription historyDescription) { + return false; + } + + @Override + public boolean savePoints(List ps, List ds) { + return false; + } + } + + private abstract class MapPointsStorage { + + protected String pointsKey; + protected String descriptionsKey; + + public MapPointsStorage() { + } + + public List getPointDescriptions(int sz) { + List list = new ArrayList<>(); + String ip = settingsAPI.getString(globalPreferences, descriptionsKey, ""); + if (ip.trim().length() > 0) { + list.addAll(Arrays.asList(ip.split("--"))); + } + while (list.size() > sz) { + list.remove(list.size() - 1); + } + while (list.size() < sz) { + list.add(""); + } + return list; + } + + public List getPoints() { + List list = new ArrayList<>(); + String ip = settingsAPI.getString(globalPreferences, pointsKey, ""); + if (ip.trim().length() > 0) { + StringTokenizer tok = new StringTokenizer(ip, ","); + while (tok.hasMoreTokens()) { + String lat = tok.nextToken(); + if (!tok.hasMoreTokens()) { + break; + } + String lon = tok.nextToken(); + list.add(new LatLon(Float.parseFloat(lat), Float.parseFloat(lon))); + } + } + return list; + } + + public boolean insertPoint(double latitude, double longitude, PointDescription historyDescription, int index) { + List ps = getPoints(); + List ds = getPointDescriptions(ps.size()); + ps.add(index, new LatLon(latitude, longitude)); + ds.add(index, PointDescription.serializeToString(historyDescription)); + if (historyDescription != null && !historyDescription.isSearchingAddress(ctx)) { + SearchHistoryHelper.getInstance(ctx).addNewItemToHistory(latitude, longitude, historyDescription); + } + return savePoints(ps, ds); + } + + public boolean updatePoint(double latitude, double longitude, PointDescription historyDescription) { + List ps = getPoints(); + List ds = getPointDescriptions(ps.size()); + int i = ps.indexOf(new LatLon(latitude, longitude)); + ds.set(i, PointDescription.serializeToString(historyDescription)); + if (historyDescription != null && !historyDescription.isSearchingAddress(ctx)) { + SearchHistoryHelper.getInstance(ctx).addNewItemToHistory(latitude, longitude, historyDescription); + } + return savePoints(ps, ds); + } + + public boolean deletePoint(int index) { + List ps = getPoints(); + List ds = getPointDescriptions(ps.size()); + ps.remove(index); + ds.remove(index); + return savePoints(ps, ds); + } + + public boolean savePoints(List ps, List ds) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < ps.size(); i++) { + if (i > 0) { + sb.append(","); + } + sb.append(((float) ps.get(i).getLatitude() + "")).append(",").append(((float) ps.get(i).getLongitude() + "")); + } + StringBuilder tb = new StringBuilder(); + for (int i = 0; i < ds.size(); i++) { + if (i > 0) { + tb.append("--"); + } + if (ds.get(i) == null) { + tb.append(""); + } else { + tb.append(ds.get(i)); + } + } + return settingsAPI.edit(globalPreferences) + .putString(pointsKey, sb.toString()) + .putString(descriptionsKey, tb.toString()) + .commit(); + } + } + + public List getIntermediatePointDescriptions(int sz) { - List list = new ArrayList(); - String ip = settingsAPI.getString(globalPreferences,INTERMEDIATE_POINTS_DESCRIPTION, ""); - if (ip.trim().length() > 0) { - list.addAll(Arrays.asList(ip.split("--"))); - } - while(list.size() > sz) { - list.remove(list.size() - 1); - } - while(list.size() < sz) { - list.add(""); - } - return list; + return intermediatePointsStorage.getPointDescriptions(sz); } public List getIntermediatePoints() { - List list = new ArrayList(); - String ip = settingsAPI.getString(globalPreferences,INTERMEDIATE_POINTS, ""); - if (ip.trim().length() > 0) { - StringTokenizer tok = new StringTokenizer(ip, ","); - while (tok.hasMoreTokens()) { - String lat = tok.nextToken(); - if (!tok.hasMoreTokens()) { - break; - } - String lon = tok.nextToken(); - list.add(new LatLon(Float.parseFloat(lat), Float.parseFloat(lon))); - } - } - return list; + return intermediatePointsStorage.getPoints(); } public boolean insertIntermediatePoint(double latitude, double longitude, PointDescription historyDescription, int index) { - List ps = getIntermediatePoints(); - List ds = getIntermediatePointDescriptions(ps.size()); - ps.add(index, new LatLon(latitude, longitude)); - ds.add(index, PointDescription.serializeToString(historyDescription)); - if (historyDescription != null && !historyDescription.isSearchingAddress(ctx)) { - SearchHistoryHelper.getInstance(ctx).addNewItemToHistory(latitude, longitude, historyDescription); - } - return saveIntermediatePoints(ps,ds); + return intermediatePointsStorage.insertPoint(latitude, longitude, historyDescription, index); } public boolean updateIntermediatePoint(double latitude, double longitude, PointDescription historyDescription) { - List ps = getIntermediatePoints(); - List ds = getIntermediatePointDescriptions(ps.size()); - int i = ps.indexOf(new LatLon(latitude, longitude)); - ds.set(i, PointDescription.serializeToString(historyDescription)); - if (historyDescription != null && !historyDescription.isSearchingAddress(ctx)) { - SearchHistoryHelper.getInstance(ctx).addNewItemToHistory(latitude, longitude, historyDescription); - } - return saveIntermediatePoints(ps,ds); + return intermediatePointsStorage.updatePoint(latitude, longitude, historyDescription); } - public boolean deleteIntermediatePoint( int index) { - List ps = getIntermediatePoints(); - List ds = getIntermediatePointDescriptions(ps.size()); - ps.remove(index); - ds.remove(index); - return saveIntermediatePoints(ps,ds); + public boolean deleteIntermediatePoint(int index) { + return intermediatePointsStorage.deletePoint(index); } public boolean saveIntermediatePoints(List ps, List ds) { - StringBuilder sb = new StringBuilder(); - for(int i=0; i 0){ - sb.append(","); - } - sb.append(((float)ps.get(i).getLatitude()+"")).append(",").append(((float)ps.get(i).getLongitude()+"")); - } - StringBuilder tb = new StringBuilder(); - for (int i = 0; i < ds.size(); i++) { - if (i > 0) { - tb.append("--"); - } - if (ds.get(i) == null) { - tb.append(""); - } else { - tb.append(ds.get(i)); - } - } - return settingsAPI.edit(globalPreferences).putString(INTERMEDIATE_POINTS, sb.toString()). - putString(INTERMEDIATE_POINTS_DESCRIPTION, tb.toString()). - commit(); + return intermediatePointsStorage.savePoints(ps, ds); } + + public List getMapMarkersPointDescriptions(int sz) { + return mapMarkersStorage.getPointDescriptions(sz); + } + + public List getMapMarkersPoints() { + return mapMarkersStorage.getPoints(); + } + + public boolean insertMapMarker(double latitude, double longitude, + PointDescription historyDescription, int color, int index) { + return mapMarkersStorage.insertPoint(latitude, longitude, historyDescription, color, index); + } + + public boolean updateMapMarker(double latitude, double longitude, + PointDescription historyDescription, int color) { + return mapMarkersStorage.updatePoint(latitude, longitude, historyDescription, color); + } + + public boolean deleteMapMarker(int index) { + return mapMarkersStorage.deletePoint(index); + } + + public boolean saveMapMarkers(List ps, List ds, List cs) { + return mapMarkersStorage.savePoints(ps, ds, cs); + } + + + public List getMapMarkersHistoryPointDescriptions(int sz) { + return mapMarkersHistoryStorage.getPointDescriptions(sz); + } + + public List getMapMarkersHistoryPoints() { + return mapMarkersHistoryStorage.getPoints(); + } + + public boolean insertMapMarkerHistory(double latitude, double longitude, + PointDescription historyDescription, int color, int index) { + return mapMarkersHistoryStorage.insertPoint(latitude, longitude, historyDescription, color, index); + } + + public boolean updateMapMarkerHistory(double latitude, double longitude, + PointDescription historyDescription, int color) { + return mapMarkersHistoryStorage.updatePoint(latitude, longitude, historyDescription, color); + } + + public boolean deleteMapMarkerHistory(int index) { + return mapMarkersHistoryStorage.deletePoint(index); + } + + public boolean saveMapMarkersHistory(List ps, List ds, List cs) { + return mapMarkersHistoryStorage.savePoints(ps, ds, cs); + } + + public boolean clearPointToNavigate() { return settingsAPI.edit(globalPreferences).remove(POINT_NAVIGATE_LAT).remove(POINT_NAVIGATE_LON). remove(POINT_NAVIGATE_DESCRIPTION).commit(); From ac59d43c22e1bde286a75a6e24a4b0f36e7b4438 Mon Sep 17 00:00:00 2001 From: Dmitriy Prodchenko Date: Fri, 5 Feb 2016 20:37:37 +0200 Subject: [PATCH 02/18] Add Markers icons. --- OsmAnd/res/drawable-hdpi/map_marker_blue.png | Bin 0 -> 2176 bytes OsmAnd/res/drawable-hdpi/map_marker_green.png | Bin 0 -> 2172 bytes OsmAnd/res/drawable-hdpi/map_marker_orange.png | Bin 0 -> 2186 bytes OsmAnd/res/drawable-hdpi/map_marker_red.png | Bin 0 -> 2154 bytes OsmAnd/res/drawable-hdpi/map_marker_yellow.png | Bin 0 -> 2187 bytes OsmAnd/res/drawable-mdpi/map_marker_blue.png | Bin 0 -> 1772 bytes OsmAnd/res/drawable-mdpi/map_marker_green.png | Bin 0 -> 1762 bytes OsmAnd/res/drawable-mdpi/map_marker_orange.png | Bin 0 -> 1764 bytes OsmAnd/res/drawable-mdpi/map_marker_red.png | Bin 0 -> 1721 bytes OsmAnd/res/drawable-mdpi/map_marker_yellow.png | Bin 0 -> 1767 bytes OsmAnd/res/drawable-xhdpi/map_marker_blue.png | Bin 0 -> 2511 bytes OsmAnd/res/drawable-xhdpi/map_marker_green.png | Bin 0 -> 2498 bytes OsmAnd/res/drawable-xhdpi/map_marker_orange.png | Bin 0 -> 2535 bytes OsmAnd/res/drawable-xhdpi/map_marker_red.png | Bin 0 -> 2455 bytes OsmAnd/res/drawable-xhdpi/map_marker_yellow.png | Bin 0 -> 2511 bytes OsmAnd/res/drawable-xxhdpi/map_marker_blue.png | Bin 0 -> 3255 bytes OsmAnd/res/drawable-xxhdpi/map_marker_green.png | Bin 0 -> 3261 bytes OsmAnd/res/drawable-xxhdpi/map_marker_orange.png | Bin 0 -> 3274 bytes OsmAnd/res/drawable-xxhdpi/map_marker_red.png | Bin 0 -> 3213 bytes OsmAnd/res/drawable-xxhdpi/map_marker_yellow.png | Bin 0 -> 3262 bytes 20 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 OsmAnd/res/drawable-hdpi/map_marker_blue.png create mode 100644 OsmAnd/res/drawable-hdpi/map_marker_green.png create mode 100644 OsmAnd/res/drawable-hdpi/map_marker_orange.png create mode 100644 OsmAnd/res/drawable-hdpi/map_marker_red.png create mode 100644 OsmAnd/res/drawable-hdpi/map_marker_yellow.png create mode 100644 OsmAnd/res/drawable-mdpi/map_marker_blue.png create mode 100644 OsmAnd/res/drawable-mdpi/map_marker_green.png create mode 100644 OsmAnd/res/drawable-mdpi/map_marker_orange.png create mode 100644 OsmAnd/res/drawable-mdpi/map_marker_red.png create mode 100644 OsmAnd/res/drawable-mdpi/map_marker_yellow.png create mode 100644 OsmAnd/res/drawable-xhdpi/map_marker_blue.png create mode 100644 OsmAnd/res/drawable-xhdpi/map_marker_green.png create mode 100644 OsmAnd/res/drawable-xhdpi/map_marker_orange.png create mode 100644 OsmAnd/res/drawable-xhdpi/map_marker_red.png create mode 100644 OsmAnd/res/drawable-xhdpi/map_marker_yellow.png create mode 100644 OsmAnd/res/drawable-xxhdpi/map_marker_blue.png create mode 100644 OsmAnd/res/drawable-xxhdpi/map_marker_green.png create mode 100644 OsmAnd/res/drawable-xxhdpi/map_marker_orange.png create mode 100644 OsmAnd/res/drawable-xxhdpi/map_marker_red.png create mode 100644 OsmAnd/res/drawable-xxhdpi/map_marker_yellow.png diff --git a/OsmAnd/res/drawable-hdpi/map_marker_blue.png b/OsmAnd/res/drawable-hdpi/map_marker_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..62d6e982178d03a31f4fbd23cf64623dc24363a9 GIT binary patch literal 2176 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 Gaqz#!r*^9V literal 0 HcmV?d00001 diff --git a/OsmAnd/res/drawable-hdpi/map_marker_orange.png b/OsmAnd/res/drawable-hdpi/map_marker_orange.png new file mode 100644 index 0000000000000000000000000000000000000000..d797f9f9e359471d8d5f13facf0b69cee55d93e8 GIT binary patch literal 2186 zcmbVOc~ld39uIUug<`eKC7076h(M0XK@JGVCWOm`E6TA|2+2TVj!Bc@hC*pYqy>Qj zBJxB9Qm)d%L)dB&sel$Jf}m7b!CGBT7us5UV8tB}-2KDXKX%@m`Tma2=X-zOo0CC& zA0q<`0}KXZoA!yu*=DI2K71sv(S*7>; zz0h#|&$xC3rUOjLmaLWDq)Lax*>lUUddy-akyeoVju z8xTas!oG4UoEHSJVKoF$@h&(K2!a5Ofd{E{GKuO8kcc3aKx7a=B8~_$K_Zhx1U4Tm zYE3PUWrlFLo3_v$3oAho6_Y?nOiaWllJT%QjsP+k3<8lvAdzq=0;fqAEJ z`mY;rL~8`eDu@sQY2bLZ2(3q~?G_o$-Jcs;2cq6E1JzQrC_*_07R4(dCE~|nVbL4B zSSn_^5Gf=YB%@0d%3ZO!pI=i!{_(E&Rgm6e&&@B-{_dXMlxV^Uu68}-_x)vkw^9Fwqt)L%RwoR19RA!> zQ-2Js`9Y94JC!^)x`TJ<&b)=QnZ+gYG$v(x^R655G>1!F(ZH97Eh89hD{*&Z4KK&* zZ|!)Y|MmTx;QSy^&%8cz!pFyn`SkHS?|fTh+TD+t$d`x>O}=zX&z!{1))4w{J-%0Z zDlJQEld13$v>ea9>;JQH`X6%I6Q_>o^rvelZ6$M=%vh3RjPX?!RLih0iOyEp+`PeBFYcW1(YiQ&0JA;Y6M}WLPp(+^{c{ zDWBM#C%+JLaOGgd0qZtgj(=OwOPT)(MOEX4hrD~{)SByevl|Pkg3;o6VV`Yq=v*vw zMB3Llh*4kErcpbzk76P&h?@7hLPd4KS0=L_643+7DQ(6bJ$<$J*r&ga&|5x>8e zY%`Av;+@C{hXiTI9|R(@TQVn#g2$XJ8k z%I;W;Tm4NMHEr-Kea}oIYY5*Sb>X5Z5Q!cK_~DZHAX&`DDO};TGMJYm)fP z58@sd+vB*F19qv?eYL|0(WXN-vt{##PRTvNDr%R6A9%Er;v?h5=J%QylgD-1OY)zY ze)hn8+ypG|-vjU+57g4D?hTJ_F9RPo7G;g6E!0hLH4Ij_)J{+D{QjcLZsj%pa|2;J zJYH&T(J^6Z)vlG{;=}tneuPPJQT}2OMhax=r~^+nOOW-(a(cYa~na= zlUK7V?)Ub#C?>D9g}*3h7uB~kEqzqhd*0!;*nz{1u3*hyyn1!*CP`-4`+`!p)~Rqx zcGYUXxE?bw89g8NLdVf)aOn9ZS8O}nVO4Ry0YjQ^tv+nHPo?ZEWu=e3o8WG|Gbj(v zso&jJQJZjNqw_Zls`B5i*q%L;dn?ck<_AB&Nw?l> zVIA#i(EOVg5iY~;+I4hh604e1d-ifleeb^nGJpja-GqQHzjMoj3#(z7I+z@5gDAsN SW6Slw13zy*r|ECeS^ojEZE+<4 literal 0 HcmV?d00001 diff --git a/OsmAnd/res/drawable-hdpi/map_marker_red.png b/OsmAnd/res/drawable-hdpi/map_marker_red.png new file mode 100644 index 0000000000000000000000000000000000000000..2ef9cdb3ac1fc4e038c913b5b6903b4593232ce0 GIT binary patch literal 2154 zcmbVNX;f2Z8jcG>VMKO{l9GuP2uzlnm86C(A&?3f2~<#!T#_3Iklc_2643Efq##JC z!{QjkA}%aS5gaPA9TkyU3o6pGDMnxfMHo(n!c-LJg5b;#Pk+ok=iYC7p67kPcR4p( z5bVFvbh9Z6h1$pu;D#V04SD@cHXz@L_L@3maM1XLYlN^=qXktE%0~jnKp4IpjDv=YoB(MsF;J{b!NyKEU&CT# z5;k@>Er=AP64_ja}AdA@ike zA{Mg@(Il|3@0aD8^Tu3ce$&?xytiUWOf-!KihK)r$eRl=9GAQW1utL2OC?sS=9jGJ%1QJm$U%J;a zTCE9z{_DmE(dy7tB}5E?)Nry&jO0VQb(M_7?vD*E0TFLlJ5@3yDPSTO7AMOgg@(^% zW04brL?&U;NmMce5_{k&9sn6H5mPfOMxUj6)eXr$C)MjfDaTgGe!(R03HMw zQhW?V1@IoASb~Ru7_n4Jp)r^Y3U-Ar`G4a_M4Tcn70dq=&*~OZkxSF}t$-}vHxr~l zI!J}IimI|vfI_X$;d6aLb%T>9;XvzH#~-fs(d#S2a=F$*+c zj%kIVBC<@LGx*@ac>cmRgYuqQ+qy9OFVF3Lb2d?Zz!yb@EkoD6e&O}}P(7D+&v4zW zcPJm5TOr*~tf>EXiaC>TuY_47-1Tdcd4<`~{Y%!fE>iPPYsP&Bh7^pF;Ml847Hb}E z&hU)6SR{%jr%E$&aQ4DXi_Mm|qc(isYyQZ&KQ=H=R)(daS#*&}v&HRbQ@MS!!m>Jd zSD=|KZqsnQWjlR+wBC4%)LdgVi57DF;@42A7K*KzcJ|(HPl>uZeTAHCtMQ?|f;!_h z)i>{d4&K=`{7SDE@2L!6p0LfJ1U4R5$+q?H4*XVDHWJiWS{`ZsJ?})mXp7#l$Jg)V zW!2Ax1{0xGb#9&BZo;9w#kUqJ&&**!zt!UQn)G(Ifbo?_a7S?kt(mwA-)qN%g;Jw< ziAZ+h<->5{LH0hO)HeQ4LIrlx&{kNLhdck}=b}3feuA%X4|9R@UG;+Q^6Ec7N?AY7 z3*^^6MTG6{^moO66MxR#Y5uK=cFJlpDzTU1-|~2-7+02NGUKj&?l}2Pn8>(!^GDVJ z&};o~FDWip-Cc%1{^#r(`j)&KhLaP<#E7p(y1mWb?tQZ%tJmzQJ-xxA+#Rhowca86fRJs|&sNIA1ABs$9=| zxbuX_xj_$9*5%SIWBmrpu)NXk?pLR&b-$;wa*x|0kc(S8od#+X_MBck(_PH_`iq;p zypKL}nr`?c;*b^Zv(CRiv7DfG#Q7IEoaGzYLiPSFnJK1cEuBsHZn#R1v$V^Nhe@r+ zs`Jw?q^sNGGM=ZOE3&aU^!U@x(qk?8O*6E0f{rYH)#FV;&;CZ<5h1WEG=h9SIPi_n zyXF+6mNIWg=0=ClI?S|_gCoiuJMNlZbt_+Nef`{MdTi&-He5k1Q!%XGVP|8|u>=R^ z!04w{S?r<6od+m7@4n<9H`h_L*S=wWSkq&Q^^D7S-d*&OsH<^A)j&;^w|9>?FEh^Yt8pEfn(^H)wBb_tJ5%-z z^xD+O;QlF7n;)n8>YGRRwdpU(d_v7Vucz?>T`ruO(%vd{g3_(ve;;vmWB-E$Uv@u` z^E++h!LY3ONPY@oV#HE4kl03udoe%ync=Sjo34`9;xi@z>$ZJjpcF3Rg!a2$y$DSM zYs?f`?3O15$8zR;ycC{j@1M?kmK?a>^Y!p0-WEvMWc4QSOxe6`E@==u7ACy_EO?DM o@m}Y8zdrY*KG5H#Y0+MUI&`vO?E>3bzV!F!`vr4rd`0R10p=ZG`v3p{ literal 0 HcmV?d00001 diff --git a/OsmAnd/res/drawable-hdpi/map_marker_yellow.png b/OsmAnd/res/drawable-hdpi/map_marker_yellow.png new file mode 100644 index 0000000000000000000000000000000000000000..6715e40614243b4c61ccc2216a84c4e72db1cb62 GIT binary patch literal 2187 zcmbVOX;c&E8V(?+sMy+D3212yq6lP}EM(D$m;`|u3=mn`f@GOMAjx1dhCo#)$fcC4 zh@he|vdg9*vM7QJR}d&$0hOf|E-DHftMv#7a?m><*!#oNA9v1~`L_3Yp7(o~b0(4R zv1^s7r6~%9TIJ@-@j^x_@^Y7%Am6e2k}_nlfVqCKHzb84genl_EP+HI#!Vp%2E9O` zByxW$DxSP0K_G6d)|bXccm$nyF=B=XsgPd~Tb7 z#mt+)VJz$ir~G()3>#8`7%JWoCk6ljLu23pDxFNCI$%gdfJz`T2mldB1egGkNg`qv z9xS4!l1Q0e9G3+xWW~aUz;HN|K!}Klz(!%p9Xo1Ra1`Sj5v0S5SoWcpr(C>V-fdAtPvo;RFCrBq$Vf_nNm> z!(QNDZhX>OEr<*U30|NYI-n9G`H)&Kf|1z$z0jN?;tg|;N`@pwDCa=p0}43N-?;oEkm>yu%y4mGTACn2tz6X1j!exfFA$C~;9i3e0?*nX*s#Ko&DZVgLkiLVza4 zi9iZ~qYK3n90-WSQYo2AW6;Rh1-#_{jUNGViZE9!|5H4RTS!IDO+U5*viR6cpc3gI z71Ao%uguI)s3pa29A|;H|G6$&{so9`%&2ixH1;d&L7jRBX&KovI)-!lOc2&?_j1p7 zm<=21jx*LezBjb6??i*GyYGB`t(Jk+VT6wcOf9q)nRbB=oj&xyjCrqI(-sQ#5Wn`4hX_$InG7il@;o_1#B z__h5l^_p_-P1I!*+wYS2o(AatT1D&tlXR|Z@=T#G$0)$CSJ{;7Ul1{G7 zXsE`A_4Lrv!oV0sJg04Ed`^&COyGc%`^;EC%PI4jWa|l|+Ye-xcI)k5zDdog-g~tS$@k5JI^+<;7r+(s=e1~#QcY4g_#!L79kqwqa@b!b4i-F;YEXA z9ykcL!PgSviEkc zvApYVF6g^X+03T9=L;$giRcUZD?>T=m^S8Mo804!oY!oOP=6nA;vld2ON7>E>pO4n z?Rl~S3wGi=&A-nTTUrTC-jli##hNh&G`g$XppvQo{luoMhhh_EUufQo_Eyg=u1ixw zm;8$`^fq-VI>R@!)ahzhU#idQD&6s-nW=mK(O!wJEijGm%Y?R)Mg=M9J+}Au zc*l&p^D6XY>GvIP*1o;i=W(a!XmD?&QF?}#X1e^>9ntTE*?XMIx`&fCnRptdx2Nsv zE_@PF$zKOE6b1s1!);&ZAS*5(F&6Q5IP_+?{f zsKM)U%NJ+Y6buaVHlQ0iC$mjQMAOp)6MSR4Cm}eEBir|+5k$rs#!%o8{y$% z22zs~XiAKX%z><#6hto1_i&0HpMxo&z!)Ylok#12PdxS?Ke8@jdBUu zTwnE=JA2Z3QkAyZb~3I5%>{*4ms%^1m;t35Q)sr{d`9X@bZFg5e@;sEiV2UX(YPNs z#Clfb%owBNlh@f!PMsHx-sdZNyS|ReGY9>eq?98j9!p~3hR1n>$~~SvJlY{DNfXEW z$Gs+9-inltjdqhatwhJ}KKPlC@Z9|kZiG~S>hsGs#=+XN`lhK}F$O3oYQ<3QX}f>U P{T{e+Jvb#hgJS;+Lmq%m literal 0 HcmV?d00001 diff --git a/OsmAnd/res/drawable-mdpi/map_marker_blue.png b/OsmAnd/res/drawable-mdpi/map_marker_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..aa798cef83ef89a91fc3d2e132d87758224a4fdb GIT binary patch literal 1772 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 literal 0 HcmV?d00001 diff --git a/OsmAnd/res/drawable-mdpi/map_marker_red.png b/OsmAnd/res/drawable-mdpi/map_marker_red.png new file mode 100644 index 0000000000000000000000000000000000000000..47ce238ff6271ca5eb2661913a103cb9d8575f61 GIT binary patch literal 1721 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 RU(R2TJT^ggIA;0Ue*nm3n>_#k literal 0 HcmV?d00001 diff --git a/OsmAnd/res/drawable-xhdpi/map_marker_blue.png b/OsmAnd/res/drawable-xhdpi/map_marker_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..744cebf0f7453f5be96f099e5dcddd13bb95cb90 GIT binary patch literal 2511 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 literal 0 HcmV?d00001 diff --git a/OsmAnd/res/drawable-xhdpi/map_marker_orange.png b/OsmAnd/res/drawable-xhdpi/map_marker_orange.png new file mode 100644 index 0000000000000000000000000000000000000000..ebcea8544f5422a9a218ada61eba218a562d8dcc GIT binary patch literal 2535 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 literal 0 HcmV?d00001 diff --git a/OsmAnd/res/drawable-xxhdpi/map_marker_blue.png b/OsmAnd/res/drawable-xxhdpi/map_marker_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..8a5015e18937e379e5ae59029f5251110cec0d6a GIT binary patch literal 3255 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 literal 0 HcmV?d00001 diff --git a/OsmAnd/res/drawable-xxhdpi/map_marker_green.png b/OsmAnd/res/drawable-xxhdpi/map_marker_green.png new file mode 100644 index 0000000000000000000000000000000000000000..236e007fa6a6fb714363c31084ac926e488ebcd5 GIT binary patch literal 3261 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 literal 0 HcmV?d00001 diff --git a/OsmAnd/res/drawable-xxhdpi/map_marker_orange.png b/OsmAnd/res/drawable-xxhdpi/map_marker_orange.png new file mode 100644 index 0000000000000000000000000000000000000000..bba7856b1c0730c2f0033a8ea2c488a0f56436b2 GIT binary patch literal 3274 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 DW_U=$ literal 0 HcmV?d00001 diff --git a/OsmAnd/res/drawable-xxhdpi/map_marker_yellow.png b/OsmAnd/res/drawable-xxhdpi/map_marker_yellow.png new file mode 100644 index 0000000000000000000000000000000000000000..8a10d4157db4bf11ebc7a3e748e57ecd83edf859 GIT binary patch literal 3262 zcmbVPdpwi-AD=s6xl~eONS17~3%1oTn;o~UVJfAVUD{$7+vHM{O1Yer*x__hL!^^R zxs)#Amr{g9xt7W$5<17V9Q2zm=Xd@%uk*+6dA*+J`+Yvo`~CiWzMsnXE6D)HDR2@tR)(R2|DfM*KASRgMReK*UWMQ6rF zK4EPF0Mzz!Y1<^*$i7&HfCr^7VxTcRp^^;%Y;uhe(i!0_2`G%Uo6E;peY|tu3dCjN zthPFm9mqlgi^KJd6R`r~C^SY~I0M79a&-Z1ioq%ccq|DW6vK<)i?J~{tFO9P<$lo& zvjTmENWyVe--6mkrh*6p5ewu9b%HS9a5%^r1BE-HkqAe75W)fO2y?)|;0_Q6I2P`J zML2-IUsg(QA|@N_Pb7W!rF_F#aU>EU76yxsj)q1fp#srv7#xGaz#I@T1OlQ&K*X_p z2|WhF7hC^OAhN^^5mzYT3izN!MS7SZN`kXeM*8gtJRzC`9f=?iesI0`VhNqkVEypTUG)8p>;A7?EJ4Jg zO9UdCKoIex3#c4{L?Gq}gdhUpYt=#Etz14+5G`K6Sf+2MCbC4_y(}h4B;bL*<{8WV zhZv9yOc(>sf8KY^0+z#u;h#ozMJ#^9NG~1zT*EzctSf zld>Zhw||X-^5w5#V)2y|BvOvb^XcI?0DyLn7ZFd3=^Dw|7ZDI>R(C*J%viHpy!tq# zx=@bSz^5%;VfhTChe}Ar?^hqN@byI{CgJmIhN|Dxn%LDQACES$25Cm7>a0V$7{U|4 zjD*gP{E>S%qImNQ{2liBH_JA3kM+&?R8>aboaqsZT;_8oaD!K`Jp4ElusN?p*h`CW zIV7^a`%(pB4}1M(*Nn;Wwi9b{bwwiwW($JDRoj2V_j(@PqV~>KAyPYGe^!3vpEV8b6Y->_IkI>h)gC+<~~JYB|`>*G#XVbp7`9( zKR>kY=Og|lcUI172~C>LoEuD^8`7da3tPz3jN=BbNn7=Ru!4oRQM^u=(q{hhu3Z~^ ze9q8(yZ=a@MnfIX?~N5Y;qu9+O)7&Y0COp`fwG$ip4)dRwp zq9|03x~wqpS8rTfzO5RuU%dQ^>gMfM%cG1u*@6winsSyM6%qO>Nz-ML6v6Jr% z$Y0zjFrZ&_xRf20Jia;I&#bpZbrel}1+AYxLI|Foeh9p-ETuW;EK^1?3kx~m@8M=M zWS|mmBg@sLk{pavu*8K6OZwA~wWJW#i!teenet)uN~g^qtFC?*tH` z#^w7yDMII!KlBcX$EH`k%JJU0v;It`tLK8tq}_q^yUq<2nYA|grLB3@bk9*A7O{;9XAmE_CSOlOIPTfAED%+A1eEx9D@b-{pwlh#b)bRU8_T%!Z zHa5C)v@2Rv*a*Id!L+huyK>H6LU=b*nwFUs^!8`D@0jZC*W)#(_4n)P)F)G#sPbbY z{dy|(dKAixoObr55n%SH@2bv%5(fLz~C+{_7ojGUU;V+>p^%XvBkw^-( zYqPlkrtsGT=Aq~~Q<}YxXKz2MXDTJLRi&uhW@~b0t6Gu8%*DjBXX)|S=AxY;>o-0<1LdVQX^IGMWc?2 zjeM=TEFr^y`qi>hUuIwLP4Wt+P;bORcb-pV%8vQ{9m_Pgv77*_*jUQfGLIQi5hO2? zmnTVQQOHtW>+6|(%7B{Tm*HoW;io!mL=Dq0#ySTZwM>~}M!>PiEF1O3@o;@%p8|rwnFne=n-#7HS;?O5+# z*(XnI7n+}MX#c%@Pb&nP-7pxZ{=wQ%<+*Q9Q2P1Hz?9My)y^9I*Bt`|*Q=_pImxp4 z^3+sg?{$Avlu7bMbEFWh7twJt@#j@lSs!zq9Dy4S6o#g}QM;AY%dd-SzaooBi&(P1 zCPMV*e$FT8o^e1{`%f0#t?xs^TRa8_KX01!+-+UZ7k_Ex2~C?$@B{wEWtRit%TK1h zEpC_{+ubu-`)js62ijD$rw8-0&Ak1H*W)xy0=%b{ba-yp)5LkyCZ+iIw|1+KW70KdW}E#^)=7JGL=_$B z`2Aymxwk|T<^jU1@yRu8?73!2jZx(XM)s8L(*BXE=XxGRfA(E3G~O9%`>{`+?S8z; z;w~MKtlzzM1nu@nh3eJuThzYI7BwAP0_*PRD>xEq;Gx3R;B#skgRna>#l5kOso_VT z{mx(U%0dz!p?w#BX6)kQif*H)_D9*J+hil9;~`nq;koFjtB11|q^I|`oeO-lj)NU8 z-C9zVu!It4t2G#Kio17pqs3{$&${EGn#G0(Kj))w2}85A6T0ZcUDt~99KWMTHc+DX$uJgm%$(S}e4z}GLnpBbZvae+>TZiV% zx%=qB=9oHsJ6?mz7k1j_s4iU|Tg?UDzKK-moU_8ut-dptI8(f-;$zU9Z8cyfv`xo2 T?L*t*ABC3(g?QCH^w56+Byx)9 literal 0 HcmV?d00001 From 201af02431f0cf4499694023e3a5f6ee2461d300 Mon Sep 17 00:00:00 2001 From: Alexey Kulish Date: Fri, 5 Feb 2016 21:41:25 +0300 Subject: [PATCH 03/18] Markers in progress --- OsmAnd/res/layout/map_markers.xml | 14 ++ OsmAnd/res/values/strings.xml | 3 + .../src/net/osmand/plus/AppInitializer.java | 1 + .../src/net/osmand/plus/MapMarkersHelper.java | 224 ++++++++++++++++++ .../net/osmand/plus/OsmandApplication.java | 5 + .../src/net/osmand/plus/OsmandSettings.java | 32 ++- .../plus/activities/MapActivityLayers.java | 5 + .../plus/activities/MapMarkersActivity.java | 201 ++++++++++++++++ .../plus/base/MapViewTrackingUtilities.java | 15 +- .../plus/mapcontextmenu/MenuController.java | 5 + .../controllers/MapMarkerMenuController.java | 74 ++++++ .../osmand/plus/views/MapMarkersLayer.java | 159 +++++++++++++ 12 files changed, 725 insertions(+), 13 deletions(-) create mode 100644 OsmAnd/res/layout/map_markers.xml create mode 100644 OsmAnd/src/net/osmand/plus/MapMarkersHelper.java create mode 100644 OsmAnd/src/net/osmand/plus/activities/MapMarkersActivity.java create mode 100644 OsmAnd/src/net/osmand/plus/mapcontextmenu/controllers/MapMarkerMenuController.java create mode 100644 OsmAnd/src/net/osmand/plus/views/MapMarkersLayer.java diff --git a/OsmAnd/res/layout/map_markers.xml b/OsmAnd/res/layout/map_markers.xml new file mode 100644 index 0000000000..885ad6464f --- /dev/null +++ b/OsmAnd/res/layout/map_markers.xml @@ -0,0 +1,14 @@ + + + + + diff --git a/OsmAnd/res/values/strings.xml b/OsmAnd/res/values/strings.xml index 413fa3077f..abd958b898 100644 --- a/OsmAnd/res/values/strings.xml +++ b/OsmAnd/res/values/strings.xml @@ -9,6 +9,9 @@ 3. All your modified/created strings are in the top of the file (to make easier find what\'s translated). PLEASE: Have a look at http://code.google.com/p/osmand/wiki/UIConsistency, it may really improve your and our work :-) Thx - Hardy --> + Active markers + Map markers + Map marker Show polygons Underlay transparency Find a parking diff --git a/OsmAnd/src/net/osmand/plus/AppInitializer.java b/OsmAnd/src/net/osmand/plus/AppInitializer.java index a7c3c33587..7c6b2c5a28 100644 --- a/OsmAnd/src/net/osmand/plus/AppInitializer.java +++ b/OsmAnd/src/net/osmand/plus/AppInitializer.java @@ -342,6 +342,7 @@ public class AppInitializer implements IProgress { app.rendererRegistry = startupInit(new RendererRegistry(app), RendererRegistry.class); app.geocodingLookupService = startupInit(new GeocodingLookupService(app), GeocodingLookupService.class); app.targetPointsHelper = startupInit(new TargetPointsHelper(app), TargetPointsHelper.class); + app.mapMarkersHelper = startupInit(new MapMarkersHelper(app), MapMarkersHelper.class); } diff --git a/OsmAnd/src/net/osmand/plus/MapMarkersHelper.java b/OsmAnd/src/net/osmand/plus/MapMarkersHelper.java new file mode 100644 index 0000000000..1fd859c3b2 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/MapMarkersHelper.java @@ -0,0 +1,224 @@ +package net.osmand.plus; + +import android.content.Context; + +import net.osmand.StateChangedListener; +import net.osmand.data.LatLon; +import net.osmand.data.LocationPoint; +import net.osmand.data.PointDescription; +import net.osmand.plus.GeocodingLookupService; +import net.osmand.plus.OsmandApplication; +import net.osmand.plus.OsmandSettings; +import net.osmand.plus.R; + +import java.util.ArrayList; +import java.util.List; + +public class MapMarkersHelper { + private List mapMarkers = new ArrayList<>(); + private List mapMarkersHistory = new ArrayList<>(); + private OsmandSettings settings; + private List> listeners = new ArrayList>(); + private OsmandApplication ctx; + + public static class MapMarker implements LocationPoint { + public LatLon point; + private PointDescription pointDescription; + public int colorIndex; + public int index; + + public MapMarker(LatLon point, PointDescription name, int colorIndex) { + this.point = point; + this.pointDescription = name; + this.colorIndex = colorIndex; + } + + public MapMarker(LatLon point, PointDescription name, int colorIndex, int index) { + this.point = point; + this.pointDescription = name; + this.colorIndex = colorIndex; + this.index = index; + } + + public PointDescription getPointDescription(Context ctx) { + return new PointDescription(PointDescription.POINT_TYPE_MAP_MARKER, ctx.getString(R.string.map_marker, ""), + getOnlyName()); + } + + public PointDescription getOriginalPointDescription() { + return pointDescription; + } + + public String getOnlyName() { + return pointDescription == null ? "" : pointDescription.getName(); + } + + public boolean isSearchingAddress(Context ctx) { + return pointDescription != null && pointDescription.isSearchingAddress(ctx); + } + + public static MapMarker create(LatLon point, PointDescription name, int color) { + if (point != null) { + return new MapMarker(point, name, color); + } + return null; + } + + public double getLatitude() { + return point.getLatitude(); + } + + public double getLongitude() { + return point.getLongitude(); + } + + public int getColorIndex() { + return colorIndex; + } + + @Override + public int getColor() { + return 0; + } + + @Override + public boolean isVisible() { + return false; + } + + } + + public MapMarkersHelper(OsmandApplication ctx) { + this.ctx = ctx; + this.settings = ctx.getSettings(); + readFromSettings(); + } + + private void readFromSettings() { + mapMarkers.clear(); + mapMarkersHistory.clear(); + List ips = settings.getMapMarkersPoints(); + List desc = settings.getMapMarkersPointDescriptions(ips.size()); + List colors = settings.getMapMarkersColors(ips.size()); + for (int i = 0; i < ips.size(); i++) { + final MapMarker mapMarker = new MapMarker(ips.get(i), + PointDescription.deserializeFromString(desc.get(i), ips.get(i)), colors.get(i), i); + mapMarkers.add(mapMarker); + lookupAddress(mapMarker, false); + } + ips = settings.getMapMarkersHistoryPoints(); + desc = settings.getMapMarkersHistoryPointDescriptions(ips.size()); + colors = settings.getMapMarkersHistoryColors(ips.size()); + for (int i = 0; i < ips.size(); i++) { + final MapMarker mapMarker = new MapMarker(ips.get(i), + PointDescription.deserializeFromString(desc.get(i), ips.get(i)), colors.get(i), i); + mapMarkersHistory.add(mapMarker); + lookupAddress(mapMarker, true); + } + } + + private void lookupAddress(final MapMarker mapMarker, final boolean history) { + if (mapMarker != null && mapMarker.pointDescription.isSearchingAddress(ctx)) { + cancelPointAddressRequests(mapMarker.point); + GeocodingLookupService.AddressLookupRequest lookupRequest = new GeocodingLookupService.AddressLookupRequest(mapMarker.point, new GeocodingLookupService.OnAddressLookupResult() { + @Override + public void geocodingDone(String address) { + mapMarker.pointDescription.setName(address); + if (history) { + settings.updateMapMarkerHistory(mapMarker.point.getLatitude(), mapMarker.point.getLongitude(), + mapMarker.pointDescription, mapMarker.colorIndex); + } else { + settings.updateMapMarker(mapMarker.point.getLatitude(), mapMarker.point.getLongitude(), + mapMarker.pointDescription, mapMarker.colorIndex); + } + refresh(); + } + }, null); + ctx.getGeocodingLookupService().lookupAddress(lookupRequest); + } + } + + public void removeMapMarker(int index) { + settings.deleteMapMarker(index); + MapMarker mapMarker = mapMarkers.remove(index); + cancelPointAddressRequests(mapMarker.point); + int ind = 0; + for (MapMarker marker : mapMarkers) { + marker.index = ind++; + } + refresh(); + } + + public List getActiveMapMarkers() { + return mapMarkers; + } + + public List getMapMarkersHistory() { + return mapMarkersHistory; + } + + public List getActiveMarkersLatLon() { + List list = new ArrayList(); + for (MapMarker m : this.mapMarkers) { + list.add(m.point); + } + return list; + } + + public List getMarkersHistoryLatLon() { + List list = new ArrayList(); + for (MapMarker m : this.mapMarkersHistory) { + list.add(m.point); + } + return list; + } + + public void removeActiveMarkers() { + cancelAddressRequests(); + + settings.clearIntermediatePoints(); + mapMarkers.clear(); + readFromSettings(); + refresh(); + } + + public void removeMarkersHistory() { + cancelAddressRequests(); + + settings.clearIntermediatePoints(); + mapMarkersHistory.clear(); + readFromSettings(); + refresh(); + } + + public void addListener(StateChangedListener l) { + listeners.add(l); + } + + private void updateListeners() { + for (StateChangedListener l : listeners) { + l.stateChanged(null); + } + } + + public void refresh() { + updateListeners(); + } + + private void cancelAddressRequests() { + List list = getActiveMarkersLatLon(); + for (LatLon latLon : list) { + cancelPointAddressRequests(latLon); + } + list = getMarkersHistoryLatLon(); + for (LatLon latLon : list) { + cancelPointAddressRequests(latLon); + } + } + + private void cancelPointAddressRequests(LatLon latLon) { + if (latLon != null) { + ctx.getGeocodingLookupService().cancel(latLon); + } + } +} diff --git a/OsmAnd/src/net/osmand/plus/OsmandApplication.java b/OsmAnd/src/net/osmand/plus/OsmandApplication.java index 23c41644d1..4e8b6b828a 100644 --- a/OsmAnd/src/net/osmand/plus/OsmandApplication.java +++ b/OsmAnd/src/net/osmand/plus/OsmandApplication.java @@ -91,6 +91,7 @@ public class OsmandApplication extends MultiDexApplication { NotificationHelper notificationHelper; LiveMonitoringHelper liveMonitoringHelper; TargetPointsHelper targetPointsHelper; + MapMarkersHelper mapMarkersHelper; WaypointHelper waypointHelper; DownloadIndexesThread downloadIndexesThread; AvoidSpecificRoads avoidSpecificRoads; @@ -540,6 +541,10 @@ public class OsmandApplication extends MultiDexApplication { return targetPointsHelper; } + public MapMarkersHelper getMapMarkersHelper() { + return mapMarkersHelper; + } + public void showShortToastMessage(final int msgId, final Object... args) { uiHandler.post(new Runnable() { @Override diff --git a/OsmAnd/src/net/osmand/plus/OsmandSettings.java b/OsmAnd/src/net/osmand/plus/OsmandSettings.java index 7df5f81a9c..7530e57995 100644 --- a/OsmAnd/src/net/osmand/plus/OsmandSettings.java +++ b/OsmAnd/src/net/osmand/plus/OsmandSettings.java @@ -1574,13 +1574,13 @@ public class OsmandSettings { } public boolean insertPoint(double latitude, double longitude, - PointDescription historyDescription, int color, int index) { + PointDescription historyDescription, int colorIndex, int index) { List ps = getPoints(); List ds = getPointDescriptions(ps.size()); List cs = getColors(ps.size()); ps.add(index, new LatLon(latitude, longitude)); ds.add(index, PointDescription.serializeToString(historyDescription)); - cs.add(index, color); + cs.add(index, colorIndex); if (historyDescription != null && !historyDescription.isSearchingAddress(ctx)) { SearchHistoryHelper.getInstance(ctx).addNewItemToHistory(latitude, longitude, historyDescription); } @@ -1588,13 +1588,13 @@ public class OsmandSettings { } public boolean updatePoint(double latitude, double longitude, - PointDescription historyDescription, int color) { + PointDescription historyDescription, int colorIndex) { List ps = getPoints(); List ds = getPointDescriptions(ps.size()); List cs = getColors(ps.size()); int i = ps.indexOf(new LatLon(latitude, longitude)); ds.set(i, PointDescription.serializeToString(historyDescription)); - cs.set(i, color); + cs.set(i, colorIndex); if (historyDescription != null && !historyDescription.isSearchingAddress(ctx)) { SearchHistoryHelper.getInstance(ctx).addNewItemToHistory(latitude, longitude, historyDescription); } @@ -1787,18 +1787,22 @@ public class OsmandSettings { return mapMarkersStorage.getPointDescriptions(sz); } + public List getMapMarkersColors(int sz) { + return mapMarkersStorage.getColors(sz); + } + public List getMapMarkersPoints() { return mapMarkersStorage.getPoints(); } public boolean insertMapMarker(double latitude, double longitude, - PointDescription historyDescription, int color, int index) { - return mapMarkersStorage.insertPoint(latitude, longitude, historyDescription, color, index); + PointDescription historyDescription, int colorIndex, int index) { + return mapMarkersStorage.insertPoint(latitude, longitude, historyDescription, colorIndex, index); } public boolean updateMapMarker(double latitude, double longitude, - PointDescription historyDescription, int color) { - return mapMarkersStorage.updatePoint(latitude, longitude, historyDescription, color); + PointDescription historyDescription, int colorIndex) { + return mapMarkersStorage.updatePoint(latitude, longitude, historyDescription, colorIndex); } public boolean deleteMapMarker(int index) { @@ -1814,18 +1818,22 @@ public class OsmandSettings { return mapMarkersHistoryStorage.getPointDescriptions(sz); } + public List getMapMarkersHistoryColors(int sz) { + return mapMarkersHistoryStorage.getColors(sz); + } + public List getMapMarkersHistoryPoints() { return mapMarkersHistoryStorage.getPoints(); } public boolean insertMapMarkerHistory(double latitude, double longitude, - PointDescription historyDescription, int color, int index) { - return mapMarkersHistoryStorage.insertPoint(latitude, longitude, historyDescription, color, index); + PointDescription historyDescription, int colorIndex, int index) { + return mapMarkersHistoryStorage.insertPoint(latitude, longitude, historyDescription, colorIndex, index); } public boolean updateMapMarkerHistory(double latitude, double longitude, - PointDescription historyDescription, int color) { - return mapMarkersHistoryStorage.updatePoint(latitude, longitude, historyDescription, color); + PointDescription historyDescription, int colorIndex) { + return mapMarkersHistoryStorage.updatePoint(latitude, longitude, historyDescription, colorIndex); } public boolean deleteMapMarkerHistory(int index) { diff --git a/OsmAnd/src/net/osmand/plus/activities/MapActivityLayers.java b/OsmAnd/src/net/osmand/plus/activities/MapActivityLayers.java index 5c2c36fbab..868e0333b0 100644 --- a/OsmAnd/src/net/osmand/plus/activities/MapActivityLayers.java +++ b/OsmAnd/src/net/osmand/plus/activities/MapActivityLayers.java @@ -38,6 +38,7 @@ import net.osmand.plus.views.GPXLayer; import net.osmand.plus.views.ImpassableRoadsLayer; import net.osmand.plus.views.MapControlsLayer; import net.osmand.plus.views.MapInfoLayer; +import net.osmand.plus.views.MapMarkersLayer; import net.osmand.plus.views.MapTextLayer; import net.osmand.plus.views.MapTileLayer; import net.osmand.plus.views.OsmandMapTileView; @@ -72,6 +73,7 @@ public class MapActivityLayers { private TransportInfoLayer transportInfoLayer; private PointLocationLayer locationLayer; private PointNavigationLayer navigationLayer; + private MapMarkersLayer mapMarkersLayer; private ImpassableRoadsLayer impassableRoadsLayer; private MapInfoLayer mapInfoLayer; private MapTextLayer mapTextLayer; @@ -143,6 +145,9 @@ public class MapActivityLayers { // 7. point navigation layer navigationLayer = new PointNavigationLayer(activity); mapView.addLayer(navigationLayer, 7); + // 7.3 map markers layer + mapMarkersLayer = new MapMarkersLayer(activity); + mapView.addLayer(mapMarkersLayer, 7.3f); // 7.5 Impassible roads impassableRoadsLayer = new ImpassableRoadsLayer(activity); mapView.addLayer(impassableRoadsLayer, 7.5f); diff --git a/OsmAnd/src/net/osmand/plus/activities/MapMarkersActivity.java b/OsmAnd/src/net/osmand/plus/activities/MapMarkersActivity.java new file mode 100644 index 0000000000..605990e7e1 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/activities/MapMarkersActivity.java @@ -0,0 +1,201 @@ +package net.osmand.plus.activities; + +import android.os.Bundle; +import android.support.v4.app.FragmentActivity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.CompoundButton; +import android.widget.TextView; + +import net.osmand.AndroidUtils; +import net.osmand.plus.GeocodingLookupService; +import net.osmand.plus.MapMarkersHelper; +import net.osmand.plus.MapMarkersHelper.MapMarker; +import net.osmand.plus.R; +import net.osmand.plus.helpers.WaypointHelper; +import net.osmand.plus.views.controls.StableArrayAdapter; + +import java.util.ArrayList; +import java.util.List; + +public class MapMarkersActivity extends OsmandListActivity { + + public static final int ACTIVE_MARKERS = 0; + public static final int MARKERS_HISTORY = 1; + + private boolean nightMode; + + @Override + protected void onCreate(Bundle savedInstanceState) { + getMyApplication().applyTheme(this); + super.onCreate(savedInstanceState); + setContentView(R.layout.map_markers); + getSupportActionBar().setTitle(R.string.map_markers); + + nightMode = getMyApplication().getDaynightHelper().isNightModeForMapControls(); + setListAdapter(getMapMarkersListAdapter()); + } + + @Override + public StableArrayAdapter getListAdapter() { + return (StableArrayAdapter) super.getListAdapter(); + } + + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + getListAdapter().getItem(position); + // + } + + @Override + protected void onResume() { + super.onResume(); + getListAdapter().notifyDataSetChanged(); + } + + public StableArrayAdapter getMapMarkersListAdapter() { + + final List objects = getListObjects(); + List activeObjects = getActiveObjects(objects); + + final StableArrayAdapter listAdapter = new StableArrayAdapter(getMyApplication(), + R.layout.waypoint_reached, R.id.title, objects, activeObjects) { + + @Override + public void buildDividers() { + dividers = getCustomDividers(ctx, getObjects(), nightMode); + } + + @Override + public View getView(final int position, View convertView, ViewGroup parent) { + // User super class to create the View + View v = convertView; + final ArrayAdapter thisAdapter = this; + Object obj = getItem(position); + boolean labelView = (obj instanceof Integer); + boolean topDividerView = (obj instanceof Boolean) && ((Boolean) obj); + boolean bottomDividerView = (obj instanceof Boolean) && !((Boolean) obj); + if (labelView) { + v = createItemForCategory(ctx, (Integer) obj, running, position, thisAdapter, nightMode); + AndroidUtils.setListItemBackground(MapMarkersActivity.this, v, nightMode); + } else if (topDividerView) { + v = ctx.getLayoutInflater().inflate(R.layout.card_top_divider, null); + } else if (bottomDividerView) { + v = ctx.getLayoutInflater().inflate(R.layout.card_bottom_divider, null); + } else if (obj instanceof MapMarker) { + MapMarker marker = (MapMarker) obj; + v = updateWaypointItemView(edit, deletedPoints, app, ctx, helper, v, marker, this, + nightMode, flat); + AndroidUtils.setListItemBackground(MapMarkersActivity.this, v, nightMode); + } + return v; + } + }; + + for (Object p : objects) { + if (p instanceof MapMarker) { + final MapMarker marker = (MapMarker) p; + if (marker.getOriginalPointDescription() != null + && marker.getOriginalPointDescription().isSearchingAddress(this)) { + GeocodingLookupService.AddressLookupRequest lookupRequest + = new GeocodingLookupService.AddressLookupRequest(marker.point, new GeocodingLookupService.OnAddressLookupResult() { + @Override + public void geocodingDone(String address) { + if (helperCallbacks != null) { + helperCallbacks.reloadAdapter(); + } else { + reloadListAdapter(listAdapter); + } + } + }, null); + getMyApplication().getGeocodingLookupService().lookupAddress(lookupRequest); + } + } + } + + return listAdapter; + } + + protected View createItemForCategory(final int type, final int position, final ArrayAdapter thisAdapter, boolean nightMode) { + View v = getLayoutInflater().inflate(R.layout.waypoint_header, null); + final CompoundButton btn = (CompoundButton) v.findViewById(R.id.check_item); + btn.setVisibility(waypointHelper.isTypeConfigurable(type) ? View.VISIBLE : View.GONE); + btn.setOnCheckedChangeListener(null); + final boolean checked = waypointHelper.isTypeEnabled(type); + btn.setChecked(checked); + btn.setEnabled(running[0] == -1); + v.findViewById(R.id.ProgressBar).setVisibility(position == running[0] ? View.VISIBLE : View.GONE); + btn.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + running[0] = position; + thisAdapter.notifyDataSetInvalidated(); + if (type == WaypointHelper.POI && isChecked) { + selectPoi(running, thisAdapter, type, isChecked, ctx); + } else { + enableType(running, thisAdapter, type, isChecked); + } + } + + }); + + TextView tv = (TextView) v.findViewById(R.id.header_text); + AndroidUtils.setTextPrimaryColor(mapActivity, tv, nightMode); + tv.setText(getHeader(type, checked, ctx)); + return v; + } + + protected String getHeader(int type) { + String str = getString(R.string.map_markers); + switch (type) { + case ACTIVE_MARKERS: + str = getString(R.string.active_markers); + break; + case MARKERS_HISTORY: + str = getString(R.string.shared_string_history); + break; + } + return str; + } + + + //LatLon lastKnownMapLocation = getMyApplication().getSettings().getLastKnownMapLocation(); + //int dist = (int) (MapUtils.getDistance(marker.getLatitude(), marker.getLongitude(), + //lastKnownMapLocation.getLatitude(), lastKnownMapLocation.getLongitude())); + + protected List getListObjects() { + final List objects = new ArrayList<>(); + final MapMarkersHelper markersHelper = getMyApplication().getMapMarkersHelper(); + + List activeMarkers = markersHelper.getActiveMapMarkers(); + if (activeMarkers.size() > 0) { + objects.add(true); + objects.add(ACTIVE_MARKERS); + objects.addAll(activeMarkers); + objects.add(false); + } + + List markersHistory = markersHelper.getMapMarkersHistory(); + if (markersHistory.size() > 0) { + objects.add(true); + objects.add(MARKERS_HISTORY); + objects.addAll(markersHistory); + objects.add(false); + } + + return objects; + } + + private List getActiveObjects(List objects) { + List activeObjects = new ArrayList<>(); + for (Object obj : objects) { + if (obj instanceof MapMarker) { + activeObjects.add(obj); + } + } + return activeObjects; + } +} \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/base/MapViewTrackingUtilities.java b/OsmAnd/src/net/osmand/plus/base/MapViewTrackingUtilities.java index ecd6adbf45..07d7ad6e5f 100644 --- a/OsmAnd/src/net/osmand/plus/base/MapViewTrackingUtilities.java +++ b/OsmAnd/src/net/osmand/plus/base/MapViewTrackingUtilities.java @@ -53,6 +53,7 @@ public class MapViewTrackingUtilities implements OsmAndLocationListener, IMapLoc app.getLocationProvider().addLocationListener(this); app.getLocationProvider().addCompassListener(this); addTargetPointListener(app); + addMapMarkersListener(app); app.getRoutingHelper().addListener(this); } @@ -67,7 +68,19 @@ public class MapViewTrackingUtilities implements OsmAndLocationListener, IMapLoc } }); } - + + private void addMapMarkersListener(OsmandApplication app) { + app.getMapMarkersHelper().addListener(new StateChangedListener() { + + @Override + public void stateChanged(Void change) { + if(mapView != null) { + mapView.refreshMap(); + } + } + }); + } + public void setMapView(OsmandMapTileView mapView) { this.mapView = mapView; if(mapView != null) { diff --git a/OsmAnd/src/net/osmand/plus/mapcontextmenu/MenuController.java b/OsmAnd/src/net/osmand/plus/mapcontextmenu/MenuController.java index 49924b84f9..532cdc6698 100644 --- a/OsmAnd/src/net/osmand/plus/mapcontextmenu/MenuController.java +++ b/OsmAnd/src/net/osmand/plus/mapcontextmenu/MenuController.java @@ -11,6 +11,8 @@ import net.osmand.data.LatLon; import net.osmand.data.PointDescription; import net.osmand.plus.GPXUtilities.WptPt; import net.osmand.plus.GpxSelectionHelper.GpxDisplayItem; +import net.osmand.plus.MapMarkersHelper; +import net.osmand.plus.MapMarkersHelper.MapMarker; import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; import net.osmand.plus.TargetPointsHelper.TargetPoint; @@ -24,6 +26,7 @@ import net.osmand.plus.mapcontextmenu.controllers.GpxItemMenuController; import net.osmand.plus.mapcontextmenu.controllers.HistoryMenuController; import net.osmand.plus.mapcontextmenu.controllers.ImpassibleRoadsMenuController; import net.osmand.plus.mapcontextmenu.controllers.MapDataMenuController; +import net.osmand.plus.mapcontextmenu.controllers.MapMarkerMenuController; import net.osmand.plus.mapcontextmenu.controllers.MyLocationMenuController; import net.osmand.plus.mapcontextmenu.controllers.PointDescriptionMenuController; import net.osmand.plus.mapcontextmenu.controllers.TargetPointMenuController; @@ -101,6 +104,8 @@ public abstract class MenuController extends BaseMenuController { menuController = new OsmBugMenuController(app, mapActivity, pointDescription, (OpenStreetNote) object); } else if (object instanceof GpxDisplayItem) { menuController = new GpxItemMenuController(app, mapActivity, pointDescription, (GpxDisplayItem) object); + } else if (object instanceof MapMarker) { + menuController = new MapMarkerMenuController(app, mapActivity, pointDescription, (MapMarker) object); } else if (object instanceof LatLon) { if (pointDescription.isParking()) { menuController = new ParkingPositionMenuController(app, mapActivity, pointDescription); diff --git a/OsmAnd/src/net/osmand/plus/mapcontextmenu/controllers/MapMarkerMenuController.java b/OsmAnd/src/net/osmand/plus/mapcontextmenu/controllers/MapMarkerMenuController.java new file mode 100644 index 0000000000..aa5e32cebf --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/mapcontextmenu/controllers/MapMarkerMenuController.java @@ -0,0 +1,74 @@ +package net.osmand.plus.mapcontextmenu.controllers; + +import android.graphics.drawable.Drawable; + +import net.osmand.data.PointDescription; +import net.osmand.plus.MapMarkersHelper; +import net.osmand.plus.MapMarkersHelper.MapMarker; +import net.osmand.plus.OsmandApplication; +import net.osmand.plus.R; +import net.osmand.plus.activities.MapActivity; +import net.osmand.plus.mapcontextmenu.MenuBuilder; +import net.osmand.plus.mapcontextmenu.MenuController; +import net.osmand.util.Algorithms; + +public class MapMarkerMenuController extends MenuController { + + private MapMarker mapMarker; + + public MapMarkerMenuController(OsmandApplication app, MapActivity mapActivity, PointDescription pointDescription, MapMarker mapMarker) { + super(new MenuBuilder(app), pointDescription, mapActivity); + this.mapMarker = mapMarker; + final MapMarkersHelper markersHelper = app.getMapMarkersHelper(); + leftTitleButtonController = new TitleButtonController() { + @Override + public void buttonPressed() { + markersHelper.removeMapMarker(getMapMarker().index); + getMapActivity().getContextMenu().close(); + } + }; + leftTitleButtonController.caption = getMapActivity().getString(R.string.shared_string_remove); + leftTitleButtonController.leftIconId = R.drawable.ic_action_delete_dark; + } + + @Override + protected void setObject(Object object) { + if (object instanceof MapMarker) { + this.mapMarker = (MapMarker) object; + } + } + + public MapMarker getMapMarker() { + return mapMarker; + } + + @Override + protected int getSupportedMenuStatesPortrait() { + return MenuState.HEADER_ONLY | MenuState.HALF_SCREEN; + } + + @Override + public boolean needTypeStr() { + return !Algorithms.isEmpty(getNameStr()); + } + + @Override + public boolean displayDistanceDirection() { + return true; + } + + @Override + public Drawable getLeftIcon() { + return getIconOrig(R.drawable.list_intermediate); + } + + @Override + public String getTypeStr() { + return mapMarker.getPointDescription(getMapActivity()).getTypeName(); + } + + @Override + public boolean needStreetName() { + return !needTypeStr(); + } +} \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/views/MapMarkersLayer.java b/OsmAnd/src/net/osmand/plus/views/MapMarkersLayer.java new file mode 100644 index 0000000000..3587f72c73 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/views/MapMarkersLayer.java @@ -0,0 +1,159 @@ +package net.osmand.plus.views; + +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.PointF; + +import net.osmand.data.LatLon; +import net.osmand.data.PointDescription; +import net.osmand.data.RotatedTileBox; +import net.osmand.plus.MapMarkersHelper; +import net.osmand.plus.MapMarkersHelper.MapMarker; +import net.osmand.plus.R; +import net.osmand.plus.TargetPointsHelper; +import net.osmand.plus.activities.MapActivity; + +import java.util.List; + +public class MapMarkersLayer extends OsmandMapLayer implements ContextMenuLayer.IContextMenuProvider { + private final MapActivity map; + private OsmandMapTileView view; + + private Paint bitmapPaint; + private Bitmap markerBitmap; + + public MapMarkersLayer(MapActivity map) { + this.map = map; + } + + private void initUI() { + bitmapPaint = new Paint(); + bitmapPaint.setDither(true); + bitmapPaint.setAntiAlias(true); + bitmapPaint.setFilterBitmap(true); + markerBitmap = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_intermediate_point); + } + + @Override + public void initLayer(OsmandMapTileView view) { + this.view = view; + initUI(); + } + + @Override + public void onDraw(Canvas canvas, RotatedTileBox tb, DrawSettings nightMode) { + if (tb.getZoom() < 3) { + return; + } + + MapMarkersHelper markersHelper = map.getMyApplication().getMapMarkersHelper(); + int index = 0; + for (MapMarker marker : markersHelper.getActiveMapMarkers()) { + index++; + if (isLocationVisible(tb, marker)) { + int marginX = markerBitmap.getWidth() / 6; + int marginY = markerBitmap.getHeight(); + int locationX = tb.getPixXFromLonNoRot(marker.getLongitude()); + int locationY = tb.getPixYFromLatNoRot(marker.getLatitude()); + canvas.rotate(-tb.getRotate(), locationX, locationY); + canvas.drawBitmap(markerBitmap, locationX - marginX, locationY - marginY, bitmapPaint); + canvas.rotate(tb.getRotate(), locationX, locationY); + } + } + } + + public boolean isLocationVisible(RotatedTileBox tb, MapMarker marker) { + if (marker == null || tb == null) { + return false; + } + return tb.containsLatLon(marker.getLatitude(), marker.getLongitude()); + } + + + @Override + public void destroyLayer() { + + } + + @Override + public boolean drawInScreenPixels() { + return false; + } + + @Override + public boolean disableSingleTap() { + return false; + } + + @Override + public boolean disableLongPressOnMap() { + return false; + } + + @Override + public void collectObjectsFromPoint(PointF point, RotatedTileBox tileBox, List o) { + MapMarkersHelper markersHelper = map.getMyApplication().getMapMarkersHelper(); + List markers = markersHelper.getActiveMapMarkers(); + int r = getRadiusPoi(tileBox); + for (int i = 0; i < markers.size(); i++) { + MapMarker marker = markers.get(i); + LatLon latLon = marker.point; + if (latLon != null) { + int ex = (int) point.x; + int ey = (int) point.y; + int x = (int) tileBox.getPixXFromLatLon(latLon.getLatitude(), latLon.getLongitude()); + int y = (int) tileBox.getPixYFromLatLon(latLon.getLatitude(), latLon.getLongitude()); + if (calculateBelongs(ex, ey, x, y, r)) { + o.add(marker); + } + } + } + + + } + + private boolean calculateBelongs(int ex, int ey, int objx, int objy, int radius) { + return Math.abs(objx - ex) <= radius && (ey - objy) <= radius && (objy - ey) <= 2.5 * radius; + } + + public int getRadiusPoi(RotatedTileBox tb) { + int r = 0; + 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()); + } + + @Override + public LatLon getObjectLocation(Object o) { + if (o instanceof MapMarker) { + return ((MapMarker) o).point; + } + return null; + } + + @Override + public String getObjectDescription(Object o) { + if (o instanceof MapMarker) { + return ((MapMarker) o).getPointDescription(view.getContext()).getFullPlainName(view.getContext()); + } + return null; + } + + @Override + public PointDescription getObjectName(Object o) { + if (o instanceof MapMarker) { + return ((MapMarker) o).getPointDescription(view.getContext()); + } + return null; + } +} From 494ae4b4d08db62f758e576104b57c291548c56b Mon Sep 17 00:00:00 2001 From: Alexey Kulish Date: Fri, 5 Feb 2016 22:59:57 +0300 Subject: [PATCH 04/18] Markers in progress --- OsmAnd/AndroidManifest.xml | 1 + OsmAnd/res/layout/waypoint_header.xml | 11 + .../osmand/plus/OsmAndAppCustomization.java | 6 +- .../plus/activities/MapActivityActions.java | 9 +- .../plus/activities/MapMarkersActivity.java | 235 ++++++++++++++---- .../osmand/plus/views/MapMarkersLayer.java | 41 ++- 6 files changed, 248 insertions(+), 55 deletions(-) diff --git a/OsmAnd/AndroidManifest.xml b/OsmAnd/AndroidManifest.xml index c0aa8be30f..49648a97e7 100644 --- a/OsmAnd/AndroidManifest.xml +++ b/OsmAnd/AndroidManifest.xml @@ -166,6 +166,7 @@ + diff --git a/OsmAnd/res/layout/waypoint_header.xml b/OsmAnd/res/layout/waypoint_header.xml index 40ff101a1a..76b9e2431c 100644 --- a/OsmAnd/res/layout/waypoint_header.xml +++ b/OsmAnd/res/layout/waypoint_header.xml @@ -32,4 +32,15 @@ +