diff --git a/OsmAnd/src/net/osmand/plus/activities/LocalIndexHelper.java b/OsmAnd/src/net/osmand/plus/activities/LocalIndexHelper.java index 1e53f97603..7c64e3a669 100644 --- a/OsmAnd/src/net/osmand/plus/activities/LocalIndexHelper.java +++ b/OsmAnd/src/net/osmand/plus/activities/LocalIndexHelper.java @@ -214,7 +214,7 @@ public class LocalIndexHelper { return result; } - public void loadVoiceData(File voiceDir, List result, boolean backup, AbstractLoadLocalIndexTask loadTask) { + private void loadVoiceData(File voiceDir, List result, boolean backup, AbstractLoadLocalIndexTask loadTask) { if (voiceDir.canRead()) { //First list TTS files, they are preferred for (File voiceF : listFilesSorted(voiceDir)) { diff --git a/OsmAnd/src/net/osmand/plus/download/DownloadActivityType.java b/OsmAnd/src/net/osmand/plus/download/DownloadActivityType.java index 95631c9c8c..b516d73d2c 100644 --- a/OsmAnd/src/net/osmand/plus/download/DownloadActivityType.java +++ b/OsmAnd/src/net/osmand/plus/download/DownloadActivityType.java @@ -342,7 +342,7 @@ public class DownloadActivityType { return FileNameTranslationHelper.getFontName(ctx, getBasename(indexItem)); } final String basename = getBasename(indexItem); - if (basename.endsWith(FileNameTranslationHelper.WIKI_NAME)){ + if (basename.endsWith(FileNameTranslationHelper.WIKI_NAME)) { return FileNameTranslationHelper.getWikiName(ctx, basename); } // if (this == HILLSHADE_FILE){ @@ -357,7 +357,7 @@ public class DownloadActivityType { final int ind = basename.indexOf("addresses-nationwide"); String downloadName = basename.substring(0, ind - 1) + basename.substring(ind + "addresses-nationwide".length()); return osmandRegions.getLocaleName(downloadName, includingParent) + - " "+ ctx.getString(R.string.index_item_nation_addresses); + " " + ctx.getString(R.string.index_item_nation_addresses); } else if (basename.startsWith("Depth_")) { final int extInd = basename.indexOf("osmand_ext"); String downloadName = extInd == -1 ? basename.substring(6, basename.length()).replace('_', ' ') @@ -438,11 +438,11 @@ public class DownloadActivityType { } if (this == HILLSHADE_FILE) { return fileName.substring(0, fileName.length() - IndexConstants.SQLITE_EXT.length()) - .replace(FileNameTranslationHelper.HILL_SHADE, ""); + .replace(FileNameTranslationHelper.HILL_SHADE + "_", ""); } if (this == SLOPE_FILE) { return fileName.substring(0, fileName.length() - IndexConstants.SQLITE_EXT.length()) - .replace(FileNameTranslationHelper.SLOPE, ""); + .replace(FileNameTranslationHelper.SLOPE + "_", ""); } if (fileName.endsWith(IndexConstants.SQLITE_EXT)) { return fileName.substring(0, fileName.length() - IndexConstants.SQLITE_EXT.length()); diff --git a/OsmAnd/src/net/osmand/plus/download/IndexItem.java b/OsmAnd/src/net/osmand/plus/download/IndexItem.java index 7173dfca66..650ab0679b 100644 --- a/OsmAnd/src/net/osmand/plus/download/IndexItem.java +++ b/OsmAnd/src/net/osmand/plus/download/IndexItem.java @@ -143,9 +143,9 @@ public class IndexItem implements Comparable { public String getTranslatedBasename() { if (type == DownloadActivityType.HILLSHADE_FILE) { - return (FileNameTranslationHelper.HILL_SHADE + getBasename()).replace("_", " "); + return (FileNameTranslationHelper.HILL_SHADE + "_" + getBasename()).replace("_", " "); } else if (type == DownloadActivityType.SLOPE_FILE) { - return (FileNameTranslationHelper.SLOPE + getBasename()).replace('_', ' '); + return (FileNameTranslationHelper.SLOPE + "_" + getBasename()).replace('_', ' '); } else { return getBasename(); } diff --git a/OsmAnd/src/net/osmand/plus/helpers/FileNameTranslationHelper.java b/OsmAnd/src/net/osmand/plus/helpers/FileNameTranslationHelper.java index 229003050e..e366d1e8bb 100644 --- a/OsmAnd/src/net/osmand/plus/helpers/FileNameTranslationHelper.java +++ b/OsmAnd/src/net/osmand/plus/helpers/FileNameTranslationHelper.java @@ -4,6 +4,7 @@ import android.content.Context; import net.osmand.IndexConstants; import net.osmand.PlatformUtil; import net.osmand.map.OsmandRegions; +import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; import net.osmand.plus.download.DownloadResources; @@ -18,10 +19,14 @@ import java.lang.reflect.Field; public class FileNameTranslationHelper { private static final Log LOG = PlatformUtil.getLog(FileNameTranslationHelper.class); public static final String WIKI_NAME = "_wiki"; - public static final String HILL_SHADE = "Hillshade_"; - public static final String SLOPE = "Slope_"; + public static final String HILL_SHADE = "Hillshade"; + public static final String SLOPE = "Slope"; public static final String SEA_DEPTH = "Depth_"; + public static String getFileNameWithRegion(OsmandApplication app, String fileName) { + return getFileName(app, app.getResourceManager().getOsmandRegions(), fileName); + } + public static String getFileName(Context ctx, OsmandRegions regions, String fileName) { String basename = getBasename(fileName); if (basename.endsWith(WIKI_NAME)) { //wiki files @@ -30,13 +35,15 @@ public class FileNameTranslationHelper { return getVoiceName(ctx, fileName); } else if (fileName.endsWith(IndexConstants.FONT_INDEX_EXT)) { //otf files return getFontName(ctx, basename); - } else if (fileName.startsWith(HILL_SHADE)){ + } else if (fileName.startsWith(HILL_SHADE)) { + basename = basename.replace(HILL_SHADE + " ", ""); return getTerrainName(ctx, regions, basename, R.string.download_hillshade_maps); } else if (fileName.startsWith(SLOPE)) { + basename = basename.replace(SLOPE + " ", ""); return getTerrainName(ctx, regions, basename, R.string.download_slope_maps); } else if (fileName.length() == 2) { //voice recorded files try { - Field f = R.string.class.getField("lang_"+fileName); + Field f = R.string.class.getField("lang_" + fileName); if (f != null) { Integer in = (Integer) f.get(null); return ctx.getString(in); @@ -62,9 +69,10 @@ public class FileNameTranslationHelper { public static String getTerrainName(Context ctx, OsmandRegions regions, String basename, int terrainNameRes) { - String terrain = ctx.getString(terrainNameRes) + " "; + basename = basename.replace(" ", "_"); + String terrain = ctx.getString(terrainNameRes); String locName = regions.getLocaleName(basename.trim(), true); - return terrain + locName; + return ctx.getString(R.string.ltr_or_rtl_combine_via_space, locName, "(" + terrain + ")"); } public static String getWikiName(Context ctx, String basename){ diff --git a/OsmAnd/src/net/osmand/plus/settings/backend/backup/DataSettingsItem.java b/OsmAnd/src/net/osmand/plus/settings/backend/backup/DataSettingsItem.java index 75529aa543..d040f20411 100644 --- a/OsmAnd/src/net/osmand/plus/settings/backend/backup/DataSettingsItem.java +++ b/OsmAnd/src/net/osmand/plus/settings/backend/backup/DataSettingsItem.java @@ -64,7 +64,7 @@ public class DataSettingsItem extends StreamSettingsItem { SettingsItemReader getReader() { return new StreamSettingsItemReader(this) { @Override - public void readFromStream(@NonNull InputStream inputStream, File destination) throws IOException, IllegalArgumentException { + public void readFromStream(@NonNull InputStream inputStream, String entryName) throws IOException, IllegalArgumentException { ByteArrayOutputStream buffer = new ByteArrayOutputStream(); int nRead; byte[] data = new byte[SettingsHelper.BUFFER]; diff --git a/OsmAnd/src/net/osmand/plus/settings/backend/backup/FavoritesSettingsItem.java b/OsmAnd/src/net/osmand/plus/settings/backend/backup/FavoritesSettingsItem.java index a035ae0146..817ec38a49 100644 --- a/OsmAnd/src/net/osmand/plus/settings/backend/backup/FavoritesSettingsItem.java +++ b/OsmAnd/src/net/osmand/plus/settings/backend/backup/FavoritesSettingsItem.java @@ -16,7 +16,6 @@ import net.osmand.plus.R; import org.json.JSONException; import org.json.JSONObject; -import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -146,7 +145,7 @@ public class FavoritesSettingsItem extends CollectionSettingsItem return new SettingsItemReader(this) { @Override - public void readFromStream(@NonNull InputStream inputStream, File destination) throws IllegalArgumentException { + public void readFromStream(@NonNull InputStream inputStream, String entryName) throws IllegalArgumentException { GPXFile gpxFile = GPXUtilities.loadGPXFile(inputStream); if (gpxFile.error != null) { warnings.add(app.getString(R.string.settings_item_read_error, String.valueOf(getType()))); diff --git a/OsmAnd/src/net/osmand/plus/settings/backend/backup/FileSettingsItem.java b/OsmAnd/src/net/osmand/plus/settings/backend/backup/FileSettingsItem.java index 3b4f8568e1..563a04fc75 100644 --- a/OsmAnd/src/net/osmand/plus/settings/backend/backup/FileSettingsItem.java +++ b/OsmAnd/src/net/osmand/plus/settings/backend/backup/FileSettingsItem.java @@ -1,5 +1,6 @@ package net.osmand.plus.settings.backend.backup; +import androidx.annotation.DrawableRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -23,34 +24,33 @@ import java.util.zip.ZipOutputStream; public class FileSettingsItem extends StreamSettingsItem { public enum FileSubtype { - UNKNOWN("", null), - OTHER("other", ""), - ROUTING_CONFIG("routing_config", IndexConstants.ROUTING_PROFILES_DIR), - RENDERING_STYLE("rendering_style", IndexConstants.RENDERERS_DIR), - WIKI_MAP("wiki_map", IndexConstants.WIKI_INDEX_DIR), - SRTM_MAP("srtm_map", IndexConstants.SRTM_INDEX_DIR), - OBF_MAP("obf_map", IndexConstants.MAPS_PATH), - TILES_MAP("tiles_map", IndexConstants.TILES_INDEX_DIR), - GPX("gpx", IndexConstants.GPX_INDEX_DIR), - TTS_VOICE("tts_voice", IndexConstants.VOICE_INDEX_DIR), - VOICE("voice", IndexConstants.VOICE_INDEX_DIR), - TRAVEL("travel", IndexConstants.WIKIVOYAGE_INDEX_DIR), - MULTIMEDIA_NOTES("multimedia_notes", IndexConstants.AV_INDEX_DIR); + UNKNOWN("", null, R.drawable.ic_type_file), + OTHER("other", "", R.drawable.ic_type_file), + ROUTING_CONFIG("routing_config", IndexConstants.ROUTING_PROFILES_DIR, R.drawable.ic_action_route_distance), + RENDERING_STYLE("rendering_style", IndexConstants.RENDERERS_DIR, R.drawable.ic_action_map_style), + WIKI_MAP("wiki_map", IndexConstants.WIKI_INDEX_DIR, R.drawable.ic_plugin_wikipedia), + SRTM_MAP("srtm_map", IndexConstants.SRTM_INDEX_DIR, R.drawable.ic_plugin_srtm), + OBF_MAP("obf_map", IndexConstants.MAPS_PATH, R.drawable.ic_map), + TILES_MAP("tiles_map", IndexConstants.TILES_INDEX_DIR, R.drawable.ic_map), + ROAD_MAP("road_map", IndexConstants.ROADS_INDEX_DIR, R.drawable.ic_map), + GPX("gpx", IndexConstants.GPX_INDEX_DIR, R.drawable.ic_action_route_distance), + TTS_VOICE("tts_voice", IndexConstants.VOICE_INDEX_DIR, R.drawable.ic_action_volume_up), + VOICE("voice", IndexConstants.VOICE_INDEX_DIR, R.drawable.ic_action_volume_up), + TRAVEL("travel", IndexConstants.WIKIVOYAGE_INDEX_DIR, R.drawable.ic_plugin_wikipedia), + MULTIMEDIA_NOTES("multimedia_notes", IndexConstants.AV_INDEX_DIR, R.drawable.ic_action_photo_dark); - private String subtypeName; - private String subtypeFolder; + private final String subtypeName; + private final String subtypeFolder; + private final int iconId; - FileSubtype(String subtypeName, String subtypeFolder) { + FileSubtype(@NonNull String subtypeName, String subtypeFolder, @DrawableRes int iconId) { this.subtypeName = subtypeName; this.subtypeFolder = subtypeFolder; + this.iconId = iconId; } public boolean isMap() { - return this == OBF_MAP || this == WIKI_MAP || this == SRTM_MAP || this == TILES_MAP; - } - - public boolean isDirectory() { - return this == TTS_VOICE || this == VOICE; + return this == OBF_MAP || this == WIKI_MAP || this == SRTM_MAP || this == TILES_MAP || this == ROAD_MAP; } public String getSubtypeName() { @@ -61,6 +61,11 @@ public class FileSettingsItem extends StreamSettingsItem { return subtypeFolder; } + @DrawableRes + public int getIconId() { + return iconId; + } + public static FileSubtype getSubtypeByName(@NonNull String name) { for (FileSubtype subtype : FileSubtype.values()) { if (name.equals(subtype.subtypeName)) { @@ -205,7 +210,12 @@ public class FileSettingsItem extends StreamSettingsItem { } public long getSize() { - return size; + if (size != 0) { + return size; + } else if (file != null && !file.isDirectory()) { + return file.length(); + } + return 0; } public void setSize(long size) { @@ -227,15 +237,28 @@ public class FileSettingsItem extends StreamSettingsItem { return file.exists(); } - private File renameFile(File file) { + private File renameFile(File oldFile) { + String oldPath = oldFile.getAbsolutePath(); + String prefix; + if (file.isDirectory()) { + prefix = file.getAbsolutePath(); + } else if (oldPath.endsWith(IndexConstants.BINARY_WIKI_MAP_INDEX_EXT)) { + prefix = oldPath.substring(0, oldPath.lastIndexOf(IndexConstants.BINARY_WIKI_MAP_INDEX_EXT)); + } else if (oldPath.endsWith(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT)) { + prefix = oldPath.substring(0, oldPath.lastIndexOf(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT)); + } else if (oldPath.endsWith(IndexConstants.BINARY_ROAD_MAP_INDEX_EXT)) { + prefix = oldPath.substring(0, oldPath.lastIndexOf(IndexConstants.BINARY_ROAD_MAP_INDEX_EXT)); + } else { + prefix = oldPath.substring(0, oldPath.lastIndexOf(".")); + } + String suffix = oldPath.replace(prefix, ""); int number = 0; - String path = file.getAbsolutePath(); while (true) { number++; - String copyName = path.replaceAll(file.getName(), file.getName().replaceFirst("[.]", "_" + number + ".")); - File copyFile = new File(copyName); - if (!copyFile.exists()) { - return copyFile; + String newName = prefix + "_" + number + suffix; + File newFile = new File(newName); + if (!newFile.exists()) { + return newFile; } } } @@ -245,12 +268,17 @@ public class FileSettingsItem extends StreamSettingsItem { SettingsItemReader getReader() { return new StreamSettingsItemReader(this) { @Override - public void readFromStream(@NonNull InputStream inputStream, File dest) throws IOException, IllegalArgumentException { + public void readFromStream(@NonNull InputStream inputStream, String entryName) throws IOException, IllegalArgumentException { OutputStream output; + File dest = FileSettingsItem.this.getFile(); + if (dest.isDirectory()) { + dest = new File(dest, entryName.substring(fileName.length())); + } if (dest.exists() && !shouldReplace) { dest = renameFile(dest); } if (dest.getParentFile() != null && !dest.getParentFile().exists()) { + //noinspection ResultOfMethodCallIgnored dest.getParentFile().mkdirs(); } output = new FileOutputStream(dest); @@ -271,46 +299,42 @@ public class FileSettingsItem extends StreamSettingsItem { @Nullable @Override public SettingsItemWriter getWriter() { - try { - if (!file.isDirectory()) { + if (!file.isDirectory()) { + try { setInputStream(new FileInputStream(file)); + } catch (FileNotFoundException e) { + warnings.add(app.getString(R.string.settings_item_read_error, file.getName())); + SettingsHelper.LOG.error("Failed to set input stream from file: " + file.getName(), e); } - } catch (FileNotFoundException e) { - warnings.add(app.getString(R.string.settings_item_read_error, file.getName())); - SettingsHelper.LOG.error("Failed to set input stream from file: " + file.getName(), e); - } - return new StreamSettingsItemWriter(this) { + return super.getWriter(); + } else { + return new StreamSettingsItemWriter(this) { - @Override - public void writeEntry(String fileName, @NonNull ZipOutputStream zos) throws IOException { - if (getSubtype().isDirectory()) { - File file = getFile(); - zipDirsWithFiles(file, zos); - } else { - super.writeEntry(fileName, zos); + @Override + public void writeEntry(String fileName, @NonNull ZipOutputStream zos) throws IOException { + writeDirWithFiles(file, zos); } - } - public void zipDirsWithFiles(File f, ZipOutputStream zos) - throws IOException { - if (f == null) { - return; - } - if (f.isDirectory()) { - File[] fs = f.listFiles(); - if (fs != null) { - for (File c : fs) { - zipDirsWithFiles(c, zos); + public void writeDirWithFiles(File file, ZipOutputStream zos) throws IOException { + if (file != null) { + if (file.isDirectory()) { + File[] files = file.listFiles(); + if (files != null) { + for (File subfolderFile : files) { + writeDirWithFiles(subfolderFile, zos); + } + } + } else { + String subtypeFolder = getSubtype().getSubtypeFolder(); + String zipEntryName = Algorithms.isEmpty(subtypeFolder) + ? file.getName() + : file.getPath().substring(file.getPath().indexOf(subtypeFolder) - 1); + setInputStream(new FileInputStream(file)); + super.writeEntry(zipEntryName, zos); } } - } else { - String zipEntryName = Algorithms.isEmpty(getSubtype().getSubtypeFolder()) - ? f.getName() - : f.getPath().substring(f.getPath().indexOf(getSubtype().getSubtypeFolder()) - 1); - setInputStream(new FileInputStream(f)); - super.writeEntry(zipEntryName, zos); } - } - }; + }; + } } } diff --git a/OsmAnd/src/net/osmand/plus/settings/backend/backup/OsmandSettingsItemReader.java b/OsmAnd/src/net/osmand/plus/settings/backend/backup/OsmandSettingsItemReader.java index df68e8a3e3..1fd27e192f 100644 --- a/OsmAnd/src/net/osmand/plus/settings/backend/backup/OsmandSettingsItemReader.java +++ b/OsmAnd/src/net/osmand/plus/settings/backend/backup/OsmandSettingsItemReader.java @@ -10,7 +10,6 @@ import org.json.JSONException; import org.json.JSONObject; import java.io.BufferedReader; -import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -30,7 +29,7 @@ public abstract class OsmandSettingsItemReader ext @NonNull JSONObject json) throws JSONException; @Override - public void readFromStream(@NonNull InputStream inputStream, File destination) throws IOException, IllegalArgumentException { + public void readFromStream(@NonNull InputStream inputStream, String entryName) throws IOException, IllegalArgumentException { StringBuilder buf = new StringBuilder(); try { BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8")); diff --git a/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsExporter.java b/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsExporter.java index 3a697b77c0..38c637e0c7 100644 --- a/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsExporter.java +++ b/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsExporter.java @@ -16,13 +16,19 @@ import java.util.Map; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; +import static net.osmand.plus.settings.backend.backup.SettingsHelper.*; + class SettingsExporter { private Map items; private Map additionalParams; + private ExportProgressListener progressListener; + + private boolean cancelled; private boolean exportItemsFiles; - SettingsExporter(boolean exportItemsFiles) { + SettingsExporter(ExportProgressListener progressListener, boolean exportItemsFiles) { + this.progressListener = progressListener; this.exportItemsFiles = exportItemsFiles; items = new LinkedHashMap<>(); additionalParams = new LinkedHashMap<>(); @@ -35,13 +41,17 @@ class SettingsExporter { items.put(item.getName(), item); } + public void setCancelled(boolean cancelled) { + this.cancelled = cancelled; + } + void addAdditionalParam(String key, String value) { additionalParams.put(key, value); } void exportSettings(File file) throws JSONException, IOException { JSONObject json = createItemsJson(); - OutputStream os = new BufferedOutputStream(new FileOutputStream(file), SettingsHelper.BUFFER); + OutputStream os = new BufferedOutputStream(new FileOutputStream(file), BUFFER); ZipOutputStream zos = new ZipOutputStream(os); try { ZipEntry entry = new ZipEntry("items.json"); @@ -60,6 +70,7 @@ class SettingsExporter { } private void writeItemFiles(ZipOutputStream zos) throws IOException { + int progress = 0; for (SettingsItem item : items.values()) { SettingsItemWriter writer = item.getWriter(); if (writer != null) { @@ -69,13 +80,22 @@ class SettingsExporter { } writer.writeEntry(fileName, zos); } + if (cancelled) { + return; + } + if (item instanceof FileSettingsItem) { + int size = (int) ((FileSettingsItem) item).getSize() / (1 << 20); + progress += size; + if (progressListener != null) { + progressListener.updateProgress(progress); + } + } } } - private JSONObject createItemsJson() throws JSONException { JSONObject json = new JSONObject(); - json.put("version", SettingsHelper.VERSION); + json.put("version", VERSION); for (Map.Entry param : additionalParams.entrySet()) { json.put(param.getKey(), param.getValue()); } diff --git a/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsHelper.java b/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsHelper.java index f3821505a2..9c47589674 100644 --- a/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsHelper.java +++ b/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsHelper.java @@ -7,7 +7,9 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import net.osmand.AndroidUtils; +import net.osmand.Collator; import net.osmand.IndexConstants; +import net.osmand.OsmAndCollator; import net.osmand.PlatformUtil; import net.osmand.data.LatLon; import net.osmand.map.ITileSource; @@ -23,6 +25,7 @@ import net.osmand.plus.audionotes.AudioVideoNotesPlugin; import net.osmand.plus.audionotes.AudioVideoNotesPlugin.Recording; import net.osmand.plus.download.ui.AbstractLoadLocalIndexTask; import net.osmand.plus.helpers.AvoidSpecificRoads.AvoidRoadInfo; +import net.osmand.plus.helpers.FileNameTranslationHelper; import net.osmand.plus.helpers.GpxUiHelper; import net.osmand.plus.helpers.GpxUiHelper.GPXInfo; import net.osmand.plus.osmedit.OpenstreetmapPoint; @@ -34,6 +37,7 @@ import net.osmand.plus.quickaction.QuickActionRegistry; import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.settings.backend.ApplicationMode.ApplicationModeBean; import net.osmand.plus.settings.backend.ExportSettingsType; +import net.osmand.util.Algorithms; import org.apache.commons.logging.Log; import org.json.JSONException; @@ -42,14 +46,16 @@ import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import static net.osmand.IndexConstants.OSMAND_SETTINGS_FILE_EXT; -import static net.osmand.plus.settings.backend.backup.FileSettingsItem.*; import static net.osmand.plus.activities.LocalIndexHelper.LocalIndexType; +import static net.osmand.plus.settings.backend.backup.FileSettingsItem.FileSubtype; /* Usage: @@ -106,6 +112,8 @@ public class SettingsHelper { public interface SettingsExportListener { void onSettingsExportFinished(@NonNull File file, boolean succeed); + + void onSettingsExportProgressUpdate(int value); } public enum ImportType { @@ -134,6 +142,14 @@ public class SettingsHelper { return importTask == null || importTask.isImportDone(); } + public boolean cancelExportForFile(File file) { + ExportAsyncTask exportTask = exportAsyncTasks.get(file); + if (exportTask != null && (exportTask.getStatus() == AsyncTask.Status.RUNNING)) { + return exportTask.cancel(true); + } + return false; + } + public boolean isFileExporting(File file) { return exportAsyncTasks.containsKey(file); } @@ -195,11 +211,15 @@ public class SettingsHelper { } } - @SuppressLint("StaticFieldLeak") - private class ExportAsyncTask extends AsyncTask { + public interface ExportProgressListener { + void updateProgress(int value); + } + + @SuppressLint("StaticFieldLeak") + public class ExportAsyncTask extends AsyncTask { - private SettingsExporter exporter; private File file; + private SettingsExporter exporter; private SettingsExportListener listener; ExportAsyncTask(@NonNull File settingsFile, @@ -207,7 +227,7 @@ public class SettingsHelper { @NonNull List items, boolean exportItemsFiles) { this.file = settingsFile; this.listener = listener; - this.exporter = new SettingsExporter(exportItemsFiles); + this.exporter = new SettingsExporter(getProgressListener(), exportItemsFiles); for (SettingsItem item : items) { exporter.addSettingsItem(item); } @@ -226,6 +246,13 @@ public class SettingsHelper { return false; } + @Override + protected void onProgressUpdate(Integer... values) { + if (listener != null) { + listener.onSettingsExportProgressUpdate(values[0]); + } + } + @Override protected void onPostExecute(Boolean success) { exportAsyncTasks.remove(file); @@ -233,6 +260,21 @@ public class SettingsHelper { listener.onSettingsExportFinished(file, success); } } + + @Override + protected void onCancelled() { + Algorithms.removeAllFiles(file); + } + + private ExportProgressListener getProgressListener() { + return new ExportProgressListener() { + @Override + public void updateProgress(int value) { + exporter.setCancelled(isCancelled()); + publishProgress(value); + } + }; + } } @SuppressLint("StaticFieldLeak") @@ -537,11 +579,11 @@ public class SettingsHelper { if (!favoriteGroups.isEmpty()) { dataList.put(ExportSettingsType.FAVORITES, favoriteGroups); } - List localIndexInfoList = getVoiceIndexInfo(); - List files; - files = getFilesByType(localIndexInfoList, LocalIndexType.MAP_DATA, LocalIndexType.TILES_DATA, + List localIndexInfoList = getLocalIndexData(); + List files = getFilesByType(localIndexInfoList, LocalIndexType.MAP_DATA, LocalIndexType.TILES_DATA, LocalIndexType.SRTM_DATA, LocalIndexType.WIKI_DATA); if (!files.isEmpty()) { + sortLocalFiles(files); dataList.put(ExportSettingsType.OFFLINE_MAPS, files); } files = getFilesByType(localIndexInfoList, LocalIndexType.TTS_VOICE_DATA); @@ -555,7 +597,7 @@ public class SettingsHelper { return dataList; } - private List getVoiceIndexInfo() { + private List getLocalIndexData() { return new LocalIndexHelper(app).getLocalIndexData(new AbstractLoadLocalIndexTask() { @Override public void loadFile(LocalIndexInfo... loaded) { @@ -801,4 +843,18 @@ public class SettingsHelper { } return settingsToOperate; } + + private void sortLocalFiles(List files) { + final Collator collator = OsmAndCollator.primaryCollator(); + Collections.sort(files, new Comparator() { + @Override + public int compare(File lhs, File rhs) { + return collator.compare(getNameToDisplay(lhs), getNameToDisplay(rhs)); + } + + private String getNameToDisplay(File item) { + return FileNameTranslationHelper.getFileNameWithRegion(app, item.getName()); + } + }); + } } \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsImporter.java b/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsImporter.java index fcc1fba2f7..7f72761066 100644 --- a/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsImporter.java +++ b/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsImporter.java @@ -124,7 +124,7 @@ class SettingsImporter { try { SettingsItemReader reader = item.getReader(); if (reader != null) { - reader.readFromStream(ois, app.getAppPath(fileName)); + reader.readFromStream(ois, fileName); } } catch (IllegalArgumentException e) { item.warnings.add(app.getString(R.string.settings_item_read_error, item.getName())); diff --git a/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsItem.java b/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsItem.java index 815710b94c..afe776db09 100644 --- a/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsItem.java +++ b/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsItem.java @@ -169,7 +169,7 @@ public abstract class SettingsItem { SettingsItemReader getJsonReader() { return new SettingsItemReader(this) { @Override - public void readFromStream(@NonNull InputStream inputStream, File destination) throws IOException, IllegalArgumentException { + public void readFromStream(@NonNull InputStream inputStream, String entryName) throws IOException, IllegalArgumentException { StringBuilder buf = new StringBuilder(); try { BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8")); diff --git a/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsItemReader.java b/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsItemReader.java index 2e38e04f08..12af0ee3c5 100644 --- a/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsItemReader.java +++ b/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsItemReader.java @@ -2,7 +2,6 @@ package net.osmand.plus.settings.backend.backup; import androidx.annotation.NonNull; -import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -14,5 +13,5 @@ public abstract class SettingsItemReader { this.item = item; } - public abstract void readFromStream(@NonNull InputStream inputStream, File destination) throws IOException, IllegalArgumentException; + public abstract void readFromStream(@NonNull InputStream inputStream, String entryName) throws IOException, IllegalArgumentException; } diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/DuplicatesSettingsAdapter.java b/OsmAnd/src/net/osmand/plus/settings/fragments/DuplicatesSettingsAdapter.java index d90f4b7429..efda7de984 100644 --- a/OsmAnd/src/net/osmand/plus/settings/fragments/DuplicatesSettingsAdapter.java +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/DuplicatesSettingsAdapter.java @@ -15,6 +15,7 @@ import net.osmand.PlatformUtil; import net.osmand.map.ITileSource; import net.osmand.plus.FavouritesDbHelper.FavoriteGroup; import net.osmand.plus.audionotes.AudioVideoNotesPlugin; +import net.osmand.plus.helpers.FileNameTranslationHelper; import net.osmand.plus.helpers.GpxUiHelper; import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.settings.backend.ApplicationMode.ApplicationModeBean; @@ -34,6 +35,8 @@ import org.apache.commons.logging.Log; import java.io.File; import java.util.List; +import static net.osmand.plus.settings.backend.backup.FileSettingsItem.*; + public class DuplicatesSettingsAdapter extends RecyclerView.Adapter { private static final Log LOG = PlatformUtil.getLog(DuplicatesSettingsAdapter.class.getName()); @@ -75,12 +78,11 @@ public class DuplicatesSettingsAdapter extends RecyclerView.Adapter> dataList = new HashMap<>(); @@ -69,6 +74,8 @@ public class ExportProfileBottomSheet extends BasePreferenceBottomSheet { private SettingsExportListener exportListener; private ProgressDialog progress; + private int progressMax; + private int progressValue; private long exportStartTime; @@ -87,6 +94,8 @@ public class ExportProfileBottomSheet extends BasePreferenceBottomSheet { includeAdditionalData = savedInstanceState.getBoolean(INCLUDE_ADDITIONAL_DATA_KEY); includeGlobalSettings = savedInstanceState.getBoolean(INCLUDE_GLOBAL_SETTINGS_KEY); exportStartTime = savedInstanceState.getLong(EXPORT_START_TIME_KEY); + progressMax = savedInstanceState.getInt(PROGRESS_MAX_KEY); + progressValue = savedInstanceState.getInt(PROGRESS_VALUE_KEY); } dataList = app.getSettingsHelper().getAdditionalData(globalExport); } @@ -99,6 +108,8 @@ public class ExportProfileBottomSheet extends BasePreferenceBottomSheet { outState.putBoolean(INCLUDE_ADDITIONAL_DATA_KEY, includeAdditionalData); outState.putBoolean(INCLUDE_GLOBAL_SETTINGS_KEY, includeGlobalSettings); outState.putLong(EXPORT_START_TIME_KEY, exportStartTime); + outState.putInt(PROGRESS_MAX_KEY, progress.getMax()); + outState.putInt(PROGRESS_VALUE_KEY, progress.getProgress()); } @Override @@ -271,10 +282,22 @@ public class ExportProfileBottomSheet extends BasePreferenceBottomSheet { showExportProgressDialog(); File tempDir = FileUtils.getTempDir(app); String fileName = getFileName(); - app.getSettingsHelper().exportSettings(tempDir, fileName, getSettingsExportListener(), prepareSettingsItemsForExport(), true); + List items = prepareSettingsItemsForExport(); + progress.setMax(getMaxProgress(items)); + app.getSettingsHelper().exportSettings(tempDir, fileName, getSettingsExportListener(), items, true); } } + private int getMaxProgress(List items) { + long maxProgress = 0; + for (SettingsItem item : items) { + if (item instanceof FileSettingsItem) { + maxProgress += ((FileSettingsItem) item).getSize(); + } + } + return (int) maxProgress / (1 << 20); + } + private String getFileName() { if (globalExport) { if (exportStartTime == 0) { @@ -295,12 +318,31 @@ public class ExportProfileBottomSheet extends BasePreferenceBottomSheet { progress.dismiss(); } progress = new ProgressDialog(context); + progress.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); + progress.setCancelable(true); progress.setTitle(app.getString(R.string.shared_string_export)); progress.setMessage(app.getString(R.string.shared_string_preparing)); - progress.setCancelable(false); + progress.setButton(DialogInterface.BUTTON_NEGATIVE, app.getString(R.string.shared_string_cancel), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + cancelExport(); + } + }); + progress.setOnCancelListener(new DialogInterface.OnCancelListener() { + @Override + public void onCancel(DialogInterface dialog) { + cancelExport(); + } + }); progress.show(); } + private void cancelExport() { + app.getSettingsHelper().cancelExportForFile(getExportFile()); + progress.dismiss(); + dismiss(); + } + private SettingsExportListener getSettingsExportListener() { if (exportListener == null) { exportListener = new SettingsExportListener() { @@ -315,6 +357,11 @@ public class ExportProfileBottomSheet extends BasePreferenceBottomSheet { app.showToastMessage(R.string.export_profile_failed); } } + + @Override + public void onSettingsExportProgressUpdate(int value) { + progress.setProgress(value); + } }; } return exportListener; @@ -326,6 +373,8 @@ public class ExportProfileBottomSheet extends BasePreferenceBottomSheet { boolean fileExporting = app.getSettingsHelper().isFileExporting(file); if (fileExporting) { showExportProgressDialog(); + progress.setMax(progressMax); + progress.setProgress(progressValue); app.getSettingsHelper().updateExportListener(file, getSettingsExportListener()); } else if (file.exists()) { dismissExportProgressDialog(); diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/ImportDuplicatesFragment.java b/OsmAnd/src/net/osmand/plus/settings/fragments/ImportDuplicatesFragment.java index cbe3f86767..14d89803e2 100644 --- a/OsmAnd/src/net/osmand/plus/settings/fragments/ImportDuplicatesFragment.java +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/ImportDuplicatesFragment.java @@ -32,6 +32,8 @@ import net.osmand.plus.R; import net.osmand.plus.UiUtilities; import net.osmand.plus.base.BaseOsmAndFragment; import net.osmand.plus.helpers.AvoidSpecificRoads.AvoidRoadInfo; +import net.osmand.plus.osmedit.OpenstreetmapPoint; +import net.osmand.plus.osmedit.OsmNotesPoint; import net.osmand.plus.poi.PoiUIFilter; import net.osmand.plus.quickaction.QuickAction; import net.osmand.plus.settings.backend.ApplicationMode; @@ -46,10 +48,7 @@ import java.io.File; import java.util.ArrayList; import java.util.List; -import static net.osmand.IndexConstants.AV_INDEX_DIR; -import static net.osmand.IndexConstants.GPX_INDEX_DIR; -import static net.osmand.IndexConstants.RENDERERS_DIR; -import static net.osmand.IndexConstants.ROUTING_PROFILES_DIR; +import static net.osmand.plus.settings.backend.backup.FileSettingsItem.*; import static net.osmand.plus.settings.fragments.ImportSettingsFragment.IMPORT_SETTINGS_TAG; @@ -196,6 +195,11 @@ public class ImportDuplicatesFragment extends BaseOsmAndFragment { List trackFilesList = new ArrayList<>(); List avoidRoads = new ArrayList<>(); List favoriteGroups = new ArrayList<>(); + List osmNotesPointList = new ArrayList<>(); + List osmEditsPointList = new ArrayList<>(); + List ttsVoiceFilesList = new ArrayList<>(); + List voiceFilesList = new ArrayList<>(); + List mapFilesList = new ArrayList<>(); for (Object object : duplicatesList) { if (object instanceof ApplicationMode.ApplicationModeBean) { @@ -208,19 +212,30 @@ public class ImportDuplicatesFragment extends BaseOsmAndFragment { tileSources.add((ITileSource) object); } else if (object instanceof File) { File file = (File) object; - if (file.getAbsolutePath().contains(RENDERERS_DIR)) { + FileSubtype fileSubtype = FileSubtype.getSubtypeByPath(app, file.getPath()); + if (fileSubtype == FileSubtype.RENDERING_STYLE) { renderFilesList.add(file); - } else if (file.getAbsolutePath().contains(ROUTING_PROFILES_DIR)) { + } else if (fileSubtype == FileSubtype.ROUTING_CONFIG) { routingFilesList.add(file); - } else if (file.getAbsolutePath().contains(AV_INDEX_DIR)) { + } else if (fileSubtype == FileSubtype.MULTIMEDIA_NOTES) { multimediaFilesList.add(file); - } else if (file.getAbsolutePath().contains(GPX_INDEX_DIR)) { + } else if (fileSubtype == FileSubtype.GPX) { trackFilesList.add(file); + } else if (fileSubtype.isMap()) { + mapFilesList.add(file); + } else if (fileSubtype == FileSubtype.TTS_VOICE) { + ttsVoiceFilesList.add(file); + } else if (fileSubtype == FileSubtype.VOICE) { + voiceFilesList.add(file); } } else if (object instanceof AvoidRoadInfo) { avoidRoads.add((AvoidRoadInfo) object); } else if (object instanceof FavoriteGroup) { favoriteGroups.add((FavoriteGroup) object); + } else if (object instanceof OsmNotesPoint) { + osmNotesPointList.add((OsmNotesPoint) object); + } else if (object instanceof OpenstreetmapPoint) { + osmEditsPointList.add((OpenstreetmapPoint) object); } } if (!profiles.isEmpty()) { @@ -263,6 +278,26 @@ public class ImportDuplicatesFragment extends BaseOsmAndFragment { duplicates.add(getString(R.string.shared_string_favorites)); duplicates.addAll(favoriteGroups); } + if (!osmNotesPointList.isEmpty()) { + duplicates.add(getString(R.string.osm_notes)); + duplicates.addAll(osmNotesPointList); + } + if (!osmEditsPointList.isEmpty()) { + duplicates.add(getString(R.string.osm_edits)); + duplicates.addAll(osmEditsPointList); + } + if (!mapFilesList.isEmpty()) { + duplicates.add(getString(R.string.shared_string_maps)); + duplicates.addAll(mapFilesList); + } + if (!ttsVoiceFilesList.isEmpty()) { + duplicates.add(getString(R.string.local_indexes_cat_tts)); + duplicates.addAll(ttsVoiceFilesList); + } + if (!voiceFilesList.isEmpty()) { + duplicates.add(getString(R.string.local_indexes_cat_voice)); + duplicates.addAll(voiceFilesList); + } return duplicates; } diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/ProfileAppearanceFragment.java b/OsmAnd/src/net/osmand/plus/settings/fragments/ProfileAppearanceFragment.java index 1bdbc38b19..bc3092d963 100644 --- a/OsmAnd/src/net/osmand/plus/settings/fragments/ProfileAppearanceFragment.java +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/ProfileAppearanceFragment.java @@ -735,6 +735,11 @@ public class ProfileAppearanceFragment extends BaseSettingsFragment { app.showToastMessage(R.string.profile_backup_failed); } } + + @Override + public void onSettingsExportProgressUpdate(int value) { + + } }; } return exportListener;