diff --git a/OsmAnd-java/src/main/java/net/osmand/IndexConstants.java b/OsmAnd-java/src/main/java/net/osmand/IndexConstants.java index 877b95c119..14401c4a04 100644 --- a/OsmAnd-java/src/main/java/net/osmand/IndexConstants.java +++ b/OsmAnd-java/src/main/java/net/osmand/IndexConstants.java @@ -45,7 +45,9 @@ public class IndexConstants { public static final String ROUTING_FILE_EXT = ".xml"; public static final String RENDERER_INDEX_EXT = ".render.xml"; //$NON-NLS-1$ - + + public static final String GPX_FILE_EXT = ".gpx"; //$NON-NLS-1$ + public final static String POI_TABLE = "poi"; //$NON-NLS-1$ public static final String INDEX_DOWNLOAD_DOMAIN = "download.osmand.net"; diff --git a/OsmAnd/res/layout/item_info_fragment.xml b/OsmAnd/res/layout/item_info_fragment.xml new file mode 100644 index 0000000000..437826d86a --- /dev/null +++ b/OsmAnd/res/layout/item_info_fragment.xml @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/OsmAnd/res/values/strings.xml b/OsmAnd/res/values/strings.xml index fad1a692d0..6c8e7682b7 100644 --- a/OsmAnd/res/values/strings.xml +++ b/OsmAnd/res/values/strings.xml @@ -11,6 +11,7 @@ Thx - Hardy --> + Extra maps Custom color Lombard Aragonese diff --git a/OsmAnd/src/net/osmand/JsonUtils.java b/OsmAnd/src/net/osmand/JsonUtils.java new file mode 100644 index 0000000000..7c8bb278fe --- /dev/null +++ b/OsmAnd/src/net/osmand/JsonUtils.java @@ -0,0 +1,78 @@ +package net.osmand; + +import android.content.Context; +import android.content.res.Configuration; + +import net.osmand.util.Algorithms; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +public class JsonUtils { + + public static String getLocalizedResFromMap(Context ctx, Map localizedMap, String defVal) { + if (!Algorithms.isEmpty(localizedMap)) { + Configuration config = ctx.getResources().getConfiguration(); + String lang = config.locale.getLanguage(); + String name = localizedMap.get(lang); + if (Algorithms.isEmpty(name)) { + name = localizedMap.get(""); + } + if (!Algorithms.isEmpty(name)) { + return name; + } + } + return defVal; + } + + public static List jsonArrayToList(String key, JSONObject json) throws JSONException { + List items = new ArrayList<>(); + JSONArray jsonArray = json.optJSONArray(key); + if (jsonArray != null) { + for (int i = 0; i < jsonArray.length(); i++) { + items.add(jsonArray.getString(i)); + } + } + return items; + } + + public static Map getLocalizedMapFromJson(String key, JSONObject json) throws JSONException { + Map localizedMap = new HashMap<>(); + JSONObject jsonObject = json.optJSONObject(key); + if (jsonObject != null) { + for (Iterator it = jsonObject.keys(); it.hasNext(); ) { + String localeKey = it.next(); + String name = jsonObject.getString(localeKey); + localizedMap.put(localeKey, name); + } + } + return localizedMap; + } + + public static void writeStringListToJson(String key, JSONObject json, List items) throws JSONException { + if (!Algorithms.isEmpty(items)) { + JSONArray jsonArray = new JSONArray(); + for (String render : items) { + jsonArray.put(render); + } + json.put(key, jsonArray); + } + } + + public static void writeLocalizedMapToJson(String jsonKey, JSONObject json, Map map) throws JSONException { + if (!Algorithms.isEmpty(map)) { + JSONObject jsonObject = new JSONObject(); + for (Map.Entry entry : map.entrySet()) { + jsonObject.put(entry.getKey(), entry.getValue()); + } + json.put(jsonKey, jsonObject); + } + } +} \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/CustomOsmandPlugin.java b/OsmAnd/src/net/osmand/plus/CustomOsmandPlugin.java index 88c9e53042..3d6fb4b321 100644 --- a/OsmAnd/src/net/osmand/plus/CustomOsmandPlugin.java +++ b/OsmAnd/src/net/osmand/plus/CustomOsmandPlugin.java @@ -1,7 +1,6 @@ package net.osmand.plus; import android.app.Activity; -import android.content.res.Configuration; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; @@ -9,9 +8,12 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import net.osmand.IndexConstants; +import net.osmand.JsonUtils; import net.osmand.PlatformUtil; +import net.osmand.data.LatLon; import net.osmand.map.ITileSource; import net.osmand.map.TileSourceManager; +import net.osmand.map.WorldRegion; import net.osmand.plus.SettingsHelper.AvoidRoadsSettingsItem; import net.osmand.plus.SettingsHelper.MapSourcesSettingsItem; import net.osmand.plus.SettingsHelper.PluginSettingsItem; @@ -20,6 +22,10 @@ import net.osmand.plus.SettingsHelper.ProfileSettingsItem; import net.osmand.plus.SettingsHelper.QuickActionsSettingsItem; import net.osmand.plus.SettingsHelper.SettingsCollectListener; import net.osmand.plus.SettingsHelper.SettingsItem; +import net.osmand.plus.download.DownloadActivityType; +import net.osmand.plus.download.DownloadIndexesThread; +import net.osmand.plus.download.DownloadResources; +import net.osmand.plus.download.IndexItem; import net.osmand.plus.helpers.AvoidSpecificRoads; import net.osmand.plus.poi.PoiUIFilter; import net.osmand.plus.quickaction.QuickAction; @@ -32,7 +38,9 @@ import org.json.JSONException; import org.json.JSONObject; import java.io.File; +import java.io.IOException; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -56,6 +64,8 @@ public class CustomOsmandPlugin extends OsmandPlugin { private List rendererNames = new ArrayList<>(); private List routerNames = new ArrayList<>(); + private List suggestedDownloadItems = new ArrayList<>(); + private List customRegions = new ArrayList<>(); public CustomOsmandPlugin(@NonNull OsmandApplication app, @NonNull JSONObject json) throws JSONException { super(app); @@ -65,6 +75,25 @@ public class CustomOsmandPlugin extends OsmandPlugin { loadResources(); } + @Override + public String getId() { + return pluginId; + } + + @Override + public String getName() { + return JsonUtils.getLocalizedResFromMap(app, names, app.getString(R.string.custom_osmand_plugin)); + } + + @Override + public String getDescription() { + return JsonUtils.getLocalizedResFromMap(app, descriptions, null); + } + + public String getResourceDirName() { + return resourceDirName; + } + @Override public boolean init(@NonNull OsmandApplication app, @Nullable Activity activity) { super.init(app, activity); @@ -78,6 +107,108 @@ public class CustomOsmandPlugin extends OsmandPlugin { return true; } + @Override + public void disable(OsmandApplication app) { + super.disable(app); + removePluginItems(null); + } + + public File getPluginDir() { + return app.getAppPath(IndexConstants.PLUGINS_DIR + pluginId); + } + + public File getPluginItemsFile() { + return new File(getPluginDir(), "items" + IndexConstants.OSMAND_SETTINGS_FILE_EXT); + } + + public File getPluginResDir() { + File pluginDir = getPluginDir(); + if (!Algorithms.isEmpty(resourceDirName)) { + return new File(pluginDir, resourceDirName); + } + return pluginDir; + } + + @Override + public List getRendererNames() { + return rendererNames; + } + + @Override + public List getRouterNames() { + return routerNames; + } + + private Drawable getIconForFile(String path, Map fileNames) { + for (Map.Entry entry : fileNames.entrySet()) { + String value = entry.getValue(); + if (value.startsWith("@")) { + value = value.substring(1); + } + if (path.endsWith(value)) { + return BitmapDrawable.createFromPath(path); + } + } + return null; + } + + @NonNull + @Override + public Drawable getLogoResource() { + return icon != null ? icon : super.getLogoResource(); + } + + @Override + public Drawable getAssetResourceImage() { + return image; + } + + @Override + public List getDownloadMaps() { + return customRegions; + } + + @Override + public List getSuggestedMaps() { + List suggestedMaps = new ArrayList<>(); + + DownloadIndexesThread downloadThread = app.getDownloadThread(); + if (!downloadThread.getIndexes().isDownloadedFromInternet && app.getSettings().isInternetConnectionAvailable()) { + downloadThread.runReloadIndexFiles(); + } + + boolean downloadIndexes = app.getSettings().isInternetConnectionAvailable() + && !downloadThread.getIndexes().isDownloadedFromInternet + && !downloadThread.getIndexes().downloadFromInternetFailed; + + if (!downloadIndexes) { + for (SuggestedDownloadItem item : suggestedDownloadItems) { + DownloadActivityType type = DownloadActivityType.getIndexType(item.scopeId); + if (type != null) { + List foundMaps = new ArrayList<>(); + String searchType = item.getSearchType(); + if ("latlon".equalsIgnoreCase(searchType)) { + LatLon latLon = app.getMapViewTrackingUtilities().getMapLocation(); + foundMaps.addAll(getMapsForType(latLon, type)); + } else if ("worldregion".equalsIgnoreCase(searchType)) { + LatLon latLon = app.getMapViewTrackingUtilities().getMapLocation(); + foundMaps.addAll(getMapsForType(latLon, type)); + } + if (!Algorithms.isEmpty(item.getNames())) { + foundMaps.addAll(getMapsForType(item.getNames(), type, item.getLimit())); + } + suggestedMaps.addAll(foundMaps); + } + } + } + + return suggestedMaps; + } + + public void setResourceDirName(String resourceDirName) { + this.resourceDirName = resourceDirName; + } + private void addPluginItemsFromFile(final File file) { app.getSettingsHelper().collectSettings(file, "", 1, new SettingsCollectListener() { @Override @@ -93,9 +224,7 @@ public class CustomOsmandPlugin extends OsmandPlugin { ApplicationMode.changeProfileAvailability(savedMode, true, app); } iterator.remove(); - } else if (item instanceof PluginSettingsItem) { - iterator.remove(); - } else { + } else if (!(item instanceof PluginSettingsItem)) { item.setShouldReplace(true); } } @@ -179,207 +308,94 @@ public class CustomOsmandPlugin extends OsmandPlugin { }); } - @Override - public void disable(OsmandApplication app) { - super.disable(app); - removePluginItems(null); - } - - public File getPluginDir() { - return app.getAppPath(IndexConstants.PLUGINS_DIR + pluginId); - } - - public File getPluginItemsFile() { - return new File(getPluginDir(), "items" + IndexConstants.OSMAND_SETTINGS_FILE_EXT); - } - - public File getPluginResDir() { - File pluginDir = getPluginDir(); - if (!Algorithms.isEmpty(resourceDirName)) { - return new File(pluginDir, resourceDirName); - } - return pluginDir; - } - - @Override - public String getId() { - return pluginId; - } - - @Override - public String getName() { - Configuration config = app.getResources().getConfiguration(); - String lang = config.locale.getLanguage(); - String name = names.get(lang); - if (Algorithms.isEmpty(name)) { - name = names.get(""); - } - if (Algorithms.isEmpty(name)) { - name = app.getString(R.string.custom_osmand_plugin); - } - return name; - } - - @Override - public String getDescription() { - Configuration config = app.getResources().getConfiguration(); - String lang = config.locale.getLanguage(); - String description = descriptions.get(lang); - if (Algorithms.isEmpty(description)) { - description = descriptions.get(""); - } - return description; - } - - public String getResourceDirName() { - return resourceDirName; - } - - public void setResourceDirName(String resourceDirName) { - this.resourceDirName = resourceDirName; - } - public void readAdditionalDataFromJson(JSONObject json) throws JSONException { - JSONObject iconJson = json.has("icon") ? json.getJSONObject("icon") : null; - if (iconJson != null) { - for (Iterator it = iconJson.keys(); it.hasNext(); ) { - String iconKey = it.next(); - String name = iconJson.getString(iconKey); - iconNames.put(iconKey, name); - } - } - JSONObject imageJson = json.has("image") ? json.getJSONObject("image") : null; - if (imageJson != null) { - for (Iterator it = imageJson.keys(); it.hasNext(); ) { - String imageKey = it.next(); - String name = imageJson.getString(imageKey); - imageNames.put(imageKey, name); - } - } - JSONObject nameJson = json.has("name") ? json.getJSONObject("name") : null; - if (nameJson != null) { - for (Iterator it = nameJson.keys(); it.hasNext(); ) { - String localeKey = it.next(); - String name = nameJson.getString(localeKey); - names.put(localeKey, name); - } - } - JSONObject descriptionJson = json.has("description") ? json.getJSONObject("description") : null; - if (descriptionJson != null) { - for (Iterator it = descriptionJson.keys(); it.hasNext(); ) { - String localeKey = it.next(); - String name = descriptionJson.getString(localeKey); - descriptions.put(localeKey, name); - } + iconNames = JsonUtils.getLocalizedMapFromJson("icon", json); + imageNames = JsonUtils.getLocalizedMapFromJson("image", json); + names = JsonUtils.getLocalizedMapFromJson("name", json); + descriptions = JsonUtils.getLocalizedMapFromJson("description", json); + + JSONArray regionsJson = json.optJSONArray("regionsJson"); + if (regionsJson != null) { + customRegions.addAll(collectRegionsFromJson(regionsJson)); } } public void writeAdditionalDataToJson(JSONObject json) throws JSONException { - JSONObject iconJson = new JSONObject(); - for (Map.Entry entry : iconNames.entrySet()) { - iconJson.put(entry.getKey(), entry.getValue()); - } - json.put("icon", iconJson); + JsonUtils.writeLocalizedMapToJson("icon", json, iconNames); + JsonUtils.writeLocalizedMapToJson("image", json, imageNames); + JsonUtils.writeLocalizedMapToJson("name", json, names); + JsonUtils.writeLocalizedMapToJson("description", json, descriptions); - JSONObject imageJson = new JSONObject(); - for (Map.Entry entry : imageNames.entrySet()) { - imageJson.put(entry.getKey(), entry.getValue()); + JSONArray regionsJson = new JSONArray(); + for (WorldRegion region : getFlatCustomRegions()) { + if (region instanceof CustomRegion) { + regionsJson.put(((CustomRegion) region).toJson()); + } } - json.put("image", imageJson); + json.put("regionsJson", regionsJson); + } - JSONObject nameJson = new JSONObject(); - for (Map.Entry entry : names.entrySet()) { - nameJson.put(entry.getKey(), entry.getValue()); + private List getFlatCustomRegions() { + List l = new ArrayList<>(customRegions); + for (WorldRegion region : customRegions) { + collectCustomSubregionsFromRegion(region, l); } - json.put("name", nameJson); + return l; + } - JSONObject descriptionJson = new JSONObject(); - for (Map.Entry entry : descriptions.entrySet()) { - descriptionJson.put(entry.getKey(), entry.getValue()); + private void collectCustomSubregionsFromRegion(WorldRegion region, List items) { + items.addAll(region.getSubregions()); + for (WorldRegion subregion : region.getSubregions()) { + collectCustomSubregionsFromRegion(subregion, items); } - json.put("description", descriptionJson); } public void readDependentFilesFromJson(JSONObject json) throws JSONException { - JSONArray rendererNamesJson = json.has("rendererNames") ? json.getJSONArray("rendererNames") : null; - if (rendererNamesJson != null) { - for (int i = 0; i < rendererNamesJson.length(); i++) { - String renderer = rendererNamesJson.getString(i); - rendererNames.add(renderer); - } - } - JSONArray routerNamesJson = json.has("routerNames") ? json.getJSONArray("routerNames") : null; - if (routerNamesJson != null) { - for (int i = 0; i < routerNamesJson.length(); i++) { - String renderer = routerNamesJson.getString(i); - routerNames.add(renderer); - } - } - JSONObject iconNamesJson = json.has("iconNames") ? json.getJSONObject("iconNames") : null; - if (iconNamesJson != null) { - for (Iterator it = iconNamesJson.keys(); it.hasNext(); ) { - String localeKey = it.next(); - String name = iconNamesJson.getString(localeKey); - iconNames.put(localeKey, name); - } - } - JSONObject imageNamesJson = json.has("imageNames") ? json.getJSONObject("imageNames") : null; - if (imageNamesJson != null) { - for (Iterator it = imageNamesJson.keys(); it.hasNext(); ) { - String localeKey = it.next(); - String name = imageNamesJson.getString(localeKey); - imageNames.put(localeKey, name); - } - } - resourceDirName = json.has("pluginResDir") ? json.getString("pluginResDir") : null; + rendererNames = JsonUtils.jsonArrayToList("rendererNames", json); + routerNames = JsonUtils.jsonArrayToList("routerNames", json); + resourceDirName = json.optString("pluginResDir"); } public void writeDependentFilesJson(JSONObject json) throws JSONException { - JSONArray rendererNamesJson = new JSONArray(); - for (String render : rendererNames) { - rendererNamesJson.put(render); - } - json.put("rendererNames", rendererNamesJson); - - JSONArray routerNamesJson = new JSONArray(); - for (String render : routerNames) { - routerNamesJson.put(render); - } - json.put("routerNames", routerNamesJson); - - JSONObject iconNamesJson = new JSONObject(); - for (Map.Entry entry : iconNames.entrySet()) { - iconNamesJson.put(entry.getKey(), entry.getValue()); - } - json.put("iconNames", iconNamesJson); - - JSONObject imageNamesJson = new JSONObject(); - for (Map.Entry entry : imageNames.entrySet()) { - imageNamesJson.put(entry.getKey(), entry.getValue()); - } - json.put("imageNames", imageNamesJson); + JsonUtils.writeStringListToJson("rendererNames", json, rendererNames); + JsonUtils.writeStringListToJson("routerNames", json, routerNames); json.put("pluginResDir", resourceDirName); } - @Override - public List getRendererNames() { - return rendererNames; - } - - @Override - public List getRouterNames() { - return routerNames; + public static List collectRegionsFromJson(JSONArray jsonArray) throws JSONException { + List customRegions = new ArrayList<>(); + Map flatRegions = new HashMap<>(); + for (int i = 0; i < jsonArray.length(); i++) { + JSONObject regionJson = jsonArray.getJSONObject(i); + CustomRegion region = CustomRegion.fromJson(regionJson); + flatRegions.put(region.getPath(), region); + } + for (CustomRegion region : flatRegions.values()) { + if (!Algorithms.isEmpty(region.getParentPath())) { + CustomRegion parentReg = flatRegions.get(region.getParentPath()); + if (parentReg != null) { + parentReg.addSubregion(region); + } + } else { + customRegions.add(region); + } + } + return customRegions; } public void addRouter(String fileName) { String routerName = Algorithms.getFileWithoutDirs(fileName); - routerNames.add(routerName); + if (!routerNames.contains(routerName)) { + routerNames.add(routerName); + } } public void addRenderer(String fileName) { String rendererName = Algorithms.getFileWithoutDirs(fileName); - rendererNames.add(rendererName); + if (!rendererNames.contains(rendererName)) { + rendererNames.add(rendererName); + } } public void loadResources() { @@ -398,28 +414,25 @@ public class CustomOsmandPlugin extends OsmandPlugin { } } - private Drawable getIconForFile(String path, Map fileNames) { - for (Map.Entry entry : fileNames.entrySet()) { - String value = entry.getValue(); - if (value.startsWith("@")) { - value = value.substring(1); - } - if (path.endsWith(value)) { - return BitmapDrawable.createFromPath(path); - } + public void updateSuggestedDownloads(List items) { + suggestedDownloadItems = new ArrayList<>(items); + } + + public void updateDownloadItems(List items) { + customRegions = new ArrayList<>(items); + } + + private List getMapsForType(LatLon latLon, DownloadActivityType type) { + try { + return DownloadResources.findIndexItemsAt(app, latLon, type); + } catch (IOException e) { + LOG.error(e); } - return null; + return Collections.emptyList(); } - @NonNull - @Override - public Drawable getLogoResource() { - return icon != null ? icon : super.getLogoResource(); - } - - @Override - public Drawable getAssetResourceImage() { - return image; + private List getMapsForType(List names, DownloadActivityType type, int limit) { + return DownloadResources.findIndexItemsAt(app, names, type, false, limit); } public interface PluginItemsListener { @@ -427,4 +440,35 @@ public class CustomOsmandPlugin extends OsmandPlugin { void onItemsRemoved(); } + + public static class SuggestedDownloadItem { + + private String scopeId; + private String searchType; + private List names; + private int limit; + + public SuggestedDownloadItem(String scopeId, String searchType, List names, int limit) { + this.scopeId = scopeId; + this.limit = limit; + this.searchType = searchType; + this.names = names; + } + + public String getScopeId() { + return scopeId; + } + + public String getSearchType() { + return searchType; + } + + public List getNames() { + return names; + } + + public int getLimit() { + return limit; + } + } } \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/CustomRegion.java b/OsmAnd/src/net/osmand/plus/CustomRegion.java new file mode 100644 index 0000000000..1838ca0c97 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/CustomRegion.java @@ -0,0 +1,173 @@ +package net.osmand.plus; + +import androidx.annotation.ColorInt; + +import net.osmand.JsonUtils; +import net.osmand.PlatformUtil; +import net.osmand.map.WorldRegion; +import net.osmand.plus.download.CustomIndexItem; +import net.osmand.plus.download.DownloadActivityType; +import net.osmand.plus.download.IndexItem; +import net.osmand.util.Algorithms; + +import org.apache.commons.logging.Log; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.File; +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class CustomRegion extends WorldRegion { + + private static final Log LOG = PlatformUtil.getLog(CustomRegion.class); + + private String scopeId; + private String path; + private String parentPath; + private String type; + private String subfolder; + private String headerButton; + + private JSONArray downloadItemsJson; + + private Map names = new HashMap<>(); + private Map icons = new HashMap<>(); + private Map headers = new HashMap<>(); + + private int headerColor = -1; + + + private CustomRegion(String scopeId, String path, String type) { + super(path, null); + this.scopeId = scopeId; + this.path = path; + this.type = type; + } + + public String getScopeId() { + return scopeId; + } + + public String getPath() { + return path; + } + + public String getParentPath() { + return parentPath; + } + + @ColorInt + public int getHeaderColor() { + return headerColor; + } + + public static CustomRegion fromJson(JSONObject object) throws JSONException { + String scopeId = object.optString("scope-id", null); + String path = object.optString("path", null); + String type = object.optString("type", null); + + CustomRegion region = new CustomRegion(scopeId, path, type); + region.subfolder = object.optString("subfolder", null); + + int index = path.lastIndexOf(File.separator); + if (index != -1) { + region.parentPath = path.substring(0, index); + } + + region.names = JsonUtils.getLocalizedMapFromJson("name", object); + if (!Algorithms.isEmpty(region.names)) { + region.regionName = region.names.get(""); + region.regionNameEn = region.names.get(""); + region.regionFullName = region.names.get(""); + region.regionNameLocale = region.names.get(""); + } + + region.icons = JsonUtils.getLocalizedMapFromJson("icon", object); + region.headers = JsonUtils.getLocalizedMapFromJson("header", object); + + region.headerButton = object.optString("header-button", null); + region.downloadItemsJson = object.optJSONArray("items"); + + String headerColor = object.optString("header-color", null); + try { + region.headerColor = Algorithms.isEmpty(headerColor) ? 0 : Algorithms.parseColor(headerColor); + } catch (IllegalArgumentException e) { + region.headerColor = 0; + } + + return region; + } + + public List loadIndexItems() { + List items = new ArrayList<>(); + if (downloadItemsJson != null) { + try { + for (int i = 0; i < downloadItemsJson.length(); i++) { + JSONObject itemJson = downloadItemsJson.getJSONObject(i); + + long timestamp = itemJson.optLong("timestamp") * 1000; + long contentSize = itemJson.optLong("contentSize"); + long containerSize = itemJson.optLong("containerSize"); + + String indexType = itemJson.optString("type", type); + String webUrl = itemJson.optString("weburl"); + String fileName = itemJson.optString("filename"); + String downloadUrl = itemJson.optString("downloadurl"); + String size = new DecimalFormat("#.#").format(containerSize / (1024f * 1024f)); + + List descrImageUrl = JsonUtils.jsonArrayToList("image-description-url", itemJson); + Map indexNames = JsonUtils.getLocalizedMapFromJson("name", itemJson); + Map descriptions = JsonUtils.getLocalizedMapFromJson("description", itemJson); + Map webButtonText = JsonUtils.getLocalizedMapFromJson("web-button-text", itemJson); + + DownloadActivityType type = DownloadActivityType.getIndexType(indexType); + if (type != null) { + IndexItem indexItem = new CustomIndexItem.CustomIndexItemBuilder() + .setFileName(fileName) + .setSubfolder(subfolder) + .setDownloadUrl(downloadUrl) + .setNames(indexNames) + .setDescriptions(descriptions) + .setImageDescrUrl(descrImageUrl) + .setWebUrl(webUrl) + .setWebButtonText(webButtonText) + .setTimestamp(timestamp) + .setSize(size) + .setContentSize(contentSize) + .setContainerSize(containerSize) + .setType(type) + .create(); + + items.add(indexItem); + } + } + } catch (JSONException e) { + LOG.error(e); + } + } + return items; + } + + public JSONObject toJson() throws JSONException { + JSONObject jsonObject = new JSONObject(); + + jsonObject.putOpt("scope-id", scopeId); + jsonObject.putOpt("path", path); + jsonObject.putOpt("type", type); + jsonObject.putOpt("subfolder", subfolder); + jsonObject.putOpt("header-button", headerButton); + + JsonUtils.writeLocalizedMapToJson("name", jsonObject, names); + JsonUtils.writeLocalizedMapToJson("icon", jsonObject, icons); + JsonUtils.writeLocalizedMapToJson("header", jsonObject, headers); + + jsonObject.putOpt("items", downloadItemsJson); + + return jsonObject; + } +} \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/GpxSelectionHelper.java b/OsmAnd/src/net/osmand/plus/GpxSelectionHelper.java index ccbbbaad7a..ee2e00b632 100644 --- a/OsmAnd/src/net/osmand/plus/GpxSelectionHelper.java +++ b/OsmAnd/src/net/osmand/plus/GpxSelectionHelper.java @@ -17,6 +17,7 @@ import net.osmand.GPXUtilities.Track; import net.osmand.GPXUtilities.TrkSegment; import net.osmand.GPXUtilities.WptPt; import net.osmand.IProgress; +import net.osmand.IndexConstants; import net.osmand.PlatformUtil; import net.osmand.data.LatLon; import net.osmand.plus.GPXDatabase.GpxDataItem; @@ -241,7 +242,7 @@ public class GpxSelectionHelper { if (i >= 0) { name = name.substring(i + 1); } - if (name.toLowerCase().endsWith(".gpx")) { + if (name.toLowerCase().endsWith(IndexConstants.GPX_FILE_EXT)) { name = name.substring(0, name.length() - 4); } name = name.replace('_', ' '); diff --git a/OsmAnd/src/net/osmand/plus/MapMarkersHelper.java b/OsmAnd/src/net/osmand/plus/MapMarkersHelper.java index e27707b5e8..426161870c 100644 --- a/OsmAnd/src/net/osmand/plus/MapMarkersHelper.java +++ b/OsmAnd/src/net/osmand/plus/MapMarkersHelper.java @@ -1009,10 +1009,10 @@ public class MapMarkersHelper { if (!dir.exists()) { dir.mkdirs(); } - File fout = new File(dir, fileName + ".gpx"); + File fout = new File(dir, fileName + IndexConstants.GPX_FILE_EXT); int ind = 1; while (fout.exists()) { - fout = new File(dir, fileName + "_" + (++ind) + ".gpx"); + fout = new File(dir, fileName + "_" + (++ind) + IndexConstants.GPX_FILE_EXT); } GPXFile file = new GPXFile(Version.getFullVersion(ctx)); for (MapMarker marker : mapMarkers) { diff --git a/OsmAnd/src/net/osmand/plus/OsmandPlugin.java b/OsmAnd/src/net/osmand/plus/OsmandPlugin.java index a386303aba..3aff417123 100644 --- a/OsmAnd/src/net/osmand/plus/OsmandPlugin.java +++ b/OsmAnd/src/net/osmand/plus/OsmandPlugin.java @@ -21,6 +21,7 @@ import net.osmand.IProgress; import net.osmand.Location; import net.osmand.PlatformUtil; import net.osmand.access.AccessibilityPlugin; +import net.osmand.map.WorldRegion; import net.osmand.plus.activities.MapActivity; import net.osmand.plus.activities.TabActivity.TabItem; import net.osmand.plus.api.SettingsAPI; @@ -182,6 +183,10 @@ public abstract class OsmandPlugin { return Collections.emptyList(); } + public List getDownloadMaps() { + return Collections.emptyList(); + } + public List getRendererNames() { return Collections.emptyList(); } @@ -645,6 +650,31 @@ public abstract class OsmandPlugin { return null; } + public static List getCustomDownloadRegions() { + List l = new ArrayList<>(); + for (OsmandPlugin plugin : getEnabledPlugins()) { + l.addAll(plugin.getDownloadMaps()); + } + return l; + } + + public static List getCustomDownloadItems() { + List l = new ArrayList<>(); + for (WorldRegion region : getCustomDownloadRegions()) { + collectIndexItemsFromSubregion(region, l); + } + return l; + } + + public static void collectIndexItemsFromSubregion(WorldRegion region, List items) { + if (region instanceof CustomRegion) { + items.addAll(((CustomRegion) region).loadIndexItems()); + } + for (WorldRegion subregion : region.getSubregions()) { + collectIndexItemsFromSubregion(subregion, items); + } + } + public static List getDisabledRendererNames() { List l = new ArrayList(); for (OsmandPlugin plugin : getNotEnabledPlugins()) { diff --git a/OsmAnd/src/net/osmand/plus/SettingsHelper.java b/OsmAnd/src/net/osmand/plus/SettingsHelper.java index 0c179c123d..faa9760aa9 100644 --- a/OsmAnd/src/net/osmand/plus/SettingsHelper.java +++ b/OsmAnd/src/net/osmand/plus/SettingsHelper.java @@ -16,10 +16,12 @@ import net.osmand.PlatformUtil; import net.osmand.data.LatLon; import net.osmand.map.ITileSource; import net.osmand.map.TileSourceManager; +import net.osmand.map.WorldRegion; import net.osmand.osm.MapPoiTypes; import net.osmand.osm.PoiCategory; import net.osmand.plus.ApplicationMode.ApplicationModeBean; import net.osmand.plus.ApplicationMode.ApplicationModeBuilder; +import net.osmand.plus.CustomOsmandPlugin.SuggestedDownloadItem; import net.osmand.plus.OsmandSettings.OsmandPreference; import net.osmand.plus.helpers.AvoidSpecificRoads; import net.osmand.plus.helpers.AvoidSpecificRoads.AvoidRoadInfo; @@ -131,7 +133,9 @@ public class SettingsHelper { QUICK_ACTIONS, POI_UI_FILTERS, MAP_SOURCES, - AVOID_ROADS + AVOID_ROADS, + SUGGESTED_DOWNLOADS, + DOWNLOADS } public abstract static class SettingsItem { @@ -410,6 +414,10 @@ public class SettingsHelper { } else if (fileItem.getSubtype() == FileSettingsItem.FileSubtype.OTHER) { plugin.setResourceDirName(item.getFileName()); } + } else if (item instanceof SuggestedDownloadsItem) { + plugin.updateSuggestedDownloads(((SuggestedDownloadsItem) item).getItems()); + } else if (item instanceof DownloadsItem) { + plugin.updateDownloadItems(((DownloadsItem) item).getItems()); } } OsmandPlugin.addCustomPlugin(app, plugin); @@ -441,6 +449,199 @@ public class SettingsHelper { } } + public static class SuggestedDownloadsItem extends SettingsItem { + + private List items; + + SuggestedDownloadsItem(@NonNull OsmandApplication app, @NonNull JSONObject json) throws JSONException { + super(app, json); + } + + @Override + protected void init() { + super.init(); + items = new ArrayList<>(); + } + + @NonNull + @Override + public SettingsItemType getType() { + return SettingsItemType.SUGGESTED_DOWNLOADS; + + } + + @NonNull + @Override + public String getName() { + return "suggested_downloads"; + } + + @NonNull + @Override + public String getPublicName(@NonNull Context ctx) { + return "suggested_downloads"; + } + + public List getItems() { + return items; + } + + @Override + void readItemsFromJson(@NonNull JSONObject json) throws IllegalArgumentException { + try { + if (!json.has("items")) { + return; + } + JSONArray jsonArray = json.getJSONArray("items"); + for (int i = 0; i < jsonArray.length(); i++) { + JSONObject object = jsonArray.getJSONObject(i); + String scopeId = object.optString("scope-id"); + String searchType = object.optString("search-type"); + int limit = object.optInt("limit", -1); + + List names = new ArrayList<>(); + if (object.has("names")) { + JSONArray namesArray = object.getJSONArray("names"); + for (int j = 0; j < namesArray.length(); j++) { + names.add(namesArray.getString(j)); + } + } + SuggestedDownloadItem suggestedDownload = new SuggestedDownloadItem(scopeId, searchType, names, limit); + items.add(suggestedDownload); + } + } catch (JSONException e) { + warnings.add(app.getString(R.string.settings_item_read_error, String.valueOf(getType()))); + throw new IllegalArgumentException("Json parse error", e); + } + } + + @Override + void writeItemsToJson(@NonNull JSONObject json) { + JSONArray jsonArray = new JSONArray(); + if (!items.isEmpty()) { + try { + for (SuggestedDownloadItem downloadItem : items) { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("scope-id", downloadItem.getScopeId()); + if (downloadItem.getLimit() != -1) { + jsonObject.put("limit", downloadItem.getLimit()); + } + if (!Algorithms.isEmpty(downloadItem.getSearchType())) { + jsonObject.put("search-type", downloadItem.getSearchType()); + } + if (!Algorithms.isEmpty(downloadItem.getNames())) { + JSONArray namesArray = new JSONArray(); + for (String downloadName : downloadItem.getNames()) { + namesArray.put(downloadName); + } + jsonObject.put("names", namesArray); + } + jsonArray.put(jsonObject); + } + json.put("items", jsonArray); + } catch (JSONException e) { + warnings.add(app.getString(R.string.settings_item_write_error, String.valueOf(getType()))); + LOG.error("Failed write to json", e); + } + } + } + + @Nullable + @Override + SettingsItemReader getReader() { + return null; + } + + @Nullable + @Override + SettingsItemWriter getWriter() { + return null; + } + } + + public static class DownloadsItem extends SettingsItem { + + private List items; + + DownloadsItem(@NonNull OsmandApplication app, @NonNull JSONObject json) throws JSONException { + super(app, json); + } + + @Override + protected void init() { + super.init(); + items = new ArrayList<>(); + } + + @NonNull + @Override + public SettingsItemType getType() { + return SettingsItemType.DOWNLOADS; + + } + + @NonNull + @Override + public String getName() { + return "downloads"; + } + + @NonNull + @Override + public String getPublicName(@NonNull Context ctx) { + return "downloads"; + } + + public List getItems() { + return items; + } + + @Override + void readItemsFromJson(@NonNull JSONObject json) throws IllegalArgumentException { + try { + if (!json.has("items")) { + return; + } + JSONArray jsonArray = json.getJSONArray("items"); + items.addAll(CustomOsmandPlugin.collectRegionsFromJson(jsonArray)); + } catch (JSONException e) { + warnings.add(app.getString(R.string.settings_item_read_error, String.valueOf(getType()))); + throw new IllegalArgumentException("Json parse error", e); + } + } + + @Override + void writeItemsToJson(@NonNull JSONObject json) { + JSONArray jsonArray = new JSONArray(); + if (!items.isEmpty()) { + try { + for (WorldRegion region : items) { + if (region instanceof CustomRegion) { + JSONObject regionJson = ((CustomRegion) region).toJson(); + jsonArray.put(regionJson); + } + } + json.put("items", jsonArray); + } catch (JSONException e) { + warnings.add(app.getString(R.string.settings_item_write_error, String.valueOf(getType()))); + LOG.error("Failed write to json", e); + } + } + } + + @Nullable + @Override + SettingsItemReader getReader() { + return null; + } + + @Nullable + @Override + SettingsItemWriter getWriter() { + return null; + } + } + public abstract static class CollectionSettingsItem extends SettingsItem { protected List items; @@ -2095,6 +2296,12 @@ public class SettingsHelper { case AVOID_ROADS: item = new AvoidRoadsSettingsItem(app, json); break; + case SUGGESTED_DOWNLOADS: + item = new SuggestedDownloadsItem(app, json); + break; + case DOWNLOADS: + item = new DownloadsItem(app, json); + break; } return item; } diff --git a/OsmAnd/src/net/osmand/plus/activities/MapActivityActions.java b/OsmAnd/src/net/osmand/plus/activities/MapActivityActions.java index 3fb019b46e..af66cc42ff 100644 --- a/OsmAnd/src/net/osmand/plus/activities/MapActivityActions.java +++ b/OsmAnd/src/net/osmand/plus/activities/MapActivityActions.java @@ -83,6 +83,7 @@ import java.util.ArrayList; import java.util.Date; import java.util.List; +import static net.osmand.IndexConstants.GPX_FILE_EXT; import static net.osmand.aidlapi.OsmAndCustomizationConstants.DRAWER_CONFIGURE_MAP_ID; import static net.osmand.aidlapi.OsmAndCustomizationConstants.DRAWER_CONFIGURE_SCREEN_ID; import static net.osmand.aidlapi.OsmAndCustomizationConstants.DRAWER_DASHBOARD_ID; @@ -111,7 +112,6 @@ import static net.osmand.aidlapi.OsmAndCustomizationConstants.MAP_CONTEXT_MENU_S import static net.osmand.plus.ContextMenuAdapter.PROFILES_CHOSEN_PROFILE_TAG; import static net.osmand.plus.ContextMenuAdapter.PROFILES_CONTROL_BUTTON_TAG; import static net.osmand.plus.ContextMenuAdapter.PROFILES_NORMAL_PROFILE_TAG; -import static net.osmand.plus.helpers.ImportHelper.GPX_SUFFIX; public class MapActivityActions implements DialogProvider { @@ -282,8 +282,8 @@ public class MapActivityActions implements DialogProvider { fileDir.mkdirs(); File toSave = fileDir; if (name.length() > 0) { - if (!name.endsWith(GPX_SUFFIX)) { - name += GPX_SUFFIX; + if (!name.endsWith(GPX_FILE_EXT)) { + name += GPX_FILE_EXT; } toSave = new File(fileDir, name); } @@ -320,7 +320,7 @@ public class MapActivityActions implements DialogProvider { if (params.length > 0) { File file = params[0]; String fileName = file.getName(); - GPXFile gpx = app.getRoutingHelper().generateGPXFileWithRoute(fileName.substring(0,fileName.length()-GPX_SUFFIX.length())); + GPXFile gpx = app.getRoutingHelper().generateGPXFileWithRoute(fileName.substring(0,fileName.length()-GPX_FILE_EXT.length())); GPXUtilities.writeGpxFile(file, gpx); return app.getString(R.string.route_successfully_saved_at, file.getName()); } diff --git a/OsmAnd/src/net/osmand/plus/activities/SavingTrackHelper.java b/OsmAnd/src/net/osmand/plus/activities/SavingTrackHelper.java index 52fe084e2e..ddf23106c7 100644 --- a/OsmAnd/src/net/osmand/plus/activities/SavingTrackHelper.java +++ b/OsmAnd/src/net/osmand/plus/activities/SavingTrackHelper.java @@ -5,6 +5,7 @@ import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.text.format.DateFormat; +import net.osmand.IndexConstants; import net.osmand.PlatformUtil; import net.osmand.data.LatLon; import net.osmand.plus.GPXDatabase.GpxDataItem; @@ -209,7 +210,7 @@ public class SavingTrackHelper extends SQLiteOpenHelper { // save file for (final String f : data.keySet()) { log.debug("Filename: " + f); - File fout = new File(dir, f + ".gpx"); //$NON-NLS-1$ + File fout = new File(dir, f + IndexConstants.GPX_FILE_EXT); if (!data.get(f).isEmpty()) { WptPt pt = data.get(f).findPointToShow(); String fileName = f + "_" + new SimpleDateFormat("HH-mm_EEE", Locale.US).format(new Date(pt.time)); //$NON-NLS-1$ @@ -227,10 +228,10 @@ public class SavingTrackHelper extends SQLiteOpenHelper { } } filenames.add(fileName); - fout = new File(dir, fileName + ".gpx"); //$NON-NLS-1$ + fout = new File(dir, fileName + IndexConstants.GPX_FILE_EXT); int ind = 1; while (fout.exists()) { - fout = new File(dir, fileName + "_" + (++ind) + ".gpx"); //$NON-NLS-1$ //$NON-NLS-2$ + fout = new File(dir, fileName + "_" + (++ind) + IndexConstants.GPX_FILE_EXT); //$NON-NLS-1$ } } diff --git a/OsmAnd/src/net/osmand/plus/activities/TrackActivity.java b/OsmAnd/src/net/osmand/plus/activities/TrackActivity.java index 522c334bb3..6659ca3ad2 100644 --- a/OsmAnd/src/net/osmand/plus/activities/TrackActivity.java +++ b/OsmAnd/src/net/osmand/plus/activities/TrackActivity.java @@ -23,6 +23,7 @@ import net.osmand.GPXUtilities; import net.osmand.GPXUtilities.GPXFile; import net.osmand.GPXUtilities.TrkSegment; import net.osmand.GPXUtilities.WptPt; +import net.osmand.IndexConstants; import net.osmand.data.LatLon; import net.osmand.data.PointDescription; import net.osmand.data.QuadRect; @@ -92,7 +93,7 @@ public class TrackActivity extends TabActivity { ActionBar actionBar = getSupportActionBar(); if (actionBar != null) { if (file != null) { - String fn = file.getName().replace(".gpx", "").replace("/", " ").replace("_", " "); + String fn = file.getName().replace(IndexConstants.GPX_FILE_EXT, "").replace("/", " ").replace("_", " "); actionBar.setTitle(fn); } else { actionBar.setTitle(getString(R.string.shared_string_currently_recording_track)); diff --git a/OsmAnd/src/net/osmand/plus/download/CustomIndexItem.java b/OsmAnd/src/net/osmand/plus/download/CustomIndexItem.java new file mode 100644 index 0000000000..6bacdb237a --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/download/CustomIndexItem.java @@ -0,0 +1,196 @@ +package net.osmand.plus.download; + +import android.content.Context; + +import androidx.annotation.NonNull; + +import net.osmand.JsonUtils; +import net.osmand.map.OsmandRegions; +import net.osmand.plus.OsmandApplication; +import net.osmand.util.Algorithms; + +import java.io.File; +import java.util.List; +import java.util.Map; + +public class CustomIndexItem extends IndexItem { + + private String subfolder; + private String downloadUrl; + private String webUrl; + + private List imageDescrUrl; + private Map names; + private Map descriptions; + private Map webButtonTexts; + + public CustomIndexItem(String fileName, + String subfolder, + String downloadUrl, + String webUrl, + String size, + long timestamp, + long contentSize, + long containerSize, + List imageDescrUrl, + Map names, + Map descriptions, + Map webButtonTexts, + @NonNull DownloadActivityType type) { + super(fileName, null, timestamp, size, contentSize, containerSize, type); + this.subfolder = subfolder; + this.downloadUrl = downloadUrl; + this.webUrl = webUrl; + this.imageDescrUrl = imageDescrUrl; + this.names = names; + this.descriptions = descriptions; + this.webButtonTexts = webButtonTexts; + } + + @Override + public DownloadEntry createDownloadEntry(OsmandApplication ctx) { + DownloadEntry entry = super.createDownloadEntry(ctx); + if (entry != null) { + entry.urlToDownload = downloadUrl; + } + return entry; + } + + @Override + public File getTargetFile(OsmandApplication ctx) { + String basename = getTranslatedBasename(); + if (!Algorithms.isEmpty(subfolder)) { + basename = subfolder + "/" + basename; + } + return new File(type.getDownloadFolder(ctx, this), basename + type.getUnzipExtension(ctx, this)); + } + + @Override + public String getVisibleName(Context ctx, OsmandRegions osmandRegions) { + return getVisibleName(ctx, osmandRegions, true); + } + + @Override + public String getVisibleName(Context ctx, OsmandRegions osmandRegions, boolean includingParent) { + String name = super.getVisibleName(ctx, osmandRegions, includingParent); + return JsonUtils.getLocalizedResFromMap(ctx, names, name); + } + + public List getDescriptionImageUrl() { + return imageDescrUrl; + } + + public String getLocalizedDescription(Context ctx) { + String description = super.getDescription(); + return JsonUtils.getLocalizedResFromMap(ctx, descriptions, description); + } + + public String getWebUrl() { + return webUrl; + } + + public String getWebButtonText(Context ctx) { + return JsonUtils.getLocalizedResFromMap(ctx, webButtonTexts, null); + } + + public static class CustomIndexItemBuilder { + + private String fileName; + private String subfolder; + private String downloadUrl; + private String webUrl; + private String size; + + private long timestamp; + private long contentSize; + private long containerSize; + + private List imageDescrUrl; + private Map names; + private Map descriptions; + private Map webButtonText; + private DownloadActivityType type; + + + public CustomIndexItemBuilder setFileName(String fileName) { + this.fileName = fileName; + return this; + } + + public CustomIndexItemBuilder setSubfolder(String subfolder) { + this.subfolder = subfolder; + return this; + } + + public CustomIndexItemBuilder setDownloadUrl(String downloadUrl) { + this.downloadUrl = downloadUrl; + return this; + } + + public CustomIndexItemBuilder setWebUrl(String webUrl) { + this.webUrl = webUrl; + return this; + } + + public CustomIndexItemBuilder setSize(String size) { + this.size = size; + return this; + } + + public CustomIndexItemBuilder setTimestamp(long timestamp) { + this.timestamp = timestamp; + return this; + } + + public CustomIndexItemBuilder setContentSize(long contentSize) { + this.contentSize = contentSize; + return this; + } + + public CustomIndexItemBuilder setContainerSize(long containerSize) { + this.containerSize = containerSize; + return this; + } + + public CustomIndexItemBuilder setImageDescrUrl(List imageDescrUrl) { + this.imageDescrUrl = imageDescrUrl; + return this; + } + + public CustomIndexItemBuilder setNames(Map names) { + this.names = names; + return this; + } + + public CustomIndexItemBuilder setDescriptions(Map descriptions) { + this.descriptions = descriptions; + return this; + } + + public CustomIndexItemBuilder setWebButtonText(Map webButtonText) { + this.webButtonText = webButtonText; + return this; + } + + public CustomIndexItemBuilder setType(@NonNull DownloadActivityType type) { + this.type = type; + return this; + } + + public CustomIndexItem create() { + return new CustomIndexItem(fileName, + subfolder, + downloadUrl, + webUrl, + size, + timestamp, + contentSize, + containerSize, + imageDescrUrl, + names, + descriptions, + webButtonText, + type); + } + } +} \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/download/DownloadActivityType.java b/OsmAnd/src/net/osmand/plus/download/DownloadActivityType.java index ee68eba279..b5671e89c8 100644 --- a/OsmAnd/src/net/osmand/plus/download/DownloadActivityType.java +++ b/OsmAnd/src/net/osmand/plus/download/DownloadActivityType.java @@ -51,6 +51,11 @@ public class DownloadActivityType { new DownloadActivityType(R.string.shared_string_wikivoyage, R.drawable.ic_plugin_wikipedia, "wikivoyage", 65); public static final DownloadActivityType LIVE_UPDATES_FILE = new DownloadActivityType(R.string.download_live_updates, "live_updates", 70); + public static final DownloadActivityType GPX_FILE = + new DownloadActivityType(R.string.shared_string_gpx_tracks, R.drawable.ic_action_polygom_dark, "gpx", 75); + public static final DownloadActivityType SQLITE_FILE = + new DownloadActivityType(R.string.shared_string_online_maps, "sqlite", 80); + private final int stringResource; private final int iconResource; @@ -136,6 +141,10 @@ public class DownloadActivityType { return fileName.endsWith(IndexConstants.SQLITE_EXT); } else if (DEPTH_CONTOUR_FILE == this) { return fileName.endsWith(addVersionToExt(IndexConstants.BINARY_MAP_INDEX_EXT_ZIP, IndexConstants.BINARY_MAP_VERSION)); + } else if (GPX_FILE == this) { + return fileName.endsWith(IndexConstants.GPX_FILE_EXT); + } else if (SQLITE_FILE == this) { + return fileName.endsWith(IndexConstants.SQLITE_EXT); } return false; } @@ -166,14 +175,18 @@ public class DownloadActivityType { return ctx.getAppPath(IndexConstants.TILES_INDEX_DIR); } else if (DEPTH_CONTOUR_FILE == this) { return ctx.getAppPath(IndexConstants.MAPS_PATH); + } else if (GPX_FILE == this) { + return ctx.getAppPath(IndexConstants.GPX_INDEX_DIR); + } else if (SQLITE_FILE == this) { + return ctx.getAppPath(IndexConstants.TILES_INDEX_DIR); } throw new UnsupportedOperationException(); } - + public boolean isZipStream(OsmandApplication ctx, IndexItem indexItem) { - return HILLSHADE_FILE != this && SLOPE_FILE != this && WIKIVOYAGE_FILE != this; + return HILLSHADE_FILE != this && SLOPE_FILE != this && SQLITE_FILE != this && WIKIVOYAGE_FILE != this && GPX_FILE != this; } - + public boolean isZipFolder(OsmandApplication ctx, IndexItem indexItem) { return this == VOICE_FILE; } @@ -213,8 +226,12 @@ public class DownloadActivityType { return IndexConstants.SQLITE_EXT; } else if (SLOPE_FILE == this) { return IndexConstants.SQLITE_EXT; + } else if (SQLITE_FILE == this) { + return IndexConstants.SQLITE_EXT; } else if (DEPTH_CONTOUR_FILE == this) { return BINARY_MAP_INDEX_EXT; + } else if (GPX_FILE == this) { + return IndexConstants.GPX_FILE_EXT; } throw new UnsupportedOperationException(); } @@ -238,6 +255,8 @@ public class DownloadActivityType { return "&fonts=yes"; } else if (this == DEPTH_CONTOUR_FILE) { return "&inapp=depth"; + } else if (this == GPX_FILE) { + return "&gpx=yes"; } return ""; } @@ -303,6 +322,8 @@ public class DownloadActivityType { return ctx.getString(R.string.download_depth_countours); } else if (this == FONT_FILE) { return ctx.getString(R.string.fonts_header); + } else if (this == GPX_FILE) { + return ctx.getString(R.string.shared_string_gpx_tracks); } return ""; } @@ -370,6 +391,8 @@ public class DownloadActivityType { return fileName.replace('_', ' '); } else if (this == SLOPE_FILE) { return fileName.replace('_', ' '); + } else if (this == SQLITE_FILE) { + return fileName.replace('_', ' '); } else if (this == LIVE_UPDATES_FILE) { int l = fileName.lastIndexOf('.'); if (l == -1) { diff --git a/OsmAnd/src/net/osmand/plus/download/DownloadIndexesThread.java b/OsmAnd/src/net/osmand/plus/download/DownloadIndexesThread.java index ccc5fb0510..4761b85586 100644 --- a/OsmAnd/src/net/osmand/plus/download/DownloadIndexesThread.java +++ b/OsmAnd/src/net/osmand/plus/download/DownloadIndexesThread.java @@ -349,6 +349,7 @@ public class DownloadIndexesThread { app.getSettings().LAST_CHECKED_UPDATES.set(System.currentTimeMillis()); result.prepareData(indexFileList.getIndexFiles()); } catch (Exception e) { + LOG.error(e); } } return result == null ? new DownloadResources(app) : result; diff --git a/OsmAnd/src/net/osmand/plus/download/DownloadResourceGroup.java b/OsmAnd/src/net/osmand/plus/download/DownloadResourceGroup.java index fa0125e8e4..416e20bc94 100644 --- a/OsmAnd/src/net/osmand/plus/download/DownloadResourceGroup.java +++ b/OsmAnd/src/net/osmand/plus/download/DownloadResourceGroup.java @@ -55,6 +55,7 @@ public class DownloadResourceGroup { FONTS(R.string.fonts_header), VOICE_REC(R.string.index_name_voice), OTHER_MAPS(R.string.download_select_map_types), + EXTRA_MAPS(R.string.extra_maps_menu_group), WORLD(-1), REGION(-1); @@ -79,7 +80,7 @@ public class DownloadResourceGroup { public boolean containsIndexItem() { return isHeader() && this != SUBREGIONS && this != OTHER_GROUP && this != OTHER_MAPS_GROUP - && this != NAUTICAL_MAPS_GROUP && this != TRAVEL_GROUP; + && this != NAUTICAL_MAPS_GROUP && this != TRAVEL_GROUP && this != EXTRA_MAPS; } public boolean isHeader() { @@ -90,7 +91,8 @@ public class DownloadResourceGroup { || this == OTHER_MAPS_HEADER || this == OTHER_MAPS_GROUP || this == FONTS_HEADER || this == NAUTICAL_MAPS_HEADER || this == NAUTICAL_MAPS_GROUP - || this == WIKIVOYAGE_HEADER || this == TRAVEL_GROUP; + || this == WIKIVOYAGE_HEADER || this == TRAVEL_GROUP + || this == EXTRA_MAPS; } public static String getVoiceTTSId() { @@ -274,7 +276,7 @@ public class DownloadResourceGroup { } public IndexItem getItemByIndex(int ind) { - if(individualResources != null && ind < individualResources.size()) { + if (individualResources != null && ind >= 0 && ind < individualResources.size()) { return individualResources.get(ind); } return null; diff --git a/OsmAnd/src/net/osmand/plus/download/DownloadResources.java b/OsmAnd/src/net/osmand/plus/download/DownloadResources.java index 926c6f0596..61ed7b303f 100644 --- a/OsmAnd/src/net/osmand/plus/download/DownloadResources.java +++ b/OsmAnd/src/net/osmand/plus/download/DownloadResources.java @@ -9,8 +9,11 @@ import net.osmand.data.LatLon; import net.osmand.map.OsmandRegions; import net.osmand.map.WorldRegion; import net.osmand.plus.OsmandApplication; +import net.osmand.plus.OsmandPlugin; +import net.osmand.plus.CustomRegion; import net.osmand.plus.download.DownloadOsmandIndexesHelper.AssetIndexItem; import net.osmand.plus.inapp.InAppPurchaseHelper; +import net.osmand.util.Algorithms; import org.apache.commons.logging.Log; @@ -290,6 +293,8 @@ public class DownloadResources extends DownloadResourceGroup { protected boolean prepareData(List resources) { this.rawResources = resources; + DownloadResourceGroup extraMapsGroup = new DownloadResourceGroup(this, DownloadResourceGroupType.EXTRA_MAPS); + DownloadResourceGroup otherMapsGroup = new DownloadResourceGroup(this, DownloadResourceGroupType.OTHER_MAPS_GROUP); DownloadResourceGroup otherMapsScreen = new DownloadResourceGroup(otherMapsGroup, DownloadResourceGroupType.OTHER_MAPS); DownloadResourceGroup otherMaps = new DownloadResourceGroup(otherMapsGroup, DownloadResourceGroupType.OTHER_MAPS_HEADER); @@ -363,6 +368,14 @@ public class DownloadResources extends DownloadResourceGroup { } this.groupByRegion = groupByRegion; + List customRegions = OsmandPlugin.getCustomDownloadRegions(); + if (!Algorithms.isEmpty(customRegions)) { + addGroup(extraMapsGroup); + for (WorldRegion region : customRegions) { + buildRegionsGroups(region, extraMapsGroup); + } + } + LinkedList queue = new LinkedList(); LinkedList parent = new LinkedList(); DownloadResourceGroup worldSubregions = new DownloadResourceGroup(this, DownloadResourceGroupType.SUBREGIONS); @@ -433,6 +446,40 @@ public class DownloadResources extends DownloadResourceGroup { return true; } + private void buildRegionsGroups(WorldRegion region, DownloadResourceGroup group) { + LinkedList queue = new LinkedList(); + LinkedList parent = new LinkedList(); + queue.add(region); + parent.add(group); + while (!queue.isEmpty()) { + WorldRegion reg = queue.pollFirst(); + DownloadResourceGroup parentGroup = parent.pollFirst(); + List subregions = reg.getSubregions(); + DownloadResourceGroup mainGrp = new DownloadResourceGroup(parentGroup, DownloadResourceGroupType.REGION, reg.getRegionId()); + mainGrp.region = reg; + parentGroup.addGroup(mainGrp); + + if (reg instanceof CustomRegion) { + CustomRegion customRegion = (CustomRegion) reg; + List indexItems = customRegion.loadIndexItems(); + if (!Algorithms.isEmpty(indexItems)) { + DownloadResourceGroup flatFiles = new DownloadResourceGroup(mainGrp, DownloadResourceGroupType.REGION_MAPS); + for (IndexItem ii : indexItems) { + flatFiles.addItem(ii); + } + mainGrp.addGroup(flatFiles); + } + } + DownloadResourceGroup subRegions = new DownloadResourceGroup(mainGrp, DownloadResourceGroupType.SUBREGIONS); + mainGrp.addGroup(subRegions); + // add to processing queue + for (WorldRegion rg : subregions) { + queue.add(rg); + parent.add(subRegions); + } + } + } + /** * @return smallest index item, if there are no downloaded index items; Downloaded item otherwise. */ @@ -465,6 +512,10 @@ public class DownloadResources extends DownloadResourceGroup { } public static List findIndexItemsAt(OsmandApplication app, LatLon latLon, DownloadActivityType type, boolean includeDownloaded) throws IOException { + return findIndexItemsAt(app, latLon, type, includeDownloaded, -1); + } + + public static List findIndexItemsAt(OsmandApplication app, LatLon latLon, DownloadActivityType type, boolean includeDownloaded, int limit) throws IOException { List res = new ArrayList<>(); OsmandRegions regions = app.getRegions(); DownloadIndexesThread downloadThread = app.getDownloadThread(); @@ -473,6 +524,25 @@ public class DownloadResources extends DownloadResourceGroup { if (includeDownloaded || !isIndexItemDownloaded(downloadThread, type, downloadRegion, res)) { addIndexItem(downloadThread, type, downloadRegion, res); } + if (limit != -1 && res.size() == limit) { + break; + } + } + return res; + } + + public static List findIndexItemsAt(OsmandApplication app, List names, DownloadActivityType type, boolean includeDownloaded, int limit) { + List res = new ArrayList<>(); + OsmandRegions regions = app.getRegions(); + DownloadIndexesThread downloadThread = app.getDownloadThread(); + for (String name : names) { + WorldRegion downloadRegion = regions.getRegionDataByDownloadName(name); + if (downloadRegion != null && (includeDownloaded || !isIndexItemDownloaded(downloadThread, type, downloadRegion, res))) { + addIndexItem(downloadThread, type, downloadRegion, res); + } + if (limit != -1 && res.size() == limit) { + break; + } } return res; } diff --git a/OsmAnd/src/net/osmand/plus/download/IndexItem.java b/OsmAnd/src/net/osmand/plus/download/IndexItem.java index 48c966832c..52c738faaa 100644 --- a/OsmAnd/src/net/osmand/plus/download/IndexItem.java +++ b/OsmAnd/src/net/osmand/plus/download/IndexItem.java @@ -135,19 +135,22 @@ public class IndexItem implements Comparable { public String getBasename() { return type.getBasename(this); } - + public File getTargetFile(OsmandApplication ctx) { - String basename; - if (type == DownloadActivityType.HILLSHADE_FILE) { - basename = (FileNameTranslationHelper.HILL_SHADE + getBasename()).replace("_", " "); - } else if (type == DownloadActivityType.SLOPE_FILE) { - basename = (FileNameTranslationHelper.SLOPE + getBasename()).replace('_', ' '); - } else { - basename = getBasename(); - } + String basename = getTranslatedBasename(); return new File(type.getDownloadFolder(ctx, this), basename + type.getUnzipExtension(ctx, this)); } + public String getTranslatedBasename() { + if (type == DownloadActivityType.HILLSHADE_FILE) { + return (FileNameTranslationHelper.HILL_SHADE + getBasename()).replace("_", " "); + } else if (type == DownloadActivityType.SLOPE_FILE) { + return (FileNameTranslationHelper.SLOPE + getBasename()).replace('_', ' '); + } else { + return getBasename(); + } + } + public File getBackupFile(OsmandApplication ctx) { File backup = new File(ctx.getAppPath(IndexConstants.BACKUP_INDEX_DIR), getTargetFile(ctx).getName()); return backup; diff --git a/OsmAnd/src/net/osmand/plus/download/ui/DownloadItemFragment.java b/OsmAnd/src/net/osmand/plus/download/ui/DownloadItemFragment.java new file mode 100644 index 0000000000..bd709d80ac --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/download/ui/DownloadItemFragment.java @@ -0,0 +1,178 @@ +package net.osmand.plus.download.ui; + +import android.graphics.drawable.Drawable; +import android.net.Uri; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.appcompat.widget.Toolbar; +import androidx.fragment.app.DialogFragment; + +import com.squareup.picasso.Callback; +import com.squareup.picasso.Picasso; +import com.squareup.picasso.RequestCreator; + +import net.osmand.AndroidUtils; +import net.osmand.PicassoUtils; +import net.osmand.map.WorldRegion; +import net.osmand.plus.CustomRegion; +import net.osmand.plus.OsmandApplication; +import net.osmand.plus.R; +import net.osmand.plus.UiUtilities; +import net.osmand.plus.download.CustomIndexItem; +import net.osmand.plus.download.DownloadActivity; +import net.osmand.plus.download.DownloadResourceGroup; +import net.osmand.plus.download.DownloadResources; +import net.osmand.plus.wikipedia.WikipediaDialogFragment; +import net.osmand.util.Algorithms; + +import static net.osmand.plus.download.ui.DownloadResourceGroupFragment.REGION_ID_DLG_KEY; + +public class DownloadItemFragment extends DialogFragment { + + public static final String ITEM_ID_DLG_KEY = "index_item_dialog_key"; + + public static final String TAG = DownloadItemFragment.class.getSimpleName(); + + private String regionId = ""; + private int itemIndex = -1; + + private DownloadResourceGroup group; + private CustomIndexItem indexItem; + + private View view; + private Toolbar toolbar; + private ImageView image; + private TextView description; + private TextView buttonTextView; + + private boolean nightMode; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + nightMode = !getMyApplication().getSettings().isLightContent(); + int themeId = nightMode ? R.style.OsmandDarkTheme : R.style.OsmandLightTheme; + setStyle(STYLE_NO_FRAME, themeId); + + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + view = inflater.inflate(R.layout.item_info_fragment, container, false); + + if (savedInstanceState != null) { + regionId = savedInstanceState.getString(REGION_ID_DLG_KEY); + itemIndex = savedInstanceState.getInt(ITEM_ID_DLG_KEY, -1); + } + if ((itemIndex == -1 || group == null) && getArguments() != null) { + regionId = getArguments().getString(REGION_ID_DLG_KEY); + itemIndex = getArguments().getInt(ITEM_ID_DLG_KEY, -1); + } + + toolbar = view.findViewById(R.id.toolbar); + Drawable icBack = getMyApplication().getUIUtilities().getIcon(AndroidUtils.getNavigationIconResId(requireContext())); + toolbar.setNavigationIcon(icBack); + toolbar.setNavigationContentDescription(R.string.access_shared_string_navigate_up); + toolbar.setNavigationOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + dismiss(); + } + }); + + description = view.findViewById(R.id.item_description); + image = view.findViewById(R.id.item_image); + + View dismissButton = view.findViewById(R.id.dismiss_button); + dismissButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (indexItem != null && !Algorithms.isEmpty(indexItem.getWebUrl())) { + WikipediaDialogFragment.showFullArticle(v.getContext(), Uri.parse(indexItem.getWebUrl()), nightMode); + } + } + }); + UiUtilities.setupDialogButton(nightMode, dismissButton, UiUtilities.DialogButtonType.PRIMARY, ""); + buttonTextView = (TextView) dismissButton.findViewById(R.id.button_text); + + return view; + } + + @Override + public void onResume() { + super.onResume(); + reloadData(); + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putString(REGION_ID_DLG_KEY, regionId); + outState.putInt(ITEM_ID_DLG_KEY, itemIndex); + } + + private void reloadData() { + DownloadActivity downloadActivity = getDownloadActivity(); + if (downloadActivity != null) { + OsmandApplication app = downloadActivity.getMyApplication(); + DownloadResources indexes = getDownloadActivity().getDownloadThread().getIndexes(); + group = indexes.getGroupById(regionId); + indexItem = (CustomIndexItem) group.getItemByIndex(itemIndex); + if (indexItem != null) { + toolbar.setTitle(indexItem.getVisibleName(app, app.getRegions())); + WorldRegion region = group.getRegion(); + if (region instanceof CustomRegion) { + CustomRegion customRegion = (CustomRegion) region; + int color = customRegion.getHeaderColor(); + if (color != -1) { + toolbar.setBackgroundColor(color); + } + } + + description.setText(indexItem.getLocalizedDescription(app)); + buttonTextView.setText(indexItem.getWebButtonText(app)); + + final PicassoUtils picassoUtils = PicassoUtils.getPicasso(app); + Picasso picasso = Picasso.get(); + for (final String imageUrl : indexItem.getDescriptionImageUrl()) { + RequestCreator rc = picasso.load(imageUrl); + rc.into(image, new Callback() { + @Override + public void onSuccess() { + image.setVisibility(View.VISIBLE); + picassoUtils.setResultLoaded(imageUrl, true); + } + + @Override + public void onError(Exception e) { + image.setVisibility(View.GONE); + picassoUtils.setResultLoaded(imageUrl, false); + } + }); + } + } + } + } + + private OsmandApplication getMyApplication() { + return (OsmandApplication) getActivity().getApplication(); + } + + private DownloadActivity getDownloadActivity() { + return (DownloadActivity) getActivity(); + } + + public static DownloadItemFragment createInstance(String regionId, int itemIndex) { + Bundle bundle = new Bundle(); + bundle.putString(REGION_ID_DLG_KEY, regionId); + bundle.putInt(ITEM_ID_DLG_KEY, itemIndex); + DownloadItemFragment fragment = new DownloadItemFragment(); + fragment.setArguments(bundle); + return fragment; + } +} \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/download/ui/DownloadResourceGroupFragment.java b/OsmAnd/src/net/osmand/plus/download/ui/DownloadResourceGroupFragment.java index 9eb898b17f..8b5d272987 100644 --- a/OsmAnd/src/net/osmand/plus/download/ui/DownloadResourceGroupFragment.java +++ b/OsmAnd/src/net/osmand/plus/download/ui/DownloadResourceGroupFragment.java @@ -33,6 +33,7 @@ import net.osmand.plus.OsmandSettings; import net.osmand.plus.R; import net.osmand.plus.UiUtilities; import net.osmand.plus.activities.OsmandBaseExpandableListAdapter; +import net.osmand.plus.download.CustomIndexItem; import net.osmand.plus.download.DownloadActivity; import net.osmand.plus.download.DownloadActivity.BannerAndDownloadFreeVersion; import net.osmand.plus.download.DownloadActivityType; @@ -60,8 +61,10 @@ public class DownloadResourceGroupFragment extends DialogFragment implements Dow InAppPurchaseListener, OnChildClickListener { public static final int RELOAD_ID = 0; public static final int SEARCH_ID = 1; + public static final String TAG = "RegionDialogFragment"; - private static final String REGION_ID_DLG_KEY = "world_region_dialog_key"; + public static final String REGION_ID_DLG_KEY = "world_region_dialog_key"; + private String groupId; private View view; private BannerAndDownloadFreeVersion banner; @@ -451,6 +454,11 @@ public class DownloadResourceGroupFragment extends DialogFragment implements Dow .createInstance(uniqueId); ((DownloadActivity) getActivity()).showDialog(getActivity(), regionDialogFragment); return true; + } else if (child instanceof CustomIndexItem) { + String regionId = group.getGroupByIndex(groupPosition).getUniqueId(); + + DownloadItemFragment downloadItemFragment = DownloadItemFragment.createInstance(regionId, childPosition); + ((DownloadActivity) getActivity()).showDialog(getActivity(), downloadItemFragment); } else if (child instanceof IndexItem) { IndexItem indexItem = (IndexItem) child; ItemViewHolder vh = (ItemViewHolder) v.getTag(); @@ -631,11 +639,12 @@ public class DownloadResourceGroupFragment extends DialogFragment implements Dow viewHolder.setShowRemoteDate(true); convertView.setTag(viewHolder); } - if(mainGroup.getType() == DownloadResourceGroupType.REGION && - group != null && group.getType() == DownloadResourceGroupType.REGION_MAPS) { + if (mainGroup.getType() == DownloadResourceGroupType.REGION && + group != null && group.getType() == DownloadResourceGroupType.REGION_MAPS + && !(item instanceof CustomIndexItem)) { viewHolder.setShowTypeInName(true); viewHolder.setShowTypeInDesc(false); - } else if(group != null && (group.getType() == DownloadResourceGroupType.SRTM_HEADER + } else if (group != null && (group.getType() == DownloadResourceGroupType.SRTM_HEADER || group.getType() == DownloadResourceGroupType.HILLSHADE_HEADER)) { viewHolder.setShowTypeInName(false); viewHolder.setShowTypeInDesc(false); diff --git a/OsmAnd/src/net/osmand/plus/helpers/GpxUiHelper.java b/OsmAnd/src/net/osmand/plus/helpers/GpxUiHelper.java index a44e460a27..efb435cc5e 100644 --- a/OsmAnd/src/net/osmand/plus/helpers/GpxUiHelper.java +++ b/OsmAnd/src/net/osmand/plus/helpers/GpxUiHelper.java @@ -115,6 +115,7 @@ import java.util.List; import java.util.Map; import static com.github.mikephil.charting.components.XAxis.XAxisPosition.BOTTOM; +import static net.osmand.IndexConstants.GPX_FILE_EXT; import static net.osmand.binary.RouteDataObject.HEIGHT_UNDEFINED; import static net.osmand.plus.OsmAndFormatter.FEET_IN_ONE_METER; import static net.osmand.plus.OsmAndFormatter.METERS_IN_KILOMETER; @@ -307,8 +308,8 @@ public class GpxUiHelper { public static String getGpxTitle(String fileName) { String s = fileName; - if (s.toLowerCase().endsWith(".gpx")) { - s = s.substring(0, s.length() - ".gpx".length()); + if (s.toLowerCase().endsWith(GPX_FILE_EXT)) { + s = s.substring(0, s.length() - GPX_FILE_EXT.length()); } s = s.replace('_', ' '); return s; @@ -901,7 +902,7 @@ public class GpxUiHelper { File[] files = dir.listFiles(); if (files != null) { for (File f : files) { - if (f.getName().toLowerCase().endsWith(".gpx")) { //$NON-NLS-1$ + if (f.getName().toLowerCase().endsWith(GPX_FILE_EXT)) { list.add(new GPXInfo(absolutePath ? f.getAbsolutePath() : parent + f.getName(), f.lastModified(), f.length())); } else if (f.isDirectory()) { diff --git a/OsmAnd/src/net/osmand/plus/helpers/ImportHelper.java b/OsmAnd/src/net/osmand/plus/helpers/ImportHelper.java index 084e58ae08..1c2c1a4b88 100644 --- a/OsmAnd/src/net/osmand/plus/helpers/ImportHelper.java +++ b/OsmAnd/src/net/osmand/plus/helpers/ImportHelper.java @@ -84,6 +84,7 @@ import java.util.Map; import java.util.zip.ZipInputStream; import static android.app.Activity.RESULT_OK; +import static net.osmand.IndexConstants.GPX_FILE_EXT; import static net.osmand.IndexConstants.OSMAND_SETTINGS_FILE_EXT; import static net.osmand.IndexConstants.RENDERER_INDEX_EXT; import static net.osmand.IndexConstants.ROUTING_FILE_EXT; @@ -99,7 +100,7 @@ public class ImportHelper { public final static Log log = PlatformUtil.getLog(ImportHelper.class); public static final String KML_SUFFIX = ".kml"; public static final String KMZ_SUFFIX = ".kmz"; - public static final String GPX_SUFFIX = ".gpx"; + private final AppCompatActivity activity; private final OsmandApplication app; private final OsmandMapTileView mapView; @@ -146,8 +147,8 @@ public class ImportHelper { boolean isOsmandSubdir = isSubDirectory(app.getAppPath(IndexConstants.GPX_INDEX_DIR), new File(contentUri.getPath())); if (!isOsmandSubdir && name != null) { String nameLC = name.toLowerCase(); - if (nameLC.endsWith(GPX_SUFFIX)) { - name = name.substring(0, name.length() - 4) + GPX_SUFFIX; + if (nameLC.endsWith(GPX_FILE_EXT)) { + name = name.substring(0, name.length() - 4) + GPX_FILE_EXT; handleGpxImport(contentUri, name, true, useImportDir); return true; } else if (nameLC.endsWith(KML_SUFFIX)) { @@ -1046,14 +1047,14 @@ public class ImportHelper { private File getFileToSave(final String fileName, final File importDir, final WptPt pt) { final StringBuilder builder = new StringBuilder(fileName); if ("".equals(fileName)) { - builder.append("import_").append(new SimpleDateFormat("HH-mm_EEE", Locale.US).format(new Date(pt.time))).append(GPX_SUFFIX); //$NON-NLS-1$ + builder.append("import_").append(new SimpleDateFormat("HH-mm_EEE", Locale.US).format(new Date(pt.time))).append(GPX_FILE_EXT); //$NON-NLS-1$ } if (fileName.endsWith(KML_SUFFIX)) { - builder.replace(builder.length() - KML_SUFFIX.length(), builder.length(), GPX_SUFFIX); + builder.replace(builder.length() - KML_SUFFIX.length(), builder.length(), GPX_FILE_EXT); } else if (fileName.endsWith(KMZ_SUFFIX)) { - builder.replace(builder.length() - KMZ_SUFFIX.length(), builder.length(), GPX_SUFFIX); - } else if (!fileName.endsWith(GPX_SUFFIX)) { - builder.append(GPX_SUFFIX); + builder.replace(builder.length() - KMZ_SUFFIX.length(), builder.length(), GPX_FILE_EXT); + } else if (!fileName.endsWith(GPX_FILE_EXT)) { + builder.append(GPX_FILE_EXT); } return new File(importDir, builder.toString()); } diff --git a/OsmAnd/src/net/osmand/plus/mapcontextmenu/builders/WptPtMenuBuilder.java b/OsmAnd/src/net/osmand/plus/mapcontextmenu/builders/WptPtMenuBuilder.java index 68c19e8319..d9b2f6c7b9 100644 --- a/OsmAnd/src/net/osmand/plus/mapcontextmenu/builders/WptPtMenuBuilder.java +++ b/OsmAnd/src/net/osmand/plus/mapcontextmenu/builders/WptPtMenuBuilder.java @@ -11,6 +11,7 @@ import androidx.core.content.ContextCompat; import net.osmand.GPXUtilities; import net.osmand.GPXUtilities.WptPt; +import net.osmand.IndexConstants; import net.osmand.data.LatLon; import net.osmand.data.PointDescription; import net.osmand.plus.GpxSelectionHelper; @@ -113,7 +114,7 @@ public class WptPtMenuBuilder extends MenuBuilder { if (points.size() > 0) { String title = view.getContext().getString(R.string.context_menu_points_of_group); File file = new File(gpx.path); - String gpxName = file.getName().replace(".gpx", "").replace("/", " ").replace("_", " "); + String gpxName = file.getName().replace(IndexConstants.GPX_FILE_EXT, "").replace("/", " ").replace("_", " "); int color = getPointColor(wpt, getFileColor(selectedGpxFile)); buildRow(view, app.getUIUtilities().getPaintedIcon(R.drawable.ic_type_waypoints_group, color), null, title, 0, gpxName, true, getCollapsableWaypointsView(view.getContext(), true, gpx, wpt), diff --git a/OsmAnd/src/net/osmand/plus/mapcontextmenu/controllers/WptPtMenuController.java b/OsmAnd/src/net/osmand/plus/mapcontextmenu/controllers/WptPtMenuController.java index d692c153a4..d94079c977 100644 --- a/OsmAnd/src/net/osmand/plus/mapcontextmenu/controllers/WptPtMenuController.java +++ b/OsmAnd/src/net/osmand/plus/mapcontextmenu/controllers/WptPtMenuController.java @@ -6,6 +6,7 @@ import androidx.annotation.NonNull; import androidx.core.content.ContextCompat; import net.osmand.GPXUtilities.WptPt; +import net.osmand.IndexConstants; import net.osmand.data.LatLon; import net.osmand.data.PointDescription; import net.osmand.plus.GpxSelectionHelper; @@ -115,7 +116,7 @@ public class WptPtMenuController extends MenuController { sb.append(", "); if (selectedGpxFile != null) { File file = new File(selectedGpxFile.getGpxFile().path); - String gpxName = file.getName().replace(".gpx", "").replace("/", " ").replace("_", " "); + String gpxName = file.getName().replace(IndexConstants.GPX_FILE_EXT, "").replace("/", " ").replace("_", " "); sb.append(gpxName); } return sb.toString(); diff --git a/OsmAnd/src/net/osmand/plus/mapmarkers/AddTracksGroupBottomSheetDialogFragment.java b/OsmAnd/src/net/osmand/plus/mapmarkers/AddTracksGroupBottomSheetDialogFragment.java index d1005e35e8..b01548be00 100644 --- a/OsmAnd/src/net/osmand/plus/mapmarkers/AddTracksGroupBottomSheetDialogFragment.java +++ b/OsmAnd/src/net/osmand/plus/mapmarkers/AddTracksGroupBottomSheetDialogFragment.java @@ -172,7 +172,7 @@ public class AddTracksGroupBottomSheetDialogFragment extends AddGroupBottomSheet String sub = gpxSubfolder.length() == 0 ? gpxFile.getName() : gpxSubfolder + "/" + gpxFile.getName(); processGPXFolder(gpxFile, sub); - } else if (gpxFile.isFile() && gpxFile.getName().toLowerCase().endsWith(".gpx")) { + } else if (gpxFile.isFile() && gpxFile.getName().toLowerCase().endsWith(IndexConstants.GPX_FILE_EXT)) { GpxDataItem item = dbHelper.getItem(gpxFile, gpxDataItemCallback); publishProgress(item); } diff --git a/OsmAnd/src/net/osmand/plus/mapmarkers/CoordinateInputDialogFragment.java b/OsmAnd/src/net/osmand/plus/mapmarkers/CoordinateInputDialogFragment.java index a4367a5cc0..232b73084c 100644 --- a/OsmAnd/src/net/osmand/plus/mapmarkers/CoordinateInputDialogFragment.java +++ b/OsmAnd/src/net/osmand/plus/mapmarkers/CoordinateInputDialogFragment.java @@ -1494,10 +1494,10 @@ public class CoordinateInputDialogFragment extends DialogFragment implements Osm if (!dir.exists()) { dir.mkdirs(); } - File fout = new File(dir, fileName + ".gpx"); + File fout = new File(dir, fileName + IndexConstants.GPX_FILE_EXT); int ind = 1; while (fout.exists()) { - fout = new File(dir, fileName + "_" + (++ind) + ".gpx"); + fout = new File(dir, fileName + "_" + (++ind) + IndexConstants.GPX_FILE_EXT); } GPXUtilities.writeGpxFile(fout, gpx); } diff --git a/OsmAnd/src/net/osmand/plus/mapmarkers/SaveAsTrackBottomSheetDialogFragment.java b/OsmAnd/src/net/osmand/plus/mapmarkers/SaveAsTrackBottomSheetDialogFragment.java index 1974f61cc7..5cdb3571c2 100644 --- a/OsmAnd/src/net/osmand/plus/mapmarkers/SaveAsTrackBottomSheetDialogFragment.java +++ b/OsmAnd/src/net/osmand/plus/mapmarkers/SaveAsTrackBottomSheetDialogFragment.java @@ -32,7 +32,6 @@ import net.osmand.plus.widgets.OsmandTextFieldBoxes; import java.io.File; import java.util.Date; -import static net.osmand.plus.helpers.ImportHelper.GPX_SUFFIX; import static net.osmand.plus.mapmarkers.CoordinateInputDialogFragment.ADDED_POINTS_NUMBER_KEY; public class SaveAsTrackBottomSheetDialogFragment extends BottomSheetDialogFragment { @@ -98,11 +97,11 @@ public class SaveAsTrackBottomSheetDialogFragment extends BottomSheetDialogFragm Date date = new Date(); final String suggestedName = app.getString(R.string.markers) + "_" + DateFormat.format("yyyy-MM-dd", date).toString(); String displayedName = suggestedName; - File fout = new File(dir, suggestedName + GPX_SUFFIX); + File fout = new File(dir, suggestedName + IndexConstants.GPX_FILE_EXT); int ind = 1; while (fout.exists()) { displayedName = suggestedName + "_" + (++ind); - fout = new File(dir, displayedName + GPX_SUFFIX); + fout = new File(dir, displayedName + IndexConstants.GPX_FILE_EXT); } final EditText nameEditText = (EditText) mainView.findViewById(R.id.name_edit_text); nameEditText.setText(displayedName); diff --git a/OsmAnd/src/net/osmand/plus/mapmarkers/SelectWptCategoriesBottomSheetDialogFragment.java b/OsmAnd/src/net/osmand/plus/mapmarkers/SelectWptCategoriesBottomSheetDialogFragment.java index f5255f0d25..0052bf655e 100644 --- a/OsmAnd/src/net/osmand/plus/mapmarkers/SelectWptCategoriesBottomSheetDialogFragment.java +++ b/OsmAnd/src/net/osmand/plus/mapmarkers/SelectWptCategoriesBottomSheetDialogFragment.java @@ -10,6 +10,7 @@ import androidx.annotation.Nullable; import net.osmand.GPXUtilities; import net.osmand.GPXUtilities.GPXFile; import net.osmand.GPXUtilities.WptPt; +import net.osmand.IndexConstants; import net.osmand.plus.GpxSelectionHelper; import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile; import net.osmand.plus.MapMarkersHelper; @@ -161,7 +162,7 @@ public class SelectWptCategoriesBottomSheetDialogFragment extends MenuBottomShee private String getGpxName(GPXFile gpxFile) { return new File(gpxFile.path).getName() - .replace(".gpx", "") + .replace(IndexConstants.GPX_FILE_EXT, "") .replace("/", " ") .replace("_", " "); } diff --git a/OsmAnd/src/net/osmand/plus/mapmarkers/adapters/MapMarkersGroupsAdapter.java b/OsmAnd/src/net/osmand/plus/mapmarkers/adapters/MapMarkersGroupsAdapter.java index c4f95fc9fa..0cd5421c3d 100644 --- a/OsmAnd/src/net/osmand/plus/mapmarkers/adapters/MapMarkersGroupsAdapter.java +++ b/OsmAnd/src/net/osmand/plus/mapmarkers/adapters/MapMarkersGroupsAdapter.java @@ -404,7 +404,7 @@ public class MapMarkersGroupsAdapter extends RecyclerView.Adapter