Merge pull request #8798 from osmandapp/custom_downloads

Custom downloads
This commit is contained in:
max-klaus 2020-04-21 14:22:36 +03:00 committed by GitHub
commit 7273372040
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
38 changed files with 1382 additions and 267 deletions

View file

@ -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";

View file

@ -0,0 +1,85 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/pstsTabBackground"
android:minHeight="@dimen/dashboard_map_toolbar"
android:theme="?attr/toolbar_theme"
app:contentInsetLeft="72dp"
app:contentInsetStart="72dp" />
</com.google.android.material.appbar.AppBarLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/activity_background_basic">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="@dimen/dialog_button_ex_height">
<ImageView
android:id="@+id/item_image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:adjustViewBounds="true"
android:background="?attr/bg_color"
android:maxHeight="132dp"
android:scaleType="fitCenter"
tools:src="@drawable/extension_stub" />
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/item_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/bg_color"
android:letterSpacing="@dimen/text_button_letter_spacing"
android:paddingStart="@dimen/content_padding"
android:paddingLeft="@dimen/content_padding"
android:paddingTop="@dimen/content_padding_small"
android:paddingEnd="@dimen/content_padding"
android:paddingRight="@dimen/content_padding"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/default_list_text_size"
app:typeface="@string/font_roboto_regular"
tools:text="@string/lorem_ipsum" />
<include layout="@layout/card_bottom_divider" />
</LinearLayout>
</ScrollView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:background="?attr/list_background_color">
<include layout="@layout/bottom_buttons" />
</LinearLayout>
</FrameLayout>
</LinearLayout>

View file

@ -11,6 +11,7 @@
Thx - Hardy
-->
<string name="extra_maps_menu_group">Extra maps</string>
<string name="custom_color">Custom color</string>
<string name="lang_lmo">Lombard</string>
<string name="lang_an">Aragonese</string>

View file

@ -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<String, String> 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<String> jsonArrayToList(String key, JSONObject json) throws JSONException {
List<String> 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<String, String> getLocalizedMapFromJson(String key, JSONObject json) throws JSONException {
Map<String, String> localizedMap = new HashMap<>();
JSONObject jsonObject = json.optJSONObject(key);
if (jsonObject != null) {
for (Iterator<String> 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<String> 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<String, String> map) throws JSONException {
if (!Algorithms.isEmpty(map)) {
JSONObject jsonObject = new JSONObject();
for (Map.Entry<String, String> entry : map.entrySet()) {
jsonObject.put(entry.getKey(), entry.getValue());
}
json.put(jsonKey, jsonObject);
}
}
}

View file

@ -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<String> rendererNames = new ArrayList<>();
private List<String> routerNames = new ArrayList<>();
private List<SuggestedDownloadItem> suggestedDownloadItems = new ArrayList<>();
private List<WorldRegion> 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<String> getRendererNames() {
return rendererNames;
}
@Override
public List<String> getRouterNames() {
return routerNames;
}
private Drawable getIconForFile(String path, Map<String, String> fileNames) {
for (Map.Entry<String, String> 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<WorldRegion> getDownloadMaps() {
return customRegions;
}
@Override
public List<IndexItem> getSuggestedMaps() {
List<IndexItem> 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<IndexItem> 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<String> 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<String> 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<String> 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<String> 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<String, String> 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<String, String> 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<String, String> entry : names.entrySet()) {
nameJson.put(entry.getKey(), entry.getValue());
private List<WorldRegion> getFlatCustomRegions() {
List<WorldRegion> l = new ArrayList<>(customRegions);
for (WorldRegion region : customRegions) {
collectCustomSubregionsFromRegion(region, l);
}
json.put("name", nameJson);
return l;
}
JSONObject descriptionJson = new JSONObject();
for (Map.Entry<String, String> entry : descriptions.entrySet()) {
descriptionJson.put(entry.getKey(), entry.getValue());
private void collectCustomSubregionsFromRegion(WorldRegion region, List<WorldRegion> 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<String> 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<String> 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<String, String> entry : iconNames.entrySet()) {
iconNamesJson.put(entry.getKey(), entry.getValue());
}
json.put("iconNames", iconNamesJson);
JSONObject imageNamesJson = new JSONObject();
for (Map.Entry<String, String> 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<String> getRendererNames() {
return rendererNames;
}
@Override
public List<String> getRouterNames() {
return routerNames;
public static List<CustomRegion> collectRegionsFromJson(JSONArray jsonArray) throws JSONException {
List<CustomRegion> customRegions = new ArrayList<>();
Map<String, CustomRegion> 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<String, String> fileNames) {
for (Map.Entry<String, String> 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<SuggestedDownloadItem> items) {
suggestedDownloadItems = new ArrayList<>(items);
}
public void updateDownloadItems(List<WorldRegion> items) {
customRegions = new ArrayList<>(items);
}
private List<IndexItem> 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<IndexItem> getMapsForType(List<String> 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<String> names;
private int limit;
public SuggestedDownloadItem(String scopeId, String searchType, List<String> 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<String> getNames() {
return names;
}
public int getLimit() {
return limit;
}
}
}

View file

@ -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<String, String> names = new HashMap<>();
private Map<String, String> icons = new HashMap<>();
private Map<String, String> 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<IndexItem> loadIndexItems() {
List<IndexItem> 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<String> descrImageUrl = JsonUtils.jsonArrayToList("image-description-url", itemJson);
Map<String, String> indexNames = JsonUtils.getLocalizedMapFromJson("name", itemJson);
Map<String, String> descriptions = JsonUtils.getLocalizedMapFromJson("description", itemJson);
Map<String, String> 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;
}
}

View file

@ -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('_', ' ');

View file

@ -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) {

View file

@ -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<WorldRegion> getDownloadMaps() {
return Collections.emptyList();
}
public List<String> getRendererNames() {
return Collections.emptyList();
}
@ -645,6 +650,31 @@ public abstract class OsmandPlugin {
return null;
}
public static List<WorldRegion> getCustomDownloadRegions() {
List<WorldRegion> l = new ArrayList<>();
for (OsmandPlugin plugin : getEnabledPlugins()) {
l.addAll(plugin.getDownloadMaps());
}
return l;
}
public static List<IndexItem> getCustomDownloadItems() {
List<IndexItem> l = new ArrayList<>();
for (WorldRegion region : getCustomDownloadRegions()) {
collectIndexItemsFromSubregion(region, l);
}
return l;
}
public static void collectIndexItemsFromSubregion(WorldRegion region, List<IndexItem> items) {
if (region instanceof CustomRegion) {
items.addAll(((CustomRegion) region).loadIndexItems());
}
for (WorldRegion subregion : region.getSubregions()) {
collectIndexItemsFromSubregion(subregion, items);
}
}
public static List<String> getDisabledRendererNames() {
List<String> l = new ArrayList<String>();
for (OsmandPlugin plugin : getNotEnabledPlugins()) {

View file

@ -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<SuggestedDownloadItem> 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<SuggestedDownloadItem> 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<String> 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<WorldRegion> 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<WorldRegion> 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<T> extends SettingsItem {
protected List<T> 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;
}

View file

@ -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());
}

View file

@ -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$
}
}

View file

@ -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));

View file

@ -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<String> imageDescrUrl;
private Map<String, String> names;
private Map<String, String> descriptions;
private Map<String, String> webButtonTexts;
public CustomIndexItem(String fileName,
String subfolder,
String downloadUrl,
String webUrl,
String size,
long timestamp,
long contentSize,
long containerSize,
List<String> imageDescrUrl,
Map<String, String> names,
Map<String, String> descriptions,
Map<String, String> 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<String> 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<String> imageDescrUrl;
private Map<String, String> names;
private Map<String, String> descriptions;
private Map<String, String> 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<String> imageDescrUrl) {
this.imageDescrUrl = imageDescrUrl;
return this;
}
public CustomIndexItemBuilder setNames(Map<String, String> names) {
this.names = names;
return this;
}
public CustomIndexItemBuilder setDescriptions(Map<String, String> descriptions) {
this.descriptions = descriptions;
return this;
}
public CustomIndexItemBuilder setWebButtonText(Map<String, String> 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);
}
}
}

View file

@ -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) {

View file

@ -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;

View file

@ -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;

View file

@ -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<IndexItem> 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<WorldRegion> customRegions = OsmandPlugin.getCustomDownloadRegions();
if (!Algorithms.isEmpty(customRegions)) {
addGroup(extraMapsGroup);
for (WorldRegion region : customRegions) {
buildRegionsGroups(region, extraMapsGroup);
}
}
LinkedList<WorldRegion> queue = new LinkedList<WorldRegion>();
LinkedList<DownloadResourceGroup> parent = new LinkedList<DownloadResourceGroup>();
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<WorldRegion> queue = new LinkedList<WorldRegion>();
LinkedList<DownloadResourceGroup> parent = new LinkedList<DownloadResourceGroup>();
queue.add(region);
parent.add(group);
while (!queue.isEmpty()) {
WorldRegion reg = queue.pollFirst();
DownloadResourceGroup parentGroup = parent.pollFirst();
List<WorldRegion> 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<IndexItem> 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<IndexItem> findIndexItemsAt(OsmandApplication app, LatLon latLon, DownloadActivityType type, boolean includeDownloaded) throws IOException {
return findIndexItemsAt(app, latLon, type, includeDownloaded, -1);
}
public static List<IndexItem> findIndexItemsAt(OsmandApplication app, LatLon latLon, DownloadActivityType type, boolean includeDownloaded, int limit) throws IOException {
List<IndexItem> 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<IndexItem> findIndexItemsAt(OsmandApplication app, List<String> names, DownloadActivityType type, boolean includeDownloaded, int limit) {
List<IndexItem> 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;
}

View file

@ -135,19 +135,22 @@ public class IndexItem implements Comparable<IndexItem> {
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;

View file

@ -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;
}
}

View file

@ -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);

View file

@ -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()) {

View file

@ -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());
}

View file

@ -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),

View file

@ -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();

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);

View file

@ -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("_", " ");
}

View file

@ -404,7 +404,7 @@ public class MapMarkersGroupsAdapter extends RecyclerView.Adapter<RecyclerView.V
if (groupName.equals("")) {
groupName = app.getString(R.string.shared_string_favorites);
} else if (group.getType() == MapMarkersGroup.GPX_TYPE) {
groupName = groupName.replace(".gpx", "").replace("/", " ").replace("_", " ");
groupName = groupName.replace(IndexConstants.GPX_FILE_EXT, "").replace("/", " ").replace("_", " ");
}
if (group.isDisabled()) {
headerString = groupName;

View file

@ -7,6 +7,7 @@ import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import net.osmand.GPXUtilities.GPXTrackAnalysis;
import net.osmand.IndexConstants;
import net.osmand.plus.GPXDatabase.GpxDataItem;
import net.osmand.plus.R;
@ -33,7 +34,7 @@ public class TracksGroupsAdapter extends GroupsAdapter {
GpxDataItem gpx = getItem(position);
MapMarkersGroupViewHolder markersGroupViewHolder = (MapMarkersGroupViewHolder) holder;
markersGroupViewHolder.icon.setImageDrawable(iconsCache.getThemedIcon(R.drawable.ic_action_polygom_dark));
markersGroupViewHolder.name.setText(gpx.getFile().getName().replace(".gpx", "").replace("/", " ").replace("_", " "));
markersGroupViewHolder.name.setText(gpx.getFile().getName().replace(IndexConstants.GPX_FILE_EXT, "").replace("/", " ").replace("_", " "));
GPXTrackAnalysis analysis = gpx.getAnalysis();
markersGroupViewHolder.numberCount.setText(analysis != null ? String.valueOf(analysis.wptPoints) : "");
String description = getDescription(gpx);

View file

@ -81,7 +81,8 @@ import java.util.Date;
import java.util.List;
import java.util.Locale;
import static net.osmand.plus.helpers.ImportHelper.GPX_SUFFIX;
import static net.osmand.IndexConstants.GPX_FILE_EXT;
public class MeasurementToolFragment extends BaseOsmAndFragment {
@ -1171,11 +1172,11 @@ public class MeasurementToolFragment extends BaseOsmAndFragment {
final String suggestedName = new SimpleDateFormat("yyyy-MM-dd_HH-mm_EEE", Locale.US).format(new Date());
String displayedName = suggestedName;
File fout = new File(dir, suggestedName + GPX_SUFFIX);
File fout = new File(dir, suggestedName + GPX_FILE_EXT);
int ind = 1;
while (fout.exists()) {
displayedName = suggestedName + "_" + (++ind);
fout = new File(dir, displayedName + GPX_SUFFIX);
fout = new File(dir, displayedName + GPX_FILE_EXT);
}
nameEt.setText(displayedName);
nameEt.setSelection(displayedName.length());
@ -1188,12 +1189,12 @@ public class MeasurementToolFragment extends BaseOsmAndFragment {
@Override
public void onClick(DialogInterface dialog, int which) {
final String name = nameEt.getText().toString();
String fileName = name + GPX_SUFFIX;
String fileName = name + GPX_FILE_EXT;
if (textChanged[0]) {
File fout = new File(dir, fileName);
int ind = 1;
while (fout.exists()) {
fileName = name + "_" + (++ind) + GPX_SUFFIX;
fileName = name + "_" + (++ind) + GPX_FILE_EXT;
fout = new File(dir, fileName);
}
}
@ -1217,7 +1218,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment {
@Override
public void afterTextChanged(Editable editable) {
if (new File(dir, editable.toString() + GPX_SUFFIX).exists()) {
if (new File(dir, editable.toString() + GPX_FILE_EXT).exists()) {
warningTextView.setVisibility(View.VISIBLE);
warningTextView.setText(R.string.file_with_name_already_exists);
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(true);
@ -1277,7 +1278,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment {
TrkSegment after = editingCtx.getAfterTrkSegmentLine();
if (gpx == null) {
toSave = new File(dir, fileName);
String trackName = fileName.substring(0, fileName.length() - GPX_SUFFIX.length());
String trackName = fileName.substring(0, fileName.length() - GPX_FILE_EXT.length());
GPXFile gpx = new GPXFile(Version.getFullVersion(activity.getMyApplication()));
if (measurementLayer != null) {
if (saveType == SaveType.LINE) {
@ -1534,11 +1535,11 @@ public class MeasurementToolFragment extends BaseOsmAndFragment {
public void onClick(DialogInterface dialog, int which) {
if (showOnMapToggle.isChecked()) {
final String name = new SimpleDateFormat("yyyy-MM-dd_HH-mm_EEE", Locale.US).format(new Date());
String fileName = name + GPX_SUFFIX;
String fileName = name + GPX_FILE_EXT;
File fout = new File(dir, fileName);
int ind = 1;
while (fout.exists()) {
fileName = name + "_" + (++ind) + GPX_SUFFIX;
fileName = name + "_" + (++ind) + GPX_FILE_EXT;
fout = new File(dir, fileName);
}
saveNewGpx(dir, fileName, true, SaveType.LINE, true);

View file

@ -25,6 +25,7 @@ import androidx.fragment.app.FragmentManager;
import net.osmand.GPXUtilities;
import net.osmand.GPXUtilities.WptPt;
import net.osmand.IndexConstants;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.UiUtilities;
@ -74,7 +75,7 @@ public class OnSaveCurrentTrackFragment extends BottomSheetDialogFragment {
}
Context ctx = requireContext();
file = new File(app.getAppCustomization().getTracksDir(), savedGpxName + ".gpx");
file = new File(app.getAppCustomization().getTracksDir(), savedGpxName + IndexConstants.GPX_FILE_EXT);
final boolean nightMode = app.getDaynightHelper().isNightModeForMapControls();
final int textPrimaryColor = nightMode ? R.color.text_color_primary_dark : R.color.text_color_primary_light;
View mainView = UiUtilities.getInflater(ctx, nightMode).inflate(R.layout.fragment_on_save_current_track, container);
@ -175,7 +176,7 @@ public class OnSaveCurrentTrackFragment extends BottomSheetDialogFragment {
return null;
}
OsmandApplication app = (OsmandApplication) activity.getApplication();
File savedFile = new File(app.getAppCustomization().getTracksDir(), new File(savedGpxDir, savedGpxName + ".gpx").getPath());
File savedFile = new File(app.getAppCustomization().getTracksDir(), new File(savedGpxDir, savedGpxName + IndexConstants.GPX_FILE_EXT).getPath());
if (savedGpxName.equalsIgnoreCase(newGpxName)) {
return savedFile;
}
@ -183,7 +184,7 @@ public class OnSaveCurrentTrackFragment extends BottomSheetDialogFragment {
Toast.makeText(app, R.string.empty_filename, Toast.LENGTH_LONG).show();
return null;
}
return LocalIndexesFragment.renameGpxFile(app, savedFile, newGpxName + ".gpx", true, null);
return LocalIndexesFragment.renameGpxFile(app, savedFile, newGpxName + IndexConstants.GPX_FILE_EXT, true, null);
}
private void showOnMap(File f, boolean animated) {

View file

@ -978,7 +978,7 @@ public class AvailableGPXFragment extends OsmandExpandableListFragment implement
String sub = gpxSubfolder.length() == 0 ? gpxFile.getName() : gpxSubfolder + "/"
+ gpxFile.getName();
loadGPXFolder(gpxFile, result, loadTask, progress, sub);
} else if (gpxFile.isFile() && gpxFile.getName().toLowerCase().endsWith(".gpx")) {
} else if (gpxFile.isFile() && gpxFile.getName().toLowerCase().endsWith(IndexConstants.GPX_FILE_EXT)) {
GpxInfo info = new GpxInfo();
info.subfolder = gpxSubfolder;
info.file = gpxFile;
@ -1233,7 +1233,7 @@ public class AvailableGPXFragment extends OsmandExpandableListFragment implement
v.findViewById(R.id.group_divider).setVisibility(View.VISIBLE);
StringBuilder t = new StringBuilder();
String groupName = group.replaceAll("_", " ").replace(".gpx", "");
String groupName = group.replaceAll("_", " ").replace(IndexConstants.GPX_FILE_EXT, "");
if (groupName.length() == 0) {
groupName = getString(R.string.shared_string_tracks);
}

View file

@ -46,6 +46,7 @@ import net.osmand.Collator;
import net.osmand.GPXUtilities;
import net.osmand.GPXUtilities.GPXFile;
import net.osmand.GPXUtilities.WptPt;
import net.osmand.IndexConstants;
import net.osmand.OsmAndCollator;
import net.osmand.data.FavouritePoint;
import net.osmand.data.LatLon;
@ -1269,7 +1270,7 @@ public class TrackPointFragment extends OsmandExpandableListFragment implements
dir.mkdir();
}
for (final String f : files.keySet()) {
File fout = new File(dir, f + ".gpx");
File fout = new File(dir, f + IndexConstants.GPX_FILE_EXT);
GPXUtilities.writeGpxFile(fout, gpx);
}
return shouldClearPath;

View file

@ -34,6 +34,7 @@ import net.osmand.AndroidUtils;
import net.osmand.GPXUtilities;
import net.osmand.GPXUtilities.GPXFile;
import net.osmand.GPXUtilities.WptPt;
import net.osmand.IndexConstants;
import net.osmand.data.PointDescription;
import net.osmand.osm.edit.Entity;
import net.osmand.osm.edit.Node;
@ -800,7 +801,7 @@ public class OsmEditsFragment extends OsmAndListFragment implements SendPoiDialo
} else {
sb.append("osm_modification");
}
sb.append(oscFile ? ".osc" : ".gpx");
sb.append(oscFile ? ".osc" : IndexConstants.GPX_FILE_EXT);
return sb.toString();
}

View file

@ -193,7 +193,7 @@ public class DataStorageHelper {
tracksMemory = DataStorageMemoryItem.builder()
.setKey(TRACKS_MEMORY)
// .setExtensions(".gpx", ".gpx.bz2")
// .setExtensions(IndexConstants.GPX_FILE_EXT, ".gpx.bz2")
.setDirectories(
new Directory(app.getAppPath(IndexConstants.GPX_INDEX_DIR).getAbsolutePath(), true, EXTENSIONS, false))
.createItem();

View file

@ -633,7 +633,8 @@ public class TravelDbHelper {
}
public String getGPXName(TravelArticle article) {
return article.getTitle().replace('/', '_').replace('\'', '_').replace('\"', '_') + ".gpx";
return article.getTitle().replace('/', '_').replace('\'', '_')
.replace('\"', '_') + IndexConstants.GPX_FILE_EXT;
}
public File createGpxFile(TravelArticle article) {