diff --git a/OsmAnd-java/src/main/java/net/osmand/IndexConstants.java b/OsmAnd-java/src/main/java/net/osmand/IndexConstants.java index c8ffd2d96b..31ac655f06 100644 --- a/OsmAnd-java/src/main/java/net/osmand/IndexConstants.java +++ b/OsmAnd-java/src/main/java/net/osmand/IndexConstants.java @@ -77,4 +77,6 @@ public class IndexConstants { public static final String TEMP_DIR = "temp/"; public static final String ROUTING_PROFILES_DIR = "routing/"; public static final String PLUGINS_DIR = "plugins/"; + + public static final String TTS_DIR_SUFFIX = "-tts"; } diff --git a/OsmAnd/src/net/osmand/plus/activities/LocalIndexHelper.java b/OsmAnd/src/net/osmand/plus/activities/LocalIndexHelper.java index 7c64e3a669..1e53f97603 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; } - private void loadVoiceData(File voiceDir, List result, boolean backup, AbstractLoadLocalIndexTask loadTask) { + public 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/settings/backend/ExportSettingsType.java b/OsmAnd/src/net/osmand/plus/settings/backend/ExportSettingsType.java index 17901458ec..4c0ebc2c11 100644 --- a/OsmAnd/src/net/osmand/plus/settings/backend/ExportSettingsType.java +++ b/OsmAnd/src/net/osmand/plus/settings/backend/ExportSettingsType.java @@ -13,5 +13,7 @@ public enum ExportSettingsType { GLOBAL, OSM_NOTES, OSM_EDITS, - OFFLINE_MAPS + OFFLINE_MAPS, + TTS_VOICE, + VOICE } 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 097e64b0d2..151aaf61f6 100644 --- a/OsmAnd/src/net/osmand/plus/settings/backend/backup/FileSettingsItem.java +++ b/OsmAnd/src/net/osmand/plus/settings/backend/backup/FileSettingsItem.java @@ -33,6 +33,7 @@ public class FileSettingsItem extends StreamSettingsItem { 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); @@ -66,6 +67,11 @@ public class FileSettingsItem extends StreamSettingsItem { return null; } + public static FileSubtype getSubtypeByPath(@NonNull OsmandApplication app, @NonNull String fileName) { + fileName = fileName.replace(app.getAppPath(null).getPath(), ""); + return getSubtypeByFileName(fileName); + } + public static FileSubtype getSubtypeByFileName(@NonNull String fileName) { String name = fileName; if (fileName.startsWith(File.separator)) { @@ -91,6 +97,11 @@ public class FileSettingsItem extends StreamSettingsItem { return subtype; } break; + case TTS_VOICE: + if (name.startsWith(subtype.subtypeFolder) && name.endsWith(IndexConstants.TTS_DIR_SUFFIX)) { + return subtype; + } + break; default: if (name.startsWith(subtype.subtypeFolder)) { return subtype; @@ -109,9 +120,10 @@ public class FileSettingsItem extends StreamSettingsItem { } protected File file; - private File appPath; + private final File appPath; protected FileSubtype subtype; private long size; + private boolean subFolders; public FileSettingsItem(@NonNull OsmandApplication app, @NonNull File file) throws IllegalArgumentException { super(app, file.getPath().replace(app.getAppPath(null).getPath(), "")); @@ -198,6 +210,14 @@ public class FileSettingsItem extends StreamSettingsItem { this.size = size; } + public boolean isSubFolders() { + return subFolders; + } + + public void setSubFolders(boolean subFolders) { + this.subFolders = subFolders; + } + @NonNull public File getFile() { return file; @@ -259,7 +279,9 @@ public class FileSettingsItem extends StreamSettingsItem { @Override public SettingsItemWriter getWriter() { try { - setInputStream(new FileInputStream(file)); + if (!file.isDirectory()) { + 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); 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 ccc23b5416..88809ea937 100644 --- a/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsExporter.java +++ b/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsExporter.java @@ -8,6 +8,7 @@ import org.json.JSONObject; import java.io.BufferedOutputStream; import java.io.File; +import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; @@ -67,14 +68,44 @@ class SettingsExporter { if (Algorithms.isEmpty(fileName)) { fileName = item.getDefaultFileName(); } - ZipEntry entry = new ZipEntry(fileName); - zos.putNextEntry(entry); - writer.writeToStream(zos); - zos.closeEntry(); + if (item instanceof FileSettingsItem && ((FileSettingsItem) item).isSubFolders()) { + File file = ((FileSettingsItem) item).getFile(); + zipDirsWithFiles(file, writer, zos); + } else { + ZipEntry entry = new ZipEntry(fileName); + zos.putNextEntry(entry); + writer.writeToStream(zos); + zos.closeEntry(); + } } } } + public void zipDirsWithFiles(File f, SettingsItemWriter writer, ZipOutputStream zos) + throws IOException { + if (f == null) { + return; + } + if (f.isDirectory()) { + File[] fs = f.listFiles(); + if (fs != null) { + for (File c : fs) { + zipDirsWithFiles(c, writer, zos); + } + } + } else { + FileSettingsItem item = (FileSettingsItem) writer.getItem(); + String zipEntryName = Algorithms.isEmpty(item.getSubtype().getSubtypeFolder()) + ? f.getName() + : f.getPath().substring(f.getPath().indexOf(item.getSubtype().getSubtypeFolder())); + ZipEntry entry = new ZipEntry(zipEntryName); + zos.putNextEntry(entry); + item.setInputStream(new FileInputStream(f)); + writer.writeToStream(zos); + zos.closeEntry(); + } + } + private JSONObject createItemsJson() throws JSONException { JSONObject json = new JSONObject(); json.put("version", SettingsHelper.VERSION); 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 0cfa472ef0..0af0aa08b8 100644 --- a/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsHelper.java +++ b/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsHelper.java @@ -48,6 +48,7 @@ import java.util.Set; import static net.osmand.IndexConstants.OSMAND_SETTINGS_FILE_EXT; import static net.osmand.plus.activities.LocalIndexHelper.*; +import static net.osmand.plus.settings.backend.backup.FileSettingsItem.*; /* Usage: @@ -535,9 +536,41 @@ public class SettingsHelper { if (!files.isEmpty()) { dataList.put(ExportSettingsType.OFFLINE_MAPS, files); } + List localVoiceFileList = getVoiceIndexInfo(); + files = getFilesByType(localVoiceFileList, LocalIndexType.TTS_VOICE_DATA); + if (!files.isEmpty()) { + dataList.put(ExportSettingsType.TTS_VOICE, files); + } + files = getFilesByType(localVoiceFileList, LocalIndexType.VOICE_DATA); + if (!files.isEmpty()) { + dataList.put(ExportSettingsType.VOICE, files); + } return dataList; } + private List getVoiceIndexInfo() { + LocalIndexHelper helper = new LocalIndexHelper(app); + List localVoiceInfoList = new ArrayList<>(); + helper.loadVoiceData(app.getAppPath(IndexConstants.VOICE_INDEX_DIR), localVoiceInfoList, false, + new AbstractLoadLocalIndexTask() { + @Override + public void loadFile(LocalIndexInfo... loaded) { + } + }); + return localVoiceInfoList; + } + + private List getFilesByType(List localVoiceFileList, LocalIndexType localIndexType) { + List files = new ArrayList<>(); + for (LocalIndexInfo map : localVoiceFileList) { + File file = new File(map.getPathToData()); + if (file.exists() && map.getType() == localIndexType) { + files.add(file); + } + } + return files; + } + private List getLocalMapFiles() { List files = new ArrayList<>(); LocalIndexHelper helper = new LocalIndexHelper(app); @@ -548,7 +581,8 @@ public class SettingsHelper { }); for (LocalIndexInfo map : localMapFileList) { File file = new File(map.getPathToData()); - if (file != null && file.exists() && map.getType() != LocalIndexType.TTS_VOICE_DATA) { + if (file.exists() && map.getType() != LocalIndexType.TTS_VOICE_DATA + && map.getType() != LocalIndexType.VOICE_DATA) { files.add(file); } } @@ -574,7 +608,11 @@ public class SettingsHelper { tileSourceTemplates.add((ITileSource) object); } else if (object instanceof File) { try { - settingsItems.add(new FileSettingsItem(app, (File) object)); + FileSettingsItem fileItem = new FileSettingsItem(app, (File) object); + settingsItems.add(fileItem); + if (FileSubtype.getSubtypeByPath(app, ((File) object).getPath()) == FileSubtype.VOICE) { + fileItem.setSubFolders(true); + } } catch (IllegalArgumentException e) { LOG.warn("Trying to export unsuported file type", e); } @@ -627,6 +665,8 @@ public class SettingsHelper { List renderFilesList = new ArrayList<>(); List multimediaFilesList = new ArrayList<>(); List tracksFilesList = new ArrayList<>(); + List ttsVoiceFilesList = new ArrayList<>(); + List voiceFilesList = new ArrayList<>(); List mapFilesList = new ArrayList<>(); List avoidRoads = new ArrayList<>(); List globalSettingsItems = new ArrayList<>(); @@ -639,19 +679,23 @@ public class SettingsHelper { break; case FILE: FileSettingsItem fileItem = (FileSettingsItem) item; - if (fileItem.getSubtype() == FileSettingsItem.FileSubtype.RENDERING_STYLE) { + if (fileItem.getSubtype() == FileSubtype.RENDERING_STYLE) { renderFilesList.add(fileItem.getFile()); - } else if (fileItem.getSubtype() == FileSettingsItem.FileSubtype.ROUTING_CONFIG) { + } else if (fileItem.getSubtype() == FileSubtype.ROUTING_CONFIG) { routingFilesList.add(fileItem.getFile()); - } else if (fileItem.getSubtype() == FileSettingsItem.FileSubtype.MULTIMEDIA_NOTES) { + } else if (fileItem.getSubtype() == FileSubtype.MULTIMEDIA_NOTES) { multimediaFilesList.add(fileItem.getFile()); - } else if (fileItem.getSubtype() == FileSettingsItem.FileSubtype.GPX) { + } else if (fileItem.getSubtype() == FileSubtype.GPX) { tracksFilesList.add(fileItem.getFile()); - } else if (fileItem.getSubtype() == FileSettingsItem.FileSubtype.OBF_MAP - || fileItem.getSubtype() == FileSettingsItem.FileSubtype.WIKI_MAP - || fileItem.getSubtype() == FileSettingsItem.FileSubtype.SRTM_MAP - || fileItem.getSubtype() == FileSettingsItem.FileSubtype.TILES_MAP) { + } else if (fileItem.getSubtype() == FileSubtype.OBF_MAP + || fileItem.getSubtype() == FileSubtype.WIKI_MAP + || fileItem.getSubtype() == FileSubtype.SRTM_MAP + || fileItem.getSubtype() == FileSubtype.TILES_MAP) { mapFilesList.add(fileItem); + } else if (fileItem.getSubtype() == FileSubtype.TTS_VOICE) { + ttsVoiceFilesList.add(fileItem.getFile()); + } else if (fileItem.getSubtype() == FileSubtype.VOICE) { + voiceFilesList.add(fileItem.getFile()); } break; case QUICK_ACTIONS: @@ -749,6 +793,12 @@ public class SettingsHelper { if (!mapFilesList.isEmpty()) { settingsToOperate.put(ExportSettingsType.OFFLINE_MAPS, mapFilesList); } + if (!ttsVoiceFilesList.isEmpty()) { + settingsToOperate.put(ExportSettingsType.TTS_VOICE, ttsVoiceFilesList); + } + if (!voiceFilesList.isEmpty()) { + settingsToOperate.put(ExportSettingsType.VOICE, voiceFilesList); + } return settingsToOperate; } } \ No newline at end of file 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 caf2d57301..e54cc99409 100644 --- a/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsItem.java +++ b/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsItem.java @@ -88,7 +88,7 @@ public abstract class SettingsItem { public boolean applyFileName(@NonNull String fileName) { String n = getFileName(); - return n != null && n.endsWith(fileName); + return n != null && (n.endsWith(fileName) || fileName.startsWith(n)); } public boolean shouldReadOnCollecting() { diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/ExportImportSettingsAdapter.java b/OsmAnd/src/net/osmand/plus/settings/fragments/ExportImportSettingsAdapter.java index 0f86486851..e865b9a21b 100644 --- a/OsmAnd/src/net/osmand/plus/settings/fragments/ExportImportSettingsAdapter.java +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/ExportImportSettingsAdapter.java @@ -287,8 +287,7 @@ class ExportImportSettingsAdapter extends OsmandBaseExpandableListAdapter { title.setText(FileNameTranslationHelper.getFileName(app, app.getResourceManager().getOsmandRegions(), file.getName())); - FileSubtype subtype = FileSubtype.getSubtypeByFileName(file.getPath().replace( - app.getAppPath(null).getPath(), "")); + FileSubtype subtype = FileSubtype.getSubtypeByPath(app, file.getPath()); switch (subtype) { case SRTM_MAP: iconId = R.drawable.ic_plugin_srtm; @@ -303,6 +302,18 @@ class ExportImportSettingsAdapter extends OsmandBaseExpandableListAdapter { subText.setText(AndroidUtils.formatSize(app, size)); subText.setVisibility(View.VISIBLE); break; + case TTS_VOICE: + file = (File) currentItem; + title.setText(FileNameTranslationHelper.getFileName(app, + app.getResourceManager().getOsmandRegions(), + file.getName())); + setupIcon(icon, R.drawable.ic_action_volume_up, itemSelected); + case VOICE: + file = (File) currentItem; + title.setText(FileNameTranslationHelper.getFileName(app, + app.getResourceManager().getOsmandRegions(), + file.getName())); + setupIcon(icon, R.drawable.ic_action_volume_up, itemSelected); default: return child; } @@ -393,6 +404,10 @@ class ExportImportSettingsAdapter extends OsmandBaseExpandableListAdapter { return R.string.osm_edit_modified_poi; case OFFLINE_MAPS: return R.string.shared_string_local_maps; + case TTS_VOICE: + return R.string.local_indexes_cat_tts; + case VOICE: + return R.string.local_indexes_cat_voice; default: return R.string.access_empty_list; }