Merge branch 'master' into color-pic
# Conflicts: # OsmAnd/res/values/strings.xml
This commit is contained in:
commit
7ca460fb80
46 changed files with 1062 additions and 298 deletions
448
OsmAnd-java/src/main/java/net/osmand/router/RouteColorize.java
Normal file
448
OsmAnd-java/src/main/java/net/osmand/router/RouteColorize.java
Normal file
|
@ -0,0 +1,448 @@
|
|||
package net.osmand.router;
|
||||
|
||||
import net.osmand.GPXUtilities;
|
||||
import net.osmand.PlatformUtil;
|
||||
import net.osmand.osm.edit.Node;
|
||||
import net.osmand.osm.edit.OsmMapUtils;
|
||||
import net.osmand.util.MapUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class RouteColorize {
|
||||
|
||||
public int zoom;
|
||||
public double[] latitudes;
|
||||
public double[] longitudes;
|
||||
public double[] values;
|
||||
public double minValue;
|
||||
public double maxValue;
|
||||
public double[][] palette;
|
||||
|
||||
private List<RouteColorizationPoint> dataList;
|
||||
|
||||
public static final int DARK_GREY = rgbaToDecimal(92, 92, 92, 255);
|
||||
public static final int LIGHT_GREY = rgbaToDecimal(200, 200, 200, 255);
|
||||
public static final int RED = rgbaToDecimal(255,1,1,255);
|
||||
public static final int GREEN = rgbaToDecimal(46,185,0,191);
|
||||
public static final int YELLOW = rgbaToDecimal(255,222,2,227);
|
||||
|
||||
public enum ValueType {
|
||||
ELEVATION,
|
||||
SPEED,
|
||||
SLOPE,
|
||||
NONE
|
||||
}
|
||||
|
||||
private final int VALUE_INDEX = 0;
|
||||
private final int DECIMAL_COLOR_INDEX = 1;//sRGB decimal format
|
||||
private final int RED_COLOR_INDEX = 1;//RGB
|
||||
private final int GREEN_COLOR_INDEX = 2;//RGB
|
||||
private final int BLUE_COLOR_INDEX = 3;//RGB
|
||||
private final int ALPHA_COLOR_INDEX = 4;//RGBA
|
||||
|
||||
private ValueType valueType;
|
||||
|
||||
public static int SLOPE_RANGE = 150;//150 meters
|
||||
private static final double MIN_DIFFERENCE_SLOPE = 0.05d;//5%
|
||||
|
||||
private static final Log LOG = PlatformUtil.getLog(RouteColorize.class);
|
||||
|
||||
/**
|
||||
* @param minValue can be NaN
|
||||
* @param maxValue can be NaN
|
||||
* @param palette array {{value,color},...} - color in sRGB (decimal) format OR {{value,RED,GREEN,BLUE,ALPHA},...} - color in RGBA format
|
||||
*/
|
||||
public RouteColorize(int zoom, double[] latitudes, double[] longitudes, double[] values, double minValue, double maxValue, double[][] palette) {
|
||||
this.zoom = zoom;
|
||||
this.latitudes = latitudes;
|
||||
this.longitudes = longitudes;
|
||||
this.values = values;
|
||||
this.minValue = minValue;
|
||||
this.maxValue = maxValue;
|
||||
this.palette = palette;
|
||||
|
||||
if (Double.isNaN(minValue) || Double.isNaN(maxValue)) {
|
||||
calculateMinMaxValue();
|
||||
}
|
||||
checkPalette();
|
||||
sortPalette();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param type ELEVATION, SPEED, SLOPE
|
||||
*/
|
||||
public RouteColorize(int zoom, GPXUtilities.GPXFile gpxFile, ValueType type) {
|
||||
|
||||
if (!gpxFile.hasTrkPt()) {
|
||||
LOG.warn("GPX file is not consist of track points");
|
||||
return;
|
||||
}
|
||||
|
||||
List<Double> latList = new ArrayList<>();
|
||||
List<Double> lonList = new ArrayList<>();
|
||||
List<Double> valList = new ArrayList<>();
|
||||
for (GPXUtilities.Track t : gpxFile.tracks) {
|
||||
for (GPXUtilities.TrkSegment ts : t.segments) {
|
||||
for (GPXUtilities.WptPt p : ts.points) {
|
||||
latList.add(p.lat);
|
||||
lonList.add(p.lon);
|
||||
if (type == ValueType.SPEED) {
|
||||
valList.add(p.speed);
|
||||
} else {
|
||||
valList.add(p.ele);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.zoom = zoom;
|
||||
latitudes = listToArray(latList);
|
||||
longitudes = listToArray(lonList);
|
||||
|
||||
if (type == ValueType.SLOPE) {
|
||||
values = calculateSlopesByElevations(latitudes, longitudes, listToArray(valList), SLOPE_RANGE);
|
||||
} else {
|
||||
values = listToArray(valList);
|
||||
}
|
||||
|
||||
calculateMinMaxValue();
|
||||
valueType = type;
|
||||
checkPalette();
|
||||
sortPalette();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate slopes from elevations needs for right colorizing
|
||||
*
|
||||
* @param slopeRange - in what range calculate the derivative, usually we used 150 meters
|
||||
* @return slopes array, in the begin and the end present NaN values!
|
||||
*/
|
||||
public double[] calculateSlopesByElevations(double[] latitudes, double[] longitudes, double[] elevations, double slopeRange) {
|
||||
|
||||
double[] newElevations = elevations;
|
||||
for (int i = 2; i < elevations.length - 2; i++) {
|
||||
newElevations[i] = elevations[i - 2]
|
||||
+ elevations[i - 1]
|
||||
+ elevations[i]
|
||||
+ elevations[i + 1]
|
||||
+ elevations[i + 2];
|
||||
newElevations[i] /= 5;
|
||||
}
|
||||
elevations = newElevations;
|
||||
|
||||
double[] slopes = new double[elevations.length];
|
||||
if (latitudes.length != longitudes.length || latitudes.length != elevations.length) {
|
||||
LOG.warn("Sizes of arrays latitudes, longitudes and values are not match");
|
||||
return slopes;
|
||||
}
|
||||
|
||||
double[] distances = new double[elevations.length];
|
||||
double totalDistance = 0.0d;
|
||||
distances[0] = totalDistance;
|
||||
for (int i = 0; i < elevations.length - 1; i++) {
|
||||
totalDistance += MapUtils.getDistance(latitudes[i], longitudes[i], latitudes[i + 1], longitudes[i + 1]);
|
||||
distances[i + 1] = totalDistance;
|
||||
}
|
||||
|
||||
for (int i = 0; i < elevations.length; i++) {
|
||||
if (distances[i] < slopeRange / 2 || distances[i] > totalDistance - slopeRange / 2) {
|
||||
slopes[i] = Double.NaN;
|
||||
} else {
|
||||
double[] arg = findDerivativeArguments(distances, elevations, i, slopeRange);
|
||||
slopes[i] = (arg[1] - arg[0]) / (arg[3] - arg[2]);
|
||||
}
|
||||
}
|
||||
return slopes;
|
||||
}
|
||||
|
||||
public List<RouteColorizationPoint> getResult(boolean simplify) {
|
||||
List<RouteColorizationPoint> result = new ArrayList<>();
|
||||
if (simplify) {
|
||||
result = simplify();
|
||||
} else {
|
||||
for (int i = 0; i < latitudes.length; i++) {
|
||||
result.add(new RouteColorizationPoint(i, latitudes[i], longitudes[i], values[i]));
|
||||
}
|
||||
}
|
||||
for (RouteColorizationPoint data : result) {
|
||||
data.color = getColorByValue(data.val);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public int getColorByValue(double value) {
|
||||
if (Double.isNaN(value)) {
|
||||
value = (minValue + maxValue) / 2;
|
||||
}
|
||||
for (int i = 0; i < palette.length - 1; i++) {
|
||||
if (value == palette[i][VALUE_INDEX])
|
||||
return (int) palette[i][DECIMAL_COLOR_INDEX];
|
||||
if (value >= palette[i][VALUE_INDEX] && value <= palette[i + 1][VALUE_INDEX]) {
|
||||
int minPaletteColor = (int) palette[i][DECIMAL_COLOR_INDEX];
|
||||
int maxPaletteColor = (int) palette[i + 1][DECIMAL_COLOR_INDEX];
|
||||
double minPaletteValue = palette[i][VALUE_INDEX];
|
||||
double maxPaletteValue = palette[i + 1][VALUE_INDEX];
|
||||
double percent = (value - minPaletteValue) / (maxPaletteValue - minPaletteValue);
|
||||
double resultRed = getRed(minPaletteColor) + percent * (getRed(maxPaletteColor) - getRed(minPaletteColor));
|
||||
double resultGreen = getGreen(minPaletteColor) + percent * (getGreen(maxPaletteColor) - getGreen(minPaletteColor));
|
||||
double resultBlue = getBlue(minPaletteColor) + percent * (getBlue(maxPaletteColor) - getBlue(minPaletteColor));
|
||||
double resultAlpha = getAlpha(minPaletteColor) + percent * (getAlpha(maxPaletteColor) - getAlpha(minPaletteColor));
|
||||
return rgbaToDecimal((int) resultRed, (int) resultGreen, (int) resultBlue, (int) resultAlpha);
|
||||
}
|
||||
}
|
||||
return getDefaultColor();
|
||||
}
|
||||
|
||||
public void setPalette(double[][] palette) {
|
||||
this.palette = palette;
|
||||
checkPalette();
|
||||
sortPalette();
|
||||
}
|
||||
|
||||
private int getDefaultColor() {
|
||||
return rgbaToDecimal(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
private List<RouteColorizationPoint> simplify() {
|
||||
if (dataList == null) {
|
||||
dataList = new ArrayList<>();
|
||||
for (int i = 0; i < latitudes.length; i++) {
|
||||
//System.out.println(latitudes[i] + " " + longitudes[i] + " " + values[i]);
|
||||
dataList.add(new RouteColorizationPoint(i, latitudes[i], longitudes[i], values[i]));
|
||||
}
|
||||
}
|
||||
List<Node> nodes = new ArrayList<>();
|
||||
List<Node> result = new ArrayList<>();
|
||||
for (RouteColorizationPoint data : dataList) {
|
||||
nodes.add(new net.osmand.osm.edit.Node(data.lat, data.lon, data.id));
|
||||
}
|
||||
OsmMapUtils.simplifyDouglasPeucker(nodes, zoom + 5, 1, result, true);
|
||||
|
||||
List<RouteColorizationPoint> simplified = new ArrayList<>();
|
||||
|
||||
for (int i = 1; i < result.size() - 1; i++) {
|
||||
int prevId = (int) result.get(i - 1).getId();
|
||||
int currentId = (int) result.get(i).getId();
|
||||
List<RouteColorizationPoint> sublist = dataList.subList(prevId, currentId);
|
||||
simplified.addAll(getExtremums(sublist));
|
||||
}
|
||||
return simplified;
|
||||
}
|
||||
|
||||
private List<RouteColorizationPoint> getExtremums(List<RouteColorizationPoint> subDataList) {
|
||||
if (subDataList.size() <= 2) {
|
||||
return subDataList;
|
||||
}
|
||||
|
||||
List<RouteColorizationPoint> result = new ArrayList<>();
|
||||
double min;
|
||||
double max;
|
||||
min = max = subDataList.get(0).val;
|
||||
for (RouteColorizationPoint pt : subDataList) {
|
||||
if (min > pt.val) {
|
||||
min = pt.val;
|
||||
}
|
||||
if (max < pt.val) {
|
||||
max = pt.val;
|
||||
}
|
||||
}
|
||||
|
||||
double diff = max - min;
|
||||
|
||||
result.add(subDataList.get(0));
|
||||
for (int i = 1; i < subDataList.size() - 1; i++) {
|
||||
double prev = subDataList.get(i - 1).val;
|
||||
double current = subDataList.get(i).val;
|
||||
double next = subDataList.get(i + 1).val;
|
||||
RouteColorizationPoint currentData = subDataList.get(i);
|
||||
|
||||
if ((current > prev && current > next) || (current < prev && current < next)
|
||||
|| (current < prev && current == next) || (current == prev && current < next)
|
||||
|| (current > prev && current == next) || (current == prev && current > next)) {
|
||||
RouteColorizationPoint prevInResult;
|
||||
if (result.size() > 0) {
|
||||
prevInResult = result.get(0);
|
||||
if (prevInResult.val / diff > MIN_DIFFERENCE_SLOPE) {
|
||||
result.add(currentData);
|
||||
}
|
||||
} else
|
||||
result.add(currentData);
|
||||
}
|
||||
}
|
||||
result.add(subDataList.get(subDataList.size() - 1));
|
||||
return result;
|
||||
}
|
||||
|
||||
private void checkPalette() {
|
||||
if (palette == null || palette.length < 2 || palette[0].length < 2 || palette[1].length < 2) {
|
||||
LOG.info("Will use default palette");
|
||||
palette = new double[3][2];
|
||||
|
||||
double[][] defaultPalette = {
|
||||
{minValue, GREEN},
|
||||
{valueType == ValueType.SLOPE ? 0 : (minValue + maxValue) / 2, YELLOW},
|
||||
{maxValue, RED}
|
||||
};
|
||||
palette = defaultPalette;
|
||||
}
|
||||
double min;
|
||||
double max = min = palette[0][VALUE_INDEX];
|
||||
int minIndex = 0;
|
||||
int maxIndex = 0;
|
||||
double[][] sRGBPalette = new double[palette.length][2];
|
||||
for (int i = 0; i < palette.length; i++) {
|
||||
double[] p = palette[i];
|
||||
if (p.length == 2) {
|
||||
sRGBPalette[i] = p;
|
||||
} else if (p.length == 4) {
|
||||
int color = rgbaToDecimal((int) p[RED_COLOR_INDEX], (int) p[GREEN_COLOR_INDEX], (int) p[BLUE_COLOR_INDEX], 255);
|
||||
sRGBPalette[i] = new double[]{p[VALUE_INDEX], color};
|
||||
} else if (p.length >= 5) {
|
||||
int color = rgbaToDecimal((int) p[RED_COLOR_INDEX], (int) p[GREEN_COLOR_INDEX], (int) p[BLUE_COLOR_INDEX], (int) p[ALPHA_COLOR_INDEX]);
|
||||
sRGBPalette[i] = new double[]{p[VALUE_INDEX], color};
|
||||
}
|
||||
if (p[VALUE_INDEX] > max) {
|
||||
max = p[VALUE_INDEX];
|
||||
maxIndex = i;
|
||||
}
|
||||
if (p[VALUE_INDEX] < min) {
|
||||
min = p[VALUE_INDEX];
|
||||
minIndex = i;
|
||||
}
|
||||
}
|
||||
palette = sRGBPalette;
|
||||
if (minValue < min) {
|
||||
palette[minIndex][VALUE_INDEX] = minValue;
|
||||
}
|
||||
if (maxValue > max) {
|
||||
palette[maxIndex][VALUE_INDEX] = maxValue;
|
||||
}
|
||||
}
|
||||
|
||||
private void sortPalette() {
|
||||
java.util.Arrays.sort(palette, new java.util.Comparator<double[]>() {
|
||||
public int compare(double[] a, double[] b) {
|
||||
return Double.compare(a[VALUE_INDEX], b[VALUE_INDEX]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @return double[minElevation, maxElevation, minDist, maxDist]
|
||||
*/
|
||||
private double[] findDerivativeArguments(double[] distances, double[] elevations, int index, double slopeRange) {
|
||||
double[] result = new double[4];
|
||||
double minDist = distances[index] - slopeRange / 2;
|
||||
double maxDist = distances[index] + slopeRange / 2;
|
||||
result[0] = Double.NaN;
|
||||
result[1] = Double.NaN;
|
||||
result[2] = minDist;
|
||||
result[3] = maxDist;
|
||||
int closestMaxIndex = -1;
|
||||
int closestMinIndex = -1;
|
||||
for (int i = index; i < distances.length; i++) {
|
||||
if (distances[i] == maxDist) {
|
||||
result[1] = elevations[i];
|
||||
break;
|
||||
}
|
||||
if (distances[i] > maxDist) {
|
||||
closestMaxIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (int i = index; i >= 0; i--) {
|
||||
if (distances[i] == minDist) {
|
||||
result[0] = elevations[i];
|
||||
break;
|
||||
}
|
||||
if (distances[i] < minDist) {
|
||||
closestMinIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (closestMaxIndex > 0) {
|
||||
double diff = distances[closestMaxIndex] - distances[closestMaxIndex - 1];
|
||||
double coef = (maxDist - distances[closestMaxIndex - 1]) / diff;
|
||||
if (coef > 1 || coef < 0) {
|
||||
LOG.warn("Coefficient fo max must be 0..1 , coef=" + coef);
|
||||
}
|
||||
result[1] = (1 - coef) * elevations[closestMaxIndex - 1] + coef * elevations[closestMaxIndex];
|
||||
}
|
||||
if (closestMinIndex >= 0) {
|
||||
double diff = distances[closestMinIndex + 1] - distances[closestMinIndex];
|
||||
double coef = (minDist - distances[closestMinIndex]) / diff;
|
||||
if (coef > 1 || coef < 0) {
|
||||
LOG.warn("Coefficient for min must be 0..1 , coef=" + coef);
|
||||
}
|
||||
result[0] = (1 - coef) * elevations[closestMinIndex] + coef * elevations[closestMinIndex + 1];
|
||||
}
|
||||
if (Double.isNaN(result[0]) || Double.isNaN(result[1])) {
|
||||
LOG.warn("Elevations wasn't calculated");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void calculateMinMaxValue() {
|
||||
if (values.length == 0)
|
||||
return;
|
||||
minValue = maxValue = Double.NaN;
|
||||
for (double value : values) {
|
||||
if ((Double.isNaN(maxValue) || Double.isNaN(minValue)) && !Double.isNaN(value))
|
||||
maxValue = minValue = value;
|
||||
if (minValue > value)
|
||||
minValue = value;
|
||||
if (maxValue < value)
|
||||
maxValue = value;
|
||||
}
|
||||
}
|
||||
|
||||
private double[] listToArray(List<Double> doubleList) {
|
||||
double[] result = new double[doubleList.size()];
|
||||
for (int i = 0; i < doubleList.size(); i++) {
|
||||
result[i] = doubleList.get(i);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static int rgbaToDecimal(int r, int g, int b, int a) {
|
||||
int value = ((a & 0xFF) << 24) |
|
||||
((r & 0xFF) << 16) |
|
||||
((g & 0xFF) << 8) |
|
||||
((b & 0xFF) << 0);
|
||||
return value;
|
||||
}
|
||||
|
||||
private int getRed(int value) {
|
||||
return (value >> 16) & 0xFF;
|
||||
}
|
||||
|
||||
private int getGreen(int value) {
|
||||
return (value >> 8) & 0xFF;
|
||||
}
|
||||
|
||||
private int getBlue(int value) {
|
||||
return (value >> 0) & 0xFF;
|
||||
}
|
||||
|
||||
private int getAlpha(int value) {
|
||||
return (value >> 24) & 0xff;
|
||||
}
|
||||
|
||||
public static class RouteColorizationPoint {
|
||||
int id;
|
||||
public double lat;
|
||||
public double lon;
|
||||
public double val;
|
||||
public int color;
|
||||
|
||||
RouteColorizationPoint(int id, double lat, double lon, double val) {
|
||||
this.id = id;
|
||||
this.lat = lat;
|
||||
this.lon = lon;
|
||||
this.val = val;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -53,6 +53,8 @@ public class Algorithms {
|
|||
public static final int XML_FILE_SIGNATURE = 0x3c3f786d;
|
||||
public static final int OBF_FILE_SIGNATURE = 0x08029001;
|
||||
public static final int SQLITE_FILE_SIGNATURE = 0x53514C69;
|
||||
public static final int BZIP_FILE_SIGNATURE = 0x425a;
|
||||
public static final int GZIP_FILE_SIGNATURE = 0x1f8b;
|
||||
|
||||
public static String normalizeSearchText(String s) {
|
||||
boolean norm = false;
|
||||
|
@ -322,6 +324,24 @@ public class Algorithms {
|
|||
return test == ZIP_FILE_SIGNATURE;
|
||||
}
|
||||
|
||||
public static boolean checkFileSignature(InputStream inputStream, int fileSignature) throws IOException {
|
||||
if (inputStream == null) return false;
|
||||
int firstBytes;
|
||||
if (isSmallFileSignature(fileSignature)) {
|
||||
firstBytes = readSmallInt(inputStream);
|
||||
} else {
|
||||
firstBytes = readInt(inputStream);
|
||||
}
|
||||
if (inputStream.markSupported()) {
|
||||
inputStream.reset();
|
||||
}
|
||||
return firstBytes == fileSignature;
|
||||
}
|
||||
|
||||
public static boolean isSmallFileSignature(int fileSignature) {
|
||||
return fileSignature == BZIP_FILE_SIGNATURE || fileSignature == GZIP_FILE_SIGNATURE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks, whether the child directory is a subdirectory of the parent
|
||||
* directory.
|
||||
|
@ -358,6 +378,14 @@ public class Algorithms {
|
|||
return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + ch4);
|
||||
}
|
||||
|
||||
public static int readSmallInt(InputStream in) throws IOException {
|
||||
int ch1 = in.read();
|
||||
int ch2 = in.read();
|
||||
if ((ch1 | ch2) < 0)
|
||||
throw new EOFException();
|
||||
return ((ch1 << 8) + ch2);
|
||||
}
|
||||
|
||||
public static String capitalizeFirstLetterAndLowercase(String s) {
|
||||
if (s != null && s.length() > 1) {
|
||||
// not very efficient algorithm
|
||||
|
@ -537,6 +565,13 @@ public class Algorithms {
|
|||
}
|
||||
}
|
||||
|
||||
public static ByteArrayInputStream createByteArrayIS(InputStream in) throws IOException {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
streamCopy(in, out);
|
||||
in.close();
|
||||
return new ByteArrayInputStream(out.toByteArray());
|
||||
}
|
||||
|
||||
@SuppressWarnings("ResultOfMethodCallIgnored")
|
||||
public static void updateAllExistingImgTilesToOsmandFormat(File f) {
|
||||
if (f.isDirectory()) {
|
||||
|
|
|
@ -4,7 +4,7 @@ import android.annotation.SuppressLint
|
|||
import android.content.Context
|
||||
import android.hardware.*
|
||||
import android.location.Location
|
||||
import android.os.HandlerThread
|
||||
import android.os.Looper
|
||||
import android.util.Log
|
||||
import com.google.android.gms.location.*
|
||||
import net.osmand.PlatformUtil
|
||||
|
@ -43,7 +43,6 @@ class TelegramLocationProvider(private val app: TelegramApplication) : SensorEve
|
|||
var lastKnownLocation: net.osmand.Location? = null
|
||||
private set
|
||||
|
||||
private val locationUpdateHandlerThread = HandlerThread("LocationProviderUpdateHandlerThread")
|
||||
private var fusedLocationProviderClient: FusedLocationProviderClient? = null
|
||||
private val locationRequest = LocationRequest().apply {
|
||||
interval = 1000
|
||||
|
@ -82,10 +81,6 @@ class TelegramLocationProvider(private val app: TelegramApplication) : SensorEve
|
|||
fun updateCompassValue(value: Float)
|
||||
}
|
||||
|
||||
init {
|
||||
locationUpdateHandlerThread.start()
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
fun resumeAllUpdates() {
|
||||
if (AndroidUtils.isLocationPermissionAvailable(app) && fusedLocationProviderClient == null) {
|
||||
|
@ -94,7 +89,7 @@ class TelegramLocationProvider(private val app: TelegramApplication) : SensorEve
|
|||
|
||||
try {
|
||||
fusedLocationProviderClient?.requestLocationUpdates(
|
||||
locationRequest, locationCallback, locationUpdateHandlerThread.looper)
|
||||
locationRequest, locationCallback, Looper.myLooper())
|
||||
} catch (unlikely: SecurityException) {
|
||||
Log.d(PlatformUtil.TAG, "Lost location permissions. Couldn't request updates. $unlikely")
|
||||
}
|
||||
|
|
|
@ -38,7 +38,6 @@ class TelegramService : Service(), TelegramIncomingMessagesListener,
|
|||
private var updateWidgetHandler: Handler? = null
|
||||
private var updateWidgetThread = HandlerThread("WidgetUpdateServiceThread")
|
||||
|
||||
private var locationUpdateHandlerThread = HandlerThread("LocationUpdateServiceThread")
|
||||
// FusedLocationProviderClient - Main class for receiving location updates.
|
||||
private lateinit var fusedLocationProviderClient: FusedLocationProviderClient
|
||||
|
||||
|
@ -63,7 +62,6 @@ class TelegramService : Service(), TelegramIncomingMessagesListener,
|
|||
mHandlerThread.start()
|
||||
tracksHandlerThread.start()
|
||||
updateWidgetThread.start()
|
||||
locationUpdateHandlerThread.start()
|
||||
updateShareInfoHandler = Handler(mHandlerThread.looper)
|
||||
updateTracksHandler = Handler(tracksHandlerThread.looper)
|
||||
updateWidgetHandler = Handler(updateWidgetThread.looper)
|
||||
|
@ -168,7 +166,6 @@ class TelegramService : Service(), TelegramIncomingMessagesListener,
|
|||
tracksHandlerThread.quit()
|
||||
mHandlerThread.quit()
|
||||
updateWidgetThread.quit()
|
||||
locationUpdateHandlerThread.quit()
|
||||
app().showLocationHelper.addOrUpdateStatusWidget(-1, false)
|
||||
|
||||
usedBy = 0
|
||||
|
@ -201,7 +198,7 @@ class TelegramService : Service(), TelegramIncomingMessagesListener,
|
|||
// request location updates
|
||||
try {
|
||||
fusedLocationProviderClient.requestLocationUpdates(
|
||||
locationRequest, locationCallback, locationUpdateHandlerThread.looper)
|
||||
locationRequest, locationCallback, Looper.myLooper())
|
||||
} catch (unlikely: SecurityException) {
|
||||
Toast.makeText(this, R.string.no_location_permission, Toast.LENGTH_LONG).show()
|
||||
Log.d(PlatformUtil.TAG, "Lost location permissions. Couldn't request updates. $unlikely")
|
||||
|
|
|
@ -373,4 +373,5 @@ dependencies {
|
|||
}
|
||||
implementation 'com.jaredrummler:colorpicker:1.1.0'
|
||||
implementation 'org.bouncycastle:bcpkix-jdk15on:1.56'
|
||||
implementation 'com.google.android.play:core:1.9.1'
|
||||
}
|
|
@ -57,5 +57,5 @@ project.afterEvaluate {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.google.android.gms:play-services-location:17.1.0'
|
||||
implementation 'com.google.android.gms:play-services-location:18.0.0'
|
||||
}
|
||||
|
|
|
@ -187,22 +187,9 @@ dependencies {
|
|||
opengldebugImplementation "net.osmand:OsmAndCore_android:0.1-SNAPSHOT@aar"
|
||||
openglImplementation "net.osmand:OsmAndCore_androidNativeRelease:0.1-SNAPSHOT@aar"
|
||||
openglImplementation "net.osmand:OsmAndCore_android:0.1-SNAPSHOT@aar"
|
||||
implementation ("com.getkeepsafe.taptargetview:taptargetview:1.12.0"){
|
||||
exclude group: 'com.android.support'
|
||||
}
|
||||
implementation 'com.github.PhilJay:MPAndroidChart:v3.0.1'
|
||||
implementation ("com.github.HITGIF:TextFieldBoxes:1.4.5"){
|
||||
exclude group: 'com.android.support'
|
||||
}
|
||||
implementation('com.github.scribejava:scribejava-apis:7.1.1'){
|
||||
exclude group: "com.fasterxml.jackson.core"
|
||||
}
|
||||
implementation 'com.jaredrummler:colorpicker:1.1.0'
|
||||
implementation "org.bouncycastle:bcpkix-jdk15on:1.56"
|
||||
implementation 'com.google.android.play:core:1.9.1'
|
||||
|
||||
huaweiImplementation 'com.huawei.hms:iap:5.0.2.300'
|
||||
|
||||
gplayFreeImplementation 'com.google.android.gms:play-services-location:17.1.0'
|
||||
gplayFullImplementation 'com.google.android.gms:play-services-location:17.1.0'
|
||||
gplayFreeImplementation 'com.google.android.gms:play-services-location:18.0.0'
|
||||
gplayFullImplementation 'com.google.android.gms:play-services-location:18.0.0'
|
||||
}
|
||||
|
|
30
OsmAnd/res/drawable/ic_action_file_report.xml
Normal file
30
OsmAnd/res/drawable/ic_action_file_report.xml
Normal file
|
@ -0,0 +1,30 @@
|
|||
<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="M6,2C4.8954,2 4,2.8954 4,4V20C4,21.1046 4.8954,22 6,22H18C19.1046,22 20,21.1046 20,20V8H16C14.8954,8 14,7.1046 14,6V2H6ZM9,9H7V11H9V9ZM7,13H9V15H7V13ZM7,17H9V19H7V17ZM11,11V9H17V11H11ZM17,15V13H11V15H17ZM17,19V17H11V19H17Z"
|
||||
android:fillColor="#ffffff"
|
||||
android:fillType="evenOdd"/>
|
||||
<path
|
||||
android:pathData="M14,2L20,8H16C14.8954,8 14,7.1046 14,6V2Z"
|
||||
android:strokeAlpha="0.5"
|
||||
android:fillColor="#ffffff"
|
||||
android:fillAlpha="0.5"/>
|
||||
<path
|
||||
android:pathData="M17,9H11V11H17V9Z"
|
||||
android:strokeAlpha="0.2"
|
||||
android:fillColor="#ffffff"
|
||||
android:fillAlpha="0.2"/>
|
||||
<path
|
||||
android:pathData="M11,13H17V15H11V13Z"
|
||||
android:strokeAlpha="0.2"
|
||||
android:fillColor="#ffffff"
|
||||
android:fillAlpha="0.2"/>
|
||||
<path
|
||||
android:pathData="M11,17H17V19H11V17Z"
|
||||
android:strokeAlpha="0.2"
|
||||
android:fillColor="#ffffff"
|
||||
android:fillAlpha="0.2"/>
|
||||
</vector>
|
12
OsmAnd/res/drawable/ic_action_update.xml
Normal file
12
OsmAnd/res/drawable/ic_action_update.xml
Normal file
|
@ -0,0 +1,12 @@
|
|||
<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,0.9999L16,4.9999L12,8.9999L12,6C8.6863,6 6,8.6863 6,12C6,12.7351 6.1322,13.4394 6.3741,14.0903L4.8574,15.6071C4.309,14.5232 4,13.2977 4,12C4,7.5817 7.5817,4 12,4V0.9999Z"
|
||||
android:fillColor="#ffffff"/>
|
||||
<path
|
||||
android:pathData="M12,15.0001L12,18C15.3137,18 18,15.3137 18,12C18,11.2649 17.8678,10.5606 17.6258,9.9097L19.1426,8.3929C19.691,9.4768 20,10.7023 20,12C20,16.4183 16.4183,20 12,20V23.0001L8,19.0001L12,15.0001Z"
|
||||
android:fillColor="#ffffff"/>
|
||||
</vector>
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
-->
|
||||
|
||||
<string name="track_recording_will_be_continued">The recording will be continued.</string>
|
||||
<string name="select_category_descr">Select category or add new one</string>
|
||||
<string name="map_widget_distance_by_tap">Distance by tap</string>
|
||||
<string name="quick_action_coordinates_widget_descr">A toggle to show or hide the Coordinates widget on the map.</string>
|
||||
|
|
|
@ -250,6 +250,8 @@
|
|||
<item name="image_help_announcement_time">@drawable/img_help_announcement_time_day</item>
|
||||
<item name="switch_button_active">@color/switch_button_active_light</item>
|
||||
<item name="bottom_navigation_item_background">@drawable/bottom_navigation_item_bg_light</item>
|
||||
|
||||
<item name="android:forceDarkAllowed">false</item>
|
||||
</style>
|
||||
|
||||
<style name="ToolbarStyle" parent="@style/Widget.AppCompat.Toolbar">
|
||||
|
@ -549,6 +551,8 @@
|
|||
<item name="image_help_announcement_time">@drawable/img_help_announcement_time_night</item>
|
||||
<item name="switch_button_active">@color/switch_button_active_dark</item>
|
||||
<item name="bottom_navigation_item_background">@drawable/bottom_navigation_item_bg_dark</item>
|
||||
|
||||
<item name="android:forceDarkAllowed">false</item>
|
||||
</style>
|
||||
|
||||
<style name="FreeVersionBanner" parent="OsmandDarkTheme">
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package net.osmand.plus;
|
||||
|
||||
import android.location.Location;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.Looper;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
@ -14,7 +13,6 @@ import com.google.android.gms.location.LocationResult;
|
|||
import com.google.android.gms.location.LocationServices;
|
||||
import com.google.android.gms.tasks.OnSuccessListener;
|
||||
import com.google.android.gms.tasks.Task;
|
||||
import com.google.android.gms.tasks.Tasks;
|
||||
|
||||
import net.osmand.PlatformUtil;
|
||||
import net.osmand.plus.helpers.DayNightHelper;
|
||||
|
@ -23,9 +21,6 @@ import net.osmand.plus.helpers.LocationServiceHelper;
|
|||
import org.apache.commons.logging.Log;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
public class LocationServiceHelperImpl extends LocationServiceHelper {
|
||||
|
||||
|
@ -33,8 +28,6 @@ public class LocationServiceHelperImpl extends LocationServiceHelper {
|
|||
|
||||
private final OsmandApplication app;
|
||||
|
||||
private final HandlerThread mHandlerThread = new HandlerThread("LocationServiceHelperThread");
|
||||
|
||||
// FusedLocationProviderClient - Main class for receiving location updates.
|
||||
private final FusedLocationProviderClient fusedLocationProviderClient;
|
||||
|
||||
|
@ -49,7 +42,6 @@ public class LocationServiceHelperImpl extends LocationServiceHelper {
|
|||
|
||||
public LocationServiceHelperImpl(@NonNull OsmandApplication app) {
|
||||
this.app = app;
|
||||
mHandlerThread.start();
|
||||
|
||||
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(app);
|
||||
|
||||
|
@ -104,7 +96,7 @@ public class LocationServiceHelperImpl extends LocationServiceHelper {
|
|||
// request location updates
|
||||
try {
|
||||
fusedLocationProviderClient.requestLocationUpdates(
|
||||
fusedLocationRequest, fusedLocationCallback, mHandlerThread.getLooper());
|
||||
fusedLocationRequest, fusedLocationCallback, Looper.myLooper());
|
||||
} catch (SecurityException e) {
|
||||
LOG.debug("Location service permission not granted");
|
||||
throw e;
|
||||
|
|
|
@ -417,8 +417,12 @@ public class OsmandAidlApi {
|
|||
}
|
||||
|
||||
private void registerReceiver(BroadcastReceiver rec, MapActivity ma, String filter) {
|
||||
try {
|
||||
receivers.put(filter, rec);
|
||||
ma.registerReceiver(rec, new IntentFilter(filter));
|
||||
} catch (IllegalStateException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void registerRemoveMapWidgetReceiver(MapActivity mapActivity) {
|
||||
|
|
|
@ -373,30 +373,22 @@ public class OsmAndLocationProvider implements SensorEventListener {
|
|||
|
||||
public void addLocationListener(@NonNull OsmAndLocationListener listener) {
|
||||
if (!locationListeners.contains(listener)) {
|
||||
List<OsmAndLocationListener> listeners = new ArrayList<>(locationListeners);
|
||||
listeners.add(listener);
|
||||
locationListeners = listeners;
|
||||
locationListeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeLocationListener(@NonNull OsmAndLocationListener listener) {
|
||||
List<OsmAndLocationListener> listeners = new ArrayList<>(locationListeners);
|
||||
listeners.remove(listener);
|
||||
locationListeners = listeners;
|
||||
locationListeners.remove(listener);
|
||||
}
|
||||
|
||||
public void addCompassListener(@NonNull OsmAndCompassListener listener) {
|
||||
if (!compassListeners.contains(listener)) {
|
||||
List<OsmAndCompassListener> listeners = new ArrayList<>(compassListeners);
|
||||
listeners.add(listener);
|
||||
compassListeners = listeners;
|
||||
compassListeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeCompassListener(@NonNull OsmAndCompassListener listener) {
|
||||
List<OsmAndCompassListener> listeners = new ArrayList<>(compassListeners);
|
||||
listeners.remove(listener);
|
||||
compassListeners = listeners;
|
||||
compassListeners.remove(listener);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
|
|
@ -468,7 +468,7 @@ public abstract class OsmandPlugin {
|
|||
FragmentManager fm = mapActivity.getSupportFragmentManager();
|
||||
Fragment fragment = fm.findFragmentByTag(fragmentData.tag);
|
||||
if (fragment != null) {
|
||||
fm.beginTransaction().remove(fragment).commit();
|
||||
fm.beginTransaction().remove(fragment).commitAllowingStateLoss();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -690,6 +690,10 @@ public abstract class OsmandPlugin {
|
|||
return null;
|
||||
}
|
||||
|
||||
public static <T extends OsmandPlugin> boolean isPluginEnabled(Class<T> clz) {
|
||||
return getEnabledPlugin(clz) != null;
|
||||
}
|
||||
|
||||
public static List<WorldRegion> getCustomDownloadRegions() {
|
||||
List<WorldRegion> l = new ArrayList<>();
|
||||
for (OsmandPlugin plugin : getEnabledPlugins()) {
|
||||
|
|
|
@ -1004,7 +1004,7 @@ public class DashboardOnMap implements ObservableScrollViewCallbacks, IRouteInfo
|
|||
new TransactionBuilder(mapActivity.getSupportFragmentManager(), settings, mapActivity);
|
||||
builder.addFragmentsData(fragmentsData)
|
||||
.addFragmentsData(OsmandPlugin.getPluginsCardsList())
|
||||
.getFragmentTransaction().commit();
|
||||
.getFragmentTransaction().commitAllowingStateLoss();
|
||||
}
|
||||
|
||||
private void removeFragment(String tag) {
|
||||
|
|
|
@ -66,14 +66,17 @@ public class RasterMapMenu {
|
|||
|
||||
final CommonPreference<Boolean> hidePolygonsPref =
|
||||
mapActivity.getMyApplication().getSettings().getCustomRenderBooleanProperty("noPolygons");
|
||||
final CommonPreference<Boolean> hideWaterPolygonsPref =
|
||||
mapActivity.getMyApplication().getSettings().getCustomRenderBooleanProperty("hideWaterPolygons");
|
||||
|
||||
|
||||
String mapTypeDescr = mapTypePreference.get();
|
||||
if (mapTypeDescr!=null && mapTypeDescr.contains(".sqlitedb")) {
|
||||
mapTypeDescr = mapTypeDescr.replaceFirst(".sqlitedb", "");
|
||||
}
|
||||
|
||||
final boolean selected = mapTypeDescr != null;
|
||||
final int toggleActionStringId = selected ? R.string.shared_string_on
|
||||
final boolean mapSelected = mapTypeDescr != null;
|
||||
final int toggleActionStringId = mapSelected ? R.string.shared_string_on
|
||||
: R.string.shared_string_off;
|
||||
|
||||
final OnMapSelectedCallback onMapSelectedCallback =
|
||||
|
@ -81,6 +84,10 @@ public class RasterMapMenu {
|
|||
@Override
|
||||
public void onMapSelected(boolean canceled) {
|
||||
mapActivity.getDashboard().refreshContent(true);
|
||||
boolean refreshToHidePolygons = type == RasterMapType.UNDERLAY;
|
||||
if (refreshToHidePolygons) {
|
||||
mapActivity.refreshMapComplete();
|
||||
}
|
||||
}
|
||||
};
|
||||
final MapActivityLayers mapLayers = mapActivity.getMapLayers();
|
||||
|
@ -89,7 +96,7 @@ public class RasterMapMenu {
|
|||
public boolean onRowItemClick(ArrayAdapter<ContextMenuItem> adapter,
|
||||
View view, int itemId, int pos) {
|
||||
if (itemId == mapTypeString) {
|
||||
if (selected) {
|
||||
if (mapSelected) {
|
||||
plugin.selectMapOverlayLayer(mapActivity.getMapView(), mapTypePreference,
|
||||
exMapTypePreference, true, mapActivity, onMapSelectedCallback);
|
||||
}
|
||||
|
@ -111,6 +118,7 @@ public class RasterMapMenu {
|
|||
});
|
||||
} else if (itemId == R.string.show_polygons) {
|
||||
hidePolygonsPref.set(!isChecked);
|
||||
hideWaterPolygonsPref.set(!isChecked);
|
||||
mapActivity.refreshMapComplete();
|
||||
} else if (itemId == R.string.show_transparency_seekbar) {
|
||||
if (isChecked) {
|
||||
|
@ -126,13 +134,13 @@ public class RasterMapMenu {
|
|||
}
|
||||
};
|
||||
|
||||
mapTypeDescr = selected ? mapTypeDescr : mapActivity.getString(R.string.shared_string_none);
|
||||
mapTypeDescr = mapSelected ? mapTypeDescr : mapActivity.getString(R.string.shared_string_none);
|
||||
contextMenuAdapter.addItem(new ContextMenuItem.ItemBuilder()
|
||||
.setTitleId(toggleActionStringId, mapActivity)
|
||||
.hideDivider(true)
|
||||
.setListener(l)
|
||||
.setSelected(selected).createItem());
|
||||
if (selected) {
|
||||
.setSelected(mapSelected).createItem());
|
||||
if (mapSelected) {
|
||||
contextMenuAdapter.addItem(new ContextMenuItem.ItemBuilder()
|
||||
.setTitleId(mapTypeString, mapActivity)
|
||||
.hideDivider(true)
|
||||
|
|
|
@ -6,6 +6,7 @@ import android.content.Intent;
|
|||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.AsyncTask.Status;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.provider.OpenableColumns;
|
||||
|
@ -25,6 +26,8 @@ import net.osmand.PlatformUtil;
|
|||
import net.osmand.data.FavouritePoint;
|
||||
import net.osmand.data.FavouritePoint.BackgroundType;
|
||||
import net.osmand.plus.AppInitializer;
|
||||
import net.osmand.plus.AppInitializer.AppInitializeListener;
|
||||
import net.osmand.plus.AppInitializer.InitEvents;
|
||||
import net.osmand.plus.GPXDatabase.GpxDataItem;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.R;
|
||||
|
@ -707,15 +710,17 @@ public class ImportHelper {
|
|||
@SuppressWarnings("unchecked")
|
||||
private <P> void executeImportTask(final AsyncTask<P, ?, ?> importTask, final P... requests) {
|
||||
if (app.isApplicationInitializing()) {
|
||||
app.getAppInitializer().addListener(new AppInitializer.AppInitializeListener() {
|
||||
app.getAppInitializer().addListener(new AppInitializeListener() {
|
||||
@Override
|
||||
public void onProgress(AppInitializer init, AppInitializer.InitEvents event) {
|
||||
public void onProgress(AppInitializer init, InitEvents event) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinish(AppInitializer init) {
|
||||
if (importTask.getStatus() == Status.PENDING) {
|
||||
importTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, requests);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
importTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, requests);
|
||||
|
|
|
@ -75,6 +75,9 @@ public class FavoritePointEditorFragmentNew extends PointEditorFragmentNew {
|
|||
FavouritesDbHelper helper = getHelper();
|
||||
if (editor != null && helper != null) {
|
||||
FavouritePoint favorite = editor.getFavorite();
|
||||
if (favorite == null && savedInstanceState != null) {
|
||||
favorite = (FavouritePoint) savedInstanceState.getSerializable(FavoriteDialogs.KEY_FAVORITE);
|
||||
}
|
||||
this.favorite = favorite;
|
||||
this.group = helper.getGroup(favorite);
|
||||
this.color = favorite.getColor();
|
||||
|
@ -109,6 +112,12 @@ public class FavoritePointEditorFragmentNew extends PointEditorFragmentNew {
|
|||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(@NonNull Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
outState.putSerializable(FavoriteDialogs.KEY_FAVORITE, getFavorite());
|
||||
}
|
||||
|
||||
private void replacePressed() {
|
||||
Bundle args = new Bundle();
|
||||
args.putSerializable(FavoriteDialogs.KEY_FAVORITE, getFavorite());
|
||||
|
|
|
@ -1444,8 +1444,9 @@ public class CoordinateInputDialogFragment extends DialogFragment implements Osm
|
|||
if (!compassUpdateAllowed) {
|
||||
return;
|
||||
}
|
||||
final OsmandApplication app = getMyApplication();
|
||||
if (app != null && adapter != null) {
|
||||
Activity activity = getActivity();
|
||||
if (activity != null && adapter != null) {
|
||||
OsmandApplication app = (OsmandApplication) activity.getApplication();
|
||||
app.runInUIThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
|
|
@ -1002,6 +1002,7 @@ public class MeasurementEditingContext implements IRouteSettingsListener {
|
|||
pts.add(pt);
|
||||
}
|
||||
calculatedPairs++;
|
||||
params.calculationProgressCallback.updateProgress(0);
|
||||
List<RouteSegmentResult> originalRoute = route.getOriginalRoute();
|
||||
if (Algorithms.isEmpty(originalRoute)) {
|
||||
originalRoute = Collections.singletonList(RoutePlannerFrontEnd.generateStraightLineSegment(
|
||||
|
@ -1011,7 +1012,6 @@ public class MeasurementEditingContext implements IRouteSettingsListener {
|
|||
application.runInUIThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
params.calculationProgressCallback.updateProgress(0);
|
||||
updateSegmentsForSnap(true, false);
|
||||
progressListener.refresh();
|
||||
RouteCalculationParams params = getParams(false);
|
||||
|
|
|
@ -22,10 +22,10 @@ import net.osmand.AndroidUtils;
|
|||
import net.osmand.plus.OsmAndFormatter;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.UiUtilities;
|
||||
import net.osmand.plus.helpers.CustomBarChartRenderer;
|
||||
import net.osmand.router.RouteStatisticsHelper;
|
||||
import net.osmand.router.RouteStatisticsHelper.RouteStatistics;
|
||||
import net.osmand.router.RouteStatisticsHelper.RouteSegmentAttribute;
|
||||
import net.osmand.router.RouteStatisticsHelper.RouteStatistics;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
@ -140,7 +140,7 @@ public class CustomGraphAdapter extends BaseGraphAdapter<HorizontalBarChart, Bar
|
|||
private void attachLegend(List<RouteSegmentAttribute> list,
|
||||
String propertyNameToFullSpan) {
|
||||
OsmandApplication app = getMyApplication();
|
||||
LayoutInflater inflater = LayoutInflater.from(app);
|
||||
LayoutInflater inflater = UiUtilities.getInflater(app, isNightMode());
|
||||
for (RouteSegmentAttribute segment : list) {
|
||||
View view = inflater.inflate(R.layout.route_details_legend, legendContainer, false);
|
||||
int segmentColor = segment.getColor();
|
||||
|
|
|
@ -90,12 +90,12 @@ public class StopTrackRecordingBottomFragment extends MenuBottomSheetDialogFragm
|
|||
@Override
|
||||
public void onClick(View v) {
|
||||
tag = (ItemType) buttonSave.getTag();
|
||||
if (plugin != null && settings.SAVE_GLOBAL_TRACK_TO_GPX.get()) {
|
||||
if (plugin != null && app.getSavingTrackHelper().hasDataToSave()) {
|
||||
plugin.saveCurrentTrack(null, mapActivity);
|
||||
app.getNotificationHelper().refreshNotifications();
|
||||
}
|
||||
dismiss();
|
||||
}
|
||||
}
|
||||
})
|
||||
.create());
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package net.osmand.plus.monitoring;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
|
@ -38,6 +37,7 @@ import com.google.android.material.snackbar.Snackbar;
|
|||
|
||||
import net.osmand.AndroidUtils;
|
||||
import net.osmand.GPXUtilities.GPXFile;
|
||||
import net.osmand.IndexConstants;
|
||||
import net.osmand.PlatformUtil;
|
||||
import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
|
@ -61,6 +61,7 @@ import net.osmand.util.Algorithms;
|
|||
import org.apache.commons.logging.Log;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -71,6 +72,7 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen
|
|||
public static final String TAG = TripRecordingActiveBottomSheet.class.getSimpleName();
|
||||
private static final Log log = PlatformUtil.getLog(TripRecordingActiveBottomSheet.class);
|
||||
private static final String UPDATE_CURRENT_GPX_FILE = "update_current_gpx_file";
|
||||
public static final String UPDATE_TRACK_ICON = "update_track_icon";
|
||||
private static final int GENERAL_UPDATE_GPS_INTERVAL = 1000;
|
||||
private static final int GENERAL_UPDATE_SAVE_INTERVAL = 1000;
|
||||
|
||||
|
@ -131,7 +133,7 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen
|
|||
|
||||
View buttonClear = itemView.findViewById(R.id.button_clear);
|
||||
final View buttonOnline = itemView.findViewById(R.id.button_online);
|
||||
View buttonSegment = itemView.findViewById(R.id.button_segment);
|
||||
final View buttonSegment = itemView.findViewById(R.id.button_segment);
|
||||
buttonSave = itemView.findViewById(R.id.button_save);
|
||||
final View buttonPause = itemView.findViewById(R.id.button_pause);
|
||||
View buttonStop = itemView.findViewById(R.id.button_stop);
|
||||
|
@ -274,6 +276,7 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen
|
|||
settings.SAVE_GLOBAL_TRACK_TO_GPX.set(wasTrackMonitored);
|
||||
updateStatus();
|
||||
createItem(buttonPause, wasTrackMonitored ? ItemType.PAUSE : ItemType.RESUME, true);
|
||||
createItem(buttonSegment, ItemType.START_SEGMENT, wasTrackMonitored);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -443,16 +446,21 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen
|
|||
|
||||
@Override
|
||||
public void gpxSavingFinished(Exception errorMessage) {
|
||||
String gpxFileName = Algorithms.getFileWithoutDirs(getGPXFile().path);
|
||||
final MapActivity mapActivity = getMapActivity();
|
||||
final Context context = getContext();
|
||||
final SaveGpxResult result = helper.saveDataToGpx(app.getAppCustomization().getTracksDir());
|
||||
ArrayList<String> filenames = new ArrayList<>(result.getFilenames());
|
||||
String fileName = "";
|
||||
if (filenames.size() > 0) {
|
||||
fileName = filenames.get(filenames.size() - 1) + IndexConstants.GPX_FILE_EXT;
|
||||
}
|
||||
String message = fileName + " " + app.getResources().getString(R.string.shared_string_is_saved) + ". "
|
||||
+ app.getResources().getString(R.string.track_recording_will_be_continued);
|
||||
if (mapActivity != null && context != null) {
|
||||
final WeakReference<MapActivity> mapActivityRef = new WeakReference<>(mapActivity);
|
||||
final FragmentManager fragmentManager = mapActivityRef.get().getSupportFragmentManager();
|
||||
@SuppressLint({"StringFormatInvalid", "LocalSuppress"})
|
||||
Snackbar snackbar = Snackbar.make(getView(),
|
||||
app.getResources().getString(R.string.shared_string_file_is_saved, gpxFileName),
|
||||
message,
|
||||
Snackbar.LENGTH_LONG)
|
||||
.setAction(R.string.shared_string_rename, new View.OnClickListener() {
|
||||
@Override
|
||||
|
@ -492,12 +500,14 @@ public class TripRecordingActiveBottomSheet extends MenuBottomSheetDialogFragmen
|
|||
}
|
||||
}
|
||||
|
||||
public void show(boolean updateTrackIcon) {
|
||||
public void show(String... keys) {
|
||||
show();
|
||||
if (updateTrackIcon && buttonAppearance != null) {
|
||||
for (String key : keys) {
|
||||
if (key.equals(UPDATE_TRACK_ICON)) {
|
||||
updateTrackIcon(buttonAppearance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void hide() {
|
||||
Dialog dialog = getDialog();
|
||||
|
|
|
@ -1005,6 +1005,7 @@ public class AvailableGPXFragment extends OsmandExpandableListFragment implement
|
|||
}
|
||||
}
|
||||
});
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public Set<GpxInfo> getSelectedGpx() {
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
package net.osmand.plus.onlinerouting;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import net.osmand.plus.onlinerouting.engine.EngineType;
|
||||
import net.osmand.plus.onlinerouting.engine.GraphhopperEngine;
|
||||
import net.osmand.plus.onlinerouting.engine.OnlineRoutingEngine;
|
||||
import net.osmand.plus.onlinerouting.engine.OrsEngine;
|
||||
import net.osmand.plus.onlinerouting.engine.OsrmEngine;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class OnlineRoutingFactory {
|
||||
|
||||
public static OnlineRoutingEngine createEngine(@NonNull EngineType type) {
|
||||
return createEngine(type, null);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static OnlineRoutingEngine createEngine(@NonNull EngineType type,
|
||||
@Nullable Map<String, String> params) {
|
||||
switch (type) {
|
||||
case GRAPHHOPPER:
|
||||
return new GraphhopperEngine(params);
|
||||
case OSRM:
|
||||
return new OsrmEngine(params);
|
||||
case ORS:
|
||||
return new OrsEngine(params);
|
||||
default:
|
||||
throw new IllegalArgumentException(
|
||||
"Online routing type {" + type.name() + "} not supported");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -18,14 +18,20 @@ import org.json.JSONException;
|
|||
import org.json.JSONObject;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
import static net.osmand.util.Algorithms.GZIP_FILE_SIGNATURE;
|
||||
import static net.osmand.util.Algorithms.ZIP_FILE_SIGNATURE;
|
||||
import static net.osmand.util.Algorithms.isEmpty;
|
||||
|
||||
public class OnlineRoutingHelper {
|
||||
|
@ -88,7 +94,7 @@ public class OnlineRoutingHelper {
|
|||
boolean leftSideNavigation) throws IOException, JSONException {
|
||||
String url = engine.getFullUrl(path);
|
||||
String content = makeRequest(url);
|
||||
return engine.parseServerResponse(content, app, leftSideNavigation);
|
||||
return engine.parseResponse(content, app, leftSideNavigation);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
|
@ -98,7 +104,7 @@ public class OnlineRoutingHelper {
|
|||
StringBuilder content = new StringBuilder();
|
||||
BufferedReader reader;
|
||||
if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
|
||||
reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
|
||||
reader = new BufferedReader(new InputStreamReader(getInputStream(connection)));
|
||||
} else {
|
||||
reader = new BufferedReader(new InputStreamReader(connection.getErrorStream()));
|
||||
}
|
||||
|
@ -113,6 +119,18 @@ public class OnlineRoutingHelper {
|
|||
return content.toString();
|
||||
}
|
||||
|
||||
private InputStream getInputStream(@NonNull HttpURLConnection connection) throws IOException {
|
||||
ByteArrayInputStream localIS = Algorithms.createByteArrayIS(connection.getInputStream());
|
||||
if (Algorithms.checkFileSignature(localIS, ZIP_FILE_SIGNATURE)) {
|
||||
ZipInputStream zipIS = new ZipInputStream(localIS);
|
||||
zipIS.getNextEntry(); // set position to reading for the first item
|
||||
return zipIS;
|
||||
} else if (Algorithms.checkFileSignature(localIS, GZIP_FILE_SIGNATURE)) {
|
||||
return new GZIPInputStream(localIS);
|
||||
}
|
||||
return localIS;
|
||||
}
|
||||
|
||||
public void saveEngine(@NonNull OnlineRoutingEngine engine) {
|
||||
deleteInaccessibleParameters(engine);
|
||||
String key = createEngineKeyIfNeeded(engine);
|
||||
|
|
|
@ -7,8 +7,8 @@ import androidx.annotation.NonNull;
|
|||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
import net.osmand.plus.onlinerouting.engine.EngineType;
|
||||
import net.osmand.plus.onlinerouting.engine.OnlineRoutingEngine;
|
||||
import net.osmand.plus.onlinerouting.engine.EngineType;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
||||
import org.json.JSONArray;
|
||||
|
@ -60,10 +60,10 @@ public class OnlineRoutingUtils {
|
|||
for (int i = 0; i < itemsJson.length(); i++) {
|
||||
JSONObject object = itemsJson.getJSONObject(i);
|
||||
if (object.has(TYPE) && object.has(PARAMS)) {
|
||||
EngineType type = EngineType.getTypeByName(object.getString(TYPE));
|
||||
OnlineRoutingEngine type = EngineType.getTypeByName(object.getString(TYPE));
|
||||
String paramsString = object.getString(PARAMS);
|
||||
HashMap<String, String> params = gson.fromJson(paramsString, typeToken);
|
||||
OnlineRoutingEngine engine = OnlineRoutingFactory.createEngine(type, params);
|
||||
OnlineRoutingEngine engine = type.newInstance(params);
|
||||
if (!Algorithms.isEmpty(engine.getStringKey())) {
|
||||
engines.add(engine);
|
||||
}
|
||||
|
@ -82,7 +82,7 @@ public class OnlineRoutingUtils {
|
|||
continue;
|
||||
}
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put(TYPE, engine.getType().name());
|
||||
jsonObject.put(TYPE, engine.getTypeName());
|
||||
jsonObject.put(PARAMS, gson.toJson(engine.getParams(), type));
|
||||
jsonArray.put(jsonObject);
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import androidx.annotation.NonNull;
|
|||
import androidx.annotation.StringRes;
|
||||
|
||||
public class VehicleType {
|
||||
|
||||
private final String key;
|
||||
@StringRes
|
||||
private final int titleId;
|
||||
|
|
|
@ -1,34 +1,38 @@
|
|||
package net.osmand.plus.onlinerouting.engine;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import net.osmand.util.Algorithms;
|
||||
|
||||
public enum EngineType {
|
||||
GRAPHHOPPER("Graphhopper"),
|
||||
OSRM("OSRM"),
|
||||
ORS("Openroute Service");
|
||||
public class EngineType {
|
||||
|
||||
private final String title;
|
||||
public final static OnlineRoutingEngine GRAPHHOPPER_TYPE = new GraphhopperEngine(null);
|
||||
public final static OnlineRoutingEngine OSRM_TYPE = new OsrmEngine(null);
|
||||
public final static OnlineRoutingEngine ORS_TYPE = new OrsEngine(null);
|
||||
public final static OnlineRoutingEngine GPX_TYPE = new GpxEngine(null);
|
||||
|
||||
EngineType(String title) {
|
||||
this.title = title;
|
||||
private static OnlineRoutingEngine[] enginesTypes;
|
||||
|
||||
public static OnlineRoutingEngine[] values() {
|
||||
if (enginesTypes == null) {
|
||||
enginesTypes = new OnlineRoutingEngine[]{
|
||||
GRAPHHOPPER_TYPE,
|
||||
OSRM_TYPE,
|
||||
ORS_TYPE,
|
||||
GPX_TYPE
|
||||
};
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
return enginesTypes;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static EngineType getTypeByName(@Nullable String name) {
|
||||
if (!Algorithms.isEmpty(name)) {
|
||||
for (EngineType type : values()) {
|
||||
if (type.name().equals(name)) {
|
||||
public static OnlineRoutingEngine getTypeByName(@NonNull String typeName) {
|
||||
for (OnlineRoutingEngine type : values()) {
|
||||
if (Algorithms.objectEquals(type.getTypeName(), typeName)) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
}
|
||||
return values()[0];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
107
OsmAnd/src/net/osmand/plus/onlinerouting/engine/GpxEngine.java
Normal file
107
OsmAnd/src/net/osmand/plus/onlinerouting/engine/GpxEngine.java
Normal file
|
@ -0,0 +1,107 @@
|
|||
package net.osmand.plus.onlinerouting.engine;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import net.osmand.GPXUtilities;
|
||||
import net.osmand.GPXUtilities.GPXFile;
|
||||
import net.osmand.data.LatLon;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.onlinerouting.EngineParameter;
|
||||
import net.osmand.plus.onlinerouting.VehicleType;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static net.osmand.plus.onlinerouting.engine.EngineType.GPX_TYPE;
|
||||
|
||||
public class GpxEngine extends OnlineRoutingEngine {
|
||||
|
||||
public GpxEngine(@Nullable Map<String, String> params) {
|
||||
super(params);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public OnlineRoutingEngine getType() {
|
||||
return GPX_TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public String getTitle() {
|
||||
return "GPX";
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getTypeName() {
|
||||
return "GPX";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void makeFullUrl(@NonNull StringBuilder sb,
|
||||
@NonNull List<LatLon> path) {
|
||||
for (int i = 0; i < path.size(); i++) {
|
||||
LatLon point = path.get(i);
|
||||
sb.append(point.getLongitude()).append(',').append(point.getLatitude());
|
||||
if (i < path.size() - 1) {
|
||||
sb.append(';');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getStandardUrl() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void collectAllowedVehicles(@NonNull List<VehicleType> vehicles) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void collectAllowedParameters(@NonNull Set<EngineParameter> params) {
|
||||
params.add(EngineParameter.KEY);
|
||||
params.add(EngineParameter.CUSTOM_NAME);
|
||||
params.add(EngineParameter.NAME_INDEX);
|
||||
params.add(EngineParameter.CUSTOM_URL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OnlineRoutingEngine newInstance(Map<String, String> params) {
|
||||
return new GpxEngine(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public OnlineRoutingResponse parseResponse(@NonNull String content,
|
||||
@NonNull OsmandApplication app,
|
||||
boolean leftSideNavigation) {
|
||||
GPXFile gpxFile = parseGpx(content);
|
||||
return gpxFile != null ? new OnlineRoutingResponse(parseGpx(content)) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isResultOk(@NonNull StringBuilder errorMessage,
|
||||
@NonNull String content) {
|
||||
return parseGpx(content) != null;
|
||||
}
|
||||
|
||||
private GPXFile parseGpx(@NonNull String content) {
|
||||
InputStream gpxStream;
|
||||
try {
|
||||
gpxStream = new ByteArrayInputStream(content.getBytes("UTF-8"));
|
||||
return GPXUtilities.loadGPXFile(gpxStream);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
LOG.debug("Error when parsing GPX from server response: " + e.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -20,10 +20,12 @@ import org.json.JSONObject;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static net.osmand.plus.onlinerouting.engine.EngineType.GRAPHHOPPER_TYPE;
|
||||
import static net.osmand.util.Algorithms.isEmpty;
|
||||
|
||||
public class GraphhopperEngine extends OnlineRoutingEngine {
|
||||
public class GraphhopperEngine extends JsonOnlineRoutingEngine {
|
||||
|
||||
public GraphhopperEngine(@Nullable Map<String, String> params) {
|
||||
super(params);
|
||||
|
@ -31,8 +33,20 @@ public class GraphhopperEngine extends OnlineRoutingEngine {
|
|||
|
||||
@NonNull
|
||||
@Override
|
||||
public EngineType getType() {
|
||||
return EngineType.GRAPHHOPPER;
|
||||
public OnlineRoutingEngine getType() {
|
||||
return GRAPHHOPPER_TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public String getTitle() {
|
||||
return "Graphhopper";
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getTypeName() {
|
||||
return "GRAPHHOPPER";
|
||||
}
|
||||
|
||||
@NonNull
|
||||
|
@ -42,8 +56,18 @@ public class GraphhopperEngine extends OnlineRoutingEngine {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void collectAllowedParameters() {
|
||||
allowParameters(EngineParameter.API_KEY);
|
||||
protected void collectAllowedParameters(@NonNull Set<EngineParameter> params) {
|
||||
params.add(EngineParameter.KEY);
|
||||
params.add(EngineParameter.VEHICLE_KEY);
|
||||
params.add(EngineParameter.CUSTOM_NAME);
|
||||
params.add(EngineParameter.NAME_INDEX);
|
||||
params.add(EngineParameter.CUSTOM_URL);
|
||||
params.add(EngineParameter.API_KEY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OnlineRoutingEngine newInstance(Map<String, String> params) {
|
||||
return new GraphhopperEngine(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -82,8 +106,7 @@ public class GraphhopperEngine extends OnlineRoutingEngine {
|
|||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public OnlineRoutingResponse parseServerResponse(@NonNull JSONObject root,
|
||||
protected OnlineRoutingResponse parseServerResponse(@NonNull JSONObject root,
|
||||
@NonNull OsmandApplication app,
|
||||
boolean leftSideNavigation) throws JSONException {
|
||||
String encoded = root.getString("points");
|
||||
|
@ -223,4 +246,5 @@ public class GraphhopperEngine extends OnlineRoutingEngine {
|
|||
protected String getRootArrayKey() {
|
||||
return "paths";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
package net.osmand.plus.onlinerouting.engine;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import net.osmand.GPXUtilities.WptPt;
|
||||
import net.osmand.Location;
|
||||
import net.osmand.data.LatLon;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.routing.RouteProvider;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static net.osmand.util.Algorithms.isEmpty;
|
||||
|
||||
public abstract class JsonOnlineRoutingEngine extends OnlineRoutingEngine {
|
||||
|
||||
public JsonOnlineRoutingEngine(@Nullable Map<String, String> params) {
|
||||
super(params);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public OnlineRoutingResponse parseResponse(@NonNull String content,
|
||||
@NonNull OsmandApplication app,
|
||||
boolean leftSideNavigation) throws JSONException {
|
||||
JSONObject root = parseRootResponseObject(content);
|
||||
return root != null ? parseServerResponse(root, app, leftSideNavigation) : null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected JSONObject parseRootResponseObject(@NonNull String content) throws JSONException {
|
||||
JSONObject fullJSON = new JSONObject(content);
|
||||
String key = getRootArrayKey();
|
||||
JSONArray array = null;
|
||||
if (fullJSON.has(key)) {
|
||||
array = fullJSON.getJSONArray(key);
|
||||
}
|
||||
return array != null && array.length() > 0 ? array.getJSONObject(0) : null;
|
||||
}
|
||||
|
||||
public boolean isResultOk(@NonNull StringBuilder errorMessage,
|
||||
@NonNull String content) throws JSONException {
|
||||
JSONObject obj = new JSONObject(content);
|
||||
String messageKey = getErrorMessageKey();
|
||||
if (obj.has(messageKey)) {
|
||||
String message = obj.getString(messageKey);
|
||||
errorMessage.append(message);
|
||||
}
|
||||
return obj.has(getRootArrayKey());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected abstract OnlineRoutingResponse parseServerResponse(@NonNull JSONObject root,
|
||||
@NonNull OsmandApplication app,
|
||||
boolean leftSideNavigation) throws JSONException;
|
||||
|
||||
@NonNull
|
||||
protected abstract String getRootArrayKey();
|
||||
|
||||
@NonNull
|
||||
protected abstract String getErrorMessageKey();
|
||||
|
||||
@NonNull
|
||||
protected static List<Location> convertRouteToLocationsList(@NonNull List<LatLon> route) {
|
||||
List<Location> result = new ArrayList<>();
|
||||
if (!isEmpty(route)) {
|
||||
for (LatLon pt : route) {
|
||||
WptPt wpt = new WptPt();
|
||||
wpt.lat = pt.getLatitude();
|
||||
wpt.lon = pt.getLongitude();
|
||||
result.add(RouteProvider.createLocation(wpt));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -5,24 +5,21 @@ import android.content.Context;
|
|||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import net.osmand.GPXUtilities.WptPt;
|
||||
import net.osmand.GPXUtilities.GPXFile;
|
||||
import net.osmand.Location;
|
||||
import net.osmand.PlatformUtil;
|
||||
import net.osmand.data.LatLon;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.onlinerouting.EngineParameter;
|
||||
import net.osmand.plus.onlinerouting.OnlineRoutingFactory;
|
||||
import net.osmand.plus.onlinerouting.VehicleType;
|
||||
import net.osmand.plus.routing.RouteDirectionInfo;
|
||||
import net.osmand.plus.routing.RouteProvider;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
|
@ -34,6 +31,8 @@ import static net.osmand.util.Algorithms.isEmpty;
|
|||
|
||||
public abstract class OnlineRoutingEngine implements Cloneable {
|
||||
|
||||
protected static final Log LOG = PlatformUtil.getLog(OnlineRoutingEngine.class);
|
||||
|
||||
public final static String ONLINE_ROUTING_ENGINE_PREFIX = "online_routing_engine_";
|
||||
public final static VehicleType CUSTOM_VEHICLE = new VehicleType("", R.string.shared_string_custom);
|
||||
|
||||
|
@ -46,11 +45,17 @@ public abstract class OnlineRoutingEngine implements Cloneable {
|
|||
this.params.putAll(params);
|
||||
}
|
||||
collectAllowedVehiclesInternal();
|
||||
collectAllowedParametersInternal();
|
||||
collectAllowedParameters(allowedParameters);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public abstract EngineType getType();
|
||||
public abstract OnlineRoutingEngine getType();
|
||||
|
||||
@NonNull
|
||||
public abstract String getTitle();
|
||||
|
||||
@NonNull
|
||||
public abstract String getTypeName();
|
||||
|
||||
@Nullable
|
||||
public String getStringKey() {
|
||||
|
@ -100,45 +105,13 @@ public abstract class OnlineRoutingEngine implements Cloneable {
|
|||
@NonNull
|
||||
public abstract String getStandardUrl();
|
||||
|
||||
public OnlineRoutingResponse parseServerResponse(@NonNull String content,
|
||||
@NonNull OsmandApplication app,
|
||||
boolean leftSideNavigation) throws JSONException {
|
||||
JSONObject root = parseRootResponseObject(content);
|
||||
return root != null ? parseServerResponse(root, app, leftSideNavigation) : null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected abstract OnlineRoutingResponse parseServerResponse(@NonNull JSONObject root,
|
||||
public abstract OnlineRoutingResponse parseResponse(@NonNull String content,
|
||||
@NonNull OsmandApplication app,
|
||||
boolean leftSideNavigation) throws JSONException;
|
||||
|
||||
@Nullable
|
||||
protected JSONObject parseRootResponseObject(@NonNull String content) throws JSONException {
|
||||
JSONObject fullJSON = new JSONObject(content);
|
||||
String responseArrayKey = getRootArrayKey();
|
||||
JSONArray array = null;
|
||||
if (fullJSON.has(responseArrayKey)) {
|
||||
array = fullJSON.getJSONArray(responseArrayKey);
|
||||
}
|
||||
return array != null && array.length() > 0 ? array.getJSONObject(0) : null;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
protected abstract String getRootArrayKey();
|
||||
|
||||
@NonNull
|
||||
protected List<Location> convertRouteToLocationsList(@NonNull List<LatLon> route) {
|
||||
List<Location> result = new ArrayList<>();
|
||||
if (!isEmpty(route)) {
|
||||
for (LatLon pt : route) {
|
||||
WptPt wpt = new WptPt();
|
||||
wpt.lat = pt.getLatitude();
|
||||
wpt.lon = pt.getLongitude();
|
||||
result.add(RouteProvider.createLocation(wpt));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
public abstract boolean isResultOk(@NonNull StringBuilder errorMessage,
|
||||
@NonNull String content) throws JSONException;
|
||||
|
||||
@NonNull
|
||||
public Map<String, String> getParams() {
|
||||
|
@ -171,23 +144,12 @@ public abstract class OnlineRoutingEngine implements Cloneable {
|
|||
return Collections.unmodifiableList(allowedVehicles);
|
||||
}
|
||||
|
||||
private void collectAllowedParametersInternal() {
|
||||
allowedParameters.clear();
|
||||
allowParameters(EngineParameter.KEY, EngineParameter.VEHICLE_KEY,
|
||||
EngineParameter.CUSTOM_NAME, EngineParameter.NAME_INDEX, EngineParameter.CUSTOM_URL);
|
||||
collectAllowedParameters();
|
||||
}
|
||||
|
||||
protected abstract void collectAllowedParameters();
|
||||
protected abstract void collectAllowedParameters(@NonNull Set<EngineParameter> params);
|
||||
|
||||
public boolean isParameterAllowed(EngineParameter key) {
|
||||
return allowedParameters.contains(key);
|
||||
}
|
||||
|
||||
protected void allowParameters(@NonNull EngineParameter... allowedParams) {
|
||||
allowedParameters.addAll(Arrays.asList(allowedParams));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private String getSelectedVehicleName(@NonNull Context ctx) {
|
||||
String key = get(EngineParameter.VEHICLE_KEY);
|
||||
|
@ -216,24 +178,10 @@ public abstract class OnlineRoutingEngine implements Cloneable {
|
|||
return CUSTOM_VEHICLE;
|
||||
}
|
||||
|
||||
public boolean checkServerResponse(@NonNull StringBuilder errorMessage,
|
||||
@NonNull String content) throws JSONException {
|
||||
JSONObject obj = new JSONObject(content);
|
||||
String messageKey = getErrorMessageKey();
|
||||
if (obj.has(messageKey)) {
|
||||
String message = obj.getString(messageKey);
|
||||
errorMessage.append(message);
|
||||
}
|
||||
return obj.has(getRootArrayKey());
|
||||
}
|
||||
|
||||
@NonNull
|
||||
protected abstract String getErrorMessageKey();
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Object clone() {
|
||||
return OnlineRoutingFactory.createEngine(getType(), getParams());
|
||||
return newInstance(getParams());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -246,20 +194,30 @@ public abstract class OnlineRoutingEngine implements Cloneable {
|
|||
return Algorithms.objectEquals(getParams(), engine.getParams());
|
||||
}
|
||||
|
||||
public abstract OnlineRoutingEngine newInstance(Map<String, String> params);
|
||||
|
||||
@NonNull
|
||||
public static String generateKey() {
|
||||
return ONLINE_ROUTING_ENGINE_PREFIX + System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public static class OnlineRoutingResponse {
|
||||
|
||||
private List<Location> route;
|
||||
private List<RouteDirectionInfo> directions;
|
||||
private GPXFile gpxFile;
|
||||
|
||||
// constructor for JSON responses
|
||||
public OnlineRoutingResponse(List<Location> route, List<RouteDirectionInfo> directions) {
|
||||
this.route = route;
|
||||
this.directions = directions;
|
||||
}
|
||||
|
||||
// constructor for GPX responses
|
||||
public OnlineRoutingResponse(GPXFile gpxFile) {
|
||||
this.gpxFile = gpxFile;
|
||||
}
|
||||
|
||||
public List<Location> getRoute() {
|
||||
return route;
|
||||
}
|
||||
|
@ -267,5 +225,10 @@ public abstract class OnlineRoutingEngine implements Cloneable {
|
|||
public List<RouteDirectionInfo> getDirections() {
|
||||
return directions;
|
||||
}
|
||||
|
||||
public GPXFile getGpxFile() {
|
||||
return gpxFile;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,10 +17,12 @@ import org.json.JSONObject;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static net.osmand.plus.onlinerouting.engine.EngineType.ORS_TYPE;
|
||||
import static net.osmand.util.Algorithms.isEmpty;
|
||||
|
||||
public class OrsEngine extends OnlineRoutingEngine {
|
||||
public class OrsEngine extends JsonOnlineRoutingEngine {
|
||||
|
||||
public OrsEngine(@Nullable Map<String, String> params) {
|
||||
super(params);
|
||||
|
@ -28,8 +30,20 @@ public class OrsEngine extends OnlineRoutingEngine {
|
|||
|
||||
@NonNull
|
||||
@Override
|
||||
public EngineType getType() {
|
||||
return EngineType.ORS;
|
||||
public OnlineRoutingEngine getType() {
|
||||
return ORS_TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public String getTitle() {
|
||||
return "Openroute Service";
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getTypeName() {
|
||||
return "ORS";
|
||||
}
|
||||
|
||||
@NonNull
|
||||
|
@ -39,8 +53,18 @@ public class OrsEngine extends OnlineRoutingEngine {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void collectAllowedParameters() {
|
||||
allowParameters(EngineParameter.API_KEY);
|
||||
protected void collectAllowedParameters(@NonNull Set<EngineParameter> params) {
|
||||
params.add(EngineParameter.KEY);
|
||||
params.add(EngineParameter.VEHICLE_KEY);
|
||||
params.add(EngineParameter.CUSTOM_NAME);
|
||||
params.add(EngineParameter.NAME_INDEX);
|
||||
params.add(EngineParameter.CUSTOM_URL);
|
||||
params.add(EngineParameter.API_KEY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OnlineRoutingEngine newInstance(Map<String, String> params) {
|
||||
return new OrsEngine(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -109,4 +133,5 @@ public class OrsEngine extends OnlineRoutingEngine {
|
|||
protected String getRootArrayKey() {
|
||||
return "features";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -22,20 +22,34 @@ import org.json.JSONObject;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static net.osmand.plus.onlinerouting.engine.EngineType.OSRM_TYPE;
|
||||
import static net.osmand.util.Algorithms.isEmpty;
|
||||
import static net.osmand.util.Algorithms.objectEquals;
|
||||
|
||||
public class OsrmEngine extends OnlineRoutingEngine {
|
||||
public class OsrmEngine extends JsonOnlineRoutingEngine {
|
||||
|
||||
public OsrmEngine(@Nullable Map<String, String> params) {
|
||||
super(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull
|
||||
EngineType getType() {
|
||||
return EngineType.OSRM;
|
||||
@NonNull
|
||||
public OnlineRoutingEngine getType() {
|
||||
return OSRM_TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public String getTitle() {
|
||||
return "OSRM";
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getTypeName() {
|
||||
return "OSRM";
|
||||
}
|
||||
|
||||
@NonNull
|
||||
|
@ -45,7 +59,17 @@ public class OsrmEngine extends OnlineRoutingEngine {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void collectAllowedParameters() {
|
||||
protected void collectAllowedParameters(@NonNull Set<EngineParameter> params) {
|
||||
params.add(EngineParameter.KEY);
|
||||
params.add(EngineParameter.VEHICLE_KEY);
|
||||
params.add(EngineParameter.CUSTOM_NAME);
|
||||
params.add(EngineParameter.NAME_INDEX);
|
||||
params.add(EngineParameter.CUSTOM_URL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OnlineRoutingEngine newInstance(Map<String, String> params) {
|
||||
return new OsrmEngine(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -76,7 +100,7 @@ public class OsrmEngine extends OnlineRoutingEngine {
|
|||
|
||||
@Nullable
|
||||
@Override
|
||||
public OnlineRoutingResponse parseServerResponse(@NonNull JSONObject root,
|
||||
protected OnlineRoutingResponse parseServerResponse(@NonNull JSONObject root,
|
||||
@NonNull OsmandApplication app,
|
||||
boolean leftSideNavigation) throws JSONException {
|
||||
String encodedPoints = root.getString("geometry");
|
||||
|
@ -225,13 +249,14 @@ public class OsrmEngine extends OnlineRoutingEngine {
|
|||
|
||||
@NonNull
|
||||
@Override
|
||||
protected String getErrorMessageKey() {
|
||||
return "message";
|
||||
protected String getRootArrayKey() {
|
||||
return "routes";
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected String getRootArrayKey() {
|
||||
return "routes";
|
||||
protected String getErrorMessageKey() {
|
||||
return "message";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -39,12 +39,11 @@ import net.osmand.plus.activities.MapActivity;
|
|||
import net.osmand.plus.base.BaseOsmAndFragment;
|
||||
import net.osmand.plus.mapcontextmenu.other.HorizontalSelectionAdapter.HorizontalSelectionItem;
|
||||
import net.osmand.plus.onlinerouting.EngineParameter;
|
||||
import net.osmand.plus.onlinerouting.OnlineRoutingFactory;
|
||||
import net.osmand.plus.onlinerouting.OnlineRoutingHelper;
|
||||
import net.osmand.plus.onlinerouting.OnlineRoutingUtils;
|
||||
import net.osmand.plus.onlinerouting.VehicleType;
|
||||
import net.osmand.plus.onlinerouting.engine.EngineType;
|
||||
import net.osmand.plus.onlinerouting.engine.OnlineRoutingEngine;
|
||||
import net.osmand.plus.onlinerouting.engine.EngineType;
|
||||
import net.osmand.plus.onlinerouting.ui.OnlineRoutingCard.OnTextChangedListener;
|
||||
import net.osmand.plus.routepreparationmenu.cards.BaseCard;
|
||||
import net.osmand.plus.settings.backend.ApplicationMode;
|
||||
|
@ -54,7 +53,9 @@ import org.json.JSONException;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static net.osmand.plus.onlinerouting.engine.OnlineRoutingEngine.CUSTOM_VEHICLE;
|
||||
|
||||
|
@ -201,15 +202,15 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment {
|
|||
typeCard = new OnlineRoutingCard(mapActivity, isNightMode(), appMode);
|
||||
typeCard.build(mapActivity);
|
||||
typeCard.setHeaderTitle(getString(R.string.shared_string_type));
|
||||
List<HorizontalSelectionItem> serverItems = new ArrayList<>();
|
||||
for (EngineType server : EngineType.values()) {
|
||||
serverItems.add(new HorizontalSelectionItem(server.getTitle(), server));
|
||||
List<HorizontalSelectionItem> typeItems = new ArrayList<>();
|
||||
for (OnlineRoutingEngine type : EngineType.values()) {
|
||||
typeItems.add(new HorizontalSelectionItem(type.getTitle(), type));
|
||||
}
|
||||
typeCard.setSelectionMenu(serverItems, engine.getType().getTitle(),
|
||||
typeCard.setSelectionMenu(typeItems, engine.getType().getTitle(),
|
||||
new CallbackWithObject<HorizontalSelectionItem>() {
|
||||
@Override
|
||||
public boolean processResult(HorizontalSelectionItem result) {
|
||||
EngineType type = (EngineType) result.getObject();
|
||||
OnlineRoutingEngine type = (OnlineRoutingEngine) result.getObject();
|
||||
if (engine.getType() != type) {
|
||||
changeEngineType(type);
|
||||
return true;
|
||||
|
@ -366,9 +367,9 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment {
|
|||
});
|
||||
}
|
||||
|
||||
private void changeEngineType(EngineType type) {
|
||||
private void changeEngineType(OnlineRoutingEngine type) {
|
||||
OnlineRoutingEngine tmp = (OnlineRoutingEngine) engine.clone();
|
||||
engine = OnlineRoutingFactory.createEngine(type, tmp.getParams());
|
||||
engine = type.newInstance(tmp.getParams());
|
||||
|
||||
// after changing the type, select the vehicle
|
||||
// with the same name that was selected before
|
||||
|
@ -462,7 +463,7 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment {
|
|||
boolean resultOk = false;
|
||||
try {
|
||||
String response = helper.makeRequest(exampleCard.getEditedText());
|
||||
resultOk = requestedEngine.checkServerResponse(errorMessage, response);
|
||||
resultOk = requestedEngine.isResultOk(errorMessage, response);
|
||||
} catch (IOException | JSONException e) {
|
||||
errorMessage.append(e.toString());
|
||||
}
|
||||
|
@ -514,6 +515,12 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment {
|
|||
} else {
|
||||
apiKeyCard.hide();
|
||||
}
|
||||
if (engine.isParameterAllowed(EngineParameter.VEHICLE_KEY)) {
|
||||
vehicleCard.show();
|
||||
} else {
|
||||
|
||||
vehicleCard.hide();
|
||||
}
|
||||
|
||||
} else if (vehicleCard.equals(card)) {
|
||||
VehicleType vt = engine.getSelectedVehicleType();
|
||||
|
@ -609,7 +616,7 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment {
|
|||
}
|
||||
|
||||
private void saveState(@NonNull Bundle outState) {
|
||||
outState.putString(ENGINE_TYPE_KEY, engine.getType().name());
|
||||
outState.putString(ENGINE_TYPE_KEY, engine.getTypeName());
|
||||
for (EngineParameter key : EngineParameter.values()) {
|
||||
String value = engine.get(key);
|
||||
if (value != null) {
|
||||
|
@ -626,14 +633,15 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment {
|
|||
editedEngineKey = savedState.getString(EngineParameter.KEY.name());
|
||||
initEngine = createInitStateEngine();
|
||||
String typeKey = savedState.getString(ENGINE_TYPE_KEY);
|
||||
EngineType type = EngineType.getTypeByName(typeKey);
|
||||
engine = OnlineRoutingFactory.createEngine(type);
|
||||
OnlineRoutingEngine type = EngineType.getTypeByName(typeKey);
|
||||
Map<String, String> params = new HashMap<>();
|
||||
for (EngineParameter key : EngineParameter.values()) {
|
||||
String value = savedState.getString(key.name());
|
||||
if (value != null) {
|
||||
engine.put(key, value);
|
||||
params.put(key.name(), value);
|
||||
}
|
||||
}
|
||||
engine = type.newInstance(params);
|
||||
customVehicleKey = savedState.getString(ENGINE_CUSTOM_VEHICLE_KEY);
|
||||
selectedLocation = ExampleLocation.valueOf(savedState.getString(EXAMPLE_LOCATION_KEY));
|
||||
appMode = ApplicationMode.valueOfStringKey(savedState.getString(APP_MODE_KEY), null);
|
||||
|
@ -656,7 +664,7 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment {
|
|||
if (editedEngine != null) {
|
||||
engine = (OnlineRoutingEngine) editedEngine.clone();
|
||||
} else {
|
||||
engine = OnlineRoutingFactory.createEngine(EngineType.values()[0]);
|
||||
engine = EngineType.values()[0].newInstance(null);
|
||||
String vehicle = engine.getAllowedVehicles().get(0).getKey();
|
||||
engine.put(EngineParameter.VEHICLE_KEY, vehicle);
|
||||
if (editedEngineKey != null) {
|
||||
|
|
|
@ -106,10 +106,12 @@ public class OsmandRasterMapsPlugin extends OsmandPlugin {
|
|||
@Override
|
||||
public boolean init(@NonNull final OsmandApplication app, Activity activity) {
|
||||
final CommonPreference<Boolean> hidePolygonsPref = settings.getCustomRenderBooleanProperty("noPolygons");
|
||||
final CommonPreference<Boolean> hideWaterPolygonsPref = settings.getCustomRenderBooleanProperty("hideWaterPolygons");
|
||||
underlayListener = new StateChangedListener<String>() {
|
||||
@Override
|
||||
public void stateChanged(String change) {
|
||||
hidePolygonsPref.set(settings.MAP_UNDERLAY.get() != null);
|
||||
hideWaterPolygonsPref.set(settings.MAP_UNDERLAY.get() != null);
|
||||
}
|
||||
};
|
||||
settings.MAP_UNDERLAY.addListener(underlayListener);
|
||||
|
|
|
@ -79,24 +79,18 @@ public class RouteStatisticCard extends BaseCard {
|
|||
((ImageView) view.findViewById(R.id.time_icon)).setImageDrawable(app.getUIUtilities().getThemedIcon(R.drawable.ic_action_time_span));
|
||||
|
||||
int dist = routingHelper.getLeftDistance();
|
||||
int time = routingHelper.getLeftTime();
|
||||
int hours = time / (60 * 60);
|
||||
int minutes = (time / 60) % 60;
|
||||
TextView distanceTv = (TextView) view.findViewById(R.id.distance);
|
||||
String text = OsmAndFormatter.getFormattedDistance(dist, app);
|
||||
SpannableStringBuilder distanceStr = new SpannableStringBuilder(text);
|
||||
int spaceIndex = text.indexOf(" ");
|
||||
if (spaceIndex != -1) {
|
||||
distanceStr.setSpan(new ForegroundColorSpan(getMainFontColor()), 0, spaceIndex, 0);
|
||||
}
|
||||
TextView distanceTv = (TextView) view.findViewById(R.id.distance);
|
||||
distanceTv.setText(distanceStr);
|
||||
|
||||
int time = routingHelper.getLeftTime();
|
||||
SpannableStringBuilder timeStr = new SpannableStringBuilder();
|
||||
if (hours > 0) {
|
||||
timeStr.append(String.valueOf(hours)).append(" ").append(app.getString(R.string.osmand_parking_hour)).append(" ");
|
||||
}
|
||||
if (minutes > 0) {
|
||||
timeStr.append(String.valueOf(minutes)).append(" ").append(app.getString(R.string.osmand_parking_minute));
|
||||
}
|
||||
timeStr.append(OsmAndFormatter.getFormattedDuration(time, app));
|
||||
spaceIndex = timeStr.toString().lastIndexOf(" ");
|
||||
if (spaceIndex != -1) {
|
||||
timeStr.setSpan(new ForegroundColorSpan(getMainFontColor()), 0, spaceIndex, 0);
|
||||
|
|
|
@ -1228,16 +1228,28 @@ public class RouteProvider {
|
|||
}
|
||||
|
||||
private RouteCalculationResult findOnlineRoute(RouteCalculationParams params) throws IOException, JSONException {
|
||||
OnlineRoutingHelper helper = params.ctx.getOnlineRoutingHelper();
|
||||
String stringKey = params.mode.getRoutingProfile();
|
||||
OsmandApplication app = params.ctx;
|
||||
OnlineRoutingHelper helper = app.getOnlineRoutingHelper();
|
||||
OsmandSettings settings = app.getSettings();
|
||||
String engineKey = params.mode.getRoutingProfile();
|
||||
OnlineRoutingResponse response =
|
||||
helper.calculateRouteOnline(stringKey, getPathFromParams(params), params.leftSide);
|
||||
helper.calculateRouteOnline(engineKey, getPathFromParams(params), params.leftSide);
|
||||
|
||||
if (response != null) {
|
||||
params.intermediates = null;
|
||||
return new RouteCalculationResult(response.getRoute(), response.getDirections(), params, null, false);
|
||||
} else {
|
||||
return new RouteCalculationResult("Route is empty");
|
||||
if (response.getGpxFile() != null) {
|
||||
GPXRouteParamsBuilder builder = new GPXRouteParamsBuilder(response.getGpxFile(), settings);
|
||||
params.gpxRoute = builder.build(app);
|
||||
return calculateGpxRoute(params);
|
||||
}
|
||||
List<Location> route = response.getRoute();
|
||||
List<RouteDirectionInfo> directions = response.getDirections();
|
||||
if (!Algorithms.isEmpty(route) && !Algorithms.isEmpty(directions)) {
|
||||
params.intermediates = null;
|
||||
return new RouteCalculationResult(route, directions, params, null, false);
|
||||
}
|
||||
}
|
||||
|
||||
return new RouteCalculationResult("Route is empty");
|
||||
}
|
||||
|
||||
private static List<LatLon> getPathFromParams(RouteCalculationParams params) {
|
||||
|
|
|
@ -232,18 +232,12 @@ class RouteRecalculationHelper {
|
|||
}
|
||||
|
||||
void startProgress(final RouteCalculationParams params) {
|
||||
app.runInUIThread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (params.calculationProgressCallback != null) {
|
||||
params.calculationProgressCallback.start();
|
||||
} else if (progressRoute != null) {
|
||||
progressRoute.start();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void updateProgress(final RouteCalculationParams params) {
|
||||
final RouteCalculationProgressCallback progressRoute;
|
||||
|
|
|
@ -237,13 +237,8 @@ public class TransportRoutingHelper {
|
|||
private void startProgress(final TransportRouteCalculationParams params) {
|
||||
final TransportRouteCalculationProgressCallback progressRoute = this.progressRoute;
|
||||
if (progressRoute != null) {
|
||||
app.runInUIThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
progressRoute.start();
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
setCurrentRoute(-1);
|
||||
}
|
||||
|
||||
|
|
|
@ -848,7 +848,8 @@ public class OsmandSettings {
|
|||
public final OsmandPreference<DrivingRegion> DRIVING_REGION = new EnumStringPreference<DrivingRegion>(this,
|
||||
"default_driving_region", DrivingRegion.EUROPE_ASIA, DrivingRegion.values()) {
|
||||
public boolean setValue(Object prefs, DrivingRegion val) {
|
||||
if (val != null) {
|
||||
boolean overrideMetricSystem = !DRIVING_REGION_AUTOMATIC.getValue(prefs, DRIVING_REGION_AUTOMATIC.getDefaultValue());
|
||||
if (overrideMetricSystem && val != null) {
|
||||
METRIC_SYSTEM.set(val.defMetrics);
|
||||
}
|
||||
return super.setValue(prefs, val);
|
||||
|
|
|
@ -66,7 +66,7 @@ public class BooleanPreferenceBottomSheet extends BasePreferenceBottomSheet {
|
|||
? getString(R.string.shared_string_disabled) : summaryOff.toString();
|
||||
final int activeColor = AndroidUtils.resolveAttribute(themedCtx, R.attr.active_color_basic);
|
||||
final int disabledColor = AndroidUtils.resolveAttribute(themedCtx, android.R.attr.textColorSecondary);
|
||||
boolean checked = pref.getModeValue(getAppMode());
|
||||
boolean checked = switchPreference.isChecked();
|
||||
|
||||
final BottomSheetItemWithCompoundButton[] preferenceBtn = new BottomSheetItemWithCompoundButton[1];
|
||||
preferenceBtn[0] = (BottomSheetItemWithCompoundButton) new BottomSheetItemWithCompoundButton.Builder()
|
||||
|
@ -77,7 +77,7 @@ public class BooleanPreferenceBottomSheet extends BasePreferenceBottomSheet {
|
|||
.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
boolean newValue = !pref.getModeValue(getAppMode());
|
||||
boolean newValue = !switchPreference.isChecked();
|
||||
Fragment targetFragment = getTargetFragment();
|
||||
if (targetFragment instanceof OnConfirmPreferenceChange) {
|
||||
ApplyQueryType applyQueryType = getApplyQueryType();
|
||||
|
|
|
@ -28,9 +28,10 @@ import net.osmand.AndroidUtils;
|
|||
import net.osmand.StateChangedListener;
|
||||
import net.osmand.plus.OsmAndFormatter;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.OsmandPlugin;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.UiUtilities;
|
||||
import net.osmand.plus.Version;
|
||||
import net.osmand.plus.development.OsmandDevelopmentPlugin;
|
||||
import net.osmand.plus.routing.RouteProvider;
|
||||
import net.osmand.plus.routing.RoutingHelper;
|
||||
import net.osmand.plus.settings.backend.ApplicationMode;
|
||||
|
@ -326,17 +327,10 @@ public class RouteParametersFragment extends BaseSettingsFragment implements OnP
|
|||
setupRouteRecalcHeader(screen);
|
||||
setupSelectRouteRecalcDistance(screen);
|
||||
setupReverseDirectionRecalculation(screen);
|
||||
addDivider(screen);
|
||||
setupDevelopmentCategoryHeader(screen);
|
||||
if (am.isDerivedRoutingFrom(ApplicationMode.PUBLIC_TRANSPORT)) {
|
||||
setupOsmLiveForPublicTransportPref();
|
||||
setupNativePublicTransport();
|
||||
|
||||
if (OsmandPlugin.isPluginEnabled(OsmandDevelopmentPlugin.class)) {
|
||||
setupDevelopmentCategoryPreferences(screen, am);
|
||||
}
|
||||
if (am.isDerivedRoutingFrom(ApplicationMode.CAR)) {
|
||||
setupOsmLiveForRoutingPref();
|
||||
setupDisableComplexRoutingPref();
|
||||
}
|
||||
setupFastRecalculationPref();
|
||||
}
|
||||
|
||||
private void setupOtherBooleanParameterSummary(ApplicationMode am, RoutingParameter p, SwitchPreferenceEx switchPreferenceEx) {
|
||||
|
@ -380,6 +374,20 @@ public class RouteParametersFragment extends BaseSettingsFragment implements OnP
|
|||
screen.addPreference(routingCategory);
|
||||
}
|
||||
|
||||
private void setupDevelopmentCategoryPreferences(PreferenceScreen screen, ApplicationMode am) {
|
||||
addDivider(screen);
|
||||
setupDevelopmentCategoryHeader(screen);
|
||||
if (am.isDerivedRoutingFrom(ApplicationMode.PUBLIC_TRANSPORT)) {
|
||||
setupOsmLiveForPublicTransportPref();
|
||||
setupNativePublicTransport();
|
||||
}
|
||||
if (am.isDerivedRoutingFrom(ApplicationMode.CAR)) {
|
||||
setupOsmLiveForRoutingPref();
|
||||
setupDisableComplexRoutingPref();
|
||||
}
|
||||
setupFastRecalculationPref();
|
||||
}
|
||||
|
||||
private void setupDevelopmentCategoryHeader(PreferenceScreen screen) {
|
||||
PreferenceCategory developmentCategory = new PreferenceCategory(requireContext());
|
||||
developmentCategory.setLayoutResource(R.layout.preference_category_with_descr);
|
||||
|
|
|
@ -64,6 +64,7 @@ import static net.osmand.plus.dialogs.ConfigureMapMenu.CURRENT_TRACK_COLOR_ATTR;
|
|||
import static net.osmand.plus.dialogs.GpxAppearanceAdapter.TRACK_WIDTH_BOLD;
|
||||
import static net.osmand.plus.dialogs.GpxAppearanceAdapter.TRACK_WIDTH_MEDIUM;
|
||||
import static net.osmand.plus.dialogs.GpxAppearanceAdapter.getAppearanceItems;
|
||||
import static net.osmand.plus.monitoring.TripRecordingActiveBottomSheet.UPDATE_TRACK_ICON;
|
||||
|
||||
public class TrackAppearanceFragment extends ContextMenuScrollFragment implements CardListener, ColorPickerListener {
|
||||
|
||||
|
@ -385,7 +386,7 @@ public class TrackAppearanceFragment extends ContextMenuScrollFragment implement
|
|||
if (target instanceof TripRecordingBottomSheet) {
|
||||
((TripRecordingBottomSheet) target).show();
|
||||
} else if (target instanceof TripRecordingActiveBottomSheet) {
|
||||
((TripRecordingActiveBottomSheet) target).show(true);
|
||||
((TripRecordingActiveBottomSheet) target).show(UPDATE_TRACK_ICON);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue