diff --git a/OsmAnd/src/net/osmand/plus/CustomOsmandPlugin.java b/OsmAnd/src/net/osmand/plus/CustomOsmandPlugin.java index b84b212f3e..ce8869f7c1 100644 --- a/OsmAnd/src/net/osmand/plus/CustomOsmandPlugin.java +++ b/OsmAnd/src/net/osmand/plus/CustomOsmandPlugin.java @@ -1,14 +1,21 @@ package net.osmand.plus; +import androidx.annotation.NonNull; + import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; +import net.osmand.PlatformUtil; import net.osmand.map.ITileSource; +import net.osmand.map.TileSourceManager; +import net.osmand.osm.MapPoiTypes; import net.osmand.osm.PoiCategory; import net.osmand.plus.helpers.AvoidSpecificRoads; import net.osmand.plus.poi.PoiUIFilter; import net.osmand.plus.quickaction.QuickAction; +import net.osmand.util.Algorithms; +import org.apache.commons.logging.Log; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -18,9 +25,12 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; +import java.util.Map; public class CustomOsmandPlugin extends OsmandPlugin { + private static final Log LOG = PlatformUtil.getLog(CustomOsmandPlugin.class); + public String pluginId; public String name; public String description; @@ -33,8 +43,11 @@ public class CustomOsmandPlugin extends OsmandPlugin { public List mapSources = new ArrayList<>(); public List avoidRoadInfos = new ArrayList<>(); - public CustomOsmandPlugin(OsmandApplication app) { + public CustomOsmandPlugin(@NonNull OsmandApplication app, @NonNull JSONObject json) throws JSONException { super(app); + pluginId = json.getString("pluginId"); + name = json.getString("name"); + description = json.getString("Description"); } // Prepare ".opr" desert-package manually + add all resources inside (extend json to describe package). @@ -89,6 +102,47 @@ public class CustomOsmandPlugin extends OsmandPlugin { return json.toString(); } + public void loadAdditionalItemsFromJson(JSONObject json) throws JSONException { + if (json.has("appModes")) { + String appModesStr = json.getString("appModes"); + if (!Algorithms.isEmpty(appModesStr)) { + JSONArray appModesJson = new JSONArray(appModesStr); + for (int i = 0; i < appModesJson.length(); i++) { + String str = appModesJson.getString(i); + ApplicationMode mode = ApplicationMode.valueOfStringKey(str, null); + if (mode != null) { + appModes.add(mode); + } + } + } + } + if (json.has("rendererNames")) { + String rendererNamesStr = json.getString("rendererNames"); + if (!Algorithms.isEmpty(rendererNamesStr)) { + JSONArray rendererNamesJson = new JSONArray(rendererNamesStr); + for (int i = 0; i < rendererNamesJson.length(); i++) { + String str = rendererNamesJson.getString(i); + rendererNames.add(str); + } + } + } + if (json.has("routerNames")) { + String routerNamesStr = json.getString("routerNames"); + if (!Algorithms.isEmpty(routerNamesStr)) { + JSONArray routerNamesJson = new JSONArray(routerNamesStr); + for (int i = 0; i < routerNamesJson.length(); i++) { + String str = routerNamesJson.getString(i); + routerNames.add(str); + } + } + } + + readPoiUIFiltersFromJson(json); + readMapSourcesFromJson(json); + readQuickActionsFromJson(json); + readAvoidRoadsFromJson(json); + } + public void saveAdditionalItemsToJson(JSONObject json) throws JSONException { if (!appModes.isEmpty()) { List appModesKeys = new ArrayList<>(); @@ -113,82 +167,248 @@ public class CustomOsmandPlugin extends OsmandPlugin { saveAvoidRoadsToJson(json); } - private void savePoiUIFiltersToJson(JSONObject json) throws JSONException { + private void savePoiUIFiltersToJson(JSONObject poiUIFiltersJson) throws JSONException { if (!poiUIFilters.isEmpty()) { + JSONObject json = new JSONObject(); JSONArray jsonArray = new JSONArray(); Gson gson = new Gson(); Type type = new TypeToken>>() { }.getType(); - for (PoiUIFilter filter : poiUIFilters) { - JSONObject jsonObject = new JSONObject(); - jsonObject.put("name", filter.getName()); - jsonObject.put("filterId", filter.getFilterId()); - jsonObject.put("acceptedTypes", gson.toJson(filter.getAcceptedTypes(), type)); - jsonArray.put(jsonObject); + try { + for (PoiUIFilter filter : poiUIFilters) { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("name", filter.getName()); + jsonObject.put("filterId", filter.getFilterId()); + jsonObject.put("acceptedTypes", gson.toJson(filter.getAcceptedTypes(), type)); + jsonArray.put(jsonObject); + } + json.put("items", jsonArray); + } catch (JSONException e) { + LOG.error("Failed write to json", e); } - json.put("poiUIFilters", jsonArray); + poiUIFiltersJson.put("poiUIFilters", json); } } - private void saveMapSourcesToJson(JSONObject json) throws JSONException { + private void saveMapSourcesToJson(JSONObject mapSourcesJson) throws JSONException { if (!mapSources.isEmpty()) { + JSONObject json = new JSONObject(); JSONArray jsonArray = new JSONArray(); - for (ITileSource template : mapSources) { - JSONObject jsonObject = new JSONObject(); - boolean sql = template instanceof SQLiteTileSource; - jsonObject.put("sql", sql); - jsonObject.put("name", template.getName()); - jsonObject.put("minZoom", template.getMinimumZoomSupported()); - jsonObject.put("maxZoom", template.getMaximumZoomSupported()); - jsonObject.put("url", template.getUrlTemplate()); - jsonObject.put("randoms", template.getRandoms()); - jsonObject.put("ellipsoid", template.isEllipticYTile()); - jsonObject.put("inverted_y", template.isInvertedYTile()); - jsonObject.put("referer", template.getReferer()); - jsonObject.put("timesupported", template.isTimeSupported()); - jsonObject.put("expire", template.getExpirationTimeMillis()); - jsonObject.put("inversiveZoom", template.getInversiveZoom()); - jsonObject.put("ext", template.getTileFormat()); - jsonObject.put("tileSize", template.getTileSize()); - jsonObject.put("bitDensity", template.getBitDensity()); - jsonObject.put("avgSize", template.getAvgSize()); - jsonObject.put("rule", template.getRule()); - jsonArray.put(jsonObject); + if (!mapSources.isEmpty()) { + try { + for (ITileSource template : mapSources) { + JSONObject jsonObject = new JSONObject(); + boolean sql = template instanceof SQLiteTileSource; + jsonObject.put("sql", sql); + jsonObject.put("name", template.getName()); + jsonObject.put("minZoom", template.getMinimumZoomSupported()); + jsonObject.put("maxZoom", template.getMaximumZoomSupported()); + jsonObject.put("url", template.getUrlTemplate()); + jsonObject.put("randoms", template.getRandoms()); + jsonObject.put("ellipsoid", template.isEllipticYTile()); + jsonObject.put("inverted_y", template.isInvertedYTile()); + jsonObject.put("referer", template.getReferer()); + jsonObject.put("timesupported", template.isTimeSupported()); + jsonObject.put("expire", template.getExpirationTimeMillis()); + jsonObject.put("inversiveZoom", template.getInversiveZoom()); + jsonObject.put("ext", template.getTileFormat()); + jsonObject.put("tileSize", template.getTileSize()); + jsonObject.put("bitDensity", template.getBitDensity()); + jsonObject.put("avgSize", template.getAvgSize()); + jsonObject.put("rule", template.getRule()); + jsonArray.put(jsonObject); + } + json.put("items", jsonArray); + } catch (JSONException e) { + LOG.error("Failed write to json", e); + } } - json.put("mapSources", jsonArray); + mapSourcesJson.put("mapSources", json); } } - private void saveAvoidRoadsToJson(JSONObject json) throws JSONException { + private void saveAvoidRoadsToJson(JSONObject avoidRoadInfosJson) throws JSONException { if (!avoidRoadInfos.isEmpty()) { + JSONObject json = new JSONObject(); JSONArray jsonArray = new JSONArray(); - for (AvoidSpecificRoads.AvoidRoadInfo avoidRoad : avoidRoadInfos) { - JSONObject jsonObject = new JSONObject(); - jsonObject.put("latitude", avoidRoad.latitude); - jsonObject.put("longitude", avoidRoad.longitude); - jsonObject.put("name", avoidRoad.name); - jsonObject.put("appModeKey", avoidRoad.appModeKey); - jsonArray.put(jsonObject); + if (!avoidRoadInfos.isEmpty()) { + try { + for (AvoidSpecificRoads.AvoidRoadInfo avoidRoad : avoidRoadInfos) { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("latitude", avoidRoad.latitude); + jsonObject.put("longitude", avoidRoad.longitude); + jsonObject.put("name", avoidRoad.name); + jsonObject.put("appModeKey", avoidRoad.appModeKey); + jsonArray.put(jsonObject); + } + json.put("items", jsonArray); + } catch (JSONException e) { + LOG.error("Failed write to json", e); + } } - json.put("avoidRoadInfos", jsonArray); + avoidRoadInfosJson.put("avoidRoadInfos", json); } } - private void saveQuickActionsToJson(JSONObject json) throws JSONException { + private void saveQuickActionsToJson(JSONObject quickActionsJson) throws JSONException { if (!quickActions.isEmpty()) { + JSONObject json = new JSONObject(); JSONArray jsonArray = new JSONArray(); Gson gson = new Gson(); Type type = new TypeToken>() { }.getType(); - - for (QuickAction action : quickActions) { - JSONObject jsonObject = new JSONObject(); - jsonObject.put("name", action.hasCustomName(app) ? action.getName(app) : ""); - jsonObject.put("type", action.getType()); - jsonObject.put("params", gson.toJson(action.getParams(), type)); - jsonArray.put(jsonObject); + if (!quickActions.isEmpty()) { + try { + for (QuickAction action : quickActions) { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("name", action.hasCustomName(app) + ? action.getName(app) : ""); + jsonObject.put("type", action.getType()); + jsonObject.put("params", gson.toJson(action.getParams(), type)); + jsonArray.put(jsonObject); + } + json.put("items", jsonArray); + } catch (JSONException e) { + LOG.error("Failed write to json", e); + } + } + quickActionsJson.put("quickActions", json); + } + } + + private void readMapSourcesFromJson(JSONObject json) { + if (json.has("mapSources")) { + try { + String mapSourcesStr = json.getString("mapSources"); + if (!Algorithms.isEmpty(mapSourcesStr)) { + json = new JSONObject(mapSourcesStr); + JSONArray jsonArray = json.getJSONArray("items"); + for (int i = 0; i < jsonArray.length(); i++) { + JSONObject object = jsonArray.getJSONObject(i); + boolean sql = object.optBoolean("sql"); + String name = object.optString("name"); + int minZoom = object.optInt("minZoom"); + int maxZoom = object.optInt("maxZoom"); + String url = object.optString("url"); + String randoms = object.optString("randoms"); + boolean ellipsoid = object.optBoolean("ellipsoid", false); + boolean invertedY = object.optBoolean("inverted_y", false); + String referer = object.optString("referer"); + boolean timesupported = object.optBoolean("timesupported", false); + long expire = object.optLong("expire"); + boolean inversiveZoom = object.optBoolean("inversiveZoom", false); + String ext = object.optString("ext"); + int tileSize = object.optInt("tileSize"); + int bitDensity = object.optInt("bitDensity"); + int avgSize = object.optInt("avgSize"); + String rule = object.optString("rule"); + + ITileSource template; + if (!sql) { + template = new TileSourceManager.TileSourceTemplate(name, url, ext, maxZoom, minZoom, tileSize, bitDensity, avgSize); + } else { + template = new SQLiteTileSource(app, name, minZoom, maxZoom, url, randoms, ellipsoid, invertedY, referer, timesupported, expire, inversiveZoom); + } + mapSources.add(template); + } + } + } catch (JSONException e) { + throw new IllegalArgumentException("Json parse error", e); + } + } + } + + private void readQuickActionsFromJson(JSONObject json) { + if (json.has("quickActions")) { + try { + String quickActionsStr = json.getString("quickActions"); + if (!Algorithms.isEmpty(quickActionsStr)) { + Gson gson = new Gson(); + Type type = new TypeToken>() { + }.getType(); + JSONObject quickActionsJson = new JSONObject(quickActionsStr); + JSONArray itemsJson = quickActionsJson.getJSONArray("items"); + for (int i = 0; i < itemsJson.length(); i++) { + JSONObject object = itemsJson.getJSONObject(i); + String name = object.getString("name"); + int actionType = object.getInt("type"); + String paramsString = object.getString("params"); + HashMap params = gson.fromJson(paramsString, type); + QuickAction quickAction = new QuickAction(actionType); + if (!name.isEmpty()) { + quickAction.setName(name); + } + quickAction.setParams(params); + quickActions.add(quickAction); + } + } + } catch (JSONException e) { + throw new IllegalArgumentException("Json parse error", e); + } + } + } + + private void readAvoidRoadsFromJson(JSONObject json) { + if (json.has("avoidRoadInfos")) { + try { + String avoidRoadInfosStr = json.getString("avoidRoadInfos"); + if (!Algorithms.isEmpty(avoidRoadInfosStr)) { + JSONObject avoidRoadInfosJson = new JSONObject(avoidRoadInfosStr); + JSONArray jsonArray = avoidRoadInfosJson.getJSONArray("items"); + for (int i = 0; i < jsonArray.length(); i++) { + JSONObject object = jsonArray.getJSONObject(i); + double latitude = object.optDouble("latitude"); + double longitude = object.optDouble("longitude"); + String name = object.optString("name"); + String appModeKey = object.optString("appModeKey"); + AvoidSpecificRoads.AvoidRoadInfo roadInfo = new AvoidSpecificRoads.AvoidRoadInfo(); + roadInfo.id = 0; + roadInfo.latitude = latitude; + roadInfo.longitude = longitude; + roadInfo.name = name; + if (ApplicationMode.valueOfStringKey(appModeKey, null) != null) { + roadInfo.appModeKey = appModeKey; + } else { + roadInfo.appModeKey = app.getRoutingHelper().getAppMode().getStringKey(); + } + avoidRoadInfos.add(roadInfo); + } + } + } catch (JSONException e) { + throw new IllegalArgumentException("Json parse error", e); + } + } + } + + private void readPoiUIFiltersFromJson(JSONObject json) { + if (json.has("poiUIFilters")) { + try { + String poiUIFiltersStr = json.getString("poiUIFilters"); + if (!Algorithms.isEmpty(poiUIFiltersStr)) { + JSONObject poiUIFiltersJson = new JSONObject(poiUIFiltersStr); + JSONArray jsonArray = poiUIFiltersJson.getJSONArray("items"); + Gson gson = new Gson(); + Type type = new TypeToken>>() { + }.getType(); + MapPoiTypes poiTypes = app.getPoiTypes(); + for (int i = 0; i < jsonArray.length(); i++) { + JSONObject object = jsonArray.getJSONObject(i); + String name = object.getString("name"); + String filterId = object.getString("filterId"); + String acceptedTypesString = object.getString("acceptedTypes"); + HashMap> acceptedTypes = gson.fromJson(acceptedTypesString, type); + Map> acceptedTypesDone = new HashMap<>(); + for (Map.Entry> mapItem : acceptedTypes.entrySet()) { + final PoiCategory a = poiTypes.getPoiCategoryByName(mapItem.getKey()); + acceptedTypesDone.put(a, mapItem.getValue()); + } + PoiUIFilter filter = new PoiUIFilter(name, filterId, acceptedTypesDone, app); + poiUIFilters.add(filter); + } + } + } catch (JSONException e) { + throw new IllegalArgumentException("Json parse error", e); } - json.put("quickActions", jsonArray); } } diff --git a/OsmAnd/src/net/osmand/plus/OsmandPlugin.java b/OsmAnd/src/net/osmand/plus/OsmandPlugin.java index 2dcabb2fca..c932d7fadf 100644 --- a/OsmAnd/src/net/osmand/plus/OsmandPlugin.java +++ b/OsmAnd/src/net/osmand/plus/OsmandPlugin.java @@ -309,15 +309,8 @@ public abstract class OsmandPlugin { JSONArray jArray = new JSONArray(customPluginsJson); for (int i = 0; i < jArray.length(); i++) { JSONObject json = jArray.getJSONObject(i); - - String pluginId = json.getString("pluginId"); - String name = json.getString("name"); - String description = json.getString("Description"); - - CustomOsmandPlugin plugin = new CustomOsmandPlugin(app); - plugin.pluginId = pluginId; - plugin.name = name; - plugin.description = description; + CustomOsmandPlugin plugin = new CustomOsmandPlugin(app, json); + plugin.loadAdditionalItemsFromJson(json); allPlugins.add(plugin); } } catch (JSONException e) { @@ -334,13 +327,15 @@ public abstract class OsmandPlugin { JSONArray itemsJson = new JSONArray(); for (CustomOsmandPlugin plugin : customOsmandPlugins) { try { - String json = plugin.toJson(); - itemsJson.put(new JSONObject(json)); + itemsJson.put(new JSONObject(plugin.toJson())); } catch (JSONException e) { e.printStackTrace(); } } - settingsAPI.edit(pluginPrefs).putString(CUSTOM_PLUGINS_KEY, itemsJson.toString()).commit(); + String jsonStr = itemsJson.toString(); + if (!jsonStr.equals(settingsAPI.getString(pluginPrefs, CUSTOM_PLUGINS_KEY, ""))) { + settingsAPI.edit(pluginPrefs).putString(CUSTOM_PLUGINS_KEY, jsonStr).commit(); + } } } diff --git a/OsmAnd/src/net/osmand/plus/SettingsHelper.java b/OsmAnd/src/net/osmand/plus/SettingsHelper.java index 3641afd60b..ce9ad08f2d 100644 --- a/OsmAnd/src/net/osmand/plus/SettingsHelper.java +++ b/OsmAnd/src/net/osmand/plus/SettingsHelper.java @@ -259,14 +259,7 @@ public class SettingsHelper { } void readFromJson(@NonNull OsmandApplication app, @NonNull JSONObject json) throws JSONException { - String pluginId = json.getString("pluginId"); - String name = json.getString("name"); - String description = json.getString("Description"); - - plugin = new CustomOsmandPlugin(app); - plugin.pluginId = pluginId; - plugin.name = name; - plugin.description = description; + plugin = new CustomOsmandPlugin(app, json); } @NonNull diff --git a/OsmAnd/src/net/osmand/plus/helpers/ImportHelper.java b/OsmAnd/src/net/osmand/plus/helpers/ImportHelper.java index 73236bf546..b0be637bfc 100644 --- a/OsmAnd/src/net/osmand/plus/helpers/ImportHelper.java +++ b/OsmAnd/src/net/osmand/plus/helpers/ImportHelper.java @@ -805,6 +805,7 @@ public class ImportHelper { CustomOsmandPlugin plugin = pluginItem.getPlugin(); List pluginItems = pluginItem.getPluginItems(); if (!Algorithms.isEmpty(pluginItems)) { + pluginIndependentItems.removeAll(pluginItems); for (SettingsHelper.SettingsItem item : pluginItems) { item.setShouldReplace(true); if (item instanceof SettingsHelper.QuickActionSettingsItem) {