Merge branch 'master' into straight_to
This commit is contained in:
commit
d0d44e8ed4
19 changed files with 1625 additions and 72 deletions
|
@ -12,6 +12,8 @@ public interface ITileSource {
|
|||
|
||||
public String getUrlToLoad(int x, int y, int zoom);
|
||||
|
||||
public String getUrlTemplate();
|
||||
|
||||
public byte[] getBytes(int x, int y, int zoom, String dirWithTiles) throws IOException;
|
||||
|
||||
public int getMinimumZoomSupported();
|
||||
|
@ -32,4 +34,15 @@ public interface ITileSource {
|
|||
|
||||
public void deleteTiles(String path);
|
||||
|
||||
public int getAvgSize();
|
||||
|
||||
public String getRule();
|
||||
|
||||
public String getRandoms();
|
||||
|
||||
public boolean isInvertedYTile();
|
||||
|
||||
public boolean isTimeSupported();
|
||||
|
||||
public boolean getInversiveZoom();
|
||||
}
|
||||
|
|
|
@ -174,6 +174,16 @@ public class TileSourceManager {
|
|||
return invertedYTile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTimeSupported() {
|
||||
return expirationTimeMillis != -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getInversiveZoom() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setInvertedYTile(boolean invertedYTile) {
|
||||
this.invertedYTile = invertedYTile;
|
||||
}
|
||||
|
@ -410,6 +420,11 @@ public class TileSourceManager {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvgSize() {
|
||||
return this.avgSize;
|
||||
}
|
||||
}
|
||||
|
||||
private static Map<String, String> readMetaInfoFile(File dir) {
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 1.2 KiB |
Binary file not shown.
Before Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
Before Width: | Height: | Size: 1.3 KiB |
Binary file not shown.
Before Width: | Height: | Size: 1.4 KiB |
9
OsmAnd/res/drawable/ic_type_audio.xml
Normal file
9
OsmAnd/res/drawable/ic_type_audio.xml
Normal file
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M12,3H18V7H14V17C14,19.2091 12.2091,21 10,21C7.7909,21 6,19.2091 6,17C6,14.7909 7.7909,13 10,13C10.7286,13 11.4117,13.1948 12,13.5351V3Z"
|
||||
android:fillColor="#727272"/>
|
||||
</vector>
|
31
OsmAnd/res/layout/bottom_sheet_item_additional_data.xml
Normal file
31
OsmAnd/res/layout/bottom_sheet_item_additional_data.xml
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="20dp">
|
||||
|
||||
<android.support.v7.widget.SwitchCompat
|
||||
android:id="@+id/switchItem"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/content_padding"
|
||||
android:layout_marginEnd="@dimen/content_padding"
|
||||
android:minHeight="48dp"
|
||||
android:text="@string/shared_string_include_data"
|
||||
android:textSize="@dimen/default_list_text_size"
|
||||
tools:text="@string/shared_string_include_data" />
|
||||
|
||||
<ExpandableListView
|
||||
android:id="@+id/list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:divider="@null"
|
||||
android:dividerHeight="0dp"
|
||||
android:drawSelectorOnTop="false"
|
||||
android:groupIndicator="@android:color/transparent"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
</LinearLayout>
|
49
OsmAnd/res/layout/profile_data_list_item_child.xml
Normal file
49
OsmAnd/res/layout/profile_data_list_item_child.xml
Normal file
|
@ -0,0 +1,49 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center_vertical"
|
||||
android:minHeight="66dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/content_padding"
|
||||
tools:src="@drawable/ic_action_info_dark" />
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:id="@+id/title_tv"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
android:textSize="@dimen/default_list_text_size"
|
||||
tools:text="Quick actions" />
|
||||
|
||||
<android.support.v7.widget.AppCompatCheckBox
|
||||
android:id="@+id/check_box"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/content_padding"
|
||||
android:layout_marginEnd="@dimen/content_padding"
|
||||
android:focusable="false" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
android:id="@+id/divider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="?attr/list_divider"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
</LinearLayout>
|
72
OsmAnd/res/layout/profile_data_list_item_group.xml
Normal file
72
OsmAnd/res/layout/profile_data_list_item_group.xml
Normal file
|
@ -0,0 +1,72 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center_vertical"
|
||||
android:minHeight="66dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/explist_indicator"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/content_padding"
|
||||
android:src="@drawable/ic_action_arrow_down" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="vertical">
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:id="@+id/title_tv"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
android:textSize="@dimen/default_list_text_size"
|
||||
tools:text="Quick actions" />
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:id="@+id/sub_text_tv"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
android:textSize="@dimen/default_desc_text_size"
|
||||
tools:text="8 of 4" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
android:id="@+id/vertical_divider"
|
||||
android:layout_width="1dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="@dimen/content_padding"
|
||||
android:layout_marginBottom="@dimen/content_padding"
|
||||
android:background="?attr/list_divider" />
|
||||
|
||||
<android.support.v7.widget.AppCompatCheckBox
|
||||
android:id="@+id/check_box"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/content_padding"
|
||||
android:focusable="false" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
android:id="@+id/divider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="?attr/list_divider"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
</LinearLayout>
|
|
@ -50,6 +50,11 @@
|
|||
<string name="ltr_or_rtl_combine_via_slash">%1$s/%2$s</string>
|
||||
<string name="sunset_at">Sunset at %1$s</string>
|
||||
<string name="sunrise_at">Sunrise at %1$s</string>
|
||||
<string name="shared_string_routing">Routing</string>
|
||||
<string name="shared_string_custom_rendering_style">Custom rendering style</string>
|
||||
<string name="shared_string_include_data">Include additional data</string>
|
||||
<string name="import_profile_dialog_description">The imported profile contains additional data. Click Import to import only profile data or select additional data to import.</string>
|
||||
<string name="export_profile_dialog_description">You can select additional data to export along with the profile.</string>
|
||||
<string name="permission_is_required">Permission is required to use this option.</string>
|
||||
<string name="logcat_buffer_descr">Check and share detailed logs of the application</string>
|
||||
<string name="file_does_not_contain_routing_rules">No routing rules in \'%1$s\'. Please choose another file.</string>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package net.osmand.plus;
|
||||
|
||||
import android.database.SQLException;
|
||||
import android.database.sqlite.SQLiteDiskIOException;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
|
@ -22,22 +23,34 @@ import java.nio.ByteBuffer;
|
|||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static net.osmand.IndexConstants.SQLITE_EXT;
|
||||
import static net.osmand.IndexConstants.TILES_INDEX_DIR;
|
||||
|
||||
|
||||
public class SQLiteTileSource implements ITileSource {
|
||||
|
||||
public static final String EXT = IndexConstants.SQLITE_EXT;
|
||||
private static final Log LOG = PlatformUtil.getLog(SQLiteTileSource.class);
|
||||
private static final String MAXZOOM_FIELD = "maxzoom";
|
||||
private static final String MINZOOM_FIELD = "minzoom";
|
||||
private static final String ELLIPSOID_FIELD = "ellipsoid";
|
||||
private static final String URL_FIELD = "url";
|
||||
private static final String EXPIREMINUTES_FIELD = "expireminutes";
|
||||
|
||||
private static final String MIN_ZOOM = "minzoom";
|
||||
private static final String MAX_ZOOM = "maxzoom";
|
||||
private static final String URL = "url";
|
||||
private static final String RANDOMS = "randoms";
|
||||
private static final String ELLIPSOID = "ellipsoid";
|
||||
private static final String INVERTED_Y = "inverted_y";
|
||||
private static final String REFERER = "referer";
|
||||
private static final String TIME_COLUMN = "timecolumn";
|
||||
private static final String EXPIRE_MINUTES = "expireminutes";
|
||||
private static final String RULE = "rule";
|
||||
private static final String TILENUMBERING = "tilenumbering";
|
||||
private static final String BIG_PLANET_TILE_NUMBERING = "BigPlanet";
|
||||
private static final String TILESIZE = "tilesize";
|
||||
|
||||
private ITileSource base;
|
||||
private String urlTemplate = null;
|
||||
private String name;
|
||||
private SQLiteConnection db = null;
|
||||
private final File file;
|
||||
private File file = null;
|
||||
private int minZoom = 1;
|
||||
private int maxZoom = 17;
|
||||
private boolean inversiveZoom = true; // BigPlanet
|
||||
|
@ -76,6 +89,45 @@ public class SQLiteTileSource implements ITileSource {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
public SQLiteTileSource(OsmandApplication ctx, String name, int minZoom, int maxZoom, String urlTemplate,
|
||||
String randoms, boolean isEllipsoid, boolean invertedY, String referer,
|
||||
boolean timeSupported, long expirationTimeMillis, boolean inversiveZoom) {
|
||||
this.ctx = ctx;
|
||||
this.name = name;
|
||||
this.urlTemplate = urlTemplate;
|
||||
this.maxZoom = maxZoom;
|
||||
this.minZoom = minZoom;
|
||||
this.isEllipsoid = isEllipsoid;
|
||||
this.expirationTimeMillis = expirationTimeMillis;
|
||||
this.randoms = randoms;
|
||||
this.referer = referer;
|
||||
this.invertedY = invertedY;
|
||||
this.timeSupported = timeSupported;
|
||||
this.inversiveZoom = inversiveZoom;
|
||||
}
|
||||
|
||||
public void createDataBase() {
|
||||
db = ctx.getSQLiteAPI().getOrCreateDatabase(
|
||||
ctx.getAppPath(TILES_INDEX_DIR).getAbsolutePath() + "/" + name + SQLITE_EXT, true);
|
||||
|
||||
db.execSQL("CREATE TABLE tiles (x int, y int, z int, s int, image blob, time long, PRIMARY KEY (x,y,z,s))");
|
||||
db.execSQL("CREATE INDEX IND on tiles (x,y,z,s)");
|
||||
db.execSQL("CREATE TABLE info(tilenumbering,minzoom,maxzoom)");
|
||||
db.execSQL("CREATE TABLE android_metadata (locale TEXT)");
|
||||
db.execSQL("INSERT INTO info (tilenumbering,minzoom,maxzoom) VALUES ('simple','" + minZoom + "','" + maxZoom + "');");
|
||||
|
||||
addInfoColumn(URL, urlTemplate);
|
||||
addInfoColumn(RANDOMS, randoms);
|
||||
addInfoColumn(ELLIPSOID, isEllipsoid ? "1" : "0");
|
||||
addInfoColumn(INVERTED_Y, invertedY ? "1" : "0");
|
||||
addInfoColumn(REFERER, referer);
|
||||
addInfoColumn(TIME_COLUMN, timeSupported ? "yes" : "no");
|
||||
addInfoColumn(EXPIRE_MINUTES, String.valueOf(getExpirationTimeMinutes()));
|
||||
|
||||
|
||||
db.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBitDensity() {
|
||||
|
@ -121,6 +173,20 @@ public class SQLiteTileSource implements ITileSource {
|
|||
return TileSourceTemplate.buildUrlToLoad(urlTemplate, randomsArray, x, y, zoom);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUrlTemplate() {
|
||||
if (this.urlTemplate != null) {
|
||||
return this.urlTemplate;
|
||||
} else {
|
||||
SQLiteConnection db = getDatabase();
|
||||
if (db == null || urlTemplate == null) {
|
||||
return null;
|
||||
} else {
|
||||
return this.urlTemplate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
|
@ -167,36 +233,36 @@ public class SQLiteTileSource implements ITileSource {
|
|||
if(cursor.moveToFirst()) {
|
||||
String[] columnNames = cursor.getColumnNames();
|
||||
List<String> list = Arrays.asList(columnNames);
|
||||
int url = list.indexOf(URL_FIELD);
|
||||
int url = list.indexOf(URL);
|
||||
if(url != -1) {
|
||||
String template = cursor.getString(url);
|
||||
if(!Algorithms.isEmpty(template)){
|
||||
urlTemplate = TileSourceTemplate.normalizeUrl(template);
|
||||
}
|
||||
}
|
||||
int ruleId = list.indexOf("rule");
|
||||
int ruleId = list.indexOf(RULE);
|
||||
if(ruleId != -1) {
|
||||
rule = cursor.getString(ruleId);
|
||||
}
|
||||
int refererId = list.indexOf("referer");
|
||||
int refererId = list.indexOf(REFERER);
|
||||
if(refererId != -1) {
|
||||
referer = cursor.getString(refererId);
|
||||
}
|
||||
int tnumbering = list.indexOf("tilenumbering");
|
||||
int tnumbering = list.indexOf(TILENUMBERING);
|
||||
if(tnumbering != -1) {
|
||||
inversiveZoom = "BigPlanet".equalsIgnoreCase(cursor.getString(tnumbering));
|
||||
inversiveZoom = BIG_PLANET_TILE_NUMBERING.equalsIgnoreCase(cursor.getString(tnumbering));
|
||||
} else {
|
||||
inversiveZoom = true;
|
||||
addInfoColumn("tilenumbering", "BigPlanet");
|
||||
addInfoColumn(TILENUMBERING, BIG_PLANET_TILE_NUMBERING);
|
||||
}
|
||||
int timecolumn = list.indexOf("timecolumn");
|
||||
int timecolumn = list.indexOf(TIME_COLUMN);
|
||||
if (timecolumn != -1) {
|
||||
timeSupported = "yes".equalsIgnoreCase(cursor.getString(timecolumn));
|
||||
} else {
|
||||
timeSupported = hasTimeColumn();
|
||||
addInfoColumn("timecolumn", timeSupported? "yes" : "no");
|
||||
addInfoColumn(TIME_COLUMN, timeSupported? "yes" : "no");
|
||||
}
|
||||
int expireminutes = list.indexOf(EXPIREMINUTES_FIELD);
|
||||
int expireminutes = list.indexOf(EXPIRE_MINUTES);
|
||||
this.expirationTimeMillis = -1;
|
||||
if(expireminutes != -1) {
|
||||
int minutes = (int) cursor.getInt(expireminutes);
|
||||
|
@ -204,39 +270,39 @@ public class SQLiteTileSource implements ITileSource {
|
|||
this.expirationTimeMillis = minutes * 60 * 1000l;
|
||||
}
|
||||
} else {
|
||||
addInfoColumn(EXPIREMINUTES_FIELD, "0");
|
||||
addInfoColumn(EXPIRE_MINUTES, "0");
|
||||
}
|
||||
int tsColumn = list.indexOf("tilesize");
|
||||
int tsColumn = list.indexOf(TILESIZE);
|
||||
this.tileSizeSpecified = tsColumn != -1;
|
||||
if(tileSizeSpecified) {
|
||||
this.tileSize = (int) cursor.getInt(tsColumn);
|
||||
}
|
||||
int ellipsoid = list.indexOf(ELLIPSOID_FIELD);
|
||||
int ellipsoid = list.indexOf(ELLIPSOID);
|
||||
if(ellipsoid != -1) {
|
||||
int set = (int) cursor.getInt(ellipsoid);
|
||||
if(set == 1){
|
||||
this.isEllipsoid = true;
|
||||
}
|
||||
}
|
||||
int invertedY = list.indexOf("inverted_y");
|
||||
int invertedY = list.indexOf(INVERTED_Y);
|
||||
if(invertedY != -1) {
|
||||
int set = (int) cursor.getInt(invertedY);
|
||||
if(set == 1){
|
||||
this.invertedY = true;
|
||||
}
|
||||
}
|
||||
int randomsId = list.indexOf("randoms");
|
||||
int randomsId = list.indexOf(RANDOMS);
|
||||
if(randomsId != -1) {
|
||||
this.randoms = cursor.getString(randomsId);
|
||||
this.randomsArray = TileSourceTemplate.buildRandomsArray(this.randoms);
|
||||
}
|
||||
//boolean inversiveInfoZoom = tnumbering != -1 && "BigPlanet".equals(cursor.getString(tnumbering));
|
||||
boolean inversiveInfoZoom = inversiveZoom;
|
||||
int mnz = list.indexOf(MINZOOM_FIELD);
|
||||
int mnz = list.indexOf(MIN_ZOOM);
|
||||
if(mnz != -1) {
|
||||
minZoom = (int) cursor.getInt(mnz);
|
||||
}
|
||||
int mxz = list.indexOf(MAXZOOM_FIELD);
|
||||
int mxz = list.indexOf(MAX_ZOOM);
|
||||
if(mxz != -1) {
|
||||
maxZoom = (int) cursor.getInt(mxz);
|
||||
}
|
||||
|
@ -264,27 +330,31 @@ public class SQLiteTileSource implements ITileSource {
|
|||
maxZoom = 17 - mnz;
|
||||
}
|
||||
if (getUrlTemplate() != null && !getUrlTemplate().equals(r.getUrlTemplate())) {
|
||||
db.execSQL("update info set " + URL_FIELD + " = '" + r.getUrlTemplate() + "'");
|
||||
db.execSQL("update info set " + URL + " = '" + r.getUrlTemplate() + "'");
|
||||
}
|
||||
if (r.getMinimumZoomSupported() != minZoom) {
|
||||
db.execSQL("update info set " + MINZOOM_FIELD + " = '" + minZoom + "'");
|
||||
db.execSQL("update info set " + MIN_ZOOM + " = '" + minZoom + "'");
|
||||
}
|
||||
if (r.getMaximumZoomSupported() != maxZoom) {
|
||||
db.execSQL("update info set " + MAXZOOM_FIELD + " = '" + maxZoom + "'");
|
||||
db.execSQL("update info set " + MAX_ZOOM + " = '" + maxZoom + "'");
|
||||
}
|
||||
if (r.isEllipticYTile() != isEllipticYTile()) {
|
||||
db.execSQL("update info set " + ELLIPSOID_FIELD + " = '" + (r.isEllipticYTile() ? 1 : 0) + "'");
|
||||
db.execSQL("update info set " + ELLIPSOID + " = '" + (r.isEllipticYTile() ? 1 : 0) + "'");
|
||||
}
|
||||
if (r.getExpirationTimeMinutes() != getExpirationTimeMinutes()) {
|
||||
db.execSQL("update info set " + EXPIREMINUTES_FIELD + " = '" + r.getExpirationTimeMinutes() + "'");
|
||||
db.execSQL("update info set " + EXPIRE_MINUTES + " = '" + r.getExpirationTimeMinutes() + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addInfoColumn(String columnName, String value) {
|
||||
if (!onlyReadonlyAvailable) {
|
||||
db.execSQL("alter table info add column " + columnName + " TEXT");
|
||||
db.execSQL("update info set " + columnName + " = '" + value + "'");
|
||||
if(!onlyReadonlyAvailable) {
|
||||
try {
|
||||
db.execSQL("alter table info add column " + columnName + " TEXT");
|
||||
} catch (SQLException e) {
|
||||
LOG.info("Error adding column " + e);
|
||||
}
|
||||
db.execSQL("update info set "+columnName+" = '"+value+"'");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -459,7 +529,37 @@ public class SQLiteTileSource implements ITileSource {
|
|||
}
|
||||
db.execSQL("DELETE FROM tiles");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getAvgSize() {
|
||||
return base != null ? base.getAvgSize() : -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return rule;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRandoms() {
|
||||
return randoms;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInvertedYTile() {
|
||||
return invertedY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTimeSupported() {
|
||||
return timeSupported;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getInversiveZoom() {
|
||||
return inversiveZoom;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes method synchronized to give a little more time for get methods and
|
||||
* let all writing attempts to wait outside of this method
|
||||
|
@ -547,9 +647,4 @@ public class SQLiteTileSource implements ITileSource {
|
|||
return referer;
|
||||
}
|
||||
|
||||
public String getUrlTemplate() {
|
||||
return urlTemplate;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -9,10 +9,21 @@ import android.support.annotation.NonNull;
|
|||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
|
||||
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.ApplicationMode.ApplicationModeBean;
|
||||
import net.osmand.plus.ApplicationMode.ApplicationModeBuilder;
|
||||
import net.osmand.plus.OsmandSettings.OsmandPreference;
|
||||
import net.osmand.plus.activities.MapActivity;
|
||||
import net.osmand.plus.poi.PoiUIFilter;
|
||||
import net.osmand.plus.quickaction.QuickAction;
|
||||
import net.osmand.plus.quickaction.QuickActionFactory;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
|
@ -33,11 +44,14 @@ import java.io.IOException;
|
|||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
@ -46,6 +60,7 @@ import java.util.zip.ZipInputStream;
|
|||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import static net.osmand.IndexConstants.OSMAND_SETTINGS_FILE_EXT;
|
||||
import static net.osmand.IndexConstants.TILES_INDEX_DIR;
|
||||
|
||||
/*
|
||||
Usage:
|
||||
|
@ -83,6 +98,7 @@ public class SettingsHelper {
|
|||
|
||||
private boolean importing;
|
||||
private boolean importSuspended;
|
||||
private boolean collectOnly;
|
||||
private ImportAsyncTask importTask;
|
||||
|
||||
public interface SettingsImportListener {
|
||||
|
@ -103,7 +119,7 @@ public class SettingsHelper {
|
|||
|
||||
public void setActivity(Activity activity) {
|
||||
this.activity = activity;
|
||||
if (importing) {
|
||||
if (importing && !collectOnly) {
|
||||
importTask.processNextItem();
|
||||
}
|
||||
}
|
||||
|
@ -128,6 +144,9 @@ public class SettingsHelper {
|
|||
PLUGIN,
|
||||
DATA,
|
||||
FILE,
|
||||
QUICK_ACTION,
|
||||
POI_UI_FILTERS,
|
||||
MAP_SOURCES,
|
||||
}
|
||||
|
||||
public abstract static class SettingsItem {
|
||||
|
@ -157,6 +176,10 @@ public class SettingsHelper {
|
|||
@NonNull
|
||||
public abstract String getFileName();
|
||||
|
||||
public Boolean shouldReadOnCollecting() {
|
||||
return false;
|
||||
}
|
||||
|
||||
static SettingsItemType parseItemType(@NonNull JSONObject json) throws IllegalArgumentException, JSONException {
|
||||
return SettingsItemType.valueOf(json.getString("type"));
|
||||
}
|
||||
|
@ -307,7 +330,6 @@ public class SettingsHelper {
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -419,6 +441,10 @@ public class SettingsHelper {
|
|||
appModeBeanPrefsIds = new HashSet<>(Arrays.asList(settings.appModeBeanPrefsIds));
|
||||
}
|
||||
|
||||
public ApplicationMode getAppMode() {
|
||||
return appMode;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getName() {
|
||||
|
@ -472,7 +498,6 @@ public class SettingsHelper {
|
|||
json.put("appMode", new JSONObject(appMode.toJson()));
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
SettingsItemReader getReader() {
|
||||
|
@ -706,6 +731,443 @@ public class SettingsHelper {
|
|||
}
|
||||
}
|
||||
|
||||
public static class QuickActionSettingsItem extends OsmandSettingsItem {
|
||||
|
||||
private List<QuickAction> quickActions;
|
||||
|
||||
private OsmandApplication app;
|
||||
|
||||
public QuickActionSettingsItem(@NonNull OsmandApplication app,
|
||||
@NonNull List<QuickAction> quickActions) {
|
||||
super(SettingsItemType.QUICK_ACTION, app.getSettings());
|
||||
this.app = app;
|
||||
this.quickActions = quickActions;
|
||||
}
|
||||
|
||||
public QuickActionSettingsItem(@NonNull OsmandApplication app,
|
||||
@NonNull JSONObject jsonObject) throws JSONException {
|
||||
super(SettingsItemType.QUICK_ACTION, app.getSettings(), jsonObject);
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
public List<QuickAction> getQuickActions() {
|
||||
return quickActions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply() {
|
||||
if (!quickActions.isEmpty()) {
|
||||
QuickActionFactory factory = new QuickActionFactory();
|
||||
List<QuickAction> savedActions = factory.parseActiveActionsList(getSettings().QUICK_ACTION_LIST.get());
|
||||
List<QuickAction> newActions = new ArrayList<>(savedActions);
|
||||
for (QuickAction action : quickActions) {
|
||||
for (QuickAction savedAction : savedActions) {
|
||||
if (action.getName(app).equals(savedAction.getName(app))) {
|
||||
newActions.remove(savedAction);
|
||||
}
|
||||
}
|
||||
}
|
||||
newActions.addAll(quickActions);
|
||||
((MapActivity) app.getSettingsHelper().getActivity()).getMapLayers().getQuickActionRegistry().updateQuickActions(newActions);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean shouldReadOnCollecting() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return "quick_actions";
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getPublicName(@NonNull Context ctx) {
|
||||
return "quick_actions";
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getFileName() {
|
||||
return getName() + ".json";
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
SettingsItemReader getReader() {
|
||||
return new OsmandSettingsItemReader(this, getSettings()) {
|
||||
|
||||
@Override
|
||||
protected void readPreferenceFromJson(@NonNull OsmandPreference<?> preference, @NonNull JSONObject json) throws JSONException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFromStream(@NonNull InputStream inputStream) throws IOException, IllegalArgumentException {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
try {
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
|
||||
String str;
|
||||
while ((str = in.readLine()) != null) {
|
||||
buf.append(str);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new IOException("Cannot read json body", e);
|
||||
}
|
||||
String jsonStr = buf.toString();
|
||||
if (Algorithms.isEmpty(jsonStr)) {
|
||||
throw new IllegalArgumentException("Cannot find json body");
|
||||
}
|
||||
final JSONObject json;
|
||||
try {
|
||||
quickActions = new ArrayList<>();
|
||||
Gson gson = new Gson();
|
||||
Type type = new TypeToken<HashMap<String, String>>() {
|
||||
}.getType();
|
||||
json = new JSONObject(jsonStr);
|
||||
JSONArray items = json.getJSONArray("items");
|
||||
for (int i = 0; i < items.length(); i++) {
|
||||
JSONObject object = items.getJSONObject(i);
|
||||
String name = object.getString("name");
|
||||
int actionType = object.getInt("type");
|
||||
String paramsString = object.getString("params");
|
||||
HashMap<String, String> params = gson.fromJson(paramsString, type);
|
||||
QuickAction quickAction = new QuickAction(actionType);
|
||||
quickAction.setName(name);
|
||||
quickAction.setParams(params);
|
||||
quickActions.add(quickAction);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
throw new IllegalArgumentException("Json parse error", e);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
SettingsItemWriter getWriter() {
|
||||
return new OsmandSettingsItemWriter(this, getSettings()) {
|
||||
@Override
|
||||
protected void writePreferenceToJson(@NonNull OsmandPreference<?> preference, @NonNull JSONObject json) throws JSONException {
|
||||
JSONArray items = new JSONArray();
|
||||
Gson gson = new Gson();
|
||||
Type type = new TypeToken<HashMap<String, String>>() {
|
||||
}.getType();
|
||||
if (!quickActions.isEmpty()) {
|
||||
for (QuickAction action : quickActions) {
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put("name", action.getName(app));
|
||||
jsonObject.put("type", action.getType());
|
||||
jsonObject.put("params", gson.toJson(action.getParams(), type));
|
||||
items.put(jsonObject);
|
||||
}
|
||||
json.put("items", items);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public static class PoiUiFilterSettingsItem extends OsmandSettingsItem {
|
||||
|
||||
private List<PoiUIFilter> poiUIFilters;
|
||||
|
||||
private OsmandApplication app;
|
||||
|
||||
public PoiUiFilterSettingsItem(OsmandApplication app, List<PoiUIFilter> poiUIFilters) {
|
||||
super(SettingsItemType.POI_UI_FILTERS, app.getSettings());
|
||||
this.app = app;
|
||||
this.poiUIFilters = poiUIFilters;
|
||||
}
|
||||
|
||||
public PoiUiFilterSettingsItem(OsmandApplication app, JSONObject jsonObject) throws JSONException {
|
||||
super(SettingsItemType.POI_UI_FILTERS, app.getSettings(), jsonObject);
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
public List<PoiUIFilter> getPoiUIFilters() {
|
||||
return this.poiUIFilters != null ? this.poiUIFilters : new ArrayList<PoiUIFilter>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply() {
|
||||
if (!poiUIFilters.isEmpty()) {
|
||||
for (PoiUIFilter filter : poiUIFilters) {
|
||||
app.getPoiFilters().createPoiFilter(filter, false);
|
||||
}
|
||||
app.getSearchUICore().refreshCustomPoiFilters();
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return "poi_ui_filters";
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getPublicName(@NonNull Context ctx) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean shouldReadOnCollecting() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getFileName() {
|
||||
return getName() + ".json";
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
SettingsItemReader getReader() {
|
||||
return new OsmandSettingsItemReader(this, getSettings()) {
|
||||
@Override
|
||||
protected void readPreferenceFromJson(@NonNull OsmandPreference<?> preference, @NonNull JSONObject json) throws JSONException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFromStream(@NonNull InputStream inputStream) throws IOException, IllegalArgumentException {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
try {
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
|
||||
String str;
|
||||
while ((str = in.readLine()) != null) {
|
||||
buf.append(str);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new IOException("Cannot read json body", e);
|
||||
}
|
||||
String jsonStr = buf.toString();
|
||||
if (Algorithms.isEmpty(jsonStr)) {
|
||||
throw new IllegalArgumentException("Cannot find json body");
|
||||
}
|
||||
final JSONObject json;
|
||||
try {
|
||||
poiUIFilters = new ArrayList<>();
|
||||
json = new JSONObject(jsonStr);
|
||||
JSONArray items = json.getJSONArray("items");
|
||||
Gson gson = new Gson();
|
||||
Type type = new TypeToken<HashMap<String, LinkedHashSet<String>>>() {
|
||||
}.getType();
|
||||
MapPoiTypes poiTypes = app.getPoiTypes();
|
||||
for (int i = 0; i < items.length(); i++) {
|
||||
JSONObject object = items.getJSONObject(i);
|
||||
String name = object.getString("name");
|
||||
String filterId = object.getString("filterId");
|
||||
String acceptedTypesString = object.getString("acceptedTypes");
|
||||
HashMap<String, LinkedHashSet<String>> acceptedTypes = gson.fromJson(acceptedTypesString, type);
|
||||
Map<PoiCategory, LinkedHashSet<String>> acceptedTypesDone = new HashMap<>();
|
||||
for (Map.Entry<String, LinkedHashSet<String>> 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);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
SettingsItemWriter getWriter() {
|
||||
return new OsmandSettingsItemWriter(this, getSettings()) {
|
||||
@Override
|
||||
protected void writePreferenceToJson(@NonNull OsmandPreference<?> preference, @NonNull JSONObject json) throws JSONException {
|
||||
JSONArray items = new JSONArray();
|
||||
Gson gson = new Gson();
|
||||
Type type = new TypeToken<HashMap<PoiCategory, LinkedHashSet<String>>>() {
|
||||
}.getType();
|
||||
if (!poiUIFilters.isEmpty()) {
|
||||
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));
|
||||
items.put(jsonObject);
|
||||
}
|
||||
json.put("items", items);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public static class MapSourcesSettingsItem extends OsmandSettingsItem {
|
||||
|
||||
private OsmandApplication app;
|
||||
|
||||
private List<ITileSource> mapSources;
|
||||
|
||||
public MapSourcesSettingsItem(OsmandApplication app, List<ITileSource> mapSources) {
|
||||
super(SettingsItemType.MAP_SOURCES, app.getSettings());
|
||||
this.app = app;
|
||||
this.mapSources = mapSources;
|
||||
}
|
||||
|
||||
public MapSourcesSettingsItem(OsmandApplication app, JSONObject jsonObject) throws JSONException {
|
||||
super(SettingsItemType.MAP_SOURCES, app.getSettings(), jsonObject);
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
public List<ITileSource> getMapSources() {
|
||||
return this.mapSources;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply() {
|
||||
if (!mapSources.isEmpty()) {
|
||||
for (ITileSource template : mapSources) {
|
||||
if (template instanceof TileSourceManager.TileSourceTemplate) {
|
||||
getSettings().installTileSource((TileSourceManager.TileSourceTemplate) template);
|
||||
} else {
|
||||
((SQLiteTileSource) template).createDataBase();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return "map_sources";
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getPublicName(@NonNull Context ctx) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean shouldReadOnCollecting() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getFileName() {
|
||||
return getName() + ".json";
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
SettingsItemReader getReader() {
|
||||
return new OsmandSettingsItemReader(this, getSettings()) {
|
||||
@Override
|
||||
protected void readPreferenceFromJson(@NonNull OsmandPreference<?> preference, @NonNull JSONObject json) throws JSONException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFromStream(@NonNull InputStream inputStream) throws IOException, IllegalArgumentException {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
try {
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
|
||||
String str;
|
||||
while ((str = in.readLine()) != null) {
|
||||
buf.append(str);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new IOException("Cannot read json body", e);
|
||||
}
|
||||
String jsonStr = buf.toString();
|
||||
if (Algorithms.isEmpty(jsonStr)) {
|
||||
throw new IllegalArgumentException("Cannot find json body");
|
||||
}
|
||||
final JSONObject json;
|
||||
try {
|
||||
mapSources = new ArrayList<>();
|
||||
json = new JSONObject(jsonStr);
|
||||
JSONArray items = json.getJSONArray("items");
|
||||
for (int i = 0; i < items.length(); i++) {
|
||||
JSONObject object = items.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);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
SettingsItemWriter getWriter() {
|
||||
return new OsmandSettingsItemWriter(this, getSettings()) {
|
||||
@Override
|
||||
protected void writePreferenceToJson(@NonNull OsmandPreference<?> preference, @NonNull JSONObject json) throws JSONException {
|
||||
JSONArray items = new JSONArray();
|
||||
if (!mapSources.isEmpty()) {
|
||||
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());
|
||||
|
||||
items.put(jsonObject);
|
||||
}
|
||||
json.put("items", items);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private static class SettingsItemsFactory {
|
||||
|
||||
private OsmandApplication app;
|
||||
|
@ -762,6 +1224,15 @@ public class SettingsHelper {
|
|||
case FILE:
|
||||
item = new FileSettingsItem(app, json);
|
||||
break;
|
||||
case QUICK_ACTION:
|
||||
item = new QuickActionSettingsItem(app, json);
|
||||
break;
|
||||
case POI_UI_FILTERS:
|
||||
item = new PoiUiFilterSettingsItem(app, json);
|
||||
break;
|
||||
case MAP_SOURCES:
|
||||
item = new MapSourcesSettingsItem(app, json);
|
||||
break;
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
@ -873,10 +1344,11 @@ public class SettingsHelper {
|
|||
LOG.error("Error parsing items: " + itemsJson, e);
|
||||
throw new IllegalArgumentException("No items");
|
||||
}
|
||||
while (!collecting && (entry = zis.getNextEntry()) != null) {
|
||||
while ((entry = zis.getNextEntry()) != null) {
|
||||
String fileName = entry.getName();
|
||||
SettingsItem item = itemsFactory.getItemByFileName(fileName);
|
||||
if (item != null) {
|
||||
if (item != null && collecting && item.shouldReadOnCollecting()
|
||||
|| item != null && !collecting && !item.shouldReadOnCollecting()) {
|
||||
try {
|
||||
item.getReader().readFromStream(ois);
|
||||
} catch (IllegalArgumentException e) {
|
||||
|
@ -924,6 +1396,17 @@ public class SettingsHelper {
|
|||
this.version = version;
|
||||
this.askBeforeImport = askBeforeImport;
|
||||
importer = new SettingsImporter(app);
|
||||
collectOnly = true;
|
||||
}
|
||||
|
||||
ImportAsyncTask(@NonNull File settingsFile, @NonNull List<SettingsItem> items, String latestChanges, int version, @Nullable SettingsImportListener listener) {
|
||||
this.file = settingsFile;
|
||||
this.listener = listener;
|
||||
this.items = items;
|
||||
this.latestChanges = latestChanges;
|
||||
this.version = version;
|
||||
importer = new SettingsImporter(app);
|
||||
collectOnly = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -938,12 +1421,16 @@ public class SettingsHelper {
|
|||
|
||||
@Override
|
||||
protected List<SettingsItem> doInBackground(Void... voids) {
|
||||
try {
|
||||
return importer.collectItems(file);
|
||||
} catch (IllegalArgumentException e) {
|
||||
LOG.error("Failed to collect items from: " + file.getName(), e);
|
||||
} catch (IOException e) {
|
||||
LOG.error("Failed to collect items from: " + file.getName(), e);
|
||||
if (collectOnly) {
|
||||
try {
|
||||
return importer.collectItems(file);
|
||||
} catch (IllegalArgumentException e) {
|
||||
LOG.error("Failed to collect items from: " + file.getName(), e);
|
||||
} catch (IOException e) {
|
||||
LOG.error("Failed to collect items from: " + file.getName(), e);
|
||||
}
|
||||
} else {
|
||||
return this.items;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -951,8 +1438,12 @@ public class SettingsHelper {
|
|||
@Override
|
||||
protected void onPostExecute(List<SettingsItem> items) {
|
||||
this.items = items;
|
||||
if (items != null && items.size() > 0) {
|
||||
processNextItem();
|
||||
if (collectOnly) {
|
||||
listener.onSettingsImportFinished(true, false, items);
|
||||
} else {
|
||||
if (items != null && items.size() > 0) {
|
||||
processNextItem();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1045,6 +1536,24 @@ public class SettingsHelper {
|
|||
processedItems.add(item);
|
||||
processNextItem();
|
||||
}
|
||||
|
||||
public List<SettingsItem> getItems() {
|
||||
return this.items;
|
||||
}
|
||||
|
||||
public File getFile() {
|
||||
return this.file;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public List<SettingsItem> getSettingsItems() {
|
||||
return this.importTask.getItems();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public File getSettingsFile() {
|
||||
return this.importTask.getFile();
|
||||
}
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
|
@ -1136,6 +1645,10 @@ public class SettingsHelper {
|
|||
new ImportAsyncTask(settingsFile, latestChanges, version, askBeforeImport, listener).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
|
||||
public void importSettings(@NonNull File settingsFile, @NonNull List<SettingsItem> items, String latestChanges, int version, @Nullable SettingsImportListener listener) {
|
||||
new ImportAsyncTask(settingsFile, items, latestChanges, version, listener).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
|
||||
public void exportSettings(@NonNull File fileDir, @NonNull String fileName,
|
||||
@Nullable SettingsExportListener listener,
|
||||
@NonNull List<SettingsItem> items) {
|
||||
|
@ -1147,4 +1660,4 @@ public class SettingsHelper {
|
|||
@NonNull SettingsItem... items) {
|
||||
exportSettings(fileDir, fileName, listener, new ArrayList<>(Arrays.asList(items)));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,6 +15,7 @@ import android.provider.OpenableColumns;
|
|||
import android.provider.Settings;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.text.style.ForegroundColorSpan;
|
||||
|
@ -33,6 +34,7 @@ import net.osmand.data.FavouritePoint;
|
|||
import net.osmand.plus.AppInitializer;
|
||||
import net.osmand.plus.AppInitializer.AppInitializeListener;
|
||||
import net.osmand.plus.AppInitializer.InitEvents;
|
||||
import net.osmand.plus.ApplicationMode;
|
||||
import net.osmand.plus.FavouritesDbHelper;
|
||||
import net.osmand.plus.GPXDatabase;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
|
@ -49,6 +51,9 @@ import net.osmand.plus.base.bottomsheetmenu.SimpleBottomSheetItem;
|
|||
import net.osmand.plus.base.bottomsheetmenu.simpleitems.DividerHalfItem;
|
||||
import net.osmand.plus.base.bottomsheetmenu.simpleitems.ShortDescriptionItem;
|
||||
import net.osmand.plus.base.bottomsheetmenu.simpleitems.TitleItem;
|
||||
import net.osmand.plus.profiles.AdditionalDataWrapper;
|
||||
import net.osmand.plus.profiles.ExportImportProfileBottomSheet;
|
||||
import net.osmand.plus.quickaction.QuickAction;
|
||||
import net.osmand.plus.rastermaps.OsmandRasterMapsPlugin;
|
||||
import net.osmand.plus.views.OsmandMapTileView;
|
||||
import net.osmand.router.RoutingConfiguration;
|
||||
|
@ -768,7 +773,7 @@ public class ImportHelper {
|
|||
@Override
|
||||
protected void onPostExecute(String error) {
|
||||
File tempDir = app.getAppPath(IndexConstants.TEMP_DIR);
|
||||
File file = new File(tempDir, name);
|
||||
final File file = new File(tempDir, name);
|
||||
if (error == null && file.exists()) {
|
||||
app.getSettingsHelper().importSettings(file, latestChanges, version, askBeforeImport, new SettingsImportListener() {
|
||||
@Override
|
||||
|
@ -777,11 +782,15 @@ public class ImportHelper {
|
|||
progress.dismiss();
|
||||
}
|
||||
if (succeed) {
|
||||
app.showShortToastMessage(app.getString(R.string.file_imported_successfully, name));
|
||||
if (callback != null) {
|
||||
callback.processResult(items);
|
||||
FragmentManager fragmentManager = activity.getSupportFragmentManager();
|
||||
if (fragmentManager != null) {
|
||||
ExportImportProfileBottomSheet.showInstance(
|
||||
fragmentManager,
|
||||
ExportImportProfileBottomSheet.State.IMPORT,
|
||||
file,
|
||||
items);
|
||||
}
|
||||
} else if (!empty) {
|
||||
} else {
|
||||
app.showShortToastMessage(app.getString(R.string.file_import_error, name, app.getString(R.string.shared_string_unexpected_error)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
package net.osmand.plus.profiles;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class AdditionalDataWrapper {
|
||||
|
||||
private Type type;
|
||||
|
||||
private List<?> items;
|
||||
|
||||
public AdditionalDataWrapper(Type type, List<?> items) {
|
||||
this.type = type;
|
||||
this.items = items;
|
||||
}
|
||||
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(Type type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public List<?> getItems() {
|
||||
return items;
|
||||
}
|
||||
|
||||
public enum Type {
|
||||
QUICK_ACTIONS,
|
||||
POI_TYPES,
|
||||
MAP_SOURCES,
|
||||
CUSTOM_RENDER_STYLE,
|
||||
CUSTOM_ROUTING
|
||||
}
|
||||
}
|
|
@ -0,0 +1,711 @@
|
|||
package net.osmand.plus.profiles;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.LayerDrawable;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.support.v4.widget.CompoundButtonCompat;
|
||||
import android.support.v7.widget.SwitchCompat;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.ExpandableListView;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import net.osmand.AndroidUtils;
|
||||
import net.osmand.IndexConstants;
|
||||
import net.osmand.PlatformUtil;
|
||||
import net.osmand.map.ITileSource;
|
||||
import net.osmand.map.TileSourceManager;
|
||||
import net.osmand.plus.ApplicationMode;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.SQLiteTileSource;
|
||||
import net.osmand.plus.SettingsHelper;
|
||||
import net.osmand.plus.UiUtilities;
|
||||
import net.osmand.plus.activities.OsmandBaseExpandableListAdapter;
|
||||
import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem;
|
||||
import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithCompoundButton;
|
||||
import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithDescription;
|
||||
import net.osmand.plus.base.bottomsheetmenu.SimpleBottomSheetItem;
|
||||
import net.osmand.plus.base.bottomsheetmenu.simpleitems.TitleItem;
|
||||
import net.osmand.plus.poi.PoiUIFilter;
|
||||
import net.osmand.plus.quickaction.QuickAction;
|
||||
import net.osmand.plus.quickaction.QuickActionFactory;
|
||||
import net.osmand.plus.render.RenderingIcons;
|
||||
import net.osmand.plus.settings.BaseSettingsFragment;
|
||||
import net.osmand.plus.settings.bottomsheets.BasePreferenceBottomSheet;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class ExportImportProfileBottomSheet extends BasePreferenceBottomSheet {
|
||||
|
||||
private static final Log LOG = PlatformUtil.getLog(ExportImportProfileBottomSheet.class);
|
||||
|
||||
public static final String TAG = ExportImportProfileBottomSheet.class.getSimpleName();
|
||||
|
||||
private static final String STATE_KEY = "EXPORT_IMPORT_DIALOG_STATE_KEY";
|
||||
|
||||
private static final String INCLUDE_ADDITIONAL_DATA_KEY = "INCLUDE_ADDITIONAL_DATA_KEY";
|
||||
|
||||
private boolean includeAdditionalData = false;
|
||||
|
||||
private boolean containsAdditionalData = false;
|
||||
|
||||
private OsmandApplication app;
|
||||
|
||||
private ApplicationMode profile;
|
||||
|
||||
private State state;
|
||||
|
||||
private List<AdditionalDataWrapper> dataList = new ArrayList<>();
|
||||
|
||||
private List<? super Object> dataToOperate = new ArrayList<>();
|
||||
|
||||
private List<SettingsHelper.SettingsItem> settingsItems;
|
||||
|
||||
private ExpandableListView listView;
|
||||
|
||||
private ProfileAdditionalDataAdapter adapter;
|
||||
|
||||
private SettingsHelper.ProfileSettingsItem profileSettingsItem;
|
||||
|
||||
private File file;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
if (savedInstanceState != null) {
|
||||
includeAdditionalData = savedInstanceState.getBoolean(INCLUDE_ADDITIONAL_DATA_KEY);
|
||||
}
|
||||
super.onCreate(savedInstanceState);
|
||||
app = requiredMyApplication();
|
||||
Bundle bundle = getArguments();
|
||||
if (bundle != null) {
|
||||
this.state = (State) getArguments().getSerializable(STATE_KEY);
|
||||
}
|
||||
if (state == State.IMPORT) {
|
||||
if (settingsItems == null) {
|
||||
settingsItems = app.getSettingsHelper().getSettingsItems();
|
||||
}
|
||||
if (file == null) {
|
||||
file = app.getSettingsHelper().getSettingsFile();
|
||||
}
|
||||
containsAdditionalData = checkAdditionalDataContains();
|
||||
} else {
|
||||
dataList = getAdditionalData();
|
||||
for (AdditionalDataWrapper dataWrapper : dataList) {
|
||||
dataToOperate.addAll(dataWrapper.getItems());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
outState.putBoolean(INCLUDE_ADDITIONAL_DATA_KEY, includeAdditionalData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createMenuItems(Bundle savedInstanceState) {
|
||||
final Context context = getContext();
|
||||
if (context == null) {
|
||||
return;
|
||||
}
|
||||
LayoutInflater inflater = UiUtilities.getInflater(app, nightMode);
|
||||
|
||||
profile = state == State.IMPORT ? getAppModeFromSettingsItems() : getAppMode();
|
||||
|
||||
int profileColor = profile.getIconColorInfo().getColor(nightMode);
|
||||
int colorNoAlpha = ContextCompat.getColor(context, profileColor);
|
||||
|
||||
Drawable backgroundIcon = UiUtilities.getColoredSelectableDrawable(context, colorNoAlpha, 0.3f);
|
||||
Drawable[] layers = {new ColorDrawable(UiUtilities.getColorWithAlpha(colorNoAlpha, 0.10f)), backgroundIcon};
|
||||
|
||||
items.add(new TitleItem(state == State.EXPORT ?
|
||||
getString(R.string.export_profile)
|
||||
: getString(R.string.import_profile)));
|
||||
|
||||
BaseBottomSheetItem profileItem = new BottomSheetItemWithCompoundButton.Builder()
|
||||
.setChecked(true)
|
||||
.setCompoundButtonColorId(profileColor)
|
||||
.setButtonTintList(ColorStateList.valueOf(getResolvedColor(profileColor)))
|
||||
.setDescription(BaseSettingsFragment.getAppModeDescription(context, profile))
|
||||
.setIcon(getIcon(profile.getIconRes(), profileColor))
|
||||
.setTitle(profile.toHumanString())
|
||||
.setBackground(new LayerDrawable(layers))
|
||||
.setLayoutId(R.layout.preference_profile_item_with_radio_btn)
|
||||
.create();
|
||||
items.add(profileItem);
|
||||
|
||||
if (state == State.IMPORT && containsAdditionalData || state == State.EXPORT && !dataList.isEmpty()) {
|
||||
BaseBottomSheetItem descriptionItem = new BottomSheetItemWithDescription.Builder()
|
||||
.setDescription(state == State.EXPORT ?
|
||||
getString(R.string.export_profile_dialog_description)
|
||||
: getString(R.string.import_profile_dialog_description))
|
||||
.setLayoutId(R.layout.bottom_sheet_item_pref_info)
|
||||
.create();
|
||||
items.add(descriptionItem);
|
||||
|
||||
final View additionalDataView = inflater.inflate(R.layout.bottom_sheet_item_additional_data, null);
|
||||
listView = additionalDataView.findViewById(R.id.list);
|
||||
SwitchCompat switchItem = additionalDataView.findViewById(R.id.switchItem);
|
||||
switchItem.setTextColor(getResources().getColor(nightMode ? R.color.active_color_primary_dark : R.color.active_color_primary_light));
|
||||
switchItem.setChecked(includeAdditionalData);
|
||||
switchItem.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
includeAdditionalData = !includeAdditionalData;
|
||||
listView.setVisibility(includeAdditionalData ?
|
||||
View.VISIBLE : View.GONE);
|
||||
if (includeAdditionalData && state == State.IMPORT) {
|
||||
updateDataToOperateFromSettingsItems();
|
||||
}
|
||||
setupHeightAndBackground(getView());
|
||||
}
|
||||
});
|
||||
listView.setVisibility(includeAdditionalData ? View.VISIBLE : View.GONE);
|
||||
adapter = new ProfileAdditionalDataAdapter(app, dataList, profileColor);
|
||||
listView.setOnGroupExpandListener(new ExpandableListView.OnGroupExpandListener() {
|
||||
@Override
|
||||
public void onGroupExpand(int i) {
|
||||
setupHeightAndBackground(getView());
|
||||
}
|
||||
});
|
||||
listView.setAdapter(adapter);
|
||||
final SimpleBottomSheetItem titleItem = (SimpleBottomSheetItem) new SimpleBottomSheetItem.Builder()
|
||||
.setCustomView(additionalDataView)
|
||||
.create();
|
||||
items.add(titleItem);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getRightBottomButtonTextId() {
|
||||
return state == State.EXPORT ? R.string.shared_string_export : R.string.shared_string_import;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRightBottomButtonClick() {
|
||||
super.onRightBottomButtonClick();
|
||||
if (state == State.EXPORT) {
|
||||
prepareFile();
|
||||
} else {
|
||||
importSettings();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getDismissButtonTextId() {
|
||||
return R.string.shared_string_cancel;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean useScrollableItemsContainer() {
|
||||
return false;
|
||||
}
|
||||
|
||||
private ApplicationMode getAppModeFromSettingsItems() {
|
||||
for (SettingsHelper.SettingsItem item : settingsItems) {
|
||||
if (item.getType().equals(SettingsHelper.SettingsItemType.PROFILE)) {
|
||||
profileSettingsItem = ((SettingsHelper.ProfileSettingsItem) item);
|
||||
return ((SettingsHelper.ProfileSettingsItem) item).getAppMode();
|
||||
}
|
||||
}
|
||||
return getAppMode();
|
||||
}
|
||||
|
||||
private List<AdditionalDataWrapper> getAdditionalData() {
|
||||
List<AdditionalDataWrapper> dataList = new ArrayList<>();
|
||||
|
||||
QuickActionFactory factory = new QuickActionFactory();
|
||||
List<QuickAction> actionsList = factory.parseActiveActionsList(app.getSettings().QUICK_ACTION_LIST.get());
|
||||
if (!actionsList.isEmpty()) {
|
||||
dataList.add(new AdditionalDataWrapper(
|
||||
AdditionalDataWrapper.Type.QUICK_ACTIONS, actionsList));
|
||||
}
|
||||
|
||||
List<PoiUIFilter> poiList = app.getPoiFilters().getUserDefinedPoiFilters(false);
|
||||
if (!poiList.isEmpty()) {
|
||||
dataList.add(new AdditionalDataWrapper(
|
||||
AdditionalDataWrapper.Type.POI_TYPES,
|
||||
poiList
|
||||
));
|
||||
}
|
||||
|
||||
List<ITileSource> iTileSources = new ArrayList<>();
|
||||
final LinkedHashMap<String, String> tileSourceEntries = new LinkedHashMap<>(app.getSettings().getTileSourceEntries(true));
|
||||
for (Map.Entry<String, String> entry : tileSourceEntries.entrySet()) {
|
||||
File f = app.getAppPath(IndexConstants.TILES_INDEX_DIR + entry.getKey());
|
||||
if (f != null) {
|
||||
ITileSource template;
|
||||
if (f.getName().endsWith(SQLiteTileSource.EXT)) {
|
||||
template = new SQLiteTileSource(app, f, TileSourceManager.getKnownSourceTemplates());
|
||||
} else {
|
||||
template = TileSourceManager.createTileSourceTemplate(f);
|
||||
}
|
||||
if (template != null && template.getUrlTemplate() != null) {
|
||||
iTileSources.add(template);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!iTileSources.isEmpty()) {
|
||||
dataList.add(new AdditionalDataWrapper(
|
||||
AdditionalDataWrapper.Type.MAP_SOURCES,
|
||||
iTileSources
|
||||
));
|
||||
}
|
||||
|
||||
Map<String, File> externalRenderers = app.getRendererRegistry().getExternalRenderers();
|
||||
if (!externalRenderers.isEmpty()) {
|
||||
dataList.add(new AdditionalDataWrapper(
|
||||
AdditionalDataWrapper.Type.CUSTOM_RENDER_STYLE,
|
||||
new ArrayList<>(externalRenderers.values())
|
||||
));
|
||||
}
|
||||
|
||||
File routingProfilesFolder = app.getAppPath(IndexConstants.ROUTING_PROFILES_DIR);
|
||||
if (routingProfilesFolder.exists() && routingProfilesFolder.isDirectory()) {
|
||||
File[] fl = routingProfilesFolder.listFiles();
|
||||
if (fl != null && fl.length > 0) {
|
||||
dataList.add(new AdditionalDataWrapper(
|
||||
AdditionalDataWrapper.Type.CUSTOM_ROUTING,
|
||||
Arrays.asList(fl)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
return dataList;
|
||||
}
|
||||
|
||||
private List<SettingsHelper.SettingsItem> prepareSettingsItemsForExport() {
|
||||
List<SettingsHelper.SettingsItem> settingsItems = new ArrayList<>();
|
||||
settingsItems.add(new SettingsHelper.ProfileSettingsItem(app.getSettings(), profile));
|
||||
if (includeAdditionalData) {
|
||||
settingsItems.addAll(prepareAdditionalSettingsItems());
|
||||
}
|
||||
return settingsItems;
|
||||
}
|
||||
|
||||
private List<SettingsHelper.SettingsItem> prepareAdditionalSettingsItems() {
|
||||
List<SettingsHelper.SettingsItem> settingsItems = new ArrayList<>();
|
||||
List<QuickAction> quickActions = new ArrayList<>();
|
||||
List<PoiUIFilter> poiUIFilters = new ArrayList<>();
|
||||
List<ITileSource> tileSourceTemplates = new ArrayList<>();
|
||||
for (Object object : dataToOperate) {
|
||||
if (object instanceof QuickAction) {
|
||||
quickActions.add((QuickAction) object);
|
||||
} else if (object instanceof PoiUIFilter) {
|
||||
poiUIFilters.add((PoiUIFilter) object);
|
||||
} else if (object instanceof TileSourceManager.TileSourceTemplate
|
||||
|| object instanceof SQLiteTileSource) {
|
||||
tileSourceTemplates.add((ITileSource) object);
|
||||
} else if (object instanceof File) {
|
||||
settingsItems.add(new SettingsHelper.FileSettingsItem(app, (File) object));
|
||||
}
|
||||
}
|
||||
if (!quickActions.isEmpty()) {
|
||||
settingsItems.add(new SettingsHelper.QuickActionSettingsItem(app, quickActions));
|
||||
}
|
||||
if (!poiUIFilters.isEmpty()) {
|
||||
settingsItems.add(new SettingsHelper.PoiUiFilterSettingsItem(app, poiUIFilters));
|
||||
}
|
||||
if (!tileSourceTemplates.isEmpty()) {
|
||||
settingsItems.add(new SettingsHelper.MapSourcesSettingsItem(app, tileSourceTemplates));
|
||||
}
|
||||
return settingsItems;
|
||||
}
|
||||
|
||||
private Boolean checkAdditionalDataContains() {
|
||||
boolean containsData = false;
|
||||
for (SettingsHelper.SettingsItem item : settingsItems) {
|
||||
containsData = item.getType().equals(SettingsHelper.SettingsItemType.QUICK_ACTION)
|
||||
|| item.getType().equals(SettingsHelper.SettingsItemType.POI_UI_FILTERS)
|
||||
|| item.getType().equals(SettingsHelper.SettingsItemType.MAP_SOURCES)
|
||||
|| item.getType().equals(SettingsHelper.SettingsItemType.FILE);
|
||||
if (containsData) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return containsData;
|
||||
}
|
||||
|
||||
private void updateDataToOperateFromSettingsItems() {
|
||||
List<AdditionalDataWrapper> dataList = new ArrayList<>();
|
||||
List<QuickAction> quickActions = new ArrayList<>();
|
||||
List<PoiUIFilter> poiUIFilters = new ArrayList<>();
|
||||
List<ITileSource> tileSourceTemplates = new ArrayList<>();
|
||||
List<File> routingFilesList = new ArrayList<>();
|
||||
List<File> renderFilesList = new ArrayList<>();
|
||||
|
||||
for (SettingsHelper.SettingsItem item : settingsItems) {
|
||||
if (item.getType().equals(SettingsHelper.SettingsItemType.QUICK_ACTION)) {
|
||||
quickActions.addAll(((SettingsHelper.QuickActionSettingsItem) item).getQuickActions());
|
||||
} else if (item.getType().equals(SettingsHelper.SettingsItemType.POI_UI_FILTERS)) {
|
||||
poiUIFilters.addAll(((SettingsHelper.PoiUiFilterSettingsItem) item).getPoiUIFilters());
|
||||
} else if (item.getType().equals(SettingsHelper.SettingsItemType.MAP_SOURCES)) {
|
||||
tileSourceTemplates.addAll(((SettingsHelper.MapSourcesSettingsItem) item).getMapSources());
|
||||
} else if (item.getType().equals(SettingsHelper.SettingsItemType.FILE)) {
|
||||
if (item.getName().startsWith("/rendering/")) {
|
||||
renderFilesList.add(((SettingsHelper.FileSettingsItem) item).getFile());
|
||||
} else if (item.getName().startsWith("/routing/")) {
|
||||
routingFilesList.add(((SettingsHelper.FileSettingsItem) item).getFile());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!quickActions.isEmpty()) {
|
||||
dataList.add(new AdditionalDataWrapper(
|
||||
AdditionalDataWrapper.Type.QUICK_ACTIONS,
|
||||
quickActions));
|
||||
dataToOperate.addAll(quickActions);
|
||||
}
|
||||
if (!poiUIFilters.isEmpty()) {
|
||||
dataList.add(new AdditionalDataWrapper(
|
||||
AdditionalDataWrapper.Type.POI_TYPES,
|
||||
poiUIFilters));
|
||||
dataToOperate.addAll(poiUIFilters);
|
||||
}
|
||||
if (!tileSourceTemplates.isEmpty()) {
|
||||
dataList.add(new AdditionalDataWrapper(
|
||||
AdditionalDataWrapper.Type.MAP_SOURCES,
|
||||
tileSourceTemplates
|
||||
));
|
||||
dataToOperate.addAll(tileSourceTemplates);
|
||||
}
|
||||
if (!renderFilesList.isEmpty()) {
|
||||
dataList.add(new AdditionalDataWrapper(
|
||||
AdditionalDataWrapper.Type.CUSTOM_RENDER_STYLE,
|
||||
renderFilesList
|
||||
));
|
||||
dataToOperate.addAll(renderFilesList);
|
||||
}
|
||||
if (!routingFilesList.isEmpty()) {
|
||||
dataList.add(new AdditionalDataWrapper(
|
||||
AdditionalDataWrapper.Type.CUSTOM_ROUTING,
|
||||
routingFilesList
|
||||
));
|
||||
dataToOperate.addAll(routingFilesList);
|
||||
}
|
||||
adapter.updateList(dataList);
|
||||
}
|
||||
|
||||
private void importSettings() {
|
||||
List<SettingsHelper.SettingsItem> list = new ArrayList<>();
|
||||
list.add(profileSettingsItem);
|
||||
if (includeAdditionalData) {
|
||||
list.addAll(prepareAdditionalSettingsItems());
|
||||
}
|
||||
app.getSettingsHelper().importSettings(file, list, "", 1, new SettingsHelper.SettingsImportListener() {
|
||||
@Override
|
||||
public void onSettingsImportFinished(boolean succeed, boolean empty, @NonNull List<SettingsHelper.SettingsItem> items) {
|
||||
if (succeed) {
|
||||
app.showShortToastMessage(app.getString(R.string.file_imported_successfully, file.getName()));
|
||||
} else if (empty) {
|
||||
app.showShortToastMessage(app.getString(R.string.file_import_error, file.getName(), app.getString(R.string.shared_string_unexpected_error)));
|
||||
}
|
||||
}
|
||||
});
|
||||
dismiss();
|
||||
}
|
||||
|
||||
private void prepareFile() {
|
||||
if (app != null) {
|
||||
File tempDir = app.getAppPath(IndexConstants.TEMP_DIR);
|
||||
if (!tempDir.exists()) {
|
||||
tempDir.mkdirs();
|
||||
}
|
||||
String fileName = profile.toHumanString();
|
||||
app.getSettingsHelper().exportSettings(tempDir, fileName, new SettingsHelper.SettingsExportListener() {
|
||||
@Override
|
||||
public void onSettingsExportFinished(@NonNull File file, boolean succeed) {
|
||||
if (succeed) {
|
||||
shareProfile(file, profile);
|
||||
} else {
|
||||
app.showToastMessage(R.string.export_profile_failed);
|
||||
}
|
||||
}
|
||||
}, prepareSettingsItemsForExport());
|
||||
}
|
||||
}
|
||||
|
||||
private void shareProfile(@NonNull File file, @NonNull ApplicationMode profile) {
|
||||
try {
|
||||
final Intent sendIntent = new Intent();
|
||||
sendIntent.setAction(Intent.ACTION_SEND);
|
||||
sendIntent.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.exported_osmand_profile, profile.toHumanString()));
|
||||
sendIntent.putExtra(Intent.EXTRA_STREAM, AndroidUtils.getUriForFile(getMyApplication(), file));
|
||||
sendIntent.setType("*/*");
|
||||
sendIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
startActivity(sendIntent);
|
||||
dismiss();
|
||||
} catch (Exception e) {
|
||||
Toast.makeText(requireContext(), R.string.export_profile_failed, Toast.LENGTH_SHORT).show();
|
||||
LOG.error("Share profile error", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean showInstance(@NonNull FragmentManager fragmentManager,
|
||||
State state,
|
||||
Fragment target,
|
||||
@NonNull ApplicationMode appMode) {
|
||||
try {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putSerializable(STATE_KEY, state);
|
||||
ExportImportProfileBottomSheet fragment = new ExportImportProfileBottomSheet();
|
||||
fragment.setArguments(bundle);
|
||||
fragment.setAppMode(appMode);
|
||||
fragment.setTargetFragment(target, 0);
|
||||
fragment.show(fragmentManager, TAG);
|
||||
return true;
|
||||
} catch (RuntimeException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean showInstance(@NonNull FragmentManager fragmentManager,
|
||||
State state,
|
||||
File file,
|
||||
List<SettingsHelper.SettingsItem> items) {
|
||||
try {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putSerializable(STATE_KEY, state);
|
||||
ExportImportProfileBottomSheet fragment = new ExportImportProfileBottomSheet();
|
||||
fragment.setArguments(bundle);
|
||||
fragment.setSettingsItems(items);
|
||||
fragment.setFile(file);
|
||||
fragment.show(fragmentManager, TAG);
|
||||
return true;
|
||||
} catch (RuntimeException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void setSettingsItems(List<SettingsHelper.SettingsItem> settingsItems) {
|
||||
this.settingsItems = settingsItems;
|
||||
}
|
||||
|
||||
public File getFile() {
|
||||
return file;
|
||||
}
|
||||
|
||||
public void setFile(File file) {
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
public enum State {
|
||||
EXPORT,
|
||||
IMPORT
|
||||
}
|
||||
|
||||
class ProfileAdditionalDataAdapter extends OsmandBaseExpandableListAdapter {
|
||||
|
||||
private OsmandApplication app;
|
||||
|
||||
private List<AdditionalDataWrapper> list;
|
||||
|
||||
private int profileColor;
|
||||
|
||||
ProfileAdditionalDataAdapter(OsmandApplication app, List<AdditionalDataWrapper> list, int profileColor) {
|
||||
this.app = app;
|
||||
this.list = list;
|
||||
this.profileColor = profileColor;
|
||||
}
|
||||
|
||||
public void updateList(List<AdditionalDataWrapper> list) {
|
||||
this.list = list;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getGroupCount() {
|
||||
return list.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getChildrenCount(int i) {
|
||||
return list.get(i).getItems().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getGroup(int i) {
|
||||
return list.get(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getChild(int groupPosition, int childPosition) {
|
||||
return list.get(groupPosition).getItems().get(childPosition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getGroupId(int i) {
|
||||
return i;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getChildId(int groupPosition, int childPosition) {
|
||||
return groupPosition * 10000 + childPosition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasStableIds() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
|
||||
View group = convertView;
|
||||
if (group == null) {
|
||||
LayoutInflater inflater = UiUtilities.getInflater(app, nightMode);
|
||||
group = inflater.inflate(R.layout.profile_data_list_item_group, parent, false);
|
||||
}
|
||||
|
||||
boolean isLastGroup = groupPosition == getGroupCount() - 1;
|
||||
final AdditionalDataWrapper.Type type = list.get(groupPosition).getType();
|
||||
|
||||
TextView titleTv = group.findViewById(R.id.title_tv);
|
||||
TextView subTextTv = group.findViewById(R.id.sub_text_tv);
|
||||
final CheckBox checkBox = group.findViewById(R.id.check_box);
|
||||
ImageView expandIv = group.findViewById(R.id.explist_indicator);
|
||||
View divider = group.findViewById(R.id.divider);
|
||||
|
||||
titleTv.setText(getGroupTitle(type));
|
||||
divider.setVisibility(isExpanded || isLastGroup ? View.GONE : View.VISIBLE);
|
||||
CompoundButtonCompat.setButtonTintList(checkBox, ColorStateList.valueOf(ContextCompat.getColor(app, profileColor)));
|
||||
|
||||
final List<?> listItems = list.get(groupPosition).getItems();
|
||||
subTextTv.setText(String.valueOf(listItems.size()));
|
||||
|
||||
checkBox.setChecked(dataToOperate.containsAll(listItems));
|
||||
checkBox.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
|
||||
if (checkBox.isChecked()) {
|
||||
for (Object object : listItems) {
|
||||
if (!dataToOperate.contains(object)) {
|
||||
dataToOperate.add(object);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
dataToOperate.removeAll(listItems);
|
||||
}
|
||||
notifyDataSetInvalidated();
|
||||
}
|
||||
});
|
||||
|
||||
adjustIndicator(app, groupPosition, isExpanded, group, true);
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getChildView(int groupPosition, final int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
|
||||
View child = convertView;
|
||||
if (child == null) {
|
||||
LayoutInflater inflater = UiUtilities.getInflater(app, nightMode);
|
||||
child = inflater.inflate(R.layout.profile_data_list_item_child, parent, false);
|
||||
}
|
||||
final Object currentItem = list.get(groupPosition).getItems().get(childPosition);
|
||||
|
||||
|
||||
boolean isLastGroup = groupPosition == getGroupCount() - 1;
|
||||
final AdditionalDataWrapper.Type type = list.get(groupPosition).getType();
|
||||
|
||||
TextView title = child.findViewById(R.id.title_tv);
|
||||
final CheckBox checkBox = child.findViewById(R.id.check_box);
|
||||
ImageView icon = child.findViewById(R.id.icon);
|
||||
View divider = child.findViewById(R.id.divider);
|
||||
|
||||
divider.setVisibility(isLastChild && !isLastGroup ? View.VISIBLE : View.GONE);
|
||||
CompoundButtonCompat.setButtonTintList(checkBox, ColorStateList.valueOf(ContextCompat.getColor(app, profileColor)));
|
||||
|
||||
checkBox.setChecked(dataToOperate.contains(currentItem));
|
||||
checkBox.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
if (checkBox.isChecked()) {
|
||||
dataToOperate.add(currentItem);
|
||||
} else {
|
||||
dataToOperate.remove(currentItem);
|
||||
}
|
||||
notifyDataSetInvalidated();
|
||||
}
|
||||
});
|
||||
|
||||
switch (type) {
|
||||
case QUICK_ACTIONS:
|
||||
title.setText(((QuickAction) currentItem).getName(app.getApplicationContext()));
|
||||
icon.setVisibility(View.INVISIBLE);
|
||||
icon.setImageResource(R.drawable.ic_action_info_dark);
|
||||
break;
|
||||
case POI_TYPES:
|
||||
title.setText(((PoiUIFilter) currentItem).getName());
|
||||
icon.setVisibility(View.VISIBLE);
|
||||
int iconRes = RenderingIcons.getBigIconResourceId(((PoiUIFilter) currentItem).getIconId());
|
||||
icon.setImageDrawable(app.getUIUtilities().getIcon(iconRes != 0 ? iconRes : R.drawable.ic_person, profileColor));
|
||||
break;
|
||||
case MAP_SOURCES:
|
||||
title.setText(((ITileSource) currentItem).getName());
|
||||
icon.setVisibility(View.INVISIBLE);
|
||||
icon.setImageResource(R.drawable.ic_action_info_dark);
|
||||
break;
|
||||
case CUSTOM_RENDER_STYLE:
|
||||
String renderName = ((File) currentItem).getName();
|
||||
renderName = renderName.replace('_', ' ').replaceAll(".render.xml", "");
|
||||
title.setText(renderName);
|
||||
icon.setVisibility(View.INVISIBLE);
|
||||
icon.setImageResource(R.drawable.ic_action_info_dark);
|
||||
break;
|
||||
case CUSTOM_ROUTING:
|
||||
String routingName = ((File) currentItem).getName();
|
||||
routingName = routingName.replace('_', ' ').replaceAll(".xml", "");
|
||||
title.setText(routingName);
|
||||
icon.setVisibility(View.INVISIBLE);
|
||||
icon.setImageResource(R.drawable.ic_action_info_dark);
|
||||
break;
|
||||
default:
|
||||
return child;
|
||||
}
|
||||
return child;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChildSelectable(int i, int i1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
private int getGroupTitle(AdditionalDataWrapper.Type type) {
|
||||
switch (type) {
|
||||
case QUICK_ACTIONS:
|
||||
return R.string.configure_screen_quick_action;
|
||||
case POI_TYPES:
|
||||
return R.string.poi_dialog_poi_type;
|
||||
case MAP_SOURCES:
|
||||
return R.string.quick_action_map_source_title;
|
||||
case CUSTOM_RENDER_STYLE:
|
||||
return R.string.shared_string_custom_rendering_style;
|
||||
case CUSTOM_ROUTING:
|
||||
return R.string.shared_string_routing;
|
||||
default:
|
||||
return R.string.access_empty_list;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -41,7 +41,7 @@ public class QuickAction {
|
|||
this.type = type;
|
||||
}
|
||||
|
||||
protected QuickAction(int type) {
|
||||
public QuickAction(int type) {
|
||||
this.id = System.currentTimeMillis();
|
||||
this.type = type;
|
||||
this.nameRes = QuickActionFactory.getActionName(type);
|
||||
|
|
|
@ -343,4 +343,8 @@ public class RendererRegistry {
|
|||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Map<String, File> getExternalRenderers() {
|
||||
return externalRenderers;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@ import net.osmand.plus.activities.MapActivity;
|
|||
import net.osmand.plus.helpers.AndroidUiHelper;
|
||||
import net.osmand.plus.helpers.FontCache;
|
||||
import net.osmand.plus.openseamapsplugin.NauticalMapsPlugin;
|
||||
import net.osmand.plus.profiles.ExportImportProfileBottomSheet;
|
||||
import net.osmand.plus.profiles.SelectCopyAppModeBottomSheet;
|
||||
import net.osmand.plus.profiles.SelectCopyAppModeBottomSheet.CopyAppModePrefsListener;
|
||||
import net.osmand.plus.settings.bottomsheets.ResetProfilePrefsBottomSheet;
|
||||
|
@ -395,23 +396,14 @@ public class ConfigureProfileFragment extends BaseSettingsFragment implements Co
|
|||
ResetProfilePrefsBottomSheet.showInstance(fragmentManager, prefId, this, false, getSelectedAppMode());
|
||||
}
|
||||
} else if (EXPORT_PROFILE.equals(prefId)) {
|
||||
Context ctx = requireContext();
|
||||
final ApplicationMode profile = getSelectedAppMode();
|
||||
File tempDir = app.getAppPath(IndexConstants.TEMP_DIR);
|
||||
if (!tempDir.exists()) {
|
||||
tempDir.mkdirs();
|
||||
FragmentManager fragmentManager = getFragmentManager();
|
||||
if (fragmentManager != null) {
|
||||
ExportImportProfileBottomSheet.showInstance(
|
||||
fragmentManager,
|
||||
ExportImportProfileBottomSheet.State.EXPORT,
|
||||
this,
|
||||
getSelectedAppMode());
|
||||
}
|
||||
String fileName = profile.toHumanString();
|
||||
app.getSettingsHelper().exportSettings(tempDir, fileName, new SettingsHelper.SettingsExportListener() {
|
||||
@Override
|
||||
public void onSettingsExportFinished(@NonNull File file, boolean succeed) {
|
||||
if (succeed) {
|
||||
shareProfile(file, profile);
|
||||
} else {
|
||||
app.showToastMessage(R.string.export_profile_failed);
|
||||
}
|
||||
}
|
||||
}, new ProfileSettingsItem(app.getSettings(), profile));
|
||||
} else if (DELETE_PROFILE.equals(prefId)) {
|
||||
onDeleteProfileClick();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue