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