Merge branch 'master' into Point_menu_change_route_type

# Conflicts:
#	OsmAnd/src/net/osmand/plus/measurementtool/RouteBetweenPointsBottomSheetDialogFragment.java
This commit is contained in:
Vitaliy 2020-11-23 00:37:57 +02:00
commit 4c100c7366
760 changed files with 44218 additions and 22788 deletions

View file

@ -1,8 +1,8 @@
---
name: "📚 Outdated FAQ"
about: Report an issue in FAQ
---
🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑
Please do not file FAQ issues on the GitHub issues tracker.

View file

@ -2,68 +2,17 @@
name: "\U0001F41E Bug report"
about: Report a bug in OsmAnd
---
<!--🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅
Oh hi there! 😄
To expedite issue processing please search open and closed issues before submitting a new one.
Existing issues often contain information about workarounds, resolution, or progress updates.
GitHub is our main development tool for our developers. There are hundreds of requests a month and there are relatively few developers.
So by opening an issue, please know that your issue will be sent out to all developers and acknowledge that it could be closed without explanation or with just a brief message.
Comments on the closed issues are also sent to all developers, so you will definitely will be heard.
However, there is no guarantee that a developer will pick up the issue to work on it.
Please be sure to read our [FAQ](https://osmand.net/help-online) before creating an issue here.
The best way to get help about an OsmAnd issue is to create a valid and detailed issue.
Please give us the following information so that we can try to **reproduce** your issue:
🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅-->
# 🐞 bug report
### Is this a regression?
<!-- Did this behavior use to work in the previous version? -->
<!-- ✍️--> Yes, the previous version in which this bug was not present was: ....
### Description
<!-- ✍️--> A clear and concise description of the problem...
### How to reproduce?
## 🔬 Minimal Reproduction
<!--
If the bug is reproducible, please describe steps below:
-->
<!-- ✍️--> 1. Open app, and click on ...
## 🔥 Exception or Error
<pre><code>
<!-- If the issue is accompanied by an exception or an error, please share it below: -->
<!-- ✍️-->
</code></pre>
## 🌍 Your Environment
**OsmAnd Version:**
<pre><code>
<!-- paste version below -->
<!-- ✍️-->
</code></pre>
**Device and Android/iOS version:**
### Your Environment
OsmAnd Version:
Android/iOS version:
Device model:
**Maps used (online or offline):**
<!-- Please tick the correct box [x] (or both) -->
- [ ] Offline maps offered within the OsmAnd app for download.
<!-- If you have an issue related to offline maps, tell us the exact name of the map file where the issue occurs and its edition date. -->
- [ ] Online (tile / raster) maps <!-- Please name it -->
**Anything else relevant?**
If you have an issue related to offline maps, tell us the exact name of the map file where the issue occurs and its edition date.

View file

@ -2,6 +2,7 @@
name: "\U0001F6A9 Routing report"
about: Report a routing issue in OsmAnd
---
<!--🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅
Oh hi there! 😄
@ -26,10 +27,12 @@ Please give us the following information so that we can try to **reproduce** you
### Routing engine
<!-- Which routing provider was used? (please tick the proper box [x]) -->
- [ ] OsmAnd's in-app offline routing
- [ ] Any online routing provider (YOURS, OpenRouteService, OSRM, etc.)
### Routing Profile
<!-- What routing profile is chosen in the OsmAnd app? (car, bike, pedestrian, fastest or shortest, etc.) -->
### Start and end points
@ -38,6 +41,7 @@ Please give us the following information so that we can try to **reproduce** you
Also, a permalink from [openstreetmap.org](https://www.openstreetmap.org/) can be helpful. -->
### Actual and expected routes
<!-- Tell us your expected routing and how OsmAnd routes, or add screenshots here. -->
### Is this a regression?
@ -48,6 +52,7 @@ Also, a permalink from [openstreetmap.org](https://www.openstreetmap.org/) can b
## 🌍 Your Environment
**OsmAnd Version:**
<pre><code>
<!-- paste version below -->
<!-- ✍️-->
@ -57,10 +62,11 @@ Also, a permalink from [openstreetmap.org](https://www.openstreetmap.org/) can b
**Device and Android/iOS version:**
**Maps used (online or offline):**
<!-- Please tick the correct box [x] (or both) -->
- [ ] Offline maps offered within the OsmAnd app for download.
<!-- If you have an issue related to offline maps, tell us the exact name of the map file where the issue occurs and its edition date. -->
- [ ] Online (tile / raster) maps <!-- Please name it -->
**Anything else relevant?**

View file

@ -1,8 +1,8 @@
---
name: "\U0001F680 Feature request"
about: Suggest a feature for OsmAnd
---
<!--🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅
Oh hi there! 😄
@ -12,7 +12,7 @@ Existing issues often contain information about workarounds, resolution, or prog
GitHub is our main development tool for our developers. There are hundreds of requests a month and there are relatively few developers.
So by opening an issue, please know that your issue will be sent out to all developers and acknowledge that it could be closed without explanation or with just a brief message.
Comments on the closed issues are also sent to all developers, so you will definitely will be heard.
Comments on the closed issues are also sent to all developers, so you definitely will be heard.
However, there is no guarantee that a developer will pick up the issue to work on it.
Please be sure to read our [FAQ](https://osmand.net/help-online) before creating an issue here.
@ -22,12 +22,13 @@ Please be sure to read our [FAQ](https://osmand.net/help-online) before creating
# 🚀 feature request
### Description
<!-- ✍️--> A clear and concise description of the problem or missing capability...
<!-- ✍️ A clear and concise description of the feature... -->
### Describe the solution you'd like
<!-- ✍️--> If you have a solution in mind, please describe it.
### Describe alternatives you've considered
<!-- ✍️--> Have you considered any alternative solutions or workarounds?

4
.gitignore vendored
View file

@ -19,6 +19,10 @@ OsmAndCore_*.aar
.project
out/
# Huawei
agconnect-services.json
OsmAndHms.jks
# Android Studio
/.idea
*.iml

157
GPX.md Normal file
View file

@ -0,0 +1,157 @@
The OsmAnd's GPX file format conforms to the GPX 1.1 specification with additional data written as extensions. There are several sections of such data:
## Track appearance
The following parameters are used to customize the appearance of a track on the map. They are used inside the "gpx" tag and apply to all tracks contained in the gpx.
#### Parameters
* **show_arrows** [*true, false*] - show / hide arrows along the path line.
* **width** [*thin, medium, bold, 1-24*] - width of the track line on the map. The thin, medium, and bold are style depended values (should be defined as currentTrackWidth attribute).
* **color** [*#AARRGGBB, #RRGGBB*] - color of a track line on the map. Hex value.
* **split_type** [*no_split, distance, time*] - split type for a track.
* **split_interval** [*double*] - split interval for a track. Distance (meters), time (seconds).
#### Example:
```xml
<gpx version="1.1" creator="OsmAndRouterV2" xmlns="http://www.topografix.com/GPX/1/1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd">
...
<extensions>
<show_arrows>true</show_arrows>
<color>#4e4eff</color>
<split_type>distance</split_type>
<split_interval>2000.0</split_interval>
<width>bold</width>
</extensions>
</gpx>
```
## Details of a track point (trkpt)
Written to a gpx file while recording a track.
* **speed** (meters per second)
* **heading** (0-359 degrees)
#### Example:
```xml
<trkpt lat="52.397799" lon="4.575998">
<ele>203</ele>
<time>2019-05-08T10:36:43Z</time>
<hdop>3</hdop>
<extensions>
<heading>273</heading>
<speed>5.02</speed>
</extensions>
</trkpt>
```
## Calculated route(s)
This data contains all details of a route built with **OsmAnd** (route segments, turns, road names, road types, restrictions, etc.). The route can be completely restored as if just built, even in the absence of the respective offline maps.
A gpx file may contain several routes. Each of them is contained in a specific segment under **trkseg** / **extensions**. A gpx file is saved in this form when exporting a constructed route or when saving a track that consists of several separate segments via the **Plan a route** functionality.
**Plan a route** also adds one (or several, in accordance with the number of contained separate segments / tracks) **rte** blocks to the gpx file, containing route key points (**rtept**).
#### Gpx structure:
```xml
<trk>
<trkseg>
<!-- List of segment points. The order of the points corresponds to the order and length of the route segments (<route><segment length="x" ... />). -->
<!-- The value of the "length" attribute corresponds to the number of points in this segment of the route. -->
<trkpt ... ></trkpt>
<extensions>
<!-- List of route segments -->
<route>
<segment ... />
</route>
<!-- Properties of segments included in the route. -->
<!-- This data is taken from offline maps during the initial construction of a route. -->
<types>
<type ... />
</types>
</extensions>
</trkseg>
</trk>
<!-- List of intermediate route points. If there are multiple routes, the order of the rte list matches the order of the route segments. -->
<rte>
<rtept ... />
<!-- For routes built with the "Plan route", the parameters of key points are saved. -->
<extensions>
<!-- Route profile type for next segment (car, bicycle, pedestrian, etc.). -->
<profile>...</profile>
<!-- The index of the point in the gpx segment that corresponds to the first point of the calculated route for this segment. -->
<trkpt_idx>...</trkpt_idx>
</extensions>
</rtept>
</rte>
```
#### Example:
```xml
<gpx version="1.1" creator="OsmAndRouterV2" xmlns="http://www.topografix.com/GPX/1/1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd">
<metadata>
<name>Fri 06 Nov 2020</name>
</metadata>
<trk>
<name>Fri 06 Nov 2020</name>
<trkseg>
<trkpt lat="52.3639849" lon="4.8900533">
<ele>0.801</ele>
</trkpt>
<trkpt lat="52.3636917" lon="4.8922849">
<ele>0.998</ele>
</trkpt>
<trkpt lat="52.3636885" lon="4.892309">
<ele>1</ele>
</trkpt>
<trkpt lat="52.3636426" lon="4.8922902">
<ele>0.963</ele>
</trkpt>
<trkpt lat="52.363564" lon="4.8922607">
<ele>0.899</ele>
</trkpt>
....
<extensions>
<route>
<segment id="7372058" length="3" segmentTime="178.44" speed="1.11" turnType="C" types="0,1,2,3,4,5,6" names="57" />
<segment id="334164679" length="5" segmentTime="86.11" speed="1.11" turnType="TR" turnAngle="91.88" types="7,8,0,9,10,11,12,13,6" pointTypes=";;14,15;16,17,18;" names="58" />
<segment id="334603581" length="6" segmentTime="75.5" speed="1.11" types="19,20,21,7,8,0,22,9,10,11,12,13,23,6" pointTypes=";14;16,24;16,24;14;" names="58" />
<segment id="446707354" length="3" segmentTime="8.32" speed="1.11" turnType="TSLL" turnAngle="-25.44" types="19,25,21,7,8,22,9,1,11,12,13,6" names="58" />
...
</route>
<types>
<type t="lit" v="yes" />
<type t="oneway" v="yes" />
<type t="highway" v="unclassified" />
<type t="surface" v="paving_stones" />
<type t="maxspeed" v="30" />
...
</types>
</extensions>
</trkseg>
</trk>
<rte>
<rtept lat="52.3639945" lon="4.8900532">
<extensions>
<profile>pedestrian</profile>
<trkpt_idx>0</trkpt_idx>
</extensions>
</rtept>
<rtept lat="52.3612797" lon="4.8911677">
<extensions>
<profile>pedestrian</profile>
<trkpt_idx>24</trkpt_idx>
</extensions>
</rtept>
<rtept lat="52.356996" lon="4.8912071">
<extensions>
<profile>pedestrian</profile>
<trkpt_idx>89</trkpt_idx>
</extensions>
</rtept>
<rtept lat="52.3542374" lon="4.8947024">
<extensions>
<profile>pedestrian</profile>
<trkpt_idx>121</trkpt_idx>
</extensions>
</rtept>
</rte>
</gpx>
```

View file

@ -20,6 +20,8 @@ import net.osmand.aidlapi.mapmarker.UpdateMapMarkerParams;
import net.osmand.aidlapi.calculateroute.CalculateRouteParams;
import net.osmand.aidlapi.profile.ExportProfileParams;
import net.osmand.aidlapi.gpx.ImportGpxParams;
import net.osmand.aidlapi.gpx.ShowGpxParams;
import net.osmand.aidlapi.gpx.StartGpxRecordingParams;
@ -103,6 +105,8 @@ import net.osmand.aidlapi.events.AKeyEventsParams;
import net.osmand.aidlapi.info.AppInfoParams;
import net.osmand.aidlapi.profile.ExportProfileParams;
// NOTE: Add new methods at the end of file!!!
interface IOsmAndAidlInterface {
@ -867,4 +871,16 @@ interface IOsmAndAidlInterface {
AppInfoParams getAppInfo();
boolean setMapMargins(in MapMarginsParams params);
boolean exportProfile(in ExportProfileParams params);
/**
* Is any fragment open.
*/
boolean isFragmentOpen();
/**
* Is contect menu open.
*/
boolean isMenuOpen();
}

View file

@ -4,6 +4,8 @@ public interface OsmAndCustomizationConstants {
// Navigation Drawer:
String DRAWER_ITEM_ID_SCHEME = "drawer.action.";
String DRAWER_SWITCH_PROFILE_ID = DRAWER_ITEM_ID_SCHEME + "switch_profile";
String DRAWER_CONFIGURE_PROFILE_ID = DRAWER_ITEM_ID_SCHEME + "configure_profile";
String DRAWER_DASHBOARD_ID = DRAWER_ITEM_ID_SCHEME + "dashboard";
String DRAWER_MAP_MARKERS_ID = DRAWER_ITEM_ID_SCHEME + "map_markers";
String DRAWER_MY_PLACES_ID = DRAWER_ITEM_ID_SCHEME + "my_places";

View file

@ -9,12 +9,21 @@ import net.osmand.aidlapi.AidlParams;
public class CopyFileParams extends AidlParams {
public static final String DESTINATION_DIR_KEY = "destinationDir";
public static final String FILE_NAME_KEY = "fileName";
public static final String FILE_PART_DATA_KEY = "filePartData";
public static final String START_TIME_KEY = "startTime";
public static final String DONE_KEY = "done";
private String destinationDir;
private String fileName;
private byte[] filePartData;
private long startTime;
private boolean done;
public CopyFileParams(@NonNull String fileName, @NonNull byte[] filePartData, long startTime, boolean done) {
public CopyFileParams(@NonNull String destinationDir, @NonNull String fileName, @NonNull byte[] filePartData,
long startTime, boolean done) {
this.destinationDir = destinationDir;
this.fileName = fileName;
this.filePartData = filePartData;
this.startTime = startTime;
@ -37,6 +46,10 @@ public class CopyFileParams extends AidlParams {
}
};
public String getDestinationDir() {
return destinationDir;
}
public String getFileName() {
return fileName;
}
@ -55,23 +68,26 @@ public class CopyFileParams extends AidlParams {
@Override
public void writeToBundle(Bundle bundle) {
bundle.putString("fileName", fileName);
bundle.putByteArray("filePartData", filePartData);
bundle.putLong("startTime", startTime);
bundle.putBoolean("done", done);
bundle.putString(DESTINATION_DIR_KEY, destinationDir);
bundle.putString(FILE_NAME_KEY, fileName);
bundle.putByteArray(FILE_PART_DATA_KEY, filePartData);
bundle.putLong(START_TIME_KEY, startTime);
bundle.putBoolean(DONE_KEY, done);
}
@Override
protected void readFromBundle(Bundle bundle) {
fileName = bundle.getString("fileName");
filePartData = bundle.getByteArray("filePartData");
startTime = bundle.getLong("startTime");
done = bundle.getBoolean("done");
destinationDir = bundle.getString(DESTINATION_DIR_KEY);
fileName = bundle.getString(FILE_NAME_KEY);
filePartData = bundle.getByteArray(FILE_PART_DATA_KEY);
startTime = bundle.getLong(START_TIME_KEY);
done = bundle.getBoolean(DONE_KEY);
}
@Override
public String toString() {
return "CopyFileParams {" +
" destinationDir=" + destinationDir +
" fileName=" + fileName +
", filePartData size=" + filePartData.length +
", startTime=" + startTime +

View file

@ -3,18 +3,31 @@ package net.osmand.aidlapi.customization;
import android.os.Bundle;
import android.os.Parcel;
import androidx.annotation.Nullable;
import net.osmand.aidlapi.AidlParams;
import java.util.ArrayList;
import java.util.List;
public class MapMarginsParams extends AidlParams {
private String appModeKey;
public static final String LEFT_MARGIN_KEY = "leftMargin";
public static final String TOP_MARGIN_KEY = "topMargin";
public static final String RIGHT_MARGIN_KEY = "rightMargin";
public static final String BOTTOM_MARGIN_KEY = "bottomMargin";
public static final String APP_MODES_KEYS_KEY = "appModesKeys";
private ArrayList<String> appModesKeys = new ArrayList<>();
private int leftMargin;
private int topMargin;
private int rightMargin;
private int bottomMargin;
public MapMarginsParams(String appModeKey, int leftMargin, int topMargin, int rightMargin, int bottomMargin) {
this.appModeKey = appModeKey;
public MapMarginsParams(int leftMargin, int topMargin, int rightMargin, int bottomMargin,
@Nullable List<String> appModesKeys) {
if (appModesKeys != null) {
this.appModesKeys.addAll(appModesKeys);
}
this.leftMargin = leftMargin;
this.topMargin = topMargin;
this.rightMargin = rightMargin;
@ -37,8 +50,8 @@ public class MapMarginsParams extends AidlParams {
}
};
public String getAppModeKey() {
return appModeKey;
public List<String> getAppModesKeys() {
return appModesKeys;
}
public int getLeftMargin() {
@ -59,19 +72,19 @@ public class MapMarginsParams extends AidlParams {
@Override
public void writeToBundle(Bundle bundle) {
bundle.putString("appModeKey", appModeKey);
bundle.putInt("leftMargin", leftMargin);
bundle.putInt("topMargin", topMargin);
bundle.putInt("rightMargin", rightMargin);
bundle.putInt("bottomMargin", bottomMargin);
bundle.putInt(LEFT_MARGIN_KEY, leftMargin);
bundle.putInt(TOP_MARGIN_KEY, topMargin);
bundle.putInt(RIGHT_MARGIN_KEY, rightMargin);
bundle.putInt(BOTTOM_MARGIN_KEY, bottomMargin);
bundle.putStringArrayList(APP_MODES_KEYS_KEY, appModesKeys);
}
@Override
protected void readFromBundle(Bundle bundle) {
appModeKey = bundle.getString("appModeKey");
leftMargin = bundle.getInt("leftMargin");
topMargin = bundle.getInt("topMargin");
rightMargin = bundle.getInt("rightMargin");
bottomMargin = bundle.getInt("bottomMargin");
leftMargin = bundle.getInt(LEFT_MARGIN_KEY);
topMargin = bundle.getInt(TOP_MARGIN_KEY);
rightMargin = bundle.getInt(RIGHT_MARGIN_KEY);
bottomMargin = bundle.getInt(BOTTOM_MARGIN_KEY);
appModesKeys = bundle.getStringArrayList(APP_MODES_KEYS_KEY);
}
}

View file

@ -5,15 +5,31 @@ import android.os.Bundle;
import android.os.Parcel;
import net.osmand.aidlapi.AidlParams;
import net.osmand.aidlapi.profile.AExportSettingsType;
import java.util.ArrayList;
import static net.osmand.aidlapi.profile.ExportProfileParams.SETTINGS_TYPE_KEY;
public class ProfileSettingsParams extends AidlParams {
public static final String VERSION_KEY = "version";
public static final String REPLACE_KEY = "replace";
public static final String LATEST_CHANGES_KEY = "latestChanges";
public static final String PROFILE_SETTINGS_URI_KEY = "profileSettingsUri";
private Uri profileSettingsUri;
private String latestChanges;
private int version;
private ArrayList<String> settingsTypeKeyList = new ArrayList<>();
boolean replace;
public ProfileSettingsParams(Uri profileSettingsUri, String latestChanges, int version) {
public ProfileSettingsParams(Uri profileSettingsUri, ArrayList<AExportSettingsType> settingsTypeList, boolean replace,
String latestChanges, int version) {
this.profileSettingsUri = profileSettingsUri;
for (AExportSettingsType settingsType : settingsTypeList) {
settingsTypeKeyList.add(settingsType.name());
}
this.replace = replace;
this.latestChanges = latestChanges;
this.version = version;
}
@ -46,17 +62,29 @@ public class ProfileSettingsParams extends AidlParams {
return profileSettingsUri;
}
public ArrayList<String> getSettingsTypeKeys() {
return settingsTypeKeyList;
}
public boolean isReplace() {
return replace;
}
@Override
public void writeToBundle(Bundle bundle) {
bundle.putInt("version", version);
bundle.putString("latestChanges", latestChanges);
bundle.putParcelable("profileSettingsUri", profileSettingsUri);
bundle.putInt(VERSION_KEY, version);
bundle.putString(LATEST_CHANGES_KEY, latestChanges);
bundle.putParcelable(PROFILE_SETTINGS_URI_KEY, profileSettingsUri);
bundle.putStringArrayList(SETTINGS_TYPE_KEY, settingsTypeKeyList);
bundle.putBoolean(REPLACE_KEY, replace);
}
@Override
protected void readFromBundle(Bundle bundle) {
version = bundle.getInt("version");
latestChanges = bundle.getString("latestChanges");
profileSettingsUri = bundle.getParcelable("profileSettingsUri");
version = bundle.getInt(VERSION_KEY);
latestChanges = bundle.getString(LATEST_CHANGES_KEY);
profileSettingsUri = bundle.getParcelable(PROFILE_SETTINGS_URI_KEY);
settingsTypeKeyList = bundle.getStringArrayList(SETTINGS_TYPE_KEY);
replace = bundle.getBoolean(REPLACE_KEY);
}
}

View file

@ -0,0 +1,3 @@
package net.osmand.aidlapi.profile;
parcelable AExportSettingsType;

View file

@ -0,0 +1,11 @@
package net.osmand.aidlapi.profile;
public enum AExportSettingsType {
PROFILE,
QUICK_ACTIONS,
POI_TYPES,
MAP_SOURCES,
CUSTOM_RENDER_STYLE,
CUSTOM_ROUTING,
AVOID_ROADS;
}

View file

@ -0,0 +1,3 @@
package net.osmand.aidlapi.profile;
parcelable ExportProfileParams;

View file

@ -0,0 +1,61 @@
package net.osmand.aidlapi.profile;
import android.os.Bundle;
import android.os.Parcel;
import net.osmand.aidlapi.AidlParams;
import java.util.ArrayList;
import java.util.List;
public class ExportProfileParams extends AidlParams {
public static final String PROFILE_KEY = "profile";
public static final String SETTINGS_TYPE_KEY = "settings_type";
private String profile;
private ArrayList<String> settingsTypeKeyList = new ArrayList<>();
public ExportProfileParams(String profile, ArrayList<AExportSettingsType> settingsTypeList) {
this.profile = profile;
for (AExportSettingsType settingsType : settingsTypeList) {
settingsTypeKeyList.add(settingsType.name());
}
}
public ExportProfileParams(Parcel in) {
readFromParcel(in);
}
public static final Creator<ExportProfileParams> CREATOR = new Creator<ExportProfileParams>() {
@Override
public ExportProfileParams createFromParcel(Parcel in) {
return new ExportProfileParams(in);
}
@Override
public ExportProfileParams[] newArray(int size) {
return new ExportProfileParams[size];
}
};
public String getProfile() {
return profile;
}
public List<String> getSettingsTypeKeys() {
return settingsTypeKeyList;
}
@Override
public void writeToBundle(Bundle bundle) {
bundle.putString(PROFILE_KEY, profile);
bundle.putStringArrayList(SETTINGS_TYPE_KEY, settingsTypeKeyList);
}
@Override
protected void readFromBundle(Bundle bundle) {
profile = bundle.getString(PROFILE_KEY);
settingsTypeKeyList = bundle.getStringArrayList(SETTINGS_TYPE_KEY);
}
}

View file

@ -104,6 +104,9 @@ dependencies {
implementation 'com.moparisthebest:junidecode:0.1.1'
implementation 'com.vividsolutions:jts-core:1.14.0'
implementation 'com.google.openlocationcode:openlocationcode:1.0.4'
implementation ('com.github.scribejava:scribejava-apis:7.1.1') {
exclude group: "com.fasterxml.jackson.core"
}
// turn off for now
//implementation 'com.atilika.kuromoji:kuromoji-ipadic:0.9.0'
implementation 'net.sf.kxml:kxml2:2.1.8'

View file

@ -14,6 +14,10 @@
package com.jwetherell.openmap.common;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class MGRSPoint extends ZonedUTMPoint {
/**
@ -104,6 +108,15 @@ public class MGRSPoint extends ZonedUTMPoint {
* an UPPERCASE coordinate string is expected.
*/
protected void decode(String mgrsString) throws NumberFormatException {
if (mgrsString.contains(" ")) {
String[] parts = mgrsString.split(" ");
StringBuilder s = new StringBuilder();
for (String i : parts) {
s.append(i);
}
mgrsString = s.toString();
}
if (mgrsString == null || mgrsString.length() == 0) {
throw new NumberFormatException("MGRSPoint coverting from nothing");
}
@ -633,6 +646,97 @@ public class MGRSPoint extends ZonedUTMPoint {
return twoLetter;
}
public String toFlavoredString() {
try {
List<String> all = new ArrayList<>();
for (int i = 0; i <= mgrs.length(); i++) {
if (Character.isAlphabetic(mgrs.charAt(i))){
all.add(mgrs.substring(0,i+1));
all.add(mgrs.substring(i+1,i+3));
String remains = mgrs.substring(i+3);
all.add(remains.substring(0,remains.length()/2));
all.add(remains.substring(remains.length()/2));
break;
}
}
StringBuilder os = new StringBuilder();
for(String part: all){
if (os.length() > 0) os.append(" ");
os.append(part);
}
return os.toString();
}catch (Exception e){
return mgrs;
}
}
public String toFlavoredString(int accuracy) {
try {
List<String> all = new ArrayList<>();
for (int i = 0; i <= mgrs.length(); i++) {
if (Character.isAlphabetic(mgrs.charAt(i))){
all.add(mgrs.substring(0,i+1));
all.add(mgrs.substring(i+1,i+3));
String remains = mgrs.substring(i+3);
int easting = Integer.parseInt(remains.substring(0,remains.length()/2));
int northing = Integer.parseInt(remains.substring(remains.length()/2));
double resolution = Math.pow(10, getAccuracy() - accuracy);
long roundedEasting = Math.round(easting/resolution);
long roundedNorthing = Math.round(northing/resolution);
int eastShift = 0;
int northShift = 0;
if (roundedEasting == resolution*10){
roundedEasting = 0L;
eastShift = 1;
}
if (roundedNorthing == resolution*10){
roundedNorthing = 0L;
northShift = 1;
}
if (eastShift != 0 || northShift != 0){
all.set(1, shiftChar(all.get(1), eastShift, northShift));
String zero = "";
}
all.add(String.format("%0" + accuracy + "d", roundedEasting));
all.add(String.format("%0" + accuracy + "d", roundedNorthing));
break;
}
}
StringBuilder os = new StringBuilder();
for(String part: all){
if (os.length() > 0) os.append(" ");
os.append(part);
}
return os.toString();
}catch (Exception e){
return toFlavoredString();
}
}
private static String shiftChar(String chars, int east, int north){
ArrayList<Character> keys = new ArrayList<Character>(
Arrays.asList('A','B','C','D','E','F','G','H','J','K','L','M','N','P','Q','R','S','T','U','V','W','X','Y','Z'));
StringBuilder s = new StringBuilder();
if (east != 0){
int idx = keys.indexOf(chars.charAt(0));
idx += east;
if (idx >= keys.size()) idx -= keys.size();
if (idx < 0) idx += keys.size();
s.append(keys.get(idx));
}else s.append(chars.charAt(0));
if (north != 0){
int idx = keys.indexOf(chars.charAt(1));
idx += north;
if (idx >= keys.size()) idx -= keys.size();
if (idx < 0) idx += keys.size();
s.append(keys.get(idx));
}else s.append(chars.charAt(1));
return s.toString();
}
/**
* {@inheritDoc}
*/

View file

@ -52,9 +52,10 @@ public class GPXUtilities {
private static final String DEFAULT_ICON_NAME = "special_star";
private static final String BACKGROUND_TYPE_EXTENSION = "background";
private static final String PROFILE_TYPE_EXTENSION = "profile";
private static final String GAP_PROFILE_TYPE = "gap";
private static final String TRKPT_INDEX_EXTENSION = "trkpt_idx";
private final static String GPX_TIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'"; //$NON-NLS-1$
public final static String GPX_TIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'"; //$NON-NLS-1$
private final static String GPX_TIME_FORMAT_MILLIS = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"; //$NON-NLS-1$
private final static NumberFormat latLonFormat = new DecimalFormat("0.00#####", new DecimalFormatSymbols(
@ -70,6 +71,7 @@ public class GPXUtilities {
WHITE(0xFFFFFFFF),
RED(0xFFFF0000),
GREEN(0xFF00FF00),
DARKGREEN(0xFF006400),
BLUE(0xFF0000FF),
YELLOW(0xFFFFFF00),
CYAN(0xFF00FFFF),
@ -324,6 +326,20 @@ public class GPXUtilities {
getExtensionsToWrite().put(PROFILE_TYPE_EXTENSION, profileType);
}
public boolean hasProfile() {
String profileType = getProfileType();
return profileType != null && !GAP_PROFILE_TYPE.equals(profileType);
}
public boolean isGap() {
String profileType = getProfileType();
return GAP_PROFILE_TYPE.equals(profileType);
}
public void setGap() {
setProfileType(GAP_PROFILE_TYPE);
}
public void removeProfileType() {
getExtensionsToWrite().remove(PROFILE_TYPE_EXTENSION);
}
@ -374,11 +390,16 @@ public class GPXUtilities {
public static class TrkSegment extends GPXExtensions {
public boolean generalSegment = false;
public List<WptPt> points = new ArrayList<>();
public Object renderer;
public List<RouteSegment> routeSegments = new ArrayList<>();
public List<RouteType> routeTypes = new ArrayList<>();
public boolean hasRoute() {
return !routeSegments.isEmpty() && !routeTypes.isEmpty();
}
public List<GPXTrackAnalysis> splitByDistance(double meters, boolean joinSegments) {
return split(getDistanceMetric(), getTimeSplit(), meters, joinSegments);
@ -393,7 +414,6 @@ public class GPXUtilities {
splitSegment(metric, secondaryMetric, metricLimit, splitSegments, this, joinSegments);
return convert(splitSegments);
}
}
public static class Track extends GPXExtensions {
@ -1078,9 +1098,6 @@ public class GPXUtilities {
private List<WptPt> points = new ArrayList<>();
public List<Route> routes = new ArrayList<>();
public List<RouteSegment> routeSegments = new ArrayList<>();
public List<RouteType> routeTypes = new ArrayList<>();
public Exception error = null;
public String path = "";
public boolean showCurrentTrack;
@ -1108,7 +1125,7 @@ public class GPXUtilities {
}
public boolean hasRoute() {
return !routeSegments.isEmpty() && !routeTypes.isEmpty();
return getNonEmptyTrkSegments(true).size() > 0;
}
public List<WptPt> getPoints() {
@ -1218,7 +1235,7 @@ public class GPXUtilities {
GPXTrackAnalysis g = new GPXTrackAnalysis();
g.wptPoints = points.size();
g.wptCategoryNames = getWaypointCategories(true);
List<SplitSegment> splitSegments = new ArrayList<GPXUtilities.SplitSegment>();
List<SplitSegment> splitSegments = new ArrayList<>();
for (int i = 0; i < tracks.size(); i++) {
Track subtrack = tracks.get(i);
for (TrkSegment segment : subtrack.segments) {
@ -1243,6 +1260,15 @@ public class GPXUtilities {
return points;
}
public List<WptPt> getRoutePoints(int routeIndex) {
List<WptPt> points = new ArrayList<>();
if (routes.size() > routeIndex) {
Route rt = routes.get(routeIndex);
points.addAll(rt.points);
}
return points;
}
public boolean hasRtePt() {
for (Route r : routes) {
if (r.points.size() > 0) {
@ -1318,15 +1344,16 @@ public class GPXUtilities {
return pt;
}
public TrkSegment getNonEmptyTrkSegment() {
for (GPXUtilities.Track t : tracks) {
public List<TrkSegment> getNonEmptyTrkSegments(boolean routesOnly) {
List<TrkSegment> segments = new ArrayList<>();
for (Track t : tracks) {
for (TrkSegment s : t.segments) {
if (s.points.size() > 0) {
return s;
if (!s.generalSegment && s.points.size() > 0 && (!routesOnly || s.hasRoute())) {
segments.add(s);
}
}
}
return null;
return segments;
}
public void addTrkSegment(List<WptPt> points) {
@ -1365,8 +1392,8 @@ public class GPXUtilities {
return false;
}
public void addRoutePoints(List<WptPt> points) {
if (routes.size() == 0) {
public void addRoutePoints(List<WptPt> points, boolean addRoute) {
if (routes.size() == 0 || addRoute) {
Route route = new Route();
routes.add(route);
}
@ -1608,7 +1635,7 @@ public class GPXUtilities {
bottom = Math.min(bottom, p.getLatitude());
}
}
for (GPXUtilities.Route route : routes) {
for (Route route : routes) {
for (WptPt p : route.points) {
if (left == 0 && right == 0) {
left = p.getLongitude();
@ -1720,7 +1747,7 @@ public class GPXUtilities {
public static String asString(GPXFile file) {
final Writer writer = new StringWriter();
GPXUtilities.writeGpx(writer, file);
writeGpx(writer, file);
return writer.toString();
}
@ -1807,6 +1834,8 @@ public class GPXUtilities {
writeWpt(format, serializer, p);
serializer.endTag(null, "trkpt"); //$NON-NLS-1$
}
assignRouteExtensionWriter(segment);
writeExtensions(serializer, segment);
serializer.endTag(null, "trkseg"); //$NON-NLS-1$
}
writeExtensions(serializer, track);
@ -1834,7 +1863,6 @@ public class GPXUtilities {
serializer.endTag(null, "wpt"); //$NON-NLS-1$
}
assignRouteExtensionWriter(file);
writeExtensions(serializer, file);
serializer.endTag(null, "gpx"); //$NON-NLS-1$
@ -1847,19 +1875,19 @@ public class GPXUtilities {
return null;
}
private static void assignRouteExtensionWriter(final GPXFile gpxFile) {
if (gpxFile.hasRoute() && gpxFile.getExtensionsWriter() == null) {
gpxFile.setExtensionsWriter(new GPXExtensionsWriter() {
private static void assignRouteExtensionWriter(final TrkSegment segment) {
if (segment.hasRoute() && segment.getExtensionsWriter() == null) {
segment.setExtensionsWriter(new GPXExtensionsWriter() {
@Override
public void writeExtensions(XmlSerializer serializer) {
StringBundle bundle = new StringBundle();
List<StringBundle> segmentsBundle = new ArrayList<>();
for (RouteSegment segment : gpxFile.routeSegments) {
for (RouteSegment segment : segment.routeSegments) {
segmentsBundle.add(segment.toStringBundle());
}
bundle.putBundleList("route", "segment", segmentsBundle);
List<StringBundle> typesBundle = new ArrayList<>();
for (RouteType routeType : gpxFile.routeTypes) {
for (RouteType routeType : segment.routeTypes) {
typesBundle.add(routeType.toStringBundle());
}
bundle.putBundleList("types", "type", typesBundle);
@ -1901,12 +1929,15 @@ public class GPXUtilities {
}
private static void writeExtensions(XmlSerializer serializer, GPXExtensions p) throws IOException {
Map<String, String> extensionsToRead = p.getExtensionsToRead();
writeExtensions(serializer, p.getExtensionsToRead(), p);
}
private static void writeExtensions(XmlSerializer serializer, Map<String, String> extensions, GPXExtensions p) throws IOException {
GPXExtensionsWriter extensionsWriter = p.getExtensionsWriter();
if (!extensionsToRead.isEmpty() || extensionsWriter != null) {
if (!extensions.isEmpty() || extensionsWriter != null) {
serializer.startTag(null, "extensions");
if (!extensionsToRead.isEmpty()) {
for (Entry<String, String> s : extensionsToRead.entrySet()) {
if (!extensions.isEmpty()) {
for (Entry<String, String> s : extensions.entrySet()) {
writeNotNullText(serializer, s.getKey(), s.getValue());
}
}
@ -1943,8 +1974,21 @@ public class GPXUtilities {
if (!Float.isNaN(p.heading)) {
p.getExtensionsToWrite().put("heading", String.valueOf(Math.round(p.heading)));
}
Map<String, String> extensions = p.getExtensionsToRead();
if (!"rtept".equals(serializer.getName())) {
// Leave "profile" and "trkpt" tags for rtept only
extensions.remove(PROFILE_TYPE_EXTENSION);
extensions.remove(TRKPT_INDEX_EXTENSION);
writeExtensions(serializer, extensions, p);
} else {
// Remove "gap" profile
String profile = extensions.get(PROFILE_TYPE_EXTENSION);
if (GAP_PROFILE_TYPE.equals(profile)) {
extensions.remove(PROFILE_TYPE_EXTENSION);
}
writeExtensions(serializer, p);
}
}
private static void writeAuthor(XmlSerializer serializer, Author author) throws IOException {
writeNotNullText(serializer, "name", author.name);
@ -2099,10 +2143,11 @@ public class GPXUtilities {
TrkSegment routeTrackSegment = new TrkSegment();
routeTrack.segments.add(routeTrackSegment);
Stack<GPXExtensions> parserState = new Stack<>();
TrkSegment firstSegment = null;
boolean extensionReadMode = false;
boolean routePointExtension = false;
List<RouteSegment> routeSegments = gpxFile.routeSegments;
List<RouteType> routeTypes = gpxFile.routeTypes;
List<RouteSegment> routeSegments = new ArrayList<>();
List<RouteType> routeTypes = new ArrayList<>();
boolean routeExtension = false;
boolean typesExtension = false;
parserState.push(gpxFile);
@ -2403,6 +2448,16 @@ public class GPXUtilities {
assert pop instanceof Route;
} else if (tag.equals("trkseg")) {
Object pop = parserState.pop();
if (pop instanceof TrkSegment) {
TrkSegment segment = (TrkSegment) pop;
segment.routeSegments = routeSegments;
segment.routeTypes = routeTypes;
routeSegments = new ArrayList<>();
routeTypes = new ArrayList<>();
if (firstSegment == null) {
firstSegment = segment;
}
}
assert pop instanceof TrkSegment;
} else if (tag.equals("rpt")) {
Object pop = parserState.pop();
@ -2413,6 +2468,10 @@ public class GPXUtilities {
if (!routeTrackSegment.points.isEmpty()) {
gpxFile.tracks.add(routeTrack);
}
if (!routeSegments.isEmpty() && !routeTypes.isEmpty() && firstSegment != null) {
firstSegment.routeSegments = routeSegments;
firstSegment.routeTypes = routeTypes;
}
} catch (Exception e) {
gpxFile.error = e;
log.error("Error reading gpx", e); //$NON-NLS-1$

View file

@ -45,7 +45,7 @@ public interface IProgress {
public boolean isInterrupted() {return false;}
@Override
public boolean isIndeterminate() {return false;}
public boolean isIndeterminate() {return true;}
@Override
public void finishTask() {}

View file

@ -15,6 +15,7 @@ public class IndexConstants {
public static final String POI_INDEX_EXT = ".poi.odb"; //$NON-NLS-1$
public static final String ZIP_EXT = ".zip"; //$NON-NLS-1$
public static final String BINARY_MAP_INDEX_EXT = ".obf"; //$NON-NLS-1$
public static final String BINARY_MAP_INDEX_EXT_ZIP = ".obf.zip"; //$NON-NLS-1$
@ -45,6 +46,9 @@ public class IndexConstants {
public static final String GPX_FILE_EXT = ".gpx"; //$NON-NLS-1$
public static final String WPT_CHART_FILE_EXT = ".wpt.chart";
public static final String SQLITE_CHART_FILE_EXT = ".3d.chart";
public final static String POI_TABLE = "poi"; //$NON-NLS-1$
public static final String INDEX_DOWNLOAD_DOMAIN = "download.osmand.net";
@ -73,4 +77,6 @@ public class IndexConstants {
public static final String TEMP_DIR = "temp/";
public static final String ROUTING_PROFILES_DIR = "routing/";
public static final String PLUGINS_DIR = "plugins/";
public static final String VOICE_PROVIDER_SUFFIX = "-tts";
}

View file

@ -15,6 +15,7 @@ public class LocationConvert {
public static final int FORMAT_SECONDS = 2;
public static final int UTM_FORMAT = 3;
public static final int OLC_FORMAT = 4;
public static final int MGRS_FORMAT = 5;
private static final char DELIM = ':';
private static final char DELIMITER_DEGREES = '°';
private static final char DELIMITER_MINUTES = '';

View file

@ -108,7 +108,9 @@ public class TspAnt {
public TspAnt readGraph(List<LatLon> intermediates, LatLon start, LatLon end) {
boolean keepEndPoint = end != null;
List<LatLon> l = new ArrayList<LatLon>();
if (start != null) {
l.add(start);
}
l.addAll(intermediates);
if (keepEndPoint) {
l.add(end);

View file

@ -11,8 +11,6 @@ import java.util.Arrays;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import net.osmand.Collator;
import net.osmand.CollatorStringMatcher;
@ -576,13 +574,12 @@ public class BinaryMapPoiReaderAdapter {
}
}
if (!matches) {
Map<String, String> lt = am.getAdditionalInfo();
for (Entry<String, String> e : lt.entrySet()) {
if(!e.getKey().contains("_name") &&
!e.getKey().equals("brand")) {
for (String key : am.getAdditionalInfoKeys()) {
if(!key.contains("_name") &&
!key.equals("brand")) {
continue;
}
matches = matcher.matches(e.getValue());
matches = matcher.matches(am.getAdditionalInfo(key));
if (matches) {
break;
}
@ -812,7 +809,6 @@ public class BinaryMapPoiReaderAdapter {
}
private boolean checkCategories(SearchRequest<Amenity> req, PoiRegion region) throws IOException {
StringBuilder subType = new StringBuilder();
while (true) {
int t = codedIS.readTag();
int tag = WireFormat.getTagFieldNumber(t);

View file

@ -334,6 +334,7 @@ public class GeocodingUtilities {
boolean eqStreet = Algorithms.stringsEqual(gr1.streetName, gr2.streetName);
if (eqStreet) {
boolean sameObj = false;
if (gr1.city != null && gr2.city != null) {
if (gr1.building != null && gr2.building != null) {
if (Algorithms.stringsEqual(gr1.building.getName(), gr2.building.getName())) {
// same building
@ -343,6 +344,7 @@ public class GeocodingUtilities {
// same street
sameObj = true;
}
}
if (sameObj) {
double cityDist1 = MapUtils.getDistance(gr1.searchPoint, gr1.city.getLocation());
double cityDist2 = MapUtils.getDistance(gr2.searchPoint, gr2.city.getLocation());

View file

@ -1,17 +1,7 @@
package net.osmand.data;
import net.osmand.Location;
import net.osmand.osm.MapPoiTypes;
import net.osmand.osm.PoiCategory;
import net.osmand.util.Algorithms;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
@ -21,9 +11,14 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeSet;
import java.util.zip.GZIPInputStream;
import org.json.JSONObject;
import gnu.trove.list.array.TIntArrayList;
import net.osmand.Location;
import net.osmand.osm.MapPoiTypes;
import net.osmand.osm.PoiCategory;
import net.osmand.util.Algorithms;
public class Amenity extends MapObject {
@ -96,13 +91,47 @@ public class Amenity extends MapObject {
}
public Map<String, String> getAdditionalInfo() {
// this method should be used carefully
public Map<String, String> getInternalAdditionalInfoMap() {
if (additionalInfo == null) {
return Collections.emptyMap();
}
return additionalInfo;
}
public Collection<String> getAdditionalInfoValues(boolean excludeZipped) {
if (additionalInfo == null) {
return Collections.emptyList();
}
boolean zipped = false;
for(String v : additionalInfo.values()) {
if(isContentZipped(v)) {
zipped = true;
break;
}
}
if(zipped) {
List<String> r = new ArrayList<>(additionalInfo.size());
for(String str : additionalInfo.values()) {
if(excludeZipped && isContentZipped(str)) {
} else {
r.add(unzipContent(str));
}
}
return r;
} else {
return additionalInfo.values();
}
}
public Collection<String> getAdditionalInfoKeys() {
if (additionalInfo == null) {
return Collections.emptyList();
}
return additionalInfo.keySet();
}
public void setAdditionalInfo(Map<String, String> additionalInfo) {
this.additionalInfo = null;
openingHours = null;
@ -134,7 +163,7 @@ public class Amenity extends MapObject {
}
this.additionalInfo.put(tag, value);
if (OPENING_HOURS.equals(tag)) {
this.openingHours = value;
this.openingHours = unzipContent(value);
}
}
}
@ -182,7 +211,7 @@ public class Amenity extends MapObject {
}
int maxLen = 0;
String lng = defLang;
for (String nm : getAdditionalInfo().keySet()) {
for (String nm : getAdditionalInfoKeys()) {
if (nm.startsWith(tag + ":")) {
String key = nm.substring(tag.length() + 1);
String cnt = getAdditionalInfo(tag + ":" + key);
@ -204,7 +233,7 @@ public class Amenity extends MapObject {
public List<String> getNames(String tag, String defTag) {
List<String> l = new ArrayList<String>();
for (String nm : getAdditionalInfo().keySet()) {
for (String nm : getAdditionalInfoKeys()) {
if (nm.startsWith(tag + ":")) {
l.add(nm.substring(tag.length() + 1));
} else if (nm.equals(tag)) {
@ -229,7 +258,7 @@ public class Amenity extends MapObject {
if (!Algorithms.isEmpty(enName)) {
return enName;
}
for (String nm : getAdditionalInfo().keySet()) {
for (String nm : getAdditionalInfoKeys()) {
if (nm.startsWith(tag + ":")) {
return getAdditionalInfo(nm);
}
@ -345,4 +374,6 @@ public class Amenity extends MapObject {
}
return a;
}
}

View file

@ -25,6 +25,10 @@ public class City extends MapObject {
return radius;
}
public boolean storedAsSeparateAdminEntity() {
return this != DISTRICT && this != NEIGHBOURHOOD && this != BOROUGH;
}
public static String valueToString(CityType t) {
return t.toString().toLowerCase();
}

View file

@ -13,7 +13,6 @@ import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
@ -351,8 +350,8 @@ public abstract class MapObject implements Comparable<MapObject> {
return json;
}
public String unzipContent(String str) {
if (str != null && str.startsWith(" gz ")) {
String unzipContent(String str) {
if (isContentZipped(str)) {
try {
int ind = 4;
byte[] bytes = new byte[str.length() - ind];
@ -369,6 +368,10 @@ public abstract class MapObject implements Comparable<MapObject> {
}
br.close();
str = bld.toString();
// ugly fix of temporary problem of map generation
if(isContentZipped(str)) {
str = unzipContent(str);
}
} catch (IOException e) {
e.printStackTrace();
}
@ -376,6 +379,10 @@ public abstract class MapObject implements Comparable<MapObject> {
return str;
}
boolean isContentZipped(String str) {
return str != null && str.startsWith(" gz ");
}
protected static void parseJSON(JSONObject json, MapObject o) {
if (json.has("name")) {
o.name = json.getString("name");

View file

@ -823,7 +823,7 @@ public class MapPoiTypes {
}
String name = keyName;
name = name.replace('_', ' ');
return Algorithms.capitalizeFirstLetterAndLowercase(name);
return Algorithms.capitalizeFirstLetter(name);
}
public boolean isRegisteredType(PoiCategory t) {

View file

@ -27,7 +27,7 @@ public abstract class MapRenderingTypes {
private static final Log log = PlatformUtil.getLog(MapRenderingTypes.class);
public static final String[] langs = new String[] { "af", "als", "ar", "az", "be", "bg", "bn", "bpy", "br", "bs", "ca", "ceb", "cs", "cy", "da", "de", "el", "eo", "es", "et", "eu", "fa", "fi", "fr", "fy", "ga", "gl", "he", "hi", "hsb",
"hr", "ht", "hu", "hy", "id", "is", "it", "ja", "ka", "ko", "ku", "la", "lb", "lo", "lt", "lv", "mk", "ml", "mr", "ms", "nds", "new", "nl", "nn", "no", "nv", "os", "pl", "pms", "pt", "ro", "ru", "sc", "sh", "sk", "sl", "sq", "sr", "sv", "sw", "ta", "te", "th", "tl", "tr", "uk", "vi", "vo", "zh", "zh-hans", "zh-hant", };
"hr", "ht", "hu", "hy", "id", "is", "it", "ja", "ka", "kn", "ko", "ku", "la", "lb", "lo", "lt", "lv", "mk", "ml", "mr", "ms", "nds", "new", "nl", "nn", "no", "nv", "os", "pl", "pms", "pt", "ro", "ru", "sc", "sh", "sk", "sl", "sq", "sr", "sv", "sw", "ta", "te", "th", "tl", "tr", "uk", "vi", "vo", "zh", "zh-hans", "zh-hant", };
public final static byte RESTRICTION_NO_RIGHT_TURN = 1;

View file

@ -114,6 +114,8 @@ public abstract class Entity implements Serializable {
public static final int MODIFY_DELETED = -1;
public static final int MODIFY_MODIFIED = 1;
public static final int MODIFY_CREATED = 2;
public static final String POI_TYPE_TAG = "poi_type_tag";
public static final String REMOVE_TAG_PREFIX = "----";
public Entity(long id) {
this.id = id;
@ -241,6 +243,11 @@ public abstract class Entity implements Serializable {
return Collections.unmodifiableMap(tags);
}
public boolean isNotValid(String tag) {
String val = getTag(tag);
return val == null || val.length() == 0 || tag.length() == 0
|| tag.startsWith(REMOVE_TAG_PREFIX) || tag.equals(POI_TYPE_TAG);
}
public Collection<String> getTagKeySet() {
if (tags == null) {

View file

@ -1,30 +1,22 @@
package net.osmand.osm.io;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.Proxy;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Map;
import java.util.zip.GZIPOutputStream;
import com.github.scribejava.core.model.OAuthRequest;
import com.github.scribejava.core.model.Response;
import com.github.scribejava.core.model.Verb;
import net.osmand.PlatformUtil;
import net.osmand.osm.oauth.OsmOAuthAuthorizationClient;
import net.osmand.util.Algorithms;
import org.apache.commons.logging.Log;
import java.io.*;
import java.net.*;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.zip.GZIPOutputStream;
public class NetworkUtils {
private static final Log log = PlatformUtil.getLog(NetworkUtils.class);
private static final String GPX_UPLOAD_USER_AGENT = "OsmGPXUploadAgent";
private static Proxy proxy = null;
public static String sendGetRequest(String urlText, String userNamePassword, StringBuilder responseBody){
@ -55,7 +47,6 @@ public class NetworkUtils {
responseBody.append("\n"); //$NON-NLS-1$
}
responseBody.append(s);
}
is.close();
}
@ -65,9 +56,10 @@ public class NetworkUtils {
return e.getMessage();
}
}
private static final String BOUNDARY = "CowMooCowMooCowCowCow"; //$NON-NLS-1$
public static String uploadFile(String urlText, File fileToUpload, String userNamePassword, String formName, boolean gzip, Map<String, String> additionalMapData){
public static String uploadFile(String urlText, File fileToUpload, String userNamePassword,
OsmOAuthAuthorizationClient client,
String formName, boolean gzip, Map<String, String> additionalMapData){
URL url;
try {
boolean firstPrm =!urlText.contains("?");
@ -77,23 +69,37 @@ public class NetworkUtils {
}
log.info("Start uploading file to " + urlText + " " +fileToUpload.getName());
url = new URL(urlText);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
HttpURLConnection conn;
if (client != null && client.isValidToken()){
OAuthRequest req = new OAuthRequest(Verb.POST, urlText);
client.getService().signRequest(client.getAccessToken(), req);
req.addHeader("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);
try {
Response r = client.getHttpClient().execute(GPX_UPLOAD_USER_AGENT, req.getHeaders(), req.getVerb(),
req.getCompleteUrl(), fileToUpload);
if (r.getCode() != 200) {
return r.getBody();
}
return null;
} catch (InterruptedException e) {
log.error(e);
} catch (ExecutionException e) {
log.error(e);
}
return null;
}
else {
conn = (HttpURLConnection) url.openConnection();
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setRequestMethod("POST");
if(userNamePassword != null) {
conn.setRequestProperty("Authorization", "Basic " + Base64.encode(userNamePassword)); //$NON-NLS-1$ //$NON-NLS-2$
}
}
conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY); //$NON-NLS-1$ //$NON-NLS-2$
conn.setRequestProperty("User-Agent", "OsmAnd"); //$NON-NLS-1$ //$NON-NLS-2$
OutputStream ous = conn.getOutputStream();
// for (String key : additionalMapData.keySet()) {
// ous.write(("--" + BOUNDARY + "\r\n").getBytes());
// ous.write(("content-disposition: form-data; name=\"" + key + "\"\r\n").getBytes()); //$NON-NLS-1$ //$NON-NLS-2$
// ous.write((additionalMapData.get(key) + "\r\n").getBytes());
// }
ous.write(("--" + BOUNDARY + "\r\n").getBytes());
String filename = fileToUpload.getName();
if (gzip) {
@ -112,7 +118,6 @@ public class NetworkUtils {
} else {
Algorithms.streamCopy(bis, ous);
}
ous.write(("\r\n--" + BOUNDARY + "--\r\n").getBytes()); //$NON-NLS-1$ //$NON-NLS-2$
ous.flush();
Algorithms.closeStream(bis);
@ -136,7 +141,6 @@ public class NetworkUtils {
responseBody.append("\n"); //$NON-NLS-1$
}
responseBody.append(s);
}
is.close();
}
@ -157,7 +161,6 @@ public class NetworkUtils {
proxy = null;
}
}
public static Proxy getProxy() {
return proxy;
}

View file

@ -0,0 +1,259 @@
package net.osmand.osm.oauth;
import com.github.scribejava.core.exceptions.OAuthException;
import com.github.scribejava.core.httpclient.HttpClient;
import com.github.scribejava.core.httpclient.jdk.JDKHttpClientConfig;
import com.github.scribejava.core.httpclient.jdk.JDKHttpFuture;
import com.github.scribejava.core.httpclient.multipart.MultipartPayload;
import com.github.scribejava.core.httpclient.multipart.MultipartUtils;
import com.github.scribejava.core.model.*;
import net.osmand.util.Algorithms;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
public class OsmAndJDKHttpClient implements HttpClient {
private static final String BOUNDARY = "CowMooCowMooCowCowCow";
private final JDKHttpClientConfig config;
public OsmAndJDKHttpClient() {
this(JDKHttpClientConfig.defaultConfig());
}
public OsmAndJDKHttpClient(JDKHttpClientConfig clientConfig) {
config = clientConfig;
}
@Override
public void close() {
}
@Override
public <T> Future<T> executeAsync(String userAgent, Map<String, String> headers, Verb httpVerb, String completeUrl,
byte[] bodyContents, OAuthAsyncRequestCallback<T> callback, OAuthRequest.ResponseConverter<T> converter) {
return doExecuteAsync(userAgent, headers, httpVerb, completeUrl, BodyType.BYTE_ARRAY, bodyContents, callback,
converter);
}
@Override
public <T> Future<T> executeAsync(String userAgent, Map<String, String> headers, Verb httpVerb, String completeUrl,
MultipartPayload bodyContents, OAuthAsyncRequestCallback<T> callback,
OAuthRequest.ResponseConverter<T> converter) {
return doExecuteAsync(userAgent, headers, httpVerb, completeUrl, BodyType.MULTIPART, bodyContents, callback,
converter);
}
@Override
public <T> Future<T> executeAsync(String userAgent, Map<String, String> headers, Verb httpVerb, String completeUrl,
String bodyContents, OAuthAsyncRequestCallback<T> callback, OAuthRequest.ResponseConverter<T> converter) {
return doExecuteAsync(userAgent, headers, httpVerb, completeUrl, BodyType.STRING, bodyContents, callback,
converter);
}
@Override
public <T> Future<T> executeAsync(String userAgent, Map<String, String> headers, Verb httpVerb, String completeUrl,
File bodyContents, OAuthAsyncRequestCallback<T> callback, OAuthRequest.ResponseConverter<T> converter) {
return doExecuteAsync(userAgent, headers, httpVerb, completeUrl, BodyType.STREAM, bodyContents, callback,
converter);
}
private <T> Future<T> doExecuteAsync(String userAgent, Map<String, String> headers, Verb httpVerb,
String completeUrl, BodyType bodyType, Object bodyContents, OAuthAsyncRequestCallback<T> callback,
OAuthRequest.ResponseConverter<T> converter) {
try {
final Response response = doExecute(userAgent, headers, httpVerb, completeUrl, bodyType, bodyContents);
@SuppressWarnings("unchecked") final T t = converter == null ? (T) response : converter.convert(response);
if (callback != null) {
callback.onCompleted(t);
}
return new JDKHttpFuture<>(t);
} catch (IOException | RuntimeException e) {
if (callback != null) {
callback.onThrowable(e);
}
return new JDKHttpFuture<>(e);
}
}
@Override
public Response execute(String userAgent, Map<String, String> headers, Verb httpVerb, String completeUrl,
byte[] bodyContents) throws InterruptedException, ExecutionException, IOException {
return doExecute(userAgent, headers, httpVerb, completeUrl, BodyType.BYTE_ARRAY, bodyContents);
}
@Override
public Response execute(String userAgent, Map<String, String> headers, Verb httpVerb, String completeUrl,
MultipartPayload multipartPayloads) throws InterruptedException, ExecutionException, IOException {
return doExecute(userAgent, headers, httpVerb, completeUrl, BodyType.MULTIPART, multipartPayloads);
}
@Override
public Response execute(String userAgent, Map<String, String> headers, Verb httpVerb, String completeUrl,
String bodyContents) throws InterruptedException, ExecutionException, IOException {
return doExecute(userAgent, headers, httpVerb, completeUrl, BodyType.STRING, bodyContents);
}
@Override
public Response execute(String userAgent, Map<String, String> headers, Verb httpVerb, String completeUrl,
File bodyContents) throws InterruptedException, ExecutionException, IOException {
return doExecute(userAgent, headers, httpVerb, completeUrl, BodyType.STREAM, bodyContents);
}
private Response doExecute(String userAgent, Map<String, String> headers, Verb httpVerb, String completeUrl,
BodyType bodyType, Object bodyContents) throws IOException {
final URL url = new URL(completeUrl);
final HttpURLConnection connection;
if (config.getProxy() == null) {
connection = (HttpURLConnection) url.openConnection();
} else {
connection = (HttpURLConnection) url.openConnection(config.getProxy());
}
connection.setInstanceFollowRedirects(config.isFollowRedirects());
connection.setRequestMethod(httpVerb.name());
if (config.getConnectTimeout() != null) {
connection.setConnectTimeout(config.getConnectTimeout());
}
if (config.getReadTimeout() != null) {
connection.setReadTimeout(config.getReadTimeout());
}
addHeaders(connection, headers, userAgent);
if (httpVerb.isPermitBody()) {
bodyType.setBody(connection, bodyContents, httpVerb.isRequiresBody());
}
try {
connection.connect();
final int responseCode = connection.getResponseCode();
return new Response(responseCode, connection.getResponseMessage(), parseHeaders(connection),
responseCode >= 200 && responseCode < 400 ? connection.getInputStream()
: connection.getErrorStream());
} catch (UnknownHostException e) {
throw new OAuthException("The IP address of a host could not be determined.", e);
}
}
private enum BodyType {
BYTE_ARRAY {
@Override
void setBody(HttpURLConnection connection, Object bodyContents, boolean requiresBody) throws IOException {
addBody(connection, (byte[]) bodyContents, requiresBody);
}
},
STREAM {
@Override
void setBody(HttpURLConnection connection, Object bodyContents, boolean requiresBody) throws IOException {
addBody(connection, (File) bodyContents, requiresBody);
}
},
MULTIPART {
@Override
void setBody(HttpURLConnection connection, Object bodyContents, boolean requiresBody) throws IOException {
addBody(connection, (MultipartPayload) bodyContents, requiresBody);
}
},
STRING {
@Override
void setBody(HttpURLConnection connection, Object bodyContents, boolean requiresBody) throws IOException {
addBody(connection, ((String) bodyContents).getBytes(), requiresBody);
}
};
abstract void setBody(HttpURLConnection connection, Object bodyContents, boolean requiresBody)
throws IOException;
}
private static Map<String, String> parseHeaders(HttpURLConnection conn) {
final Map<String, String> headers = new HashMap<>();
for (Map.Entry<String, List<String>> headerField : conn.getHeaderFields().entrySet()) {
final String key = headerField.getKey();
final String value = headerField.getValue().get(0);
if ("Content-Encoding".equalsIgnoreCase(key)) {
headers.put("Content-Encoding", value);
} else {
headers.put(key, value);
}
}
return headers;
}
private static void addHeaders(HttpURLConnection connection, Map<String, String> headers, String userAgent) {
for (Map.Entry<String, String> header : headers.entrySet()) {
connection.setRequestProperty(header.getKey(), header.getValue());
}
if (userAgent != null) {
connection.setRequestProperty(OAuthConstants.USER_AGENT_HEADER_NAME, userAgent);
}
}
private static void addBody(HttpURLConnection connection, File file, boolean requiresBody) throws IOException {
if (requiresBody) {
String filename = file.getName();
String formName = "file";
InputStream stream = new FileInputStream(file);
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY); //$NON-NLS-1$ //$NON-NLS-2$
connection.setRequestProperty("User-Agent", "OsmAnd"); //$NON-NLS-1$ //$NON-NLS-2$
final OutputStream ous = connection.getOutputStream();
ous.write(("--" + BOUNDARY + "\r\n").getBytes());
ous.write(("content-disposition: form-data; name=\"" + formName + "\"; filename=\"" + filename + "\"\r\n").getBytes()); //$NON-NLS-1$ //$NON-NLS-2$
ous.write(("Content-Type: application/octet-stream\r\n\r\n").getBytes()); //$NON-NLS-1$
BufferedInputStream bis = new BufferedInputStream(stream, 20 * 1024);
ous.flush();
Algorithms.streamCopy(bis, ous);
ous.write(("\r\n--" + BOUNDARY + "--\r\n").getBytes()); //$NON-NLS-1$ //$NON-NLS-2$
ous.flush();
Algorithms.closeStream(bis);
}
}
private static void addBody(HttpURLConnection connection, byte[] content, boolean requiresBody) throws IOException {
final int contentLength = content.length;
if (requiresBody || contentLength > 0) {
connection.setDoOutput(true);
final OutputStream outputStream = prepareConnectionForBodyAndGetOutputStream(connection, contentLength);
if (contentLength > 0) {
outputStream.write(content);
}
}
}
private static void addBody(HttpURLConnection connection, MultipartPayload multipartPayload, boolean requiresBody)
throws IOException {
for (Map.Entry<String, String> header : multipartPayload.getHeaders().entrySet()) {
connection.setRequestProperty(header.getKey(), header.getValue());
}
if (requiresBody) {
final ByteArrayOutputStream os = MultipartUtils.getPayload(multipartPayload);
final int contentLength = os.size();
connection.setDoOutput(true);
final OutputStream outputStream = prepareConnectionForBodyAndGetOutputStream(connection, contentLength);
if (contentLength > 0) {
os.writeTo(outputStream);
}
}
}
private static OutputStream prepareConnectionForBodyAndGetOutputStream(HttpURLConnection connection,
int contentLength) throws IOException {
connection.setRequestProperty(CONTENT_LENGTH, String.valueOf(contentLength));
if (connection.getRequestProperty(CONTENT_TYPE) == null) {
connection.setRequestProperty(CONTENT_TYPE, DEFAULT_CONTENT_TYPE);
}
return connection.getOutputStream();
}
}

View file

@ -0,0 +1,171 @@
// License: GPL. For details, see LICENSE file.
package net.osmand.osm.oauth;
import com.github.scribejava.core.builder.ServiceBuilder;
import com.github.scribejava.core.builder.api.DefaultApi10a;
import com.github.scribejava.core.builder.api.OAuth1SignatureType;
import com.github.scribejava.core.httpclient.jdk.JDKHttpClientConfig;
import com.github.scribejava.core.model.*;
import com.github.scribejava.core.oauth.OAuth10aService;
import net.osmand.PlatformUtil;
import org.apache.commons.logging.Log;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
/**
* An OAuth 1.0 authorization client.
*
* @since 2746
*/
public class OsmOAuthAuthorizationClient {
private OAuth1RequestToken requestToken;
private OAuth1AccessToken accessToken;
private final OAuth10aService service;
private final OsmAndJDKHttpClient httpClient;
public final static Log log = PlatformUtil.getLog(OsmOAuthAuthorizationClient.class);
public OsmOAuthAuthorizationClient(String key, String secret, DefaultApi10a api) {
httpClient = new OsmAndJDKHttpClient(JDKHttpClientConfig.defaultConfig());
service = new ServiceBuilder(key)
.apiSecret(secret)
.httpClient(httpClient)
.callback("osmand-oauth://example.com/oauth")
.build(api);
}
public static class OsmApi extends DefaultApi10a {
@Override
public OAuth1SignatureType getSignatureType() {
return OAuth1SignatureType.QUERY_STRING;
}
@Override
public String getRequestTokenEndpoint() {
return "https://www.openstreetmap.org/oauth/request_token";
}
@Override
public String getAccessTokenEndpoint() {
return "https://www.openstreetmap.org/oauth/access_token";
}
@Override
protected String getAuthorizationBaseUrl() {
return "https://www.openstreetmap.org/oauth/authorize";
}
}
public static class OsmDevApi extends DefaultApi10a {
@Override
public OAuth1SignatureType getSignatureType() {
return OAuth1SignatureType.QUERY_STRING;
}
@Override
public String getRequestTokenEndpoint() {
return "https://master.apis.dev.openstreetmap.org/oauth/request_token";
}
@Override
public String getAccessTokenEndpoint() {
return "https://master.apis.dev.openstreetmap.org/oauth/access_token";
}
@Override
protected String getAuthorizationBaseUrl() {
return "https://master.apis.dev.openstreetmap.org/oauth/authorize";
}
}
public OsmAndJDKHttpClient getHttpClient() {
return httpClient;
}
public OAuth10aService getService() {
return service;
}
public void setAccessToken(OAuth1AccessToken accessToken) {
this.accessToken = accessToken;
}
public OAuth1AccessToken getAccessToken() {
return accessToken;
}
public Response performRequestWithoutAuth(String url, String requestMethod, String requestBody)
throws InterruptedException, ExecutionException, IOException {
Verb verb = parseRequestMethod(requestMethod);
OAuthRequest req = new OAuthRequest(verb, url);
req.setPayload(requestBody);
return service.execute(req);
}
public void performGetRequest(String url, OAuthAsyncRequestCallback<Response> callback) {
if (accessToken == null) {
throw new IllegalStateException("Access token is null");
}
OAuthRequest req = new OAuthRequest(Verb.GET, url);
service.signRequest(accessToken, req);
service.execute(req, callback);
}
public Response performRequest(String url, String method, String body)
throws InterruptedException, ExecutionException, IOException {
service.getApi().getSignatureType();
if (accessToken == null) {
throw new IllegalStateException("Access token is null");
}
Verb verbMethod = parseRequestMethod(method);
OAuthRequest req = new OAuthRequest(verbMethod, url);
req.setPayload(body);
service.signRequest(accessToken, req);
req.addHeader("Content-Type", "application/xml");
return service.execute(req);
}
public OAuth1RequestToken startOAuth() {
try {
requestToken = service.getRequestToken();
} catch (IOException e) {
log.error(e);
} catch (InterruptedException e) {
log.error(e);
} catch (ExecutionException e) {
log.error(e);
}
return requestToken;
}
public OAuth1AccessToken authorize(String oauthVerifier) {
try {
setAccessToken(service.getAccessToken(requestToken, oauthVerifier));
} catch (IOException e) {
log.error(e);
} catch (InterruptedException e) {
log.error(e);
} catch (ExecutionException e) {
log.error(e);
}
return accessToken;
}
public boolean isValidToken() {
return !(accessToken == null);
}
private Verb parseRequestMethod(String method) {
Verb m = Verb.GET;
if (method.equals("POST")) {
m = Verb.POST;
}
if (method.equals("PUT")) {
m = Verb.PUT;
}
if (method.equals("DELETE")) {
m = Verb.DELETE;
}
return m;
}
}

View file

@ -41,7 +41,7 @@ public class RenderingRule {
public void init(Map<String, String> attributes) {
ArrayList<RenderingRuleProperty> props = new ArrayList<RenderingRuleProperty>(attributes.size());
intProperties = new int[attributes.size()];
floatProperties = null;
floatProperties = new float[attributes.size()];
attributesRef = null;
int i = 0;
Iterator<Entry<String, String>> it = attributes.entrySet().iterator();
@ -58,14 +58,13 @@ public class RenderingRule {
attributesRef[i] = storage.getRenderingAttributeRule(vl.substring(1));
} else if (property.isString()) {
intProperties[i] = storage.getDictionaryValue(vl);
} else if (property.isFloat()) {
if (floatProperties == null) {
// lazy creates
floatProperties = new float[attributes.size()];
}
floatProperties[i] = property.parseFloatValue(vl);
intProperties[i] = property.parseIntValue(vl);
} else {
float floatVal = property.parseFloatValue(vl);
// if (floatProperties == null && floatVal != 0) {
// // lazy creates
// floatProperties = new float[attributes.size()];
floatProperties[i] = floatVal;
// }
intProperties[i] = property.parseIntValue(vl);
}
i++;
@ -95,7 +94,7 @@ public class RenderingRule {
public float getFloatPropertyValue(String property) {
int i = getPropertyIndex(property);
if(i >= 0 && floatProperties != null){
if (i >= 0) {
return floatProperties[i];
}
return 0;

View file

@ -155,12 +155,7 @@ public class RenderingRuleProperty {
try {
int colon = value.indexOf(':');
if(colon != -1) {
int c = 0;
if(colon > 0) {
c += (int) Float.parseFloat(value.substring(0, colon));
}
c += (int) Float.parseFloat(value.substring(colon + 1));
return c;
return (int) Float.parseFloat(value.substring(colon + 1));
}
return (int) Float.parseFloat(value);
} catch (NumberFormatException e) {
@ -190,15 +185,15 @@ public class RenderingRuleProperty {
} catch (NumberFormatException e) {
log.error("Rendering parse " + value + " in " + attrName);
}
return -1;
return 0;
} else {
return -1;
}
}
public float parseFloatValue(String value) {
if(type == FLOAT_TYPE){
try {
if (type == FLOAT_TYPE) {
int colon = value.indexOf(':');
if (colon != -1) {
if (colon > 0) {
@ -207,13 +202,18 @@ public class RenderingRuleProperty {
return 0;
}
return Float.parseFloat(value);
} else if (type == INT_TYPE) {
int colon = value.indexOf(':');
if (colon != -1 && colon > 0) {
return Float.parseFloat(value.substring(0, colon));
}
return 0;
}
} catch (NumberFormatException e) {
log.error("Rendering parse " + value + " in " + attrName);
}
return -1;
} else {
return -1;
}
return 0;
}

View file

@ -244,8 +244,6 @@ public class RenderingRuleStorageProperties {
R_TEXT_HALO_COLOR = registerRuleInternal(RenderingRuleProperty.createOutputColorProperty(TEXT_HALO_COLOR));
R_TEXT_SIZE = registerRuleInternal(RenderingRuleProperty.createOutputFloatProperty(TEXT_SIZE));
R_TEXT_ORDER = registerRuleInternal(RenderingRuleProperty.createOutputIntProperty(TEXT_ORDER));
R_ICON_ORDER = registerRuleInternal(RenderingRuleProperty.createOutputIntProperty(ICON_ORDER));
R_ICON_VISIBLE_SIZE = registerRuleInternal(RenderingRuleProperty.createOutputFloatProperty(ICON_VISIBLE_SIZE));
R_TEXT_MIN_DISTANCE = registerRuleInternal(RenderingRuleProperty.createOutputFloatProperty(TEXT_MIN_DISTANCE));
R_TEXT_SHIELD = registerRuleInternal(RenderingRuleProperty.createOutputStringProperty(TEXT_SHIELD));
@ -265,7 +263,9 @@ public class RenderingRuleStorageProperties {
R_ICON_3 = registerRuleInternal(RenderingRuleProperty.createOutputStringProperty("icon_3"));
R_ICON_4 = registerRuleInternal(RenderingRuleProperty.createOutputStringProperty("icon_4"));
R_ICON_5 = registerRuleInternal(RenderingRuleProperty.createOutputStringProperty("icon_5"));
R_ICON_ORDER = registerRuleInternal(RenderingRuleProperty.createOutputIntProperty(ICON_ORDER));
R_SHIELD = registerRuleInternal(RenderingRuleProperty.createOutputStringProperty(SHIELD));
R_ICON_VISIBLE_SIZE = registerRuleInternal(RenderingRuleProperty.createOutputFloatProperty(ICON_VISIBLE_SIZE));
// polygon/way
R_COLOR = registerRuleInternal(RenderingRuleProperty.createOutputColorProperty(COLOR));

View file

@ -20,10 +20,10 @@ public class RouteExporter {
public static final String OSMAND_ROUTER_V2 = "OsmAndRouterV2";
private String name;
private List<RouteSegmentResult> route;
private List<Location> locations;
private List<WptPt> points;
private final String name;
private final List<RouteSegmentResult> route;
private final List<Location> locations;
private final List<WptPt> points;
public RouteExporter(String name, List<RouteSegmentResult> route, List<Location> locations, List<WptPt> points) {
this.name = name;
@ -33,6 +33,34 @@ public class RouteExporter {
}
public GPXFile exportRoute() {
GPXFile gpx = new GPXFile(OSMAND_ROUTER_V2);
Track track = new Track();
track.name = name;
gpx.tracks.add(track);
track.segments.add(generateRouteSegment());
if (points != null) {
for (WptPt pt : points) {
gpx.addPoint(pt);
}
}
return gpx;
}
public static GPXFile exportRoute(String name, List<TrkSegment> trkSegments, List<WptPt> points) {
GPXFile gpx = new GPXFile(OSMAND_ROUTER_V2);
Track track = new Track();
track.name = name;
gpx.tracks.add(track);
track.segments.addAll(trkSegments);
if (points != null) {
for (WptPt pt : points) {
gpx.addPoint(pt);
}
}
return gpx;
}
public TrkSegment generateRouteSegment() {
RouteDataResources resources = new RouteDataResources(locations);
List<StringBundle> routeItems = new ArrayList<>();
if (!Algorithms.isEmpty(route)) {
@ -57,15 +85,9 @@ public class RouteExporter {
typeList.add(typeBundle);
}
GPXFile gpx = new GPXFile(OSMAND_ROUTER_V2);
Track track = new Track();
track.name = name;
gpx.tracks.add(track);
TrkSegment trkSegment = new TrkSegment();
track.segments.add(trkSegment);
if (locations == null || locations.isEmpty()) {
return gpx;
return trkSegment;
}
for (int i = 0; i < locations.size(); i++) {
Location loc = locations.get(i);
@ -83,23 +105,17 @@ public class RouteExporter {
}
trkSegment.points.add(pt);
}
if (points != null) {
for (WptPt pt : points) {
gpx.addPoint(pt);
}
}
List<RouteSegment> routeSegments = new ArrayList<>();
for (StringBundle item : routeItems) {
routeSegments.add(RouteSegment.fromStringBundle(item));
}
gpx.routeSegments = routeSegments;
trkSegment.routeSegments = routeSegments;
List<RouteType> routeTypes = new ArrayList<>();
for (StringBundle item : typeList) {
routeTypes.add(RouteType.fromStringBundle(item));
}
gpx.routeTypes = routeTypes;
return gpx;
trkSegment.routeTypes = routeTypes;
return trkSegment;
}
}

View file

@ -4,6 +4,7 @@ import net.osmand.GPXUtilities;
import net.osmand.GPXUtilities.GPXFile;
import net.osmand.GPXUtilities.RouteSegment;
import net.osmand.GPXUtilities.RouteType;
import net.osmand.GPXUtilities.TrkSegment;
import net.osmand.GPXUtilities.WptPt;
import net.osmand.Location;
import net.osmand.PlatformUtil;
@ -28,10 +29,9 @@ public class RouteImporter {
private File file;
private GPXFile gpxFile;
private TrkSegment segment;
private List<RouteSegmentResult> route = new ArrayList<>();
private RouteRegion region = new RouteRegion();
private RouteDataResources resources = new RouteDataResources();
private final List<RouteSegmentResult> route = new ArrayList<>();
public RouteImporter(File file) {
this.file = file;
@ -41,8 +41,12 @@ public class RouteImporter {
this.gpxFile = gpxFile;
}
public RouteImporter(TrkSegment segment) {
this.segment = segment;
}
public List<RouteSegmentResult> importRoute() {
if (gpxFile != null) {
if (gpxFile != null || segment != null) {
parseRoute();
} else if (file != null) {
FileInputStream fis = null;
@ -69,19 +73,34 @@ public class RouteImporter {
}
private void parseRoute() {
collectLocations();
collectSegments();
collectTypes();
for (RouteSegmentResult segment : route) {
segment.fillNames(resources);
if (segment != null) {
parseRoute(segment);
} else if (gpxFile != null) {
List<TrkSegment> segments = gpxFile.getNonEmptyTrkSegments(true);
for (TrkSegment s : segments) {
parseRoute(s);
}
}
}
private void collectLocations() {
private void parseRoute(TrkSegment segment) {
RouteRegion region = new RouteRegion();
RouteDataResources resources = new RouteDataResources();
collectLocations(resources, segment);
List<RouteSegmentResult> route = collectRouteSegments(region, resources, segment);
collectRouteTypes(region, segment);
for (RouteSegmentResult routeSegment : route) {
routeSegment.fillNames(resources);
}
this.route.addAll(route);
}
private void collectLocations(RouteDataResources resources, TrkSegment segment) {
List<Location> locations = resources.getLocations();
double lastElevation = HEIGHT_UNDEFINED;
if (gpxFile.tracks.size() > 0 && gpxFile.tracks.get(0).segments.size() > 0 && gpxFile.tracks.get(0).segments.get(0).points.size() > 0) {
for (WptPt point : gpxFile.tracks.get(0).segments.get(0).points) {
if (segment.hasRoute()) {
for (WptPt point : segment.points) {
Location loc = new Location("", point.getLatitude(), point.getLongitude());
if (!Double.isNaN(point.ele)) {
loc.setAltitude(point.ele);
@ -94,18 +113,20 @@ public class RouteImporter {
}
}
private void collectSegments() {
for (RouteSegment segment : gpxFile.routeSegments) {
private List<RouteSegmentResult> collectRouteSegments(RouteRegion region, RouteDataResources resources, TrkSegment segment) {
List<RouteSegmentResult> route = new ArrayList<>();
for (RouteSegment routeSegment : segment.routeSegments) {
RouteDataObject object = new RouteDataObject(region);
RouteSegmentResult segmentResult = new RouteSegmentResult(object);
segmentResult.readFromBundle(new RouteDataBundle(resources, segment.toStringBundle()));
segmentResult.readFromBundle(new RouteDataBundle(resources, routeSegment.toStringBundle()));
route.add(segmentResult);
}
return route;
}
private void collectTypes() {
private void collectRouteTypes(RouteRegion region, TrkSegment segment) {
int i = 0;
for (RouteType routeType : gpxFile.routeTypes) {
for (RouteType routeType : segment.routeTypes) {
StringBundle bundle = routeType.toStringBundle();
String t = bundle.getString("t", null);
String v = bundle.getString("v", null);

View file

@ -546,10 +546,12 @@ public class RoutePlannerFrontEnd {
if (start != null && start.pnt == null) {
gctx.routePointsSearched++;
RouteSegmentPoint rsp = findRouteSegment(start.loc.getLatitude(), start.loc.getLongitude(), gctx.ctx, null, false);
if (rsp != null) {
if (MapUtils.getDistance(rsp.getPreciseLatLon(), start.loc) < distThreshold) {
start.pnt = rsp;
}
}
}
if (start != null && start.pnt != null) {
return true;
}
@ -734,7 +736,7 @@ public class RoutePlannerFrontEnd {
res = searchRouteImpl(ctx, points, routeDirection);
}
if (ctx.calculationProgress != null) {
ctx.calculationProgress.timeToCalculate += (System.nanoTime() - timeToCalculate);
ctx.calculationProgress.timeToCalculate = (System.nanoTime() - timeToCalculate);
}
BinaryRoutePlanner.printDebugMemoryInformation(ctx);
if (res != null) {

View file

@ -255,7 +255,8 @@ public class RouteSegmentResult implements StringExternalizable<RouteDataBundle>
@Override
public void writeToBundle(RouteDataBundle bundle) {
Map<RouteTypeRule, Integer> rules = bundle.getResources().getRules();
bundle.putInt("length", (Math.abs(endPointIndex - startPointIndex) + 1) * (endPointIndex >= startPointIndex ? 1 : -1));
boolean reversed = endPointIndex < startPointIndex;
bundle.putInt("length", Math.abs(endPointIndex - startPointIndex) + 1);
bundle.putFloat("segmentTime", segmentTime, 2);
bundle.putFloat("speed", speed, 2);
if (turnType != null) {
@ -271,24 +272,29 @@ public class RouteSegmentResult implements StringExternalizable<RouteDataBundle>
bundle.putString("turnLanes", TurnType.lanesToString(turnLanes));
}
}
bundle.putLong("id", object.id);
bundle.putLong("id", object.id >> 6); // OsmAnd ID to OSM ID
bundle.putArray("types", convertTypes(object.types, rules));
int start = Math.min(startPointIndex, endPointIndex);
int end = Math.max(startPointIndex, endPointIndex) + 1;
if (object.pointTypes != null && start < object.pointTypes.length) {
int[][] types = Arrays.copyOfRange(object.pointTypes, start, Math.min(end, object.pointTypes.length));
if (reversed) {
Algorithms.reverseArray(types);
}
bundle.putArray("pointTypes", convertTypes(types, rules));
}
if (object.nameIds != null) {
bundle.putArray("names", convertNameIds(object.nameIds, rules));
}
if (object.pointNameTypes != null && start < object.pointNameTypes.length) {
if (object.pointNameTypes != null && start < object.pointNameTypes.length && object.pointNames != null) {
int[][] types = Arrays.copyOfRange(object.pointNameTypes, start, Math.min(end, object.pointNameTypes.length));
if (object.pointNames != null) {
String[][] names = Arrays.copyOfRange(object.pointNames, start, Math.min(end, object.pointNames.length));
bundle.putArray("pointNames", convertPointNames(types, names, rules));
if (reversed) {
Algorithms.reverseArray(types);
Algorithms.reverseArray(names);
}
bundle.putArray("pointNames", convertPointNames(types, names, rules));
}
}
@ -327,9 +333,7 @@ public class RouteSegmentResult implements StringExternalizable<RouteDataBundle>
Location prevLocation = null;
for (int i = 0; i < length; i++) {
Location location = resources.getLocation(index);
if (location == null) {
break;
}
if (location != null) {
double dist = 0;
if (prevLocation != null) {
dist = MapUtils.getDistance(prevLocation.getLatitude(), prevLocation.getLongitude(), location.getLatitude(), location.getLongitude());
@ -344,6 +348,7 @@ public class RouteSegmentResult implements StringExternalizable<RouteDataBundle>
} else {
object.heightDistanceArray = new float[0];
}
}
if (plus) {
index++;
} else {

View file

@ -289,7 +289,8 @@ public class RoutingContext {
if(excludeNotAllowed != null && !excludeNotAllowed.contains(ro.getId())) {
ts.add(ro);
}
} else if(excludeNotAllowed != null && ro.getId() > 0){
}
if(excludeNotAllowed != null && ro.getId() > 0){
excludeNotAllowed.add(ro.getId());
if(ts.excludedIds == null ){
ts.excludedIds = new TLongHashSet();

View file

@ -741,7 +741,7 @@ public class SearchUICore {
}
}
if (Algorithms.isEmpty(object.alternateName) && object.object instanceof Amenity) {
for (String value : ((Amenity) object.object).getAdditionalInfo().values()) {
for (String value : ((Amenity) object.object).getAdditionalInfoValues(true)) {
if (phrase.getFirstUnknownNameStringMatcher().matches(value)) {
object.alternateName = value;
break;

View file

@ -33,6 +33,7 @@ import net.osmand.util.LocationParser.ParsedOpenLocationCode;
import net.osmand.util.MapUtils;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@ -601,7 +602,7 @@ public class SearchCoreFactory {
sr.localeName = object.getName(phrase.getSettings().getLang(),
phrase.getSettings().isTransliterate());
if (!nm.matches(sr.localeName) && !nm.matches(sr.otherNames)
&& !nm.matches(object.getAdditionalInfo().values())) {
&& !nm.matches(object.getAdditionalInfoValues(false))) {
return false;
}
sr.object = object;
@ -922,6 +923,7 @@ public class SearchCoreFactory {
public static class SearchAmenityByTypeAPI extends SearchBaseAPI {
private static final int BBOX_RADIUS = 10000;
private static final int BBOX_RADIUS_NEAREST = 1000;
private SearchAmenityTypesAPI searchAmenityTypesAPI;
private MapPoiTypes types;
private AbstractPoiType unselectedPoiType;
@ -1006,7 +1008,14 @@ public class SearchCoreFactory {
}
this.nameFilter = nameFilter;
if (poiTypeFilter != null) {
QuadRect bbox = phrase.getRadiusBBoxToSearch(BBOX_RADIUS);
int radius = BBOX_RADIUS;
if (phrase.getRadiusLevel() == 1 && poiTypeFilter instanceof CustomSearchPoiFilter) {
String name = ((CustomSearchPoiFilter) poiTypeFilter).getFilterId();
if ("std_null".equals(name)) {
radius = BBOX_RADIUS_NEAREST;
}
}
QuadRect bbox = phrase.getRadiusBBoxToSearch(radius);
List<BinaryMapIndexReader> offlineIndexes = phrase.getOfflineIndexes();
Set<String> searchedPois = new TreeSet<>();
for (BinaryMapIndexReader r : offlineIndexes) {
@ -1050,7 +1059,7 @@ public class SearchCoreFactory {
if (!poiAdditionals.isEmpty()) {
boolean found = false;
for (String add : poiAdditionals) {
if(object.getAdditionalInfo().containsKey(add)) {
if (object.getAdditionalInfoKeys().contains(add)) {
found = true;
break;
}
@ -1407,6 +1416,7 @@ public class SearchCoreFactory {
private LatLon olcPhraseLocation;
private ParsedOpenLocationCode cachedParsedCode;
private final List<String> citySubTypes = Arrays.asList("city", "town", "village");
private final DecimalFormat latLonFormatter = new DecimalFormat("#.0####");
public SearchLocationAndUrlAPI() {
super(ObjectType.LOCATION, ObjectType.PARTIAL_LOCATION);
@ -1498,7 +1508,7 @@ public class SearchCoreFactory {
sp.priority = SEARCH_LOCATION_PRIORITY;
sp.object = sp.location = ll;
sp.localeName = ((float) sp.location.getLatitude()) + ", <input> ";
sp.localeName = formatLatLon(sp.location.getLatitude()) + ", <input> ";
sp.objectType = ObjectType.PARTIAL_LOCATION;
resultMatcher.publish(sp);
}
@ -1510,7 +1520,7 @@ public class SearchCoreFactory {
SearchResult sp = new SearchResult(phrase);
sp.priority = SEARCH_LOCATION_PRIORITY;
sp.object = sp.location = l;
sp.localeName = ((float) sp.location.getLatitude()) + ", " + ((float) sp.location.getLongitude());
sp.localeName = formatLatLon(sp.location.getLatitude()) + ", " + formatLatLon(sp.location.getLongitude());
sp.objectType = ObjectType.LOCATION;
sp.wordsSpan = lw;
resultMatcher.publish(sp);
@ -1525,7 +1535,7 @@ public class SearchCoreFactory {
sp.object = pnt;
sp.wordsSpan = text;
sp.location = new LatLon(pnt.getLatitude(), pnt.getLongitude());
sp.localeName = ((float)pnt.getLatitude()) +", " + ((float) pnt.getLongitude());
sp.localeName = formatLatLon(pnt.getLatitude()) +", " + formatLatLon(pnt.getLongitude());
if (pnt.getZoom() > 0) {
sp.preferredZoom = pnt.getZoom();
}
@ -1555,6 +1565,10 @@ public class SearchCoreFactory {
}
return cachedParsedCode == null ? SEARCH_LOCATION_PRIORITY : SEARCH_MAX_PRIORITY;
}
private String formatLatLon(double latLon) {
return latLonFormatter.format(latLon);
}
}
private static String stripBraces(String localeName) {

View file

@ -229,14 +229,16 @@ public class SearchPhrase {
}
public int countWords(String w) {
String[] ws = w.split(ALLDELIMITERS);
int cnt = 0;
if (!Algorithms.isEmpty(w)) {
String[] ws = w.split(ALLDELIMITERS);
for (int i = 0; i < ws.length; i++) {
String wd = ws[i].trim();
if (wd.length() > 0) {
cnt++;
}
}
}
return cnt;
}

View file

@ -49,6 +49,11 @@ public class Algorithms {
private static char[] CHARS_TO_NORMALIZE_KEY = new char[''];
private static char[] CHARS_TO_NORMALIZE_VALUE = new char['\''];
public static final int ZIP_FILE_SIGNATURE = 0x504b0304;
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 String normalizeSearchText(String s) {
boolean norm = false;
for (int i = 0; i < s.length() && !norm; i++) {
@ -119,9 +124,11 @@ public class Algorithms {
}
public static String getFileNameWithoutExtension(String name) {
int i = name.indexOf('.');
if (i >= 0) {
name = name.substring(0, i);
if (name != null) {
int index = name.lastIndexOf('.');
if (index != -1) {
return name.substring(0, index);
}
}
return name;
}
@ -293,7 +300,7 @@ public class Algorithms {
FileInputStream in = new FileInputStream(file);
int test = readInt(in);
in.close();
return test == 0x504b0304;
return test == ZIP_FILE_SIGNATURE;
}
/**
@ -322,7 +329,7 @@ public class Algorithms {
return false;
}
private static int readInt(InputStream in) throws IOException {
public static int readInt(InputStream in) throws IOException {
int ch1 = in.read();
int ch2 = in.read();
int ch3 = in.read();
@ -879,6 +886,14 @@ public class Algorithms {
return map;
}
public static <T> void reverseArray(T[] array) {
for (int i = 0; i < array.length / 2; i++) {
T temp = array[i];
array[i] = array[array.length - i - 1];
array[array.length - i - 1] = temp;
}
}
public static boolean containsInArrayL(long[] array, long value) {
return Arrays.binarySearch(array, value) >= 0;
}
@ -942,4 +957,20 @@ public class Algorithms {
}
return res;
}
public static boolean isValidMessageFormat(CharSequence sequence) {
if (!isEmpty(sequence)) {
int counter = 0;
for (int i = 0; i < sequence.length(); i++) {
char ch = sequence.charAt(i);
if (ch == '{') {
counter++;
} else if (ch == '}') {
counter--;
}
}
return counter == 0;
}
return false;
}
}

View file

@ -3,6 +3,7 @@ package net.osmand.util;
import com.google.openlocationcode.OpenLocationCode;
import com.google.openlocationcode.OpenLocationCode.CodeArea;
import com.jwetherell.openmap.common.LatLonPoint;
import com.jwetherell.openmap.common.MGRSPoint;
import com.jwetherell.openmap.common.UTMPoint;
import net.osmand.data.LatLon;
@ -111,7 +112,7 @@ public class LocationParser {
return null;
}
// detect UTM
if (all.size() == 4 && d.size() == 3 && all.get(1) instanceof String) {
if (all.size() == 4 && d.size() == 3 && all.get(1) instanceof String && ((String) all.get(1)).length() == 1) {
char ch = all.get(1).toString().charAt(0);
if (Character.isLetter(ch)) {
UTMPoint upoint = new UTMPoint(d.get(2), d.get(1), d.get(0).intValue(), ch);
@ -120,7 +121,7 @@ public class LocationParser {
}
}
if (all.size() == 3 && d.size() == 2 && all.get(1) instanceof String) {
if (all.size() == 3 && d.size() == 2 && all.get(1) instanceof String && ((String) all.get(1)).length() == 1) {
char ch = all.get(1).toString().charAt(0);
String combined = strings.get(2);
if (Character.isLetter(ch)) {
@ -135,6 +136,17 @@ public class LocationParser {
}
}
}
//detect MGRS
if (all.size() >= 3 && (d.size() == 2 || d.size() == 3) && all.get(1) instanceof String) {
try {
MGRSPoint mgrsPoint = new MGRSPoint(locPhrase);
LatLonPoint ll = mgrsPoint.toLatLonPoint();
return validateAndCreateLatLon(ll.getLatitude(), ll.getLongitude());
} catch (NumberFormatException e) {
//do nothing
}
}
// try to find split lat/lon position
int jointNumbers = 0;
int lastJoin = 0;

View file

@ -15,6 +15,7 @@ import java.util.TreeSet;
import net.osmand.binary.BinaryMapIndexReader;
import net.osmand.data.LatLon;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
@ -62,9 +63,19 @@ public class RouteTestingTest {
RandomAccessFile raf = new RandomAccessFile(fl, "r");
RoutePlannerFrontEnd fe = new RoutePlannerFrontEnd();
BinaryMapIndexReader[] binaryMapIndexReaders = { new BinaryMapIndexReader(raf, new File(fl)) };
BinaryMapIndexReader[] binaryMapIndexReaders;// = { new BinaryMapIndexReader(raf, new File(fl)) };
RoutingConfiguration.Builder builder = RoutingConfiguration.getDefault();
Map<String, String> params = te.getParams();
if (params.containsKey("map")) {
String fl1 = "src/test/resources/" + params.get("map");
RandomAccessFile raf1 = new RandomAccessFile(fl1, "r");
binaryMapIndexReaders = new BinaryMapIndexReader[]{
new BinaryMapIndexReader(raf1, new File(fl1)),
new BinaryMapIndexReader(raf, new File(fl))
};
} else {
binaryMapIndexReaders = new BinaryMapIndexReader[]{new BinaryMapIndexReader(raf, new File(fl))};
}
RoutingConfiguration config = builder.build(params.containsKey("vehicle") ? params.get("vehicle") : "car",
RoutingConfiguration.DEFAULT_MEMORY_LIMIT * 3, params);
RoutingContext ctx = fe.buildRoutingContext(config, null, binaryMapIndexReaders,
@ -102,6 +113,4 @@ public class RouteTestingTest {
}
}

View file

@ -20,7 +20,7 @@
android:screenOrientation="unspecified"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".ui.TrackerLogcatActivity" />
<activity
android:name=".ui.MainActivity"
android:configChanges="orientation|screenSize"

View file

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:orientation="vertical">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/app_bar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/card_bg_color">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="@dimen/action_bar_height">
<net.osmand.telegram.ui.views.TextViewEx
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:gravity="center_vertical"
android:maxLines="1"
android:text="@string/logcat_buffer"
android:textColor="@color/app_bar_title_light"
android:textSize="@dimen/title_text_size"
app:typeface="@string/font_roboto_mono_bold"/>
</androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.AppBarLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/screen_bg_light"
android:clipToPadding="false"
android:orientation="vertical"
android:scrollbars="vertical" />
</LinearLayout>

View file

@ -447,6 +447,50 @@
</LinearLayout>
<include layout="@layout/list_item_divider"/>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/card_bg_color">
<LinearLayout
android:id="@+id/logcat_row"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:orientation="vertical">
<net.osmand.telegram.ui.views.TextViewEx
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:gravity="center_vertical"
android:maxLines="1"
android:paddingLeft="@dimen/content_padding_standard"
android:paddingRight="@dimen/content_padding_standard"
android:text="@string/logcat_buffer"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/list_item_title_text_size"
app:firstBaselineToTopHeight="28sp"
app:typeface="@string/font_roboto_medium" />
<net.osmand.telegram.ui.views.TextViewEx
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="@dimen/content_padding_standard"
android:paddingRight="@dimen/content_padding_standard"
android:text="@string/logcat_buffer_descr"
android:textColor="?android:attr/textColorSecondary"
android:textSize="@dimen/list_item_description_text_size"
app:firstBaselineToTopHeight="20sp"
app:lastBaselineToBottomHeight="16sp"
app:typeface="@string/font_roboto_regular" />
</LinearLayout>
</FrameLayout>
<include layout="@layout/card_bottom_divider"/>
</LinearLayout>

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:minHeight="@dimen/list_description_height"
android:paddingLeft="@dimen/content_padding_standard"
android:paddingRight="@dimen/content_padding_standard"
android:textColor="?android:textColorSecondary"
android:textSize="@dimen/hint_text_size"
android:linksClickable="true"
android:lineSpacingMultiplier="@dimen/text_description_line_spacing_multiplier"
tools:text="Some long description"
android:paddingEnd="@dimen/content_padding_standard"
android:paddingStart="@dimen/content_padding_standard" />

View file

@ -267,4 +267,8 @@
<string name="location_sharing_status">مشاركة: %1$s</string>
<string name="shared_string_enabled">مفعل</string>
<string name="duration_ago">%1$s منذ</string>
<string name="shared_string_export">تصدير</string>
<string name="logcat_buffer">لوجكات العازلة</string>
<string name="logcat_buffer_descr">تحقق من السجلات التفصيلية للتطبيق وشاركها</string>
<string name="send_report">إرسال تقرير</string>
</resources>

View file

@ -38,7 +38,7 @@
<string name="shared_string_password">كلمة المرور</string>
<string name="shared_string_continue">استمرار</string>
<string name="shared_string_cancel">إلغاء</string>
<string name="shared_string_settings">الإعدادات</string>
<string name="shared_string_settings">إعدادات</string>
<string name="shared_string_distance">المسافة</string>
<string name="yard">ياردة</string>
<string name="foot">قدم</string>
@ -267,4 +267,8 @@
<string name="status_widget_title">تتبع حالة أوسماند</string>
<string name="back_to_osmand">العودة إلى OsmAnd</string>
<string name="duration_ago">%1$s منذ</string>
<string name="send_report">إرسال التقرير</string>
<string name="shared_string_export">تصدير</string>
<string name="logcat_buffer">سجل الاستخدام</string>
<string name="logcat_buffer_descr">التحقق من السجلات التفصيلية للتطبيق ومشاركتها</string>
</resources>

View file

@ -267,4 +267,8 @@
<string name="last_response_duration">Апошні адказ: %1$s таму</string>
<string name="duration_ago">%1$s таму</string>
<string name="shared_string_error_short">ERR</string>
<string name="send_report">Даслаць справаздачу</string>
<string name="shared_string_export">Экспартаваць</string>
<string name="logcat_buffer">Буфер logcat</string>
<string name="logcat_buffer_descr">Праверце і падзяліцеся падрабязнымі журналамі праграмы</string>
</resources>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="send_report">Изпращане на доклад</string>
<string name="last_response_date">Последен отговор: %1$s</string>
<string name="last_update_from_telegram_date">Последна актуализация от Telegram: %1$s</string>
<string name="shared_string_error_short">ГРЕШКА</string>
<string name="shared_string_export">Експорт</string>
</resources>

View file

@ -131,7 +131,7 @@
<string name="send_my_location">Envia la meva ubicació</string>
<string name="gps_and_location">Ubicació</string>
<string name="sharing_time">Temps de compartició</string>
<string name="expire_at">"Expiració: "</string>
<string name="expire_at">Finalitza</string>
<string name="open_osmand">Obre l\'OsmAnd</string>
<string name="shared_string_live">En directe</string>
<string name="shared_string_bot">Bot</string>
@ -267,4 +267,8 @@
<string name="last_response_duration">Darrera resposta: fa %1$s</string>
<string name="duration_ago">fa %1$s</string>
<string name="shared_string_error_short">ERR</string>
<string name="shared_string_export">Exporta</string>
<string name="logcat_buffer">Memòria intermèdia del Logcat</string>
<string name="logcat_buffer_descr">Valida i comparteix enregistraments detallats de l\'aplicació</string>
<string name="send_report">Envia un informe</string>
</resources>

View file

@ -72,4 +72,6 @@
<string name="shared_string_enabled">Povolen</string>
<string name="unit_of_length">Jednotky vzdálenosti</string>
<string name="shared_string_appearance">Vzhled</string>
<string name="logcat_buffer">Zásobník logcat</string>
<string name="logcat_buffer_descr">Zkontrolovat a sdílet podrobné záznamy aplikace</string>
</resources>

View file

@ -269,4 +269,8 @@
<string name="last_response_duration">Sidste svar: %1$s siden</string>
<string name="duration_ago">%1$s siden</string>
<string name="shared_string_error_short">ERR</string>
<string name="shared_string_export">Eksporter</string>
<string name="logcat_buffer">Logcat-buffer</string>
<string name="logcat_buffer_descr">Kontroller og del detaljerede logfiler for programmet</string>
<string name="send_report">Send rapport</string>
</resources>

View file

@ -267,4 +267,8 @@
<string name="last_response_duration">Letzte Antwort: vor %1$s</string>
<string name="duration_ago">vor %1$s</string>
<string name="shared_string_error_short">ERR</string>
<string name="shared_string_export">Export</string>
<string name="logcat_buffer">Logcat-Puffer</string>
<string name="logcat_buffer_descr">Protokolle der Anwendung einsehen und freigeben</string>
<string name="send_report">Bericht senden</string>
</resources>

View file

@ -268,4 +268,8 @@
<string name="last_response_duration">Última respuesta: Hace %1$s</string>
<string name="duration_ago">Hace %1$s</string>
<string name="shared_string_error_short">ERR</string>
<string name="shared_string_export">Exportar</string>
<string name="logcat_buffer">Búfer de Logcat</string>
<string name="logcat_buffer_descr">Comprueba y comparte los registros detallados de la aplicación</string>
<string name="send_report">Enviar informe</string>
</resources>

View file

@ -250,7 +250,7 @@
<string name="set_time_timeline_descr">Elige la hora de visualización</string>
<string name="start_end_date">Fecha de Inicio — Fin</string>
<string name="saved_messages">Mensajes guardados</string>
<string name="time_zone_descr">Seleccione la zona horaria que desea mostrar en los mensajes de ubicación.</string>
<string name="time_zone_descr">Seleccione la zona horaria a mostrar en sus mensajes de ubicación.</string>
<string name="time_zone">Zona horaria</string>
<string name="units_and_formats">Unidades y formatos</string>
<string name="unit_of_length_descr">Cambia las unidades de longitud.</string>
@ -268,4 +268,8 @@
<string name="last_response_duration">Última respuesta: hace %1$s</string>
<string name="duration_ago">hace %1$s</string>
<string name="shared_string_error_short">ERR</string>
<string name="shared_string_export">Exportar</string>
<string name="logcat_buffer">Búfer de Logcat</string>
<string name="logcat_buffer_descr">Selecciona y comparte logs detallados de la app</string>
<string name="send_report">Enviar informe</string>
</resources>

View file

@ -267,4 +267,8 @@
<string name="last_response_duration">Viimane vastus: %1$s tagasi</string>
<string name="duration_ago">%1$s tagasi</string>
<string name="shared_string_error_short">ERR</string>
<string name="shared_string_export">Ekspordi</string>
<string name="logcat_buffer">Logcati puhver</string>
<string name="logcat_buffer_descr">Vaata ja jaga rakenduse detailseid logisid</string>
<string name="send_report">Saada ettekanne</string>
</resources>

View file

@ -38,8 +38,8 @@
<string name="yard">yd</string>
<string name="foot">ft</string>
<string name="mile">mi</string>
<string name="km">ک‌م</string>
<string name="m">متر</string>
<string name="km">km</string>
<string name="m">m</string>
<string name="nm">nmi</string>
<string name="min_mile">min/m</string>
<string name="min_km">min/km</string>
@ -73,4 +73,13 @@
<string name="unit_of_length_descr">یکاهای طول را تغییر دهید.</string>
<string name="unit_of_length">یکاهای طول</string>
<string name="shared_string_appearance">ظاهر</string>
<string name="last_response_duration">آخرین پاسخ: %1$s پیش</string>
<string name="last_update_from_telegram_duration">آخرین به‌روزرسانی تلگرام: %1$s پیش</string>
<string name="last_response_date">آخرین پاسخ: %1$s</string>
<string name="last_update_from_telegram_date">آخرین به‌روزرسانی تلگرام: %1$s</string>
<string name="shared_string_error_short">خطا</string>
<string name="send_report">ارسال گزارش</string>
<string name="shared_string_export">برون‌برد</string>
<string name="logcat_buffer">بافر لاگ‌کت</string>
<string name="logcat_buffer_descr">لاگ‌های جزئی برنامه را بررسی و هم‌رسانی کنید</string>
</resources>

View file

@ -266,4 +266,9 @@
<string name="location_history_desc">Cacher les contacts qui ne se sont pas déplacés depuis un temps donné.</string>
<string name="set_time_description">Définissez l\'heure à laquelle les contacts et groupes sélectionnés verront votre position en temps réel.</string>
<string name="osmand_connect">OsmAnd connect</string>
<string name="time_ago">depuis</string>
<string name="logcat_buffer">Buffer Logcat</string>
<string name="logcat_buffer_descr">Vérifier et partager les logs détaillés de l\'application</string>
<string name="shared_string_export">Exporter</string>
<string name="send_report">Envoyer le rapport</string>
</resources>

View file

@ -268,4 +268,8 @@
<string name="time_zone_descr">Escolle a zona horaria que desexas amosar nas mensaxes de localización.</string>
<string name="buffer_time">Tempo de caducidade do búfer</string>
<string name="buffer_time_descr">Tempo máximo para almacenar puntos no búfer</string>
<string name="shared_string_export">Exportar</string>
<string name="logcat_buffer">Búfer de Logcat</string>
<string name="logcat_buffer_descr">Verifica e comparte rexistros detallados da aplicación</string>
<string name="send_report">Enviar denuncia</string>
</resources>

View file

@ -268,4 +268,8 @@
<string name="last_response_duration">תגובה אחרונה: לפני %1$s</string>
<string name="duration_ago">לפני %1$s</string>
<string name="shared_string_error_short">שגיאה</string>
<string name="shared_string_export">ייצוא</string>
<string name="logcat_buffer">מכלא Logcat</string>
<string name="logcat_buffer_descr">בדיקה ושיתוף יומני תיעוד מפורטים של היישומים</string>
<string name="send_report">שליחת דיווח</string>
</resources>

View file

@ -268,4 +268,8 @@
<string name="last_response_duration">Utolsó válasz: %1$s</string>
<string name="duration_ago">Ennyivel ezelőtt: %1$s</string>
<string name="shared_string_error_short">HIBA</string>
<string name="shared_string_export">Exportálás</string>
<string name="logcat_buffer">Logcat-puffer (hibanapló)</string>
<string name="logcat_buffer_descr">Az alkalmazás részletes naplóinak ellenőrzése és megosztása</string>
<string name="send_report">Jelentés küldése</string>
</resources>

View file

@ -0,0 +1,274 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="units_and_formats">Einingar og snið</string>
<string name="install_osmand">Setja upp OsmAnd</string>
<string name="proxy_password">Lykilorð</string>
<string name="average_altitude">Meðalhæð</string>
<string name="shared_string_hide">Fela</string>
<string name="gps_points_in_buffer">sendi (%1$d í biðminni)</string>
<string name="re_send_location">Endursenda staðsetningu</string>
<string name="searching_for_gps">Staðsetning…</string>
<string name="average_speed">Meðalhraði</string>
<string name="logcat_buffer_descr">Athugaðu og deildu nákvæmum atvikaskrám úr forritinu</string>
<string name="si_mi_meters">Mílur/metrar</string>
<string name="password_descr">Lykilorð í Telegram</string>
<string name="share_location_as">Deila staðsetningu sem</string>
<string name="share_location">Deila staðsetningu</string>
<string name="min_logging_distance_descr">Sía: Stilltu lágmarksfjarlægð frá síðustu staðsetningu þar sem punktur er tekinn í skráningu</string>
<string name="shared_string_back">Til baka</string>
<string name="shared_string_off">Slökkt</string>
<string name="no_internet_connection">Engin internettenging</string>
<string name="set_time">Stilla tíma</string>
<string name="shared_string_accept">Samþykkja</string>
<string name="shared_string_second_short">sek</string>
<string name="minutes_format">%1$d mín</string>
<string name="si_mi_feet">Mílur/fet</string>
<string name="shared_string_bot">Vélmenni</string>
<string name="osmand_privacy_policy">Meðferð persónuupplýsinga í OsmAnd</string>
<string name="sending_location_messages">Sendi staðsetningu</string>
<string name="proxy_type">Tegund milliþjóns (proxy)</string>
<string name="unit_of_length_descr">Breyta einingum sem notaðar eru við lengdarmælingar.</string>
<string name="location_history">Staðsetningaferill</string>
<string name="osmand_logo">Merki OsmAnd</string>
<string name="error_adding_new_device">Gat ekki bætt við nýju tæki</string>
<string name="gps_and_location">Staða</string>
<string name="proxy_settings">Stillingar milliþjóns (proxy)</string>
<string name="proxy_port">Gátt</string>
<string name="by_name">Eftir nafni</string>
<string name="time_zone">Tímabelti</string>
<string name="min_km">mín/km</string>
<string name="m">m</string>
<string name="location_recording_enabled">Skráning staðsetningar virk</string>
<string name="shared_string_connection">Tenging</string>
<string name="si_km_m">Kílómetrar/metrar</string>
<string name="last_update_from_telegram_duration">Síðasta uppfærsla frá Telegram: Fyrir %1$s síðan</string>
<string name="monitoring_is_disabled">Vöktun er óvirk</string>
<string name="status_widget_title">Staða OsmAnd-rakningar</string>
<string name="app_name_short">OsmAnd-rakning</string>
<string name="shared_string_group">Hópur</string>
<string name="min_mile">mín/ml</string>
<string name="proxy_server">Netþjónn</string>
<string name="turn_off_all">Slökkva á öllu</string>
<string name="back_to_osmand">Til baka í OsmAnd</string>
<string name="device_name_is_too_long">Heiti tækis er of langt</string>
<string name="closing">Loka</string>
<string name="hours_and_minutes_format">%1$d klst %2$d mín</string>
<string name="si_min_m">Mínútur á mílu</string>
<string name="shared_string_minute_short">mín</string>
<string name="shared_string_start">Byrja</string>
<string name="shared_string_save">Vista</string>
<string name="map_and_text">Landakort og texti</string>
<string name="shared_string_password">Lykilorð</string>
<string name="device_added_successfully">%1$s bætt við.</string>
<string name="open_in_osmand">Birta í OsmAnd</string>
<string name="last_available_location">Síðasta tiltæka staðsetning</string>
<string name="shared_string_sent">Sent</string>
<string name="authentication_code">Auðkenningarkóði</string>
<string name="search_contacts">Leita í tengiliðum</string>
<string name="open_osmand">Opna OsmAnd</string>
<string name="shared_string_end">Endar</string>
<string name="enter_authentication_code">Settu inn auðkenningarkóða</string>
<string name="my_location">Staðsetning mín</string>
<string name="shared_string_logout">Skrá út</string>
<string name="show_on_map">Birta á korti</string>
<string name="sharing_status">Staða deilingar</string>
<string name="shared_string_cancel">Hætta við</string>
<string name="waiting_for_response_from_telegram">Bíð eftir svari frá Telegram</string>
<string name="successfully_sent_and_updated">Tókst að senda og uppfæra</string>
<string name="shared_string_select">Velja</string>
<string name="si_m_s">Metrar á sekúndu</string>
<string name="device_name">Heiti tækis</string>
<string name="shared_string_welcome">Velkomin</string>
<string name="how_it_works">Hvernig það virkar</string>
<string name="direction">Stefna</string>
<string name="proxy">Milliþjónn</string>
<string name="no_gps_connection">Engin GPS-tenging</string>
<string name="send_location_as">Senda staðsetningu sem</string>
<string name="points_size">%1$d punktar</string>
<string name="yard">yd</string>
<string name="shared_string_disable">Gera óvirkt</string>
<string name="time_on_the_move">Tími á ferðinni</string>
<string name="si_nm_h">Sjómílur á klukkustund (hnútar)</string>
<string name="hours_format">%1$d klst</string>
<string name="proxy_key">Lykill</string>
<string name="background_work">Bakgrunnsvinna</string>
<string name="shared_string_install">Setja upp</string>
<string name="shared_string_add">Bæta við</string>
<string name="shared_string_sort_by">Raða eftir</string>
<string name="last_response_date">Síðasta svar: %1$s</string>
<string name="shared_string_all">Allt</string>
<string name="altitude">Hæð</string>
<string name="show_gps_points">Birta GPS-punkta</string>
<string name="device_name_cannot_be_empty">Heiti tækis getur ekki verið tómt</string>
<string name="shared_string_search">Leita</string>
<string name="by_distance">Eftir vegalengd</string>
<string name="si_nm">Sjómílur</string>
<string name="m_s">m/sek</string>
<string name="not_logged_in">Þú ert ekki skráð/ur inn</string>
<string name="initializing">Ræsing</string>
<string name="min_logging_accuracy">Lágmarksnákvæmni skráningar</string>
<string name="shared_string_close">Loka</string>
<string name="min_logging_speed">Lágmarkshraði skráninga</string>
<string name="process_service">OsmAnd rakningarþjónusta</string>
<string name="shared_string_telegram">Telegram</string>
<string name="gps_network_not_enabled">Kveikja á \"Staðsetning\"\?</string>
<string name="connected_account">Tengdur aðgangur</string>
<string name="mile">mi</string>
<string name="proxy_username">Notandanafn</string>
<string name="shared_string_authorization">Heimild</string>
<string name="unit_of_length">Lengdareiningar</string>
<string name="gpx_settings">GPX-stillingar</string>
<string name="get_telegram_title">Nýskráning í Telegram</string>
<string name="shared_string_distance">Vegalengd</string>
<string name="shared_string_hour_short">klst</string>
<string name="km_h">km/klst</string>
<string name="shared_string_login">Skrá inn</string>
<string name="last_response">Síðasta svar</string>
<string name="start_location_sharing">Deila staðsetningu</string>
<string name="foot">ft</string>
<string name="shared_string_name">Nafn</string>
<string name="duration_ago">%1$s síðan</string>
<string name="location_sharing_description">Veldu notendur eða hópa til að deila með staðsetningu þinni.</string>
<string name="do_not_have_telegram">Ég er ekki með Telegram-aðgang</string>
<string name="monitoring_is_enabled">Vöktun er virk</string>
<string name="expire_at">Rennur út</string>
<string name="privacy">Gagnaleynd</string>
<string name="shared_string_account">Notandaaðgangur</string>
<string name="shared_string_enabled">Virkt</string>
<string name="precision">Nákvæmni</string>
<string name="shared_string_error_short">VILL</string>
<string name="stale_location">Ekki á ferð</string>
<string name="shared_string_continue">Halda áfram</string>
<string name="shared_string_status">Staða</string>
<string name="start_end_date">Upphafs — Endadagsetning</string>
<string name="proxy_disconnected">Aftengt</string>
<string name="nm">sml</string>
<string name="shared_string_update">Uppfæra</string>
<string name="enter_password">Settu inn lykilorð</string>
<string name="shared_string_share">Deila</string>
<string name="logcat_buffer">Logcat biðminni</string>
<string name="enter_phone_number">Settu inn símanúmer</string>
<string name="si_min_km">Mínútur á kílómetra</string>
<string name="shared_string_exit">Hætta</string>
<string name="shared_string_appearance">Útlit</string>
<string name="shared_string_date">Dagsetning</string>
<string name="shared_string_later">Síðar</string>
<string name="bearing">Stefna</string>
<string name="unit_of_speed_system">Hraðaeining</string>
<string name="shared_string_map">Landakort</string>
<string name="min_logging_speed_descr">Sía: Engin skráning punkta fyrir neðan valinn hraða</string>
<string name="in_time">í %1$s</string>
<string name="my_location_search_hint">Leit: Hópur eða tengiliður</string>
<string name="nm_h">hnútar</string>
<string name="km">km</string>
<string name="timeline">Tímalína</string>
<string name="saved_messages">Vistuð skilaboð</string>
<string name="gps_points">GPS-punktar</string>
<string name="shared_string_apply">Virkja</string>
<string name="min_logging_distance">Lágmarksfjarlægð skráninga</string>
<string name="last_update_from_telegram">Síðasta uppfærsla frá Telegram</string>
<string name="shared_string_collected">Safnað</string>
<string name="logging_out">Skrái út</string>
<string name="si_mi_yard">Mílur/yardar</string>
<string name="set_time_timeline_descr">Veldu tíma sem á að birta</string>
<string name="proxy_credentials">Auðkenni</string>
<string name="si_kmh">Kílómetrar á klukkustund</string>
<string name="last_response_duration">Síðasta svar: Fyrir %1$s síðan</string>
<string name="connecting_to_the_internet">Tengist internetinu</string>
<string name="send_report">Senda skýrslu</string>
<string name="shared_string_export">Flytja út</string>
<string name="si_mph">Mílur á klukkustund</string>
<string name="shared_string_ok">Í lagi</string>
<string name="shared_string_enable">Virkja</string>
<string name="telegram_privacy_policy">Persónuverndarstefna Telegram</string>
<string name="active_chats">Virkt spjall</string>
<string name="send_my_location">Senda staðsetningu mína</string>
<string name="shared_string_suggested">Stungið upp á</string>
<string name="go_to_settings">Fara í stillingar</string>
<string name="mile_per_hour">mi/klst</string>
<string name="sharing_in_background">Deiling í bakgrunni</string>
<string name="location_sharing_status">Deiling: %1$s</string>
<string name="last_update_from_telegram_date">Síðasta uppfærsla frá Telegram: %1$s</string>
<string name="initialization">Byrja</string>
<string name="shared_string_sort">Raða</string>
<string name="timeline_no_data">Engin gögn</string>
<string name="by_group">Eftir hópi</string>
<string name="add_device">Bæta við tæki</string>
<string name="shared_string_text">Texti</string>
<string name="shared_string_settings">Stillingar</string>
<string name="show_users_on_map">Birta notendur á kortinu</string>
<string name="proxy_connected">Tengt</string>
<string name="phone_number_title">Símanúmer</string>
<string name="start_date">Upphafsdagsetning</string>
<string name="unit_of_speed_system_descr">Skilgreindu einingu fyrir hraða.</string>
<string name="time_ago">síðan</string>
<string name="enter_code">Settu inn kóða</string>
<string name="disable_monitoring">Gera vöktun óvirka</string>
<string name="no_location_permission">Forritið hefur ekki heimildir til að nota staðsetningargögn.</string>
<string name="end_date">Lokadagsetning</string>
<string name="osmand_service">Bakgrunnshamur</string>
<string name="osmand_service_descr">OsmAnd-rakning keyrir í bakgrunni á meðan slökkt er á skjá.</string>
<string name="not_found_yet">Ekki fundist ennþá</string>
<string name="received_gps_points">Móttók GPX-punkta: %1$s</string>
<string name="sharing_location">Deili staðsetningu</string>
<string name="logout_help_desc">Hvernig á að slökkva á OsmAnd-rakningu úr Telegram</string>
<string name="not_sent_yet">Ekki sent ennþá</string>
<string name="app_name">OsmAnd nettengdur GPS-rekjari</string>
<string name="logout_from_osmand_telegram">Skrá út úr OsmAnd-rakningu\?</string>
<string name="stop_sharing_all">Kveikt er á deilingu (slökkva)</string>
<string name="disconnect_from_telegram">Hvernig á að slökkva á OsmAnd-rakningu úr Telegram</string>
<string name="gps_not_available">Virkjaðu \"Staðsetning\" í stillingunum stýrikerfisins</string>
<string name="live_now_description">Tengiliðir og hópar sem deila staðsetningu til þín.</string>
<string name="logout_no_internet_msg">Tengstu við internetið til að geta skráð þig til fulls út úr Telegram.</string>
<string name="privacy_policy_agree">Með því að smella á \'Halda áfram\', samþykkir þú ákvæði og skilyrði varðandi gagnaleynd hjá Telegram og OsmAnd.</string>
<string name="buffer_time">Gildistími biðminnis</string>
<string name="sharing_time">Tími deilingar</string>
<string name="send_location_as_descr">Veldu hvernig skilaboð með staðsetningu þinni líti út.</string>
<string name="install_osmand_dialog_message">Þú þarft fyrst að setja upp ókeypis eða greidda útgáfu OsmAnd</string>
<string name="disable_all_sharing_desc">Slekkur á deilingu staðsetningar til allra valinna spjalla (%1$d).</string>
<string name="turn_off_location_sharing">Slökkva á deilingu staðsetningar</string>
<string name="type_contact_or_group_name">Settu inn nafn tengiliðar eða hóps</string>
<string name="timeline_available_for_free_now">Tímalína er eiginleiki sem er núna aðgengilegur ókeypis.</string>
<string name="already_registered_in_telegram">Þú þarft skráðan Telegram-aðgang og símanúmer</string>
<string name="authentication_code_descr">Telegram hefur sent þér kóða fyrir OsmAnd til að skrá þig inn í notandaaðganginn þinn.</string>
<string name="choose_osmand">Veldu hvaða útgáfu OsmAnd þú vilt nota</string>
<string name="disable_all_sharing">Gera alla deilingu óvirka</string>
<string name="please_update_osmand">Uppfærðu OsmAnd til að skoða gögn á kortinu</string>
<string name="time_zone_descr">Veldu tímabelti til birtingar í staðsetningarskilaboðum þínum.</string>
<string name="location_service_no_gps_available">Veldu eina af staðsetningarþjónustunum til að deila staðsetningu þinni.</string>
<string name="set_visible_time_for_all">Stilla tímabil þar sem allir eru sýnilegir</string>
<string name="osmand_connect_desc">Veldu þá útgáfu OsmAnd sem OsmAnd-rakningin notar til að birta staðsetningar.</string>
<string name="get_telegram_description_continue">Endilega settu upp Telegram og skráðu notandaaðgang.</string>
<string name="shared_string_authorization_descr">Settu inn Telegram-símanúmerið þitt á alþjóðlegu sniði</string>
<string name="timeline_description">Virkja vöktun til að vista allar staðsetningar í aðgerðaferli.</string>
<string name="visible_time_for_all">Tímabil þar sem allir eru sýnilegir</string>
<string name="send_my_location_desc">Stilla minnsta bil á milli deilingar staðsetningar.</string>
<string name="buffer_time_descr">Hámarkstími sem punktar eru geymdir í biðminninu</string>
<string name="get_telegram_account_first">Þú þarft skráðan Telegram-aðgang til að geta notað deilingu staðsetningar.</string>
<string name="phone_number_descr">Símanúmer á alþjóðlegu sniði</string>
<string name="choose_osmand_desc">Veldu þá útgáfu OsmAnd þar sem tengiliðir verða birtir á kortinu.</string>
<string name="osmand_connect">Tengjast OsmAnd</string>
<string name="show_gps_points_descr">Birta fjölda safnaðra og sendra GPS-punkta.</string>
<string name="privacy_policy_use_telegram">Telegram (skilaboðaforritið) er notað til að tengjast og eiga í samskiptum við fólk.</string>
<string name="get_telegram_after_creating_account">þá geturðu notað þetta forrit.</string>
<string name="enter_device_name_description">Gefðu nýja tækinu þínu nafn að hámarki 200 stafir.</string>
<string name="timeline_no_data_descr">Við erum ekki með söfnuð gögn fyrir valinn dag</string>
<string name="search_contacts_descr">Leita í öllum þínum hópum og tengiliðum.</string>
<string name="min_logging_accuracy_descr">Sía: Stilltu lágmarksnákvæmni punkts til að hann sé tekinn í skráningu</string>
<string name="location_history_desc">Fela tengiliði sem ekki hafa hreyfst á tilteknu tímabili.</string>
<string name="stale_location_desc">Síðasta skiptið sem tengiliður hreyfðist.</string>
<string name="last_updated_location">Síðasta uppfærða staðsetning:</string>
<string name="enter_another_device_name">Veldu nafn sem þú hefur ekki þegar notað</string>
<string name="not_possible_to_send_to_telegram_chats">Ekki mögulegt að senda á Telegram-spjöll:</string>
<string name="disconnect_from_telegram_desc">Til að afturkalla heimildir til deilingar á staðsetningu, opnaðu Telegram, farðu í Stillingar → Gagnaleynd og öryggi → Setur, og bittu enda á setu OsmAnd-rakningar.</string>
<string name="share_location_as_description_second_line">Þú getur útbúið og skoðað auðkenningu tækis (device ID) í Telegram-biðlaraforritinu með því að nota %1$s spjallvélmennið. %2$s</string>
<string name="logout_from_osmand_telegram_descr">Ertu viss að þú viljir skrá þig út úr OsmAnd-rakningu þannig að þú getir ekki lengur deilt þinni staðsetningu eða séð staðsetningu annarra\?</string>
<string name="battery_optimization_description">Slokktu á bestun rafhlöðunýtingar fyrir OsmAnd-rakningu svo ekki slökkni á henni þegar forritið fer í bakgrunnsham (t.d. slökkt er á skjá).</string>
<string name="privacy_policy_telegram_client">OsmAnd-rakning er eitt af biðlaraforritunum sem nota opna Telegram-kerfið. Tengiliðirnir þínir geta notað eitthvað annað Telegram-biðlaraforrit.</string>
<string name="welcome_descr"><b>OsmAnd-rakning</b> gerir þér kleift að deila staðsetningu þinni og að sjá aðra í OsmAnd.<br/><br/>Forritið notar Telegram API-forritsviðmótið, þannig að þú verður að vera með Telegram-aðgang.</string>
<string name="share_location_as_description">Ef þú ætlar að tengja mörg tæki við einn Telegram-notandaaðgang, þarftu að nota annað tæki til að deila staðsetningunni þinni.</string>
<string name="shared_string_live">Rauntíma</string>
<string name="background_work_description">Breyta bestunarstillingum rafhlöðu til að auka stöðugleika í deilingu staðsetningar.</string>
<string name="set_time_description">Veldu tímann sem valdir tengiliðir og hópar munu sjá staðsetningu þína í rauntíma.</string>
<string name="live_now">Rauntíma núna</string>
</resources>

View file

@ -265,4 +265,6 @@
<string name="last_response_date">Ultima risposta: %1$s</string>
<string name="last_update_from_telegram_date">Ultimo aggiornamento da Telegram: %1$s</string>
<string name="shared_string_error_short">ERR</string>
<string name="logcat_buffer_descr">Controlla e condividi i log dettagliati dell\'applicazione</string>
<string name="logcat_buffer">Logcat buffer</string>
</resources>

View file

@ -219,8 +219,8 @@
<string name="shared_string_authorization_descr">国際形式でTelegramを利用する端末の電話番号を入力してください(日本の場合+81を先頭につけて電話番号最初の0を除いた番号を入力)</string>
<string name="shared_string_welcome">ようこそ</string>
<string name="yard">ヤード</string>
<string name="foot">フィート</string>
<string name="mile">マイル</string>
<string name="foot">ft</string>
<string name="mile">mi</string>
<string name="km">km</string>
<string name="m">m</string>
<string name="nm">海里</string>

View file

@ -179,7 +179,7 @@
<string name="monitoring_is_enabled">Oppsyn er påskrudd</string>
<string name="monitoring_is_disabled">Oppsyn er ikke aktivert</string>
<string name="time_on_the_move">Tid i bevegelse</string>
<string name="average_altitude">Gjennomsnittlig høyde</string>
<string name="average_altitude">Gjennomsnittshøyde</string>
<string name="average_speed">Gjennomsnittsfart</string>
<string name="open_in_osmand">Vis i OsmAnd</string>
<string name="end_date">Sluttdato</string>
@ -267,4 +267,8 @@
<string name="last_response_duration">Siste respons: %1$s siden</string>
<string name="duration_ago">%1$s siden</string>
<string name="shared_string_error_short">FEIL</string>
<string name="logcat_buffer">Logcat-mellomlager</string>
<string name="shared_string_export">Eksporter</string>
<string name="logcat_buffer_descr">Sjekk og del detaljert loggføring fra programmet</string>
<string name="send_report">Send rapport</string>
</resources>

View file

@ -257,4 +257,8 @@
<string name="unit_of_length">Afstand eenheden</string>
<string name="unit_of_speed_system_descr">Definieer de eenheid voor snelheid.</string>
<string name="unit_of_speed_system">Eenheid van snelheid</string>
<string name="send_report">Stuur rapport</string>
<string name="shared_string_export">Exporteer naar OSM</string>
<string name="logcat_buffer">Logcat buffer</string>
<string name="logcat_buffer_descr">Controleer en deel gedetailleerde logs van de app</string>
</resources>

View file

@ -267,4 +267,8 @@
<string name="shared_string_error_short">ERR</string>
<string name="last_response_date">Ostatnia odpowiedź: %1$s</string>
<string name="last_response_duration">Ostatnia odpowiedź: %1$s temu</string>
<string name="shared_string_export">Eksportuj</string>
<string name="logcat_buffer">Bufor katalogu dziennika</string>
<string name="logcat_buffer_descr">Sprawdzanie i udostępnianie szczegółowych logów aplikacji</string>
<string name="send_report">Wyślij raport</string>
</resources>

View file

@ -267,4 +267,8 @@
<string name="last_response_duration">Última resposta: %1$s atrás</string>
<string name="duration_ago">%1$s atrás</string>
<string name="shared_string_error_short">ERR</string>
<string name="shared_string_export">Exportar</string>
<string name="logcat_buffer">Buffer de Logcat</string>
<string name="logcat_buffer_descr">Verifique e compartilhe registros detalhados do aplicativo</string>
<string name="send_report">Enviar o relatório</string>
</resources>

View file

@ -267,4 +267,8 @@
<string name="last_response_date">Última resposta: %1$s</string>
<string name="last_update_from_telegram_date">Última atualização do Telegram: %1$s</string>
<string name="shared_string_error_short">ERR</string>
<string name="shared_string_export">Exportar</string>
<string name="logcat_buffer">Buffer de logcat</string>
<string name="logcat_buffer_descr">Verifique e compartilhe registos detalhados da app</string>
<string name="send_report">Enviar o relatório</string>
</resources>

View file

@ -108,7 +108,7 @@
<string name="not_found_yet">Ainda não encontrado</string>
<string name="re_send_location">Reenvie o local</string>
<string name="last_available_location">Última localização disponível</string>
<string name="sharing_status">Status de compartilhamento</string>
<string name="sharing_status">Estado de compartilhamento</string>
<string name="location_sharing_status">Compartilhamento: %1$s</string>
<string name="shared_string_enabled">Ativado</string>
<string name="no_gps_connection">Sem conexão GPS</string>
@ -163,7 +163,7 @@
<string name="get_telegram_description_continue">Por favor, instale o Telegram e configure uma conta.</string>
<string name="get_telegram_after_creating_account">Então pode usar esta app.</string>
<string name="shared_string_all">Todos</string>
<string name="shared_string_off">Desativado</string>
<string name="shared_string_off">Desligado</string>
<string name="already_registered_in_telegram">Precisa de uma conta e número de telefone registados no Telegram</string>
<string name="do_not_have_telegram">Não tenho uma conta do Telegram</string>
<string name="enter_phone_number">Digite o número de telefone</string>
@ -204,7 +204,7 @@
<string name="no_location_permission">A app não tem permissão para acessar os dados de localização.</string>
<string name="gps_not_available">Por favor, ligue \"Localização\" nas configurações do sistema</string>
<string name="location_service_no_gps_available">Selecione um dos provedores de localização para compartilhar sua localização.</string>
<string name="osmand_service">Modo em segundo plano</string>
<string name="osmand_service">Modo de fundo</string>
<string name="osmand_service_descr">OsmAnd Tracker é executado em segundo plano com o ecrã desligado.</string>
<string name="shared_string_distance">Distância</string>
<string name="share_location">Compartilhar localização</string>
@ -230,15 +230,15 @@
<string name="m_s">m/s</string>
<string name="km_h">km/h</string>
<string name="mile_per_hour">mph</string>
<string name="si_kmh">Quilômetros por hora</string>
<string name="si_kmh">Quilómetros por hora</string>
<string name="si_mph">Milhas por hora</string>
<string name="si_m_s">Metros por segundo</string>
<string name="si_min_km">Minutos por quilômetro</string>
<string name="si_min_km">Minutos por quilómetro</string>
<string name="si_min_m">Minutos por milha</string>
<string name="si_nm_h">Milhas náuticas por hora (nó)</string>
<string name="si_mi_feet">Milhas/pés</string>
<string name="si_mi_yard">Milhas/jardas</string>
<string name="si_km_m">Quilômetros/metros</string>
<string name="si_km_m">Quilómetros/metros</string>
<string name="si_nm">Milhas náuticas</string>
<string name="si_mi_meters">Milhas/metros</string>
<string name="shared_string_hour_short">h</string>
@ -252,7 +252,7 @@
<string name="time_zone_descr">Selecione o fuso horário a mostrar nas suas mensagens de localização.</string>
<string name="time_zone">Fuso horário</string>
<string name="units_and_formats">Unidades e formatos</string>
<string name="unit_of_length_descr">Alterar unidade de distância.</string>
<string name="unit_of_length_descr">Alterar a unidade de medida de distância.</string>
<string name="unit_of_length">Unidades de comprimento</string>
<string name="unit_of_speed_system_descr">Definir unidade de velocidade.</string>
<string name="unit_of_speed_system">Unidade de velocidade</string>
@ -267,4 +267,8 @@
<string name="last_response_date">Última resposta: %1$s</string>
<string name="last_update_from_telegram_date">Última atualização do Telegram: %1$s</string>
<string name="shared_string_error_short">ERR</string>
<string name="send_report">Enviar o relatório</string>
<string name="shared_string_export">Exportar</string>
<string name="logcat_buffer">Buffer de logcat</string>
<string name="logcat_buffer_descr">Verifique e compartilhe registos detalhados da app</string>
</resources>

View file

@ -75,7 +75,7 @@
<string name="by_distance">По расстоянию</string>
<string name="by_name">По имени</string>
<string name="by_group">По группе</string>
<string name="shared_string_sort">Сортировать</string>
<string name="shared_string_sort">Сортировка</string>
<string name="shared_string_sort_by">Сортировать по</string>
<string name="turn_off_all">Отстановить все</string>
<string name="shared_string_exit">Выход</string>
@ -267,4 +267,8 @@
<string name="last_update_from_telegram_duration">Последнее обновление от Telegram: %1$s назад</string>
<string name="last_response_date">Последний ответ: %1$s</string>
<string name="last_update_from_telegram_date">Последнее обновление от Telegram: %1$s</string>
<string name="shared_string_export">Экспорт</string>
<string name="logcat_buffer">Буфер Logcat</string>
<string name="logcat_buffer_descr">Проверьте и поделитесь подробными журналами приложения</string>
<string name="send_report">Отправить отчёт</string>
</resources>

View file

@ -268,4 +268,8 @@
<string name="last_response_duration">Ùrtima risposta: %1$s a como</string>
<string name="duration_ago">%1$s a como</string>
<string name="shared_string_error_short">ERR</string>
<string name="shared_string_export">Esporta</string>
<string name="logcat_buffer">Buffer de Logcat</string>
<string name="logcat_buffer_descr">Verìfica e cumpartzi sos registros de s\'aplicatzione fatos a sa minuda</string>
<string name="send_report">Imbia resumu</string>
</resources>

View file

@ -267,4 +267,8 @@
<string name="last_response_date">Последњи одговор: %1$</string>
<string name="last_update_from_telegram_date">Последње ажурирање из Телеграма: %1$</string>
<string name="shared_string_error_short">Грешка</string>
<string name="shared_string_export">Извези</string>
<string name="logcat_buffer">Logcat бафер</string>
<string name="logcat_buffer_descr">Проверите и поделите детаљне записе апликације</string>
<string name="send_report">Пошаљи извештај</string>
</resources>

View file

@ -233,7 +233,7 @@
<string name="osmand_service_descr">OsmAnd Tracker, ekran kapalıyken arka planda çalışır.</string>
<string name="share_location">Konumu paylaş</string>
<string name="sharing_location">Konum paylaşılıyor</string>
<string name="process_service">OsmAnd Tracker servisi</string>
<string name="process_service">OsmAnd Tracker hizmeti</string>
<string name="osmand_logo">OsmAnd logosu</string>
<string name="install_osmand_dialog_message">Önce OsmAnd\'ın ücretsiz veya ücretli sürümünü yüklemeniz gerekmektedir</string>
<string name="install_osmand">OsmAnd\'ı yükle</string>
@ -267,4 +267,8 @@
<string name="last_response_duration">Son cevap: %1$s önce</string>
<string name="duration_ago">%1$s önce</string>
<string name="shared_string_error_short">HATA</string>
<string name="shared_string_export">Dışa aktar</string>
<string name="logcat_buffer">Logcat tamponu</string>
<string name="logcat_buffer_descr">Uygulamanın ayrıntılı günlük kayıtlarına göz atın ve paylaşın</string>
<string name="send_report">Rapor gönder</string>
</resources>

View file

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="shared_string_back">Aɣul</string>
<string name="shared_string_share">Bḍu</string>
<string name="enter_phone_number">Ssekcem uṭṭun n utilifun</string>
<string name="shared_string_all">Akk</string>
<string name="shared_string_bot">Abut</string>
<string name="shared_string_live">Usrid</string>
<string name="in_time">g %1$s</string>
<string name="shared_string_account">Amiḍan</string>
<string name="shared_string_close">Rgel</string>
<string name="shared_string_group">Tarabbut</string>
<string name="time_ago">aya</string>
<string name="shared_string_exit">Ffeɣ</string>
<string name="shared_string_sort_by">Fren s</string>
<string name="shared_string_sort">Fren</string>
<string name="by_group">S trabbut</string>
<string name="by_name">S isem</string>
<string name="shared_string_name">Isem</string>
<string name="share_location_as">Bḍu adɣar am</string>
<string name="add_device">Rnu allal</string>
<string name="shared_string_save">Ḥḍu</string>
<string name="shared_string_status">Addad</string>
<string name="go_to_settings">Ddu ɣer tesɣal</string>
<string name="sending_location_messages">Azan n udɣar</string>
<string name="shared_string_hide">Ssentel</string>
<string name="shared_string_add">Rnu</string>
<string name="last_update_from_telegram">Taleqqemt tameggarut seg Tiligṛam</string>
<string name="map_and_text">Takaṛḍa d uḍṛiṣ</string>
<string name="shared_string_text">Aḍṛiṣ</string>
<string name="shared_string_map">Takaṛḍa</string>
<string name="send_location_as">Azen adɣar am</string>
<string name="start_date">Asakud n usenti</string>
<string name="shared_string_date">Asakud</string>
<string name="shared_string_update">Ssedɣi</string>
<string name="shared_string_telegram">Tiligṛam</string>
<string name="shared_string_ok">WAX</string>
<string name="shared_string_search">Rzu</string>
<string name="direction">Tanila</string>
<string name="privacy">Tinnutla</string>
<string name="proxy">Apṛuksi</string>
<string name="proxy_settings">Tisɣal n Upṛuksi</string>
<string name="proxy_connected">Izdey</string>
<string name="proxy_type">Anaw n upṛuksi</string>
<string name="proxy_password">Taguri n uzray</string>
<string name="proxy_key">Tasarut</string>
<string name="gpx_settings">Tisɣal n GPX</string>
<string name="shared_string_select">Stey</string>
<string name="shared_string_start">Ssenti</string>
<string name="back_to_osmand">Aɣul ɣer OsmAnd</string>
<string name="duration_ago">%1$s aya</string>
</resources>

View file

@ -115,10 +115,10 @@
<string name="not_logged_in">Ви не увійшли до системи</string>
<string name="shared_string_continue">Продовжити</string>
<string name="shared_string_cancel">Скасувати</string>
<string name="shared_string_settings">Налаштування</string>
<string name="shared_string_settings">Параметри</string>
<string name="no_location_permission">Застосунок не має дозволу до отримання даних позиціювання.</string>
<string name="gps_not_available">Будь ласка, увімкніть «Позиціювання» у системних налаштуваннях</string>
<string name="osmand_service">Фоновий режим</string>
<string name="osmand_service">Режим тла</string>
<string name="osmand_service_descr">OsmAnd Tracker працює у фоновому режимі з вимкненим екраном.</string>
<string name="shared_string_distance">Відстань</string>
<string name="share_location">Поділитися позицією</string>
@ -267,4 +267,8 @@
<string name="last_response_duration">Остання відповідь: %1$s тому</string>
<string name="duration_ago">%1$s тому</string>
<string name="shared_string_error_short">ПМЛК</string>
<string name="shared_string_export">Експорт</string>
<string name="logcat_buffer">Буфер logcat</string>
<string name="logcat_buffer_descr">Переглянути та надіслати докладний журнал застосунку</string>
<string name="send_report">Надіслати звіт</string>
</resources>

View file

@ -270,4 +270,8 @@
<string name="last_response_duration">最後回應:%1$s 前</string>
<string name="duration_ago">%1$s 前</string>
<string name="shared_string_error_short">ERR</string>
<string name="send_report">傳送報告</string>
<string name="shared_string_export">匯出</string>
<string name="logcat_buffer">Logcat 緩衝</string>
<string name="logcat_buffer_descr">檢查及分享應用程式的詳細紀錄</string>
</resources>

View file

@ -27,6 +27,7 @@
<dimen name="dialog_welcome_title_top_margin">89dp</dimen>
<dimen name="list_header_height">48dp</dimen>
<dimen name="list_description_height">44dp</dimen>
<dimen name="list_header_with_descr_height">42dp</dimen>
<dimen name="list_item_height">56dp</dimen>

View file

@ -1,5 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="send_report">Send report</string>
<string name="logcat_buffer_descr">Check and share detailed logs of the app</string>
<string name="logcat_buffer">Logcat buffer</string>
<string name="shared_string_export">Export</string>
<string name="shared_string_error_short">ERR</string>
<string name="last_update_from_telegram_date">Last update from Telegram: %1$s</string>
<string name="last_response_date">Last response: %1$s</string>

View file

@ -3,16 +3,20 @@ package net.osmand.telegram
import android.app.Application
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.net.ConnectivityManager
import android.net.NetworkInfo
import android.os.Build
import android.os.Handler
import net.osmand.PlatformUtil
import net.osmand.telegram.ui.TrackerLogcatActivity
import net.osmand.telegram.helpers.*
import net.osmand.telegram.helpers.OsmandAidlHelper.OsmandHelperListener
import net.osmand.telegram.helpers.OsmandAidlHelper.UpdatesListener
import net.osmand.telegram.notifications.NotificationHelper
import net.osmand.telegram.utils.AndroidUtils
import net.osmand.telegram.utils.UiUtils
import java.io.File
class TelegramApplication : Application() {
@ -200,4 +204,33 @@ class TelegramApplication : Application() {
fun runInUIThread(action: (() -> Unit), delay: Long) {
uiHandler.postDelayed(action, delay)
}
fun sendCrashLog(file: File) {
val intent = Intent(Intent.ACTION_SEND)
intent.putExtra(Intent.EXTRA_EMAIL, arrayOf("crash@osmand.net"))
intent.putExtra(Intent.EXTRA_STREAM, AndroidUtils.getUriForFile(this, file))
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
intent.type = "vnd.android.cursor.dir/email"
intent.putExtra(Intent.EXTRA_SUBJECT, "OsmAnd bug")
val text = StringBuilder()
text.append("\nDevice : ").append(Build.DEVICE)
text.append("\nBrand : ").append(Build.BRAND)
text.append("\nModel : ").append(Build.MODEL)
text.append("\nProduct : ").append(Build.PRODUCT)
text.append("\nBuild : ").append(Build.DISPLAY)
text.append("\nVersion : ").append(Build.VERSION.RELEASE)
text.append("\nApp : ").append(getString(R.string.app_name_short))
try {
val info = packageManager.getPackageInfo(packageName, 0)
if (info != null) {
text.append("\nApk Version : ").append(info.versionName).append(" ").append(info.versionCode)
}
} catch (e: PackageManager.NameNotFoundException) {
PlatformUtil.getLog(TrackerLogcatActivity::class.java).error("", e)
}
intent.putExtra(Intent.EXTRA_TEXT, text.toString())
val chooserIntent = Intent.createChooser(intent, getString(R.string.send_report))
chooserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(chooserIntent)
}
}

View file

@ -18,7 +18,6 @@ import net.osmand.telegram.helpers.TelegramHelper
import net.osmand.telegram.helpers.TelegramHelper.*
import net.osmand.telegram.notifications.TelegramNotification.NotificationType
import net.osmand.telegram.utils.AndroidUtils
import net.osmand.telegram.utils.OsmandLocationUtils
import org.drinkless.td.libcore.telegram.TdApi
import java.util.*
@ -377,7 +376,10 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
Log.d(PlatformUtil.TAG, "Send live location error: $code - $message")
when (messageType) {
TelegramHelper.MESSAGE_TYPE_TEXT -> shareInfo.pendingTdLibText--
TelegramHelper.MESSAGE_TYPE_MAP -> shareInfo.pendingTdLibMap--
TelegramHelper.MESSAGE_TYPE_MAP -> {
shareInfo.pendingTdLibMap--
shareInfo.currentMapMessageId = -1L
}
}
}

View file

@ -110,7 +110,7 @@ private const val PROXY_ENABLED = "proxy_enabled"
private const val PROXY_PREFERENCES_KEY = "proxy_preferences"
private const val SHARING_INITIALIZATION_TIME = 60 * 2L // 2 minutes
private const val WAITING_TDLIB_TIME = 3 // 3 seconds
private const val WAITING_TDLIB_TIME = 7 // 7 seconds
private const val GPS_UPDATE_EXPIRED_TIME = 60 * 3L // 3 minutes
@ -304,27 +304,18 @@ class TelegramSettings(private val app: TelegramApplication) {
fun prepareForSharingNewMessages() {
shareChatsInfo.forEach { (_, shareInfo) ->
prepareForSharingNewMessages(shareInfo)
shareInfo.resetMessagesInfo()
}
}
fun prepareForSharingNewMessages(chatsIds: List<Long>) {
chatsIds.forEach {
shareChatsInfo[it]?.also { shareInfo ->
prepareForSharingNewMessages(shareInfo)
shareInfo.resetMessagesInfo()
}
}
}
fun prepareForSharingNewMessages(shareInfo: ShareChatInfo) {
shareInfo.pendingTdLibText = 0
shareInfo.pendingTdLibMap = 0
shareInfo.currentTextMessageId = -1L
shareInfo.currentMapMessageId = -1L
shareInfo.pendingTextMessage = false
shareInfo.pendingMapMessage = false
}
fun getChatLivePeriod(chatId: Long) = shareChatsInfo[chatId]?.livePeriod
fun getChatsShareInfo() = shareChatsInfo
@ -540,14 +531,24 @@ class TelegramSettings(private val app: TelegramApplication) {
if (initTime && initSending) {
initializing = true
} else {
var waitingTimeError = false
val maxWaitingTime = WAITING_TDLIB_TIME * MAX_MESSAGES_IN_TDLIB_PER_CHAT * max(1, chatsCount)
val textSharingError = !shareInfo.lastTextMessageHandled && currentTime - shareInfo.lastSendTextMessageTime > maxWaitingTime
val mapSharingError = !shareInfo.lastMapMessageHandled && currentTime - shareInfo.lastSendMapMessageTime > maxWaitingTime
if (shareInfo.hasSharingError
|| (shareTypeValue == SHARE_TYPE_MAP_AND_TEXT && (textSharingError || mapSharingError))
val textSharingWaitingTime = currentTime - shareInfo.lastSendTextMessageTime
val mapSharingWaitingTime = currentTime - shareInfo.lastSendMapMessageTime
val textSharingError = !shareInfo.lastTextMessageHandled && textSharingWaitingTime > maxWaitingTime
val mapSharingError = !shareInfo.lastMapMessageHandled && mapSharingWaitingTime > maxWaitingTime
if ((shareTypeValue == SHARE_TYPE_MAP_AND_TEXT && (textSharingError || mapSharingError))
|| textSharingError && (shareTypeValue == SHARE_TYPE_TEXT)
|| mapSharingError && (shareTypeValue == SHARE_TYPE_MAP)
) {
|| mapSharingError && (shareTypeValue == SHARE_TYPE_MAP)) {
waitingTimeError = true
log.debug("Send chats error for share type \"$shareTypeValue\"" +
"\nMax waiting time: ${maxWaitingTime}s" +
"\nLast text message handled: ${shareInfo.lastTextMessageHandled}" +
"\nText sharing waiting time: ${textSharingWaitingTime}s" +
"\nLast map message handled: ${shareInfo.lastMapMessageHandled}" +
"\nMap sharing waiting time: ${mapSharingWaitingTime}s")
}
if (shareInfo.hasSharingError || waitingTimeError) {
sendChatsErrors = true
locationTime = max(shareInfo.lastTextSuccessfulSendTime, shareInfo.lastMapSuccessfulSendTime)
chatsIds.add(shareInfo.chatId)
@ -1487,6 +1488,27 @@ class TelegramSettings(private val app: TelegramApplication) {
fun isPendingMapMessagesLimitReached() = pendingTdLibMap >= MAX_MESSAGES_IN_TDLIB_PER_CHAT
fun resetMessagesInfo() {
resetTextMessageInfo()
resetMapMessageInfo()
}
fun resetTextMessageInfo() {
pendingTdLibText = 0
currentTextMessageId = -1L
pendingTextMessage = false
}
fun resetMapMessageInfo() {
pendingTdLibMap = 0
currentMapMessageId = -1L
pendingMapMessage = false
}
fun isTextMessageIdPresent() = currentTextMessageId != -1L
fun isMapMessageIdPresent() = currentMapMessageId != -1L
companion object {
internal const val CHAT_ID_KEY = "chatId"

View file

@ -138,7 +138,7 @@ class ShareLocationHelper(private val app: TelegramApplication) {
}
}
if (pendingMessagesLimitReached && checkNetworkTypeAllowed) {
checkNetworkType()
updateNetworkType()
}
}
@ -167,7 +167,7 @@ class ShareLocationHelper(private val app: TelegramApplication) {
app.locationMessages.getBufferedTextMessagesForChat(chatId).take(MAX_MESSAGES_IN_TDLIB_PER_CHAT).forEach {
if (!shareInfo.isPendingTextMessagesLimitReached()) {
if (it.deviceName.isEmpty()) {
if (!shareInfo.pendingTextMessage && shareInfo.currentTextMessageId != -1L) {
if (!shareInfo.pendingTextMessage && shareInfo.isTextMessageIdPresent()) {
val content = OsmandLocationUtils.getTextMessageContent(shareInfo.updateTextMessageId, it, app)
app.telegramHelper.editTextLocation(shareInfo, content)
app.locationMessages.removeBufferedMessage(it)
@ -180,8 +180,12 @@ class ShareLocationHelper(private val app: TelegramApplication) {
app.locationMessages.getBufferedMapMessagesForChat(chatId).take(MAX_MESSAGES_IN_TDLIB_PER_CHAT).forEach {
if (!shareInfo.isPendingMapMessagesLimitReached()) {
if (it.deviceName.isEmpty()) {
if (!shareInfo.pendingMapMessage && shareInfo.currentMapMessageId != -1L) {
if (!shareInfo.pendingMapMessage) {
if (shareInfo.isMapMessageIdPresent()) {
app.telegramHelper.editMapLocation(shareInfo, it)
} else {
app.telegramHelper.sendNewMapLocation(shareInfo, it)
}
app.locationMessages.removeBufferedMessage(it)
}
} else {
@ -279,7 +283,7 @@ class ShareLocationHelper(private val app: TelegramApplication) {
}
}
if (pendingMessagesLimitReached) {
checkNetworkType()
updateNetworkType()
}
}
@ -347,7 +351,7 @@ class ShareLocationHelper(private val app: TelegramApplication) {
}
}
fun checkNetworkType(){
fun updateNetworkType(){
if (app.isInternetConnectionAvailable) {
val networkType = when {
app.isWifiConnected -> TdApi.NetworkTypeWiFi()

View file

@ -776,6 +776,7 @@ class TelegramHelper private constructor() {
client?.send(TdApi.CreatePrivateChat(userId, false)) { obj ->
when (obj.constructor) {
TdApi.Error.CONSTRUCTOR -> {
log.debug("createPrivateChatWithUser ERROR $obj")
val error = obj as TdApi.Error
if (error.code != IGNORED_ERROR_CODE) {
shareInfo.hasSharingError = true
@ -839,7 +840,7 @@ class TelegramHelper private constructor() {
}
fun stopSendingLiveLocationToChat(shareInfo: ShareChatInfo) {
if (shareInfo.currentMapMessageId != -1L && shareInfo.chatId != -1L) {
if (!shareInfo.isMapMessageIdPresent() && shareInfo.chatId != -1L) {
shareInfo.lastSendMapMessageTime = (System.currentTimeMillis() / 1000).toInt()
client?.send(
TdApi.EditMessageLiveLocation(shareInfo.chatId, shareInfo.currentMapMessageId, null, null)) { obj ->
@ -969,7 +970,7 @@ class TelegramHelper private constructor() {
val messageType = if (isBot) MESSAGE_TYPE_BOT else MESSAGE_TYPE_TEXT
when (obj.constructor) {
TdApi.Error.CONSTRUCTOR -> {
log.debug("handleTextLocationMessageUpdate - ERROR")
log.debug("handleTextLocationMessageUpdate - ERROR $obj")
val error = obj as TdApi.Error
if (error.code != IGNORED_ERROR_CODE) {
shareInfo.hasSharingError = true

View file

@ -15,7 +15,6 @@ import android.widget.TextView
import androidx.appcompat.widget.ListPopupWindow
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import net.osmand.Location
import net.osmand.data.LatLon
import net.osmand.telegram.R
@ -99,7 +98,7 @@ class LiveNowTabFragment : Fragment(), TelegramListener, TelegramIncomingMessage
mainView.findViewById<androidx.swiperefreshlayout.widget.SwipeRefreshLayout>(R.id.swipe_refresh).apply {
setOnRefreshListener {
app.shareLocationHelper.checkNetworkType()
app.shareLocationHelper.updateNetworkType()
app.telegramHelper.scanChatsHistory()
updateList()
isRefreshing = false

View file

@ -213,6 +213,12 @@ class SettingsDialogFragment : BaseDialogFragment() {
DisconnectTelegramBottomSheet.showInstance(childFragmentManager)
}
mainView.findViewById<View>(R.id.logcat_row).setOnClickListener {
val intent = Intent(activity, TrackerLogcatActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
app.startActivity(intent)
}
return mainView
}

View file

@ -72,7 +72,7 @@ class SharingStatusBottomSheet : DialogFragment() {
if (sharingStatusType.canResendLocation) {
if (i == 0) {
setOnClickListener {
app.shareLocationHelper.checkNetworkType()
app.shareLocationHelper.updateNetworkType()
app.settings.prepareForSharingNewMessages(sharingStatus.chatsIds)
app.shareLocationHelper.checkAndSendBufferMessages()
app.forceUpdateMyLocation()

View file

@ -0,0 +1,271 @@
package net.osmand.telegram.ui
import android.os.AsyncTask
import android.os.Bundle
import android.view.*
import android.widget.ProgressBar
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import net.osmand.PlatformUtil
import net.osmand.telegram.R
import net.osmand.telegram.TelegramApplication
import java.io.*
import java.lang.ref.WeakReference
import java.util.*
class TrackerLogcatActivity : AppCompatActivity() {
private var logcatAsyncTask: LogcatAsyncTask? = null
private val logs: MutableList<String> = ArrayList()
private var adapter: LogcatAdapter? = null
private val LEVELS = arrayOf("D", "I", "W", "E")
private var filterLevel = 1
private lateinit var recyclerView: RecyclerView
override fun onCreate(savedInstanceState: Bundle?) {
val app: TelegramApplication = getApplication() as TelegramApplication
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_tracker_logcat)
val toolbar = findViewById<Toolbar>(R.id.toolbar).apply {
navigationIcon = app.uiUtils.getThemedIcon(R.drawable.ic_arrow_back)
setNavigationOnClickListener { onBackPressed() }
}
setSupportActionBar(toolbar)
setupIntermediateProgressBar()
adapter = LogcatAdapter()
recyclerView = findViewById<View>(R.id.recycler_view) as RecyclerView
recyclerView!!.layoutManager = LinearLayoutManager(this)
recyclerView!!.adapter = adapter
}
protected fun setupIntermediateProgressBar() {
val progressBar = ProgressBar(this)
progressBar.visibility = View.GONE
progressBar.isIndeterminate = true
val supportActionBar = supportActionBar
if (supportActionBar != null) {
supportActionBar.setDisplayShowCustomEnabled(true)
supportActionBar.customView = progressBar
setSupportProgressBarIndeterminateVisibility(false)
}
}
override fun setSupportProgressBarIndeterminateVisibility(visible: Boolean) {
val supportActionBar = supportActionBar
if (supportActionBar != null) {
supportActionBar.customView.visibility = if (visible) View.VISIBLE else View.GONE
}
}
override fun onResume() {
super.onResume()
startLogcatAsyncTask()
}
override fun onPause() {
super.onPause()
stopLogcatAsyncTask()
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
val app: TelegramApplication = applicationContext as TelegramApplication
val share: MenuItem = menu.add(0, SHARE_ID, 0, R.string.shared_string_export)
share.icon = app.uiUtils.getThemedIcon(R.drawable.ic_action_share)
share.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS)
val level = menu.add(0, LEVEL_ID, 0, "")
level.title = getFilterLevel()
level.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS)
return super.onCreateOptionsMenu(menu)
}
private fun getFilterLevel(): String {
return "*:" + LEVELS[filterLevel]
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
val itemId = item.itemId
when (itemId) {
android.R.id.home -> {
finish()
return true
}
LEVEL_ID -> {
filterLevel++
if (filterLevel >= LEVELS.size) {
filterLevel = 0
}
item.title = getFilterLevel()
stopLogcatAsyncTask()
logs.clear()
adapter!!.notifyDataSetChanged()
startLogcatAsyncTask()
return true
}
SHARE_ID -> {
startSaveLogsAsyncTask()
return true
}
}
return false
}
private fun startSaveLogsAsyncTask() {
val saveLogsAsyncTask = SaveLogsAsyncTask(this, logs)
saveLogsAsyncTask.execute()
}
private fun startLogcatAsyncTask() {
logcatAsyncTask = LogcatAsyncTask(this, getFilterLevel())
logcatAsyncTask!!.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR)
}
private fun stopLogcatAsyncTask() {
if (logcatAsyncTask != null && logcatAsyncTask!!.status == AsyncTask.Status.RUNNING) {
logcatAsyncTask!!.cancel(false)
logcatAsyncTask!!.stopLogging()
}
}
private inner class LogcatAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val inflater = LayoutInflater.from(viewGroup.context)
val itemView = inflater.inflate(R.layout.item_description_long, viewGroup, false) as TextView
itemView.gravity = Gravity.CENTER_VERTICAL
return LogViewHolder(itemView)
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if (holder is LogViewHolder) {
val log = getLog(position)
holder.logTextView.text = log
}
}
override fun getItemCount(): Int {
return logs.size
}
private fun getLog(position: Int): String {
return logs[position]
}
private inner class LogViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val logTextView: TextView = itemView.findViewById(R.id.description)
}
}
class SaveLogsAsyncTask internal constructor(logcatActivity: TrackerLogcatActivity, logs: Collection<String>) : AsyncTask<Void?, String?, File?>() {
private val logcatActivity: WeakReference<TrackerLogcatActivity>
private val logs: Collection<String>
override fun onPreExecute() {
val activity = logcatActivity.get()
activity?.setSupportProgressBarIndeterminateVisibility(true)
}
override fun doInBackground(vararg voids: Void?): File {
val app: TelegramApplication = logcatActivity.get()?.applicationContext as TelegramApplication
val file = File(app.getExternalFilesDir(null), LOGCAT_PATH)
try {
if (file.exists()) {
file.delete()
}
val stringBuilder = StringBuilder()
for (log in logs) {
stringBuilder.append(log)
stringBuilder.append("\n")
}
if (file.parentFile.canWrite()) {
val writer = BufferedWriter(FileWriter(file, true))
writer.write(stringBuilder.toString())
writer.close()
}
} catch (e: Exception) {
log.error(e)
}
return file
}
override fun onPostExecute(file: File?) {
val activity = logcatActivity.get()
if (activity != null && file != null) {
val app: TelegramApplication = activity.applicationContext as TelegramApplication
activity.setSupportProgressBarIndeterminateVisibility(false)
app.sendCrashLog(file)
}
}
init {
this.logcatActivity = WeakReference(logcatActivity)
this.logs = logs
}
}
class LogcatAsyncTask internal constructor(logcatActivity: TrackerLogcatActivity?, filterLevel: String) : AsyncTask<Void?, String?, Void?>() {
private var processLogcat: Process? = null
private val logcatActivity: WeakReference<TrackerLogcatActivity?>
private val filterLevel: String
override fun doInBackground(vararg voids: Void?): Void? {
try {
val filter = android.os.Process.myPid().toString()
val command = arrayOf("logcat", filterLevel, "--pid=$filter", "-T", MAX_BUFFER_LOG.toString())
processLogcat = Runtime.getRuntime().exec(command)
val bufferedReader = BufferedReader(InputStreamReader(processLogcat?.inputStream))
var line: String?
while (bufferedReader.readLine().also { line = it } != null && logcatActivity.get() != null) {
if (isCancelled) {
break
}
publishProgress(line)
}
stopLogging()
} catch (e: IOException) { // ignore
} catch (e: Exception) {
log.error(e)
}
return null
}
override fun onProgressUpdate(vararg values: String?) {
if (values.size > 0 && !isCancelled) {
val activity = logcatActivity.get()
if (activity != null) {
val autoscroll = !activity.recyclerView!!.canScrollVertically(1)
for (s in values) {
if (s != null) {
activity.logs.add(s)
}
}
activity.adapter!!.notifyDataSetChanged()
if (autoscroll) {
activity.recyclerView!!.scrollToPosition(activity.logs.size - 1)
}
}
}
}
fun stopLogging() {
if (processLogcat != null) {
processLogcat!!.destroy()
}
}
init {
this.logcatActivity = WeakReference(logcatActivity)
this.filterLevel = filterLevel
}
}
companion object {
private const val LOGCAT_PATH = "logcat.log"
private const val MAX_BUFFER_LOG = 10000
private const val SHARE_ID = 0
private const val LEVEL_ID = 1
private val log = PlatformUtil.getLog(TrackerLogcatActivity::class.java)
}
}

3
OsmAnd/.gitignore vendored
View file

@ -13,10 +13,13 @@ libs/it.unibo.alice.tuprolog-tuprolog-3.2.1.jar
libs/commons-codec-commons-codec-1.11.jar
libs/OsmAndCore_android-0.1-SNAPSHOT.jar
# Huawei
libs/huawei-*.jar
huaweidrmlib/
HwDRM_SDK_*
drm_strings.xml
agconnect-services.json
OsmAndHms.jks
# copy_widget_icons.sh
res/drawable-large/map_*

View file

@ -1,25 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application
android:icon="@mipmap/icon_free"
android:label="@string/app_name_free"
tools:replace="android:icon">
<meta-data
android:name="com.facebook.sdk.ApplicationId"
android:value="fb131313131043971"/>
<activity
android:name="net.osmand.plus.activities.MapActivity"
android:theme="@style/FirstSplashScreenCustom"
tools:replace="android:theme"/>
<service
android:name="net.osmand.plus.NavigationService"
android:process="net.osmand.freecustom"
tools:replace="android:process"/>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="net.osmand.freecustom.fileprovider"
tools:replace="android:authorities"/>
</application>
</manifest>

View file

@ -2,24 +2,31 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application>
<activity android:name="com.huawei.android.sdk.drm.DrmDialogActivity"
android:configChanges="screenSize|orientation|keyboardHidden"
android:exported="false"
android:theme="@android:style/Theme.Translucent">
<application
android:icon="@mipmap/icon_free"
android:label="@string/app_name_free"
tools:replace="android:icon, android:label">
<meta-data
android:name="hwc-theme"
android:value="androidhwext:style/Theme.Emui.Translucent" />
</activity>
android:name="com.huawei.hms.client.appid"
android:value="101486545" />
<meta-data
android:name="com.huawei.hms.client.cpid"
android:value="890031000000000038" />
<activity
android:name="net.osmand.plus.activities.MapActivity"
android:theme="@style/FirstSplashScreenFree"
tools:replace="android:theme"/>
<service
android:name="net.osmand.plus.NavigationService"
tools:replace="android:process"
android:process="net.osmand.huawei"/>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="net.osmand.huawei.fileprovider"
tools:replace="android:authorities" />
<service
android:name="net.osmand.plus.NavigationService"
android:process="net.osmand.huawei"
tools:replace="android:process" />
tools:replace="android:authorities"
android:authorities="net.osmand.huawei.fileprovider"/>
</application>
</manifest>

View file

@ -1,25 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application>
<activity android:name="com.huawei.android.sdk.drm.DrmDialogActivity"
android:configChanges="screenSize|orientation|keyboardHidden"
android:exported="false"
android:theme="@android:style/Theme.Translucent">
<meta-data
android:name="hwc-theme"
android:value="androidhwext:style/Theme.Emui.Translucent" />
</activity>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="net.osmand.plus.huawei.fileprovider"
tools:replace="android:authorities" />
<service
android:name="net.osmand.plus.NavigationService"
android:process="net.osmand.plus.huawei"
tools:replace="android:process" />
</application>
</manifest>

View file

@ -53,7 +53,8 @@
android:icon="@mipmap/icon" android:label="@string/app_name"
android:name="net.osmand.plus.OsmandApplication" android:configChanges="locale"
android:theme="@style/OsmandDarkTheme" android:restoreAnyVersion="true" android:largeHeap="true"
android:supportsRtl="true" android:usesCleartextTraffic="true">
android:supportsRtl="true" android:usesCleartextTraffic="true"
android:hasFragileUserData="true" android:requestLegacyExternalStorage="true">
<meta-data android:name="com.google.android.backup.api_key" android:value="AEdPqrEAAAAIqF3tNGT66etVBn_vgzpfAY1wmIzKV1Ss6Ku-2A" />
<meta-data android:name="com.sec.android.support.multiwindow" android:value="true" />
@ -65,6 +66,7 @@
<meta-data android:name="com.sec.minimode.icon.landscape.normal" android:resource="@mipmap/icon" android:value="" />
<activity android:name="net.osmand.plus.activities.HelpActivity" />
<activity android:name="net.osmand.plus.activities.ExitActivity" />
<activity android:name="net.osmand.plus.openplacereviews.OPRWebviewActivity" android:theme="@style/Theme.AppCompat.NoActionBar" />
<provider
android:name="androidx.core.content.FileProvider"
@ -246,6 +248,7 @@
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="content"/>
<data android:scheme="file"/>
<data android:host="*"/>
<data android:pathPattern=".*\\.obf" />
@ -261,6 +264,7 @@
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="content"/>
<data android:scheme="file"/>
<data android:host="*"/>
<data android:mimeType="*/*"/>
@ -371,6 +375,72 @@
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.xml" />
</intent-filter>
<intent-filter
android:label="@string/app_name"
android:priority="50">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="file"/>
<data android:scheme="content"/>
<data android:host="*"/>
<data android:pathPattern=".*\\.wpt.chart" />
<data android:pathPattern=".*\\..*\\.wpt.chart" />
<data android:pathPattern=".*\\..*\\..*\\.wpt.chart" />
<data android:pathPattern=".*\\..*\\..*\\..*\\.wpt.chart" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.wpt.chart" />
</intent-filter>
<intent-filter
android:label="@string/app_name"
android:priority="50">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="file"/>
<data android:scheme="content"/>
<data android:host="*"/>
<data android:mimeType="*/*"/>
<data android:pathPattern=".*\\.wpt.chart" />
<data android:pathPattern=".*\\..*\\.wpt.chart" />
<data android:pathPattern=".*\\..*\\..*\\.wpt.chart" />
<data android:pathPattern=".*\\..*\\..*\\..*\\.wpt.chart" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.wpt.chart" />
</intent-filter>
<intent-filter
android:label="@string/app_name"
android:priority="50">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="file"/>
<data android:scheme="content"/>
<data android:host="*"/>
<data android:pathPattern=".*\\.3d.chart" />
<data android:pathPattern=".*\\..*\\.3d.chart" />
<data android:pathPattern=".*\\..*\\..*\\.3d.chart" />
<data android:pathPattern=".*\\..*\\..*\\..*\\.3d.chart" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.3d.chart" />
</intent-filter>
<intent-filter
android:label="@string/app_name"
android:priority="50">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="file"/>
<data android:scheme="content"/>
<data android:host="*"/>
<data android:mimeType="*/*"/>
<data android:pathPattern=".*\\.3d.chart" />
<data android:pathPattern=".*\\..*\\.3d.chart" />
<data android:pathPattern=".*\\..*\\..*\\.3d.chart" />
<data android:pathPattern=".*\\..*\\..*\\..*\\.3d.chart" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.3d.chart" />
</intent-filter>
<!--trying to handle emails-->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
@ -399,6 +469,13 @@
<data android:mimeType="text/plain" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="osmand-oauth" />
</intent-filter>
</activity>
<receiver android:name="net.osmand.plus.audionotes.MediaRemoteControlReceiver">
@ -408,22 +485,10 @@
</intent-filter>
</receiver>
<activity android:name="net.osmand.plus.activities.SettingsActivity" android:label="@string/shared_string_settings" android:configChanges="keyboardHidden|orientation" />
<activity android:name="net.osmand.plus.activities.SettingsGeneralActivity" android:configChanges="keyboardHidden|orientation" />
<activity android:name="net.osmand.plus.activities.SettingsNavigationActivity" android:configChanges="keyboardHidden|orientation" />
<activity android:name="net.osmand.plus.monitoring.SettingsMonitoringActivity" android:configChanges="keyboardHidden|orientation" />
<activity android:name="net.osmand.plus.osmedit.SettingsOsmEditingActivity" android:configChanges="keyboardHidden|orientation" />
<activity android:name="net.osmand.plus.development.SettingsDevelopmentActivity" android:configChanges="keyboardHidden|orientation" />
<activity android:name="net.osmand.plus.audionotes.SettingsAudioVideoActivity" android:configChanges="keyboardHidden|orientation" />
<activity android:name="net.osmand.access.SettingsAccessibilityActivity" android:configChanges="keyboardHidden|orientation" />
<activity android:name="net.osmand.plus.activities.search.SearchActivity" android:label="@string/search_activity" />
<activity android:name="net.osmand.plus.activities.FavoritesListActivity" android:label="@string/favourites_list_activity" />
<activity android:name=".myplaces.FavoritesActivity" android:windowSoftInputMode="adjustPan" />
<activity android:name="net.osmand.plus.activities.TrackActivity"/>
<activity android:name="net.osmand.plus.activities.PluginsActivity" />
<activity android:name="net.osmand.plus.activities.PluginActivity" />
<activity android:name="net.osmand.plus.activities.ContributionVersionActivity" android:configChanges="keyboardHidden|orientation" android:label="@string/contribution_activity" />
@ -484,7 +549,13 @@
<data android:host="map.wap.qq.com" />
<data android:host="map.qq.com" />
<data android:host="maps.apple.com" />
<data android:host="ge0.me" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
</intent-filter>
<intent-filter>
<data android:host="ge0.me" android:scheme="https"/>
<data android:host="ge0.me" android:scheme="http"/>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>

View file

@ -12,6 +12,7 @@
<asset source="voice/cs/cs_tts.js" destination="voice/cs-tts/cs_tts.js" mode="overwriteOnlyIfExists" />
<asset source="voice/da/da_tts.js" destination="voice/da-tts/da_tts.js" mode="overwriteOnlyIfExists" />
<asset source="voice/de/de_tts.js" destination="voice/de-tts/de_tts.js" mode="alwaysOverwriteOrCopy" />
<asset source="voice/de-casual/de-casual_tts.js" destination="voice/de-casual-tts/de-casual_tts.js" mode="overwriteOnlyIfExists" />
<asset source="voice/el/el_tts.js" destination="voice/el-tts/el_tts.js" mode="overwriteOnlyIfExists" />
<asset source="voice/en/en_tts.js" destination="voice/en-tts/en_tts.js" mode="alwaysOverwriteOrCopy" />
<asset source="voice/en-gb/en-gb_tts.js" destination="voice/en-gb-tts/en-gb_tts.js" mode="overwriteOnlyIfExists" />

Some files were not shown because too many files have changed in this diff Show more