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" name: "📚 Outdated FAQ"
about: Report an issue in FAQ about: Report an issue in FAQ
--- ---
🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑 🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑
Please do not file FAQ issues on the GitHub issues tracker. Please do not file FAQ issues on the GitHub issues tracker.

View file

@ -2,68 +2,17 @@
name: "\U0001F41E Bug report" name: "\U0001F41E Bug report"
about: Report a bug in OsmAnd 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 ### Description
<!-- ✍️--> A clear and concise description of the problem...
### How to reproduce?
## 🔬 Minimal Reproduction ### Your Environment
<!-- OsmAnd Version:
If the bug is reproducible, please describe steps below: Android/iOS version:
--> Device model:
<!-- ✍️--> 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:**
**Maps used (online or offline):** **Maps used (online or offline):**
<!-- Please tick the correct box [x] (or both) --> 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.
- [ ] 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

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

View file

@ -1,8 +1,8 @@
--- ---
name: "\U0001F680 Feature request" name: "\U0001F680 Feature request"
about: Suggest a feature for OsmAnd about: Suggest a feature for OsmAnd
--- ---
<!--🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅 <!--🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅
Oh hi there! 😄 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. 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. 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. 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. 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 # 🚀 feature request
### Description ### 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 ### Describe the solution you'd like
<!-- ✍️--> If you have a solution in mind, please describe it. <!-- ✍️--> If you have a solution in mind, please describe it.
### Describe alternatives you've considered ### Describe alternatives you've considered
<!-- ✍️--> Have you considered any alternative solutions or workarounds? <!-- ✍️--> Have you considered any alternative solutions or workarounds?

4
.gitignore vendored
View file

@ -19,6 +19,10 @@ OsmAndCore_*.aar
.project .project
out/ out/
# Huawei
agconnect-services.json
OsmAndHms.jks
# Android Studio # Android Studio
/.idea /.idea
*.iml *.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.calculateroute.CalculateRouteParams;
import net.osmand.aidlapi.profile.ExportProfileParams;
import net.osmand.aidlapi.gpx.ImportGpxParams; import net.osmand.aidlapi.gpx.ImportGpxParams;
import net.osmand.aidlapi.gpx.ShowGpxParams; import net.osmand.aidlapi.gpx.ShowGpxParams;
import net.osmand.aidlapi.gpx.StartGpxRecordingParams; 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.info.AppInfoParams;
import net.osmand.aidlapi.profile.ExportProfileParams;
// NOTE: Add new methods at the end of file!!! // NOTE: Add new methods at the end of file!!!
interface IOsmAndAidlInterface { interface IOsmAndAidlInterface {
@ -867,4 +871,16 @@ interface IOsmAndAidlInterface {
AppInfoParams getAppInfo(); AppInfoParams getAppInfo();
boolean setMapMargins(in MapMarginsParams params); 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: // Navigation Drawer:
String DRAWER_ITEM_ID_SCHEME = "drawer.action."; 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_DASHBOARD_ID = DRAWER_ITEM_ID_SCHEME + "dashboard";
String DRAWER_MAP_MARKERS_ID = DRAWER_ITEM_ID_SCHEME + "map_markers"; String DRAWER_MAP_MARKERS_ID = DRAWER_ITEM_ID_SCHEME + "map_markers";
String DRAWER_MY_PLACES_ID = DRAWER_ITEM_ID_SCHEME + "my_places"; 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 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 String fileName;
private byte[] filePartData; private byte[] filePartData;
private long startTime; private long startTime;
private boolean done; 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.fileName = fileName;
this.filePartData = filePartData; this.filePartData = filePartData;
this.startTime = startTime; this.startTime = startTime;
@ -37,6 +46,10 @@ public class CopyFileParams extends AidlParams {
} }
}; };
public String getDestinationDir() {
return destinationDir;
}
public String getFileName() { public String getFileName() {
return fileName; return fileName;
} }
@ -55,23 +68,26 @@ public class CopyFileParams extends AidlParams {
@Override @Override
public void writeToBundle(Bundle bundle) { public void writeToBundle(Bundle bundle) {
bundle.putString("fileName", fileName); bundle.putString(DESTINATION_DIR_KEY, destinationDir);
bundle.putByteArray("filePartData", filePartData); bundle.putString(FILE_NAME_KEY, fileName);
bundle.putLong("startTime", startTime); bundle.putByteArray(FILE_PART_DATA_KEY, filePartData);
bundle.putBoolean("done", done); bundle.putLong(START_TIME_KEY, startTime);
bundle.putBoolean(DONE_KEY, done);
} }
@Override @Override
protected void readFromBundle(Bundle bundle) { protected void readFromBundle(Bundle bundle) {
fileName = bundle.getString("fileName"); destinationDir = bundle.getString(DESTINATION_DIR_KEY);
filePartData = bundle.getByteArray("filePartData"); fileName = bundle.getString(FILE_NAME_KEY);
startTime = bundle.getLong("startTime"); filePartData = bundle.getByteArray(FILE_PART_DATA_KEY);
done = bundle.getBoolean("done"); startTime = bundle.getLong(START_TIME_KEY);
done = bundle.getBoolean(DONE_KEY);
} }
@Override @Override
public String toString() { public String toString() {
return "CopyFileParams {" + return "CopyFileParams {" +
" destinationDir=" + destinationDir +
" fileName=" + fileName + " fileName=" + fileName +
", filePartData size=" + filePartData.length + ", filePartData size=" + filePartData.length +
", startTime=" + startTime + ", startTime=" + startTime +

View file

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

View file

@ -5,15 +5,31 @@ import android.os.Bundle;
import android.os.Parcel; import android.os.Parcel;
import net.osmand.aidlapi.AidlParams; 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 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 Uri profileSettingsUri;
private String latestChanges; private String latestChanges;
private int version; 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; this.profileSettingsUri = profileSettingsUri;
for (AExportSettingsType settingsType : settingsTypeList) {
settingsTypeKeyList.add(settingsType.name());
}
this.replace = replace;
this.latestChanges = latestChanges; this.latestChanges = latestChanges;
this.version = version; this.version = version;
} }
@ -46,17 +62,29 @@ public class ProfileSettingsParams extends AidlParams {
return profileSettingsUri; return profileSettingsUri;
} }
public ArrayList<String> getSettingsTypeKeys() {
return settingsTypeKeyList;
}
public boolean isReplace() {
return replace;
}
@Override @Override
public void writeToBundle(Bundle bundle) { public void writeToBundle(Bundle bundle) {
bundle.putInt("version", version); bundle.putInt(VERSION_KEY, version);
bundle.putString("latestChanges", latestChanges); bundle.putString(LATEST_CHANGES_KEY, latestChanges);
bundle.putParcelable("profileSettingsUri", profileSettingsUri); bundle.putParcelable(PROFILE_SETTINGS_URI_KEY, profileSettingsUri);
bundle.putStringArrayList(SETTINGS_TYPE_KEY, settingsTypeKeyList);
bundle.putBoolean(REPLACE_KEY, replace);
} }
@Override @Override
protected void readFromBundle(Bundle bundle) { protected void readFromBundle(Bundle bundle) {
version = bundle.getInt("version"); version = bundle.getInt(VERSION_KEY);
latestChanges = bundle.getString("latestChanges"); latestChanges = bundle.getString(LATEST_CHANGES_KEY);
profileSettingsUri = bundle.getParcelable("profileSettingsUri"); 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.moparisthebest:junidecode:0.1.1'
implementation 'com.vividsolutions:jts-core:1.14.0' implementation 'com.vividsolutions:jts-core:1.14.0'
implementation 'com.google.openlocationcode:openlocationcode:1.0.4' 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 // turn off for now
//implementation 'com.atilika.kuromoji:kuromoji-ipadic:0.9.0' //implementation 'com.atilika.kuromoji:kuromoji-ipadic:0.9.0'
implementation 'net.sf.kxml:kxml2:2.1.8' implementation 'net.sf.kxml:kxml2:2.1.8'

View file

@ -14,6 +14,10 @@
package com.jwetherell.openmap.common; package com.jwetherell.openmap.common;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class MGRSPoint extends ZonedUTMPoint { public class MGRSPoint extends ZonedUTMPoint {
/** /**
@ -104,6 +108,15 @@ public class MGRSPoint extends ZonedUTMPoint {
* an UPPERCASE coordinate string is expected. * an UPPERCASE coordinate string is expected.
*/ */
protected void decode(String mgrsString) throws NumberFormatException { 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) { if (mgrsString == null || mgrsString.length() == 0) {
throw new NumberFormatException("MGRSPoint coverting from nothing"); throw new NumberFormatException("MGRSPoint coverting from nothing");
} }
@ -633,6 +646,97 @@ public class MGRSPoint extends ZonedUTMPoint {
return twoLetter; 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} * {@inheritDoc}
*/ */

View file

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

View file

@ -45,7 +45,7 @@ public interface IProgress {
public boolean isInterrupted() {return false;} public boolean isInterrupted() {return false;}
@Override @Override
public boolean isIndeterminate() {return false;} public boolean isIndeterminate() {return true;}
@Override @Override
public void finishTask() {} 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 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 = ".obf"; //$NON-NLS-1$
public static final String BINARY_MAP_INDEX_EXT_ZIP = ".obf.zip"; //$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 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 final static String POI_TABLE = "poi"; //$NON-NLS-1$
public static final String INDEX_DOWNLOAD_DOMAIN = "download.osmand.net"; public static final String INDEX_DOWNLOAD_DOMAIN = "download.osmand.net";
@ -68,9 +72,11 @@ public class IndexConstants {
public static final String FONT_INDEX_DIR = "fonts/"; //$NON-NLS-1$ public static final String FONT_INDEX_DIR = "fonts/"; //$NON-NLS-1$
public static final String VOICE_INDEX_DIR = "voice/"; //$NON-NLS-1$ public static final String VOICE_INDEX_DIR = "voice/"; //$NON-NLS-1$
public static final String RENDERERS_DIR = "rendering/"; //$NON-NLS-1$ public static final String RENDERERS_DIR = "rendering/"; //$NON-NLS-1$
public static final String ROUTING_XML_FILE= "routing.xml"; public static final String ROUTING_XML_FILE = "routing.xml";
public static final String SETTINGS_DIR = "settings/"; //$NON-NLS-1$ public static final String SETTINGS_DIR = "settings/"; //$NON-NLS-1$
public static final String TEMP_DIR = "temp/"; public static final String TEMP_DIR = "temp/";
public static final String ROUTING_PROFILES_DIR = "routing/"; public static final String ROUTING_PROFILES_DIR = "routing/";
public static final String PLUGINS_DIR = "plugins/"; 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 FORMAT_SECONDS = 2;
public static final int UTM_FORMAT = 3; public static final int UTM_FORMAT = 3;
public static final int OLC_FORMAT = 4; public static final int OLC_FORMAT = 4;
public static final int MGRS_FORMAT = 5;
private static final char DELIM = ':'; private static final char DELIM = ':';
private static final char DELIMITER_DEGREES = '°'; private static final char DELIMITER_DEGREES = '°';
private static final char DELIMITER_MINUTES = ''; private static final char DELIMITER_MINUTES = '';

View file

@ -106,9 +106,11 @@ public class TspAnt {
// Allocates all memory. // Allocates all memory.
// Adds 1 to edge lengths to ensure no zero length edges. // Adds 1 to edge lengths to ensure no zero length edges.
public TspAnt readGraph(List<LatLon> intermediates, LatLon start, LatLon end) { public TspAnt readGraph(List<LatLon> intermediates, LatLon start, LatLon end) {
boolean keepEndPoint = end != null; boolean keepEndPoint = end != null;
List<LatLon> l = new ArrayList<LatLon>(); List<LatLon> l = new ArrayList<LatLon>();
l.add(start); if (start != null) {
l.add(start);
}
l.addAll(intermediates); l.addAll(intermediates);
if (keepEndPoint) { if (keepEndPoint) {
l.add(end); l.add(end);

View file

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

View file

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

View file

@ -1,17 +1,7 @@
package net.osmand.data; 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.ArrayList;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
@ -21,9 +11,14 @@ import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Set; import java.util.Set;
import java.util.TreeSet; import java.util.TreeSet;
import java.util.zip.GZIPInputStream;
import org.json.JSONObject;
import gnu.trove.list.array.TIntArrayList; 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 { 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) { if (additionalInfo == null) {
return Collections.emptyMap(); return Collections.emptyMap();
} }
return additionalInfo; 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) { public void setAdditionalInfo(Map<String, String> additionalInfo) {
this.additionalInfo = null; this.additionalInfo = null;
openingHours = null; openingHours = null;
@ -134,7 +163,7 @@ public class Amenity extends MapObject {
} }
this.additionalInfo.put(tag, value); this.additionalInfo.put(tag, value);
if (OPENING_HOURS.equals(tag)) { if (OPENING_HOURS.equals(tag)) {
this.openingHours = value; this.openingHours = unzipContent(value);
} }
} }
} }
@ -182,7 +211,7 @@ public class Amenity extends MapObject {
} }
int maxLen = 0; int maxLen = 0;
String lng = defLang; String lng = defLang;
for (String nm : getAdditionalInfo().keySet()) { for (String nm : getAdditionalInfoKeys()) {
if (nm.startsWith(tag + ":")) { if (nm.startsWith(tag + ":")) {
String key = nm.substring(tag.length() + 1); String key = nm.substring(tag.length() + 1);
String cnt = getAdditionalInfo(tag + ":" + key); String cnt = getAdditionalInfo(tag + ":" + key);
@ -204,7 +233,7 @@ public class Amenity extends MapObject {
public List<String> getNames(String tag, String defTag) { public List<String> getNames(String tag, String defTag) {
List<String> l = new ArrayList<String>(); List<String> l = new ArrayList<String>();
for (String nm : getAdditionalInfo().keySet()) { for (String nm : getAdditionalInfoKeys()) {
if (nm.startsWith(tag + ":")) { if (nm.startsWith(tag + ":")) {
l.add(nm.substring(tag.length() + 1)); l.add(nm.substring(tag.length() + 1));
} else if (nm.equals(tag)) { } else if (nm.equals(tag)) {
@ -229,7 +258,7 @@ public class Amenity extends MapObject {
if (!Algorithms.isEmpty(enName)) { if (!Algorithms.isEmpty(enName)) {
return enName; return enName;
} }
for (String nm : getAdditionalInfo().keySet()) { for (String nm : getAdditionalInfoKeys()) {
if (nm.startsWith(tag + ":")) { if (nm.startsWith(tag + ":")) {
return getAdditionalInfo(nm); return getAdditionalInfo(nm);
} }
@ -345,4 +374,6 @@ public class Amenity extends MapObject {
} }
return a; return a;
} }
} }

View file

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

View file

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

View file

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

View file

@ -27,7 +27,7 @@ public abstract class MapRenderingTypes {
private static final Log log = PlatformUtil.getLog(MapRenderingTypes.class); 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", 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; 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_DELETED = -1;
public static final int MODIFY_MODIFIED = 1; public static final int MODIFY_MODIFIED = 1;
public static final int MODIFY_CREATED = 2; 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) { public Entity(long id) {
this.id = id; this.id = id;
@ -241,6 +243,11 @@ public abstract class Entity implements Serializable {
return Collections.unmodifiableMap(tags); 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() { public Collection<String> getTagKeySet() {
if (tags == null) { if (tags == null) {

View file

@ -1,30 +1,22 @@
package net.osmand.osm.io; package net.osmand.osm.io;
import java.io.BufferedInputStream; import com.github.scribejava.core.model.OAuthRequest;
import java.io.BufferedReader; import com.github.scribejava.core.model.Response;
import java.io.File; import com.github.scribejava.core.model.Verb;
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 net.osmand.PlatformUtil; import net.osmand.PlatformUtil;
import net.osmand.osm.oauth.OsmOAuthAuthorizationClient;
import net.osmand.util.Algorithms; import net.osmand.util.Algorithms;
import org.apache.commons.logging.Log; 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 { public class NetworkUtils {
private static final Log log = PlatformUtil.getLog(NetworkUtils.class); private static final Log log = PlatformUtil.getLog(NetworkUtils.class);
private static final String GPX_UPLOAD_USER_AGENT = "OsmGPXUploadAgent";
private static Proxy proxy = null; private static Proxy proxy = null;
public static String sendGetRequest(String urlText, String userNamePassword, StringBuilder responseBody){ 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("\n"); //$NON-NLS-1$
} }
responseBody.append(s); responseBody.append(s);
} }
is.close(); is.close();
} }
@ -65,9 +56,10 @@ public class NetworkUtils {
return e.getMessage(); return e.getMessage();
} }
} }
private static final String BOUNDARY = "CowMooCowMooCowCowCow"; //$NON-NLS-1$ 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; URL url;
try { try {
boolean firstPrm =!urlText.contains("?"); boolean firstPrm =!urlText.contains("?");
@ -77,34 +69,48 @@ public class NetworkUtils {
} }
log.info("Start uploading file to " + urlText + " " +fileToUpload.getName()); log.info("Start uploading file to " + urlText + " " +fileToUpload.getName());
url = new URL(urlText); url = new URL(urlText);
HttpURLConnection conn = (HttpURLConnection) url.openConnection(); HttpURLConnection conn;
conn.setDoInput(true); if (client != null && client.isValidToken()){
conn.setDoOutput(true); OAuthRequest req = new OAuthRequest(Verb.POST, urlText);
conn.setRequestMethod("POST"); client.getService().signRequest(client.getAccessToken(), req);
if(userNamePassword != null) { req.addHeader("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);
conn.setRequestProperty("Authorization", "Basic " + Base64.encode(userNamePassword)); //$NON-NLS-1$ //$NON-NLS-2$ 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("Content-Type", "multipart/form-data; boundary=" + BOUNDARY); //$NON-NLS-1$ //$NON-NLS-2$
conn.setRequestProperty("User-Agent", "OsmAnd"); //$NON-NLS-1$ //$NON-NLS-2$ conn.setRequestProperty("User-Agent", "OsmAnd"); //$NON-NLS-1$ //$NON-NLS-2$
OutputStream ous = conn.getOutputStream(); OutputStream ous = conn.getOutputStream();
// for (String key : additionalMapData.keySet()) { ous.write(("--" + BOUNDARY + "\r\n").getBytes());
// 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(); String filename = fileToUpload.getName();
if(gzip){ if (gzip) {
filename+=".gz"; filename += ".gz";
} }
ous.write(("content-disposition: form-data; name=\""+formName+"\"; filename=\"" + filename + "\"\r\n").getBytes()); //$NON-NLS-1$ //$NON-NLS-2$ 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$ ous.write(("Content-Type: application/octet-stream\r\n\r\n").getBytes()); //$NON-NLS-1$
InputStream fis = new FileInputStream(fileToUpload); InputStream fis = new FileInputStream(fileToUpload);
BufferedInputStream bis = new BufferedInputStream(fis, 20 * 1024); BufferedInputStream bis = new BufferedInputStream(fis, 20 * 1024);
ous.flush(); ous.flush();
if(gzip){ if (gzip) {
GZIPOutputStream gous = new GZIPOutputStream(ous, 1024); GZIPOutputStream gous = new GZIPOutputStream(ous, 1024);
Algorithms.streamCopy(bis, gous); Algorithms.streamCopy(bis, gous);
gous.flush(); gous.flush();
@ -112,8 +118,7 @@ public class NetworkUtils {
} else { } else {
Algorithms.streamCopy(bis, ous); Algorithms.streamCopy(bis, ous);
} }
ous.write(("\r\n--" + BOUNDARY + "--\r\n").getBytes()); //$NON-NLS-1$ //$NON-NLS-2$
ous.write(("\r\n--" + BOUNDARY + "--\r\n").getBytes()); //$NON-NLS-1$ //$NON-NLS-2$
ous.flush(); ous.flush();
Algorithms.closeStream(bis); Algorithms.closeStream(bis);
Algorithms.closeStream(ous); Algorithms.closeStream(ous);
@ -136,7 +141,6 @@ public class NetworkUtils {
responseBody.append("\n"); //$NON-NLS-1$ responseBody.append("\n"); //$NON-NLS-1$
} }
responseBody.append(s); responseBody.append(s);
} }
is.close(); is.close();
} }
@ -157,7 +161,6 @@ public class NetworkUtils {
proxy = null; proxy = null;
} }
} }
public static Proxy getProxy() { public static Proxy getProxy() {
return proxy; 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) { public void init(Map<String, String> attributes) {
ArrayList<RenderingRuleProperty> props = new ArrayList<RenderingRuleProperty>(attributes.size()); ArrayList<RenderingRuleProperty> props = new ArrayList<RenderingRuleProperty>(attributes.size());
intProperties = new int[attributes.size()]; intProperties = new int[attributes.size()];
floatProperties = null; floatProperties = new float[attributes.size()];
attributesRef = null; attributesRef = null;
int i = 0; int i = 0;
Iterator<Entry<String, String>> it = attributes.entrySet().iterator(); Iterator<Entry<String, String>> it = attributes.entrySet().iterator();
@ -58,14 +58,13 @@ public class RenderingRule {
attributesRef[i] = storage.getRenderingAttributeRule(vl.substring(1)); attributesRef[i] = storage.getRenderingAttributeRule(vl.substring(1));
} else if (property.isString()) { } else if (property.isString()) {
intProperties[i] = storage.getDictionaryValue(vl); 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 { } 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); intProperties[i] = property.parseIntValue(vl);
} }
i++; i++;
@ -95,7 +94,7 @@ public class RenderingRule {
public float getFloatPropertyValue(String property) { public float getFloatPropertyValue(String property) {
int i = getPropertyIndex(property); int i = getPropertyIndex(property);
if(i >= 0 && floatProperties != null){ if (i >= 0) {
return floatProperties[i]; return floatProperties[i];
} }
return 0; return 0;

View file

@ -155,12 +155,7 @@ public class RenderingRuleProperty {
try { try {
int colon = value.indexOf(':'); int colon = value.indexOf(':');
if(colon != -1) { if(colon != -1) {
int c = 0; return (int) Float.parseFloat(value.substring(colon + 1));
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); return (int) Float.parseFloat(value);
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
@ -190,30 +185,35 @@ public class RenderingRuleProperty {
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
log.error("Rendering parse " + value + " in " + attrName); log.error("Rendering parse " + value + " in " + attrName);
} }
return -1; return 0;
} else { } else {
return -1; return -1;
} }
} }
public float parseFloatValue(String value){ public float parseFloatValue(String value) {
if(type == FLOAT_TYPE){ try {
try { if (type == FLOAT_TYPE) {
int colon = value.indexOf(':'); int colon = value.indexOf(':');
if(colon != -1) { if (colon != -1) {
if(colon > 0) { if (colon > 0) {
return Float.parseFloat(value.substring(0, colon)); return Float.parseFloat(value.substring(0, colon));
} }
return 0; return 0;
} }
return Float.parseFloat(value); return Float.parseFloat(value);
} catch (NumberFormatException e) {
log.error("Rendering parse " + value + " in " + attrName); } else if (type == INT_TYPE) {
int colon = value.indexOf(':');
if (colon != -1 && colon > 0) {
return Float.parseFloat(value.substring(0, colon));
}
return 0;
} }
return -1; } catch (NumberFormatException e) {
} else { log.error("Rendering parse " + value + " in " + attrName);
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_HALO_COLOR = registerRuleInternal(RenderingRuleProperty.createOutputColorProperty(TEXT_HALO_COLOR));
R_TEXT_SIZE = registerRuleInternal(RenderingRuleProperty.createOutputFloatProperty(TEXT_SIZE)); R_TEXT_SIZE = registerRuleInternal(RenderingRuleProperty.createOutputFloatProperty(TEXT_SIZE));
R_TEXT_ORDER = registerRuleInternal(RenderingRuleProperty.createOutputIntProperty(TEXT_ORDER)); 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_MIN_DISTANCE = registerRuleInternal(RenderingRuleProperty.createOutputFloatProperty(TEXT_MIN_DISTANCE));
R_TEXT_SHIELD = registerRuleInternal(RenderingRuleProperty.createOutputStringProperty(TEXT_SHIELD)); 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_3 = registerRuleInternal(RenderingRuleProperty.createOutputStringProperty("icon_3"));
R_ICON_4 = registerRuleInternal(RenderingRuleProperty.createOutputStringProperty("icon_4")); R_ICON_4 = registerRuleInternal(RenderingRuleProperty.createOutputStringProperty("icon_4"));
R_ICON_5 = registerRuleInternal(RenderingRuleProperty.createOutputStringProperty("icon_5")); R_ICON_5 = registerRuleInternal(RenderingRuleProperty.createOutputStringProperty("icon_5"));
R_ICON_ORDER = registerRuleInternal(RenderingRuleProperty.createOutputIntProperty(ICON_ORDER));
R_SHIELD = registerRuleInternal(RenderingRuleProperty.createOutputStringProperty(SHIELD)); R_SHIELD = registerRuleInternal(RenderingRuleProperty.createOutputStringProperty(SHIELD));
R_ICON_VISIBLE_SIZE = registerRuleInternal(RenderingRuleProperty.createOutputFloatProperty(ICON_VISIBLE_SIZE));
// polygon/way // polygon/way
R_COLOR = registerRuleInternal(RenderingRuleProperty.createOutputColorProperty(COLOR)); R_COLOR = registerRuleInternal(RenderingRuleProperty.createOutputColorProperty(COLOR));

View file

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

View file

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

View file

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

View file

@ -255,7 +255,8 @@ public class RouteSegmentResult implements StringExternalizable<RouteDataBundle>
@Override @Override
public void writeToBundle(RouteDataBundle bundle) { public void writeToBundle(RouteDataBundle bundle) {
Map<RouteTypeRule, Integer> rules = bundle.getResources().getRules(); 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("segmentTime", segmentTime, 2);
bundle.putFloat("speed", speed, 2); bundle.putFloat("speed", speed, 2);
if (turnType != null) { if (turnType != null) {
@ -271,24 +272,29 @@ public class RouteSegmentResult implements StringExternalizable<RouteDataBundle>
bundle.putString("turnLanes", TurnType.lanesToString(turnLanes)); 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)); bundle.putArray("types", convertTypes(object.types, rules));
int start = Math.min(startPointIndex, endPointIndex); int start = Math.min(startPointIndex, endPointIndex);
int end = Math.max(startPointIndex, endPointIndex) + 1; int end = Math.max(startPointIndex, endPointIndex) + 1;
if (object.pointTypes != null && start < object.pointTypes.length) { if (object.pointTypes != null && start < object.pointTypes.length) {
int[][] types = Arrays.copyOfRange(object.pointTypes, start, Math.min(end, 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)); bundle.putArray("pointTypes", convertTypes(types, rules));
} }
if (object.nameIds != null) { if (object.nameIds != null) {
bundle.putArray("names", convertNameIds(object.nameIds, rules)); 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)); 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));
String[][] names = Arrays.copyOfRange(object.pointNames, start, Math.min(end, object.pointNames.length)); if (reversed) {
bundle.putArray("pointNames", convertPointNames(types, names, rules)); Algorithms.reverseArray(types);
Algorithms.reverseArray(names);
} }
bundle.putArray("pointNames", convertPointNames(types, names, rules));
} }
} }
@ -327,22 +333,21 @@ public class RouteSegmentResult implements StringExternalizable<RouteDataBundle>
Location prevLocation = null; Location prevLocation = null;
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
Location location = resources.getLocation(index); Location location = resources.getLocation(index);
if (location == null) { if (location != null) {
break; double dist = 0;
} if (prevLocation != null) {
double dist = 0; dist = MapUtils.getDistance(prevLocation.getLatitude(), prevLocation.getLongitude(), location.getLatitude(), location.getLongitude());
if (prevLocation != null) { distance += dist;
dist = MapUtils.getDistance(prevLocation.getLatitude(), prevLocation.getLongitude(), location.getLatitude(), location.getLongitude()); }
distance += dist; prevLocation = location;
} object.pointsX[i] = MapUtils.get31TileNumberX(location.getLongitude());
prevLocation = location; object.pointsY[i] = MapUtils.get31TileNumberY(location.getLatitude());
object.pointsX[i] = MapUtils.get31TileNumberX(location.getLongitude()); if (location.hasAltitude() && object.heightDistanceArray.length > 0) {
object.pointsY[i] = MapUtils.get31TileNumberY(location.getLatitude()); object.heightDistanceArray[i * 2] = (float) dist;
if (location.hasAltitude() && object.heightDistanceArray.length > 0) { object.heightDistanceArray[i * 2 + 1] = (float) location.getAltitude();
object.heightDistanceArray[i * 2] = (float) dist; } else {
object.heightDistanceArray[i * 2 + 1] = (float) location.getAltitude(); object.heightDistanceArray = new float[0];
} else { }
object.heightDistanceArray = new float[0];
} }
if (plus) { if (plus) {
index++; index++;

View file

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

View file

@ -741,7 +741,7 @@ public class SearchUICore {
} }
} }
if (Algorithms.isEmpty(object.alternateName) && object.object instanceof Amenity) { 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)) { if (phrase.getFirstUnknownNameStringMatcher().matches(value)) {
object.alternateName = value; object.alternateName = value;
break; break;

View file

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

View file

@ -229,12 +229,14 @@ public class SearchPhrase {
} }
public int countWords(String w) { public int countWords(String w) {
String[] ws = w.split(ALLDELIMITERS);
int cnt = 0; int cnt = 0;
for (int i = 0; i < ws.length; i++) { if (!Algorithms.isEmpty(w)) {
String wd = ws[i].trim(); String[] ws = w.split(ALLDELIMITERS);
if (wd.length() > 0) { for (int i = 0; i < ws.length; i++) {
cnt++; String wd = ws[i].trim();
if (wd.length() > 0) {
cnt++;
}
} }
} }
return 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_KEY = new char[''];
private static char[] CHARS_TO_NORMALIZE_VALUE = 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) { public static String normalizeSearchText(String s) {
boolean norm = false; boolean norm = false;
for (int i = 0; i < s.length() && !norm; i++) { for (int i = 0; i < s.length() && !norm; i++) {
@ -119,9 +124,11 @@ public class Algorithms {
} }
public static String getFileNameWithoutExtension(String name) { public static String getFileNameWithoutExtension(String name) {
int i = name.indexOf('.'); if (name != null) {
if (i >= 0) { int index = name.lastIndexOf('.');
name = name.substring(0, i); if (index != -1) {
return name.substring(0, index);
}
} }
return name; return name;
} }
@ -293,7 +300,7 @@ public class Algorithms {
FileInputStream in = new FileInputStream(file); FileInputStream in = new FileInputStream(file);
int test = readInt(in); int test = readInt(in);
in.close(); in.close();
return test == 0x504b0304; return test == ZIP_FILE_SIGNATURE;
} }
/** /**
@ -322,7 +329,7 @@ public class Algorithms {
return false; return false;
} }
private static int readInt(InputStream in) throws IOException { public static int readInt(InputStream in) throws IOException {
int ch1 = in.read(); int ch1 = in.read();
int ch2 = in.read(); int ch2 = in.read();
int ch3 = in.read(); int ch3 = in.read();
@ -879,6 +886,14 @@ public class Algorithms {
return map; 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) { public static boolean containsInArrayL(long[] array, long value) {
return Arrays.binarySearch(array, value) >= 0; return Arrays.binarySearch(array, value) >= 0;
} }
@ -942,4 +957,20 @@ public class Algorithms {
} }
return res; 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;
import com.google.openlocationcode.OpenLocationCode.CodeArea; import com.google.openlocationcode.OpenLocationCode.CodeArea;
import com.jwetherell.openmap.common.LatLonPoint; import com.jwetherell.openmap.common.LatLonPoint;
import com.jwetherell.openmap.common.MGRSPoint;
import com.jwetherell.openmap.common.UTMPoint; import com.jwetherell.openmap.common.UTMPoint;
import net.osmand.data.LatLon; import net.osmand.data.LatLon;
@ -111,7 +112,7 @@ public class LocationParser {
return null; return null;
} }
// detect UTM // 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); char ch = all.get(1).toString().charAt(0);
if (Character.isLetter(ch)) { if (Character.isLetter(ch)) {
UTMPoint upoint = new UTMPoint(d.get(2), d.get(1), d.get(0).intValue(), 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); char ch = all.get(1).toString().charAt(0);
String combined = strings.get(2); String combined = strings.get(2);
if (Character.isLetter(ch)) { 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 // try to find split lat/lon position
int jointNumbers = 0; int jointNumbers = 0;
int lastJoin = 0; int lastJoin = 0;

View file

@ -15,6 +15,7 @@ import java.util.TreeSet;
import net.osmand.binary.BinaryMapIndexReader; import net.osmand.binary.BinaryMapIndexReader;
import net.osmand.data.LatLon;
import org.junit.Assert; import org.junit.Assert;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
@ -29,42 +30,52 @@ public class RouteTestingTest {
private TestEntry te; private TestEntry te;
public RouteTestingTest(String name, TestEntry te) { public RouteTestingTest(String name, TestEntry te) {
this.te = te; this.te = te;
} }
@BeforeClass @BeforeClass
public static void setUp() throws Exception { public static void setUp() throws Exception {
RouteResultPreparation.PRINT_TO_CONSOLE_ROUTE_INFORMATION_TO_TEST = true; RouteResultPreparation.PRINT_TO_CONSOLE_ROUTE_INFORMATION_TO_TEST = true;
} }
@Parameterized.Parameters(name = "{index}: {0}") @Parameterized.Parameters(name = "{index}: {0}")
public static Iterable<Object[]> data() throws IOException { public static Iterable<Object[]> data() throws IOException {
String fileName = "/test_routing.json"; String fileName = "/test_routing.json";
Reader reader = new InputStreamReader(RouteTestingTest.class.getResourceAsStream(fileName)); Reader reader = new InputStreamReader(RouteTestingTest.class.getResourceAsStream(fileName));
Gson gson = new GsonBuilder().setPrettyPrinting().create(); Gson gson = new GsonBuilder().setPrettyPrinting().create();
TestEntry[] testEntries = gson.fromJson(reader, TestEntry[].class); TestEntry[] testEntries = gson.fromJson(reader, TestEntry[].class);
ArrayList<Object[]> arrayList = new ArrayList<>(); ArrayList<Object[]> arrayList = new ArrayList<>();
for(TestEntry te : testEntries) { for (TestEntry te : testEntries) {
if(te.isIgnore()) { if (te.isIgnore()) {
continue; continue;
} }
arrayList.add(new Object[] {te.getTestName(), te}); arrayList.add(new Object[]{te.getTestName(), te});
} }
reader.close(); reader.close();
return arrayList; return arrayList;
} }
@Test @Test
public void testRouting() throws Exception { public void testRouting() throws Exception {
String fl = "src/test/resources/Routing_test.obf"; String fl = "src/test/resources/Routing_test.obf";
RandomAccessFile raf = new RandomAccessFile(fl, "r"); RandomAccessFile raf = new RandomAccessFile(fl, "r");
RoutePlannerFrontEnd fe = new RoutePlannerFrontEnd(); 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(); RoutingConfiguration.Builder builder = RoutingConfiguration.getDefault();
Map<String, String> params = te.getParams(); 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 config = builder.build(params.containsKey("vehicle") ? params.get("vehicle") : "car",
RoutingConfiguration.DEFAULT_MEMORY_LIMIT * 3, params); RoutingConfiguration.DEFAULT_MEMORY_LIMIT * 3, params);
RoutingContext ctx = fe.buildRoutingContext(config, null, binaryMapIndexReaders, RoutingContext ctx = fe.buildRoutingContext(config, null, binaryMapIndexReaders,
@ -102,6 +113,4 @@ public class RouteTestingTest {
} }
} }

View file

@ -20,7 +20,7 @@
android:screenOrientation="unspecified" android:screenOrientation="unspecified"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/AppTheme"> android:theme="@style/AppTheme">
<activity android:name=".ui.TrackerLogcatActivity" />
<activity <activity
android:name=".ui.MainActivity" android:name=".ui.MainActivity"
android:configChanges="orientation|screenSize" 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> </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"/> <include layout="@layout/card_bottom_divider"/>
</LinearLayout> </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="location_sharing_status">مشاركة: %1$s</string>
<string name="shared_string_enabled">مفعل</string> <string name="shared_string_enabled">مفعل</string>
<string name="duration_ago">%1$s منذ</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> </resources>

View file

@ -38,7 +38,7 @@
<string name="shared_string_password">كلمة المرور</string> <string name="shared_string_password">كلمة المرور</string>
<string name="shared_string_continue">استمرار</string> <string name="shared_string_continue">استمرار</string>
<string name="shared_string_cancel">إلغاء</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="shared_string_distance">المسافة</string>
<string name="yard">ياردة</string> <string name="yard">ياردة</string>
<string name="foot">قدم</string> <string name="foot">قدم</string>
@ -267,4 +267,8 @@
<string name="status_widget_title">تتبع حالة أوسماند</string> <string name="status_widget_title">تتبع حالة أوسماند</string>
<string name="back_to_osmand">العودة إلى OsmAnd</string> <string name="back_to_osmand">العودة إلى OsmAnd</string>
<string name="duration_ago">%1$s منذ</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> </resources>

View file

@ -267,4 +267,8 @@
<string name="last_response_duration">Апошні адказ: %1$s таму</string> <string name="last_response_duration">Апошні адказ: %1$s таму</string>
<string name="duration_ago">%1$s таму</string> <string name="duration_ago">%1$s таму</string>
<string name="shared_string_error_short">ERR</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> </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="send_my_location">Envia la meva ubicació</string>
<string name="gps_and_location">Ubicació</string> <string name="gps_and_location">Ubicació</string>
<string name="sharing_time">Temps de compartició</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="open_osmand">Obre l\'OsmAnd</string>
<string name="shared_string_live">En directe</string> <string name="shared_string_live">En directe</string>
<string name="shared_string_bot">Bot</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="last_response_duration">Darrera resposta: fa %1$s</string>
<string name="duration_ago">fa %1$s</string> <string name="duration_ago">fa %1$s</string>
<string name="shared_string_error_short">ERR</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> </resources>

View file

@ -72,4 +72,6 @@
<string name="shared_string_enabled">Povolen</string> <string name="shared_string_enabled">Povolen</string>
<string name="unit_of_length">Jednotky vzdálenosti</string> <string name="unit_of_length">Jednotky vzdálenosti</string>
<string name="shared_string_appearance">Vzhled</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> </resources>

View file

@ -269,4 +269,8 @@
<string name="last_response_duration">Sidste svar: %1$s siden</string> <string name="last_response_duration">Sidste svar: %1$s siden</string>
<string name="duration_ago">%1$s siden</string> <string name="duration_ago">%1$s siden</string>
<string name="shared_string_error_short">ERR</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> </resources>

View file

@ -267,4 +267,8 @@
<string name="last_response_duration">Letzte Antwort: vor %1$s</string> <string name="last_response_duration">Letzte Antwort: vor %1$s</string>
<string name="duration_ago">vor %1$s</string> <string name="duration_ago">vor %1$s</string>
<string name="shared_string_error_short">ERR</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> </resources>

View file

@ -268,4 +268,8 @@
<string name="last_response_duration">Última respuesta: Hace %1$s</string> <string name="last_response_duration">Última respuesta: Hace %1$s</string>
<string name="duration_ago">Hace %1$s</string> <string name="duration_ago">Hace %1$s</string>
<string name="shared_string_error_short">ERR</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> </resources>

View file

@ -250,7 +250,7 @@
<string name="set_time_timeline_descr">Elige la hora de visualización</string> <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="start_end_date">Fecha de Inicio — Fin</string>
<string name="saved_messages">Mensajes guardados</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="time_zone">Zona horaria</string>
<string name="units_and_formats">Unidades y formatos</string> <string name="units_and_formats">Unidades y formatos</string>
<string name="unit_of_length_descr">Cambia las unidades de longitud.</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="last_response_duration">Última respuesta: hace %1$s</string>
<string name="duration_ago">hace %1$s</string> <string name="duration_ago">hace %1$s</string>
<string name="shared_string_error_short">ERR</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> </resources>

View file

@ -267,4 +267,8 @@
<string name="last_response_duration">Viimane vastus: %1$s tagasi</string> <string name="last_response_duration">Viimane vastus: %1$s tagasi</string>
<string name="duration_ago">%1$s tagasi</string> <string name="duration_ago">%1$s tagasi</string>
<string name="shared_string_error_short">ERR</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> </resources>

View file

@ -38,8 +38,8 @@
<string name="yard">yd</string> <string name="yard">yd</string>
<string name="foot">ft</string> <string name="foot">ft</string>
<string name="mile">mi</string> <string name="mile">mi</string>
<string name="km">ک‌م</string> <string name="km">km</string>
<string name="m">متر</string> <string name="m">m</string>
<string name="nm">nmi</string> <string name="nm">nmi</string>
<string name="min_mile">min/m</string> <string name="min_mile">min/m</string>
<string name="min_km">min/km</string> <string name="min_km">min/km</string>
@ -73,4 +73,13 @@
<string name="unit_of_length_descr">یکاهای طول را تغییر دهید.</string> <string name="unit_of_length_descr">یکاهای طول را تغییر دهید.</string>
<string name="unit_of_length">یکاهای طول</string> <string name="unit_of_length">یکاهای طول</string>
<string name="shared_string_appearance">ظاهر</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> </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="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="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="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> </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="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">Tempo de caducidade do búfer</string>
<string name="buffer_time_descr">Tempo máximo para almacenar puntos no 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> </resources>

View file

@ -268,4 +268,8 @@
<string name="last_response_duration">תגובה אחרונה: לפני %1$s</string> <string name="last_response_duration">תגובה אחרונה: לפני %1$s</string>
<string name="duration_ago">לפני %1$s</string> <string name="duration_ago">לפני %1$s</string>
<string name="shared_string_error_short">שגיאה</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> </resources>

View file

@ -268,4 +268,8 @@
<string name="last_response_duration">Utolsó válasz: %1$s</string> <string name="last_response_duration">Utolsó válasz: %1$s</string>
<string name="duration_ago">Ennyivel ezelőtt: %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_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> </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_response_date">Ultima risposta: %1$s</string>
<string name="last_update_from_telegram_date">Ultimo aggiornamento da Telegram: %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="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> </resources>

View file

@ -219,8 +219,8 @@
<string name="shared_string_authorization_descr">国際形式でTelegramを利用する端末の電話番号を入力してください(日本の場合+81を先頭につけて電話番号最初の0を除いた番号を入力)</string> <string name="shared_string_authorization_descr">国際形式でTelegramを利用する端末の電話番号を入力してください(日本の場合+81を先頭につけて電話番号最初の0を除いた番号を入力)</string>
<string name="shared_string_welcome">ようこそ</string> <string name="shared_string_welcome">ようこそ</string>
<string name="yard">ヤード</string> <string name="yard">ヤード</string>
<string name="foot">フィート</string> <string name="foot">ft</string>
<string name="mile">マイル</string> <string name="mile">mi</string>
<string name="km">km</string> <string name="km">km</string>
<string name="m">m</string> <string name="m">m</string>
<string name="nm">海里</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_enabled">Oppsyn er påskrudd</string>
<string name="monitoring_is_disabled">Oppsyn er ikke aktivert</string> <string name="monitoring_is_disabled">Oppsyn er ikke aktivert</string>
<string name="time_on_the_move">Tid i bevegelse</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="average_speed">Gjennomsnittsfart</string>
<string name="open_in_osmand">Vis i OsmAnd</string> <string name="open_in_osmand">Vis i OsmAnd</string>
<string name="end_date">Sluttdato</string> <string name="end_date">Sluttdato</string>
@ -267,4 +267,8 @@
<string name="last_response_duration">Siste respons: %1$s siden</string> <string name="last_response_duration">Siste respons: %1$s siden</string>
<string name="duration_ago">%1$s siden</string> <string name="duration_ago">%1$s siden</string>
<string name="shared_string_error_short">FEIL</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> </resources>

View file

@ -257,4 +257,8 @@
<string name="unit_of_length">Afstand eenheden</string> <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_descr">Definieer de eenheid voor snelheid.</string>
<string name="unit_of_speed_system">Eenheid van 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> </resources>

View file

@ -267,4 +267,8 @@
<string name="shared_string_error_short">ERR</string> <string name="shared_string_error_short">ERR</string>
<string name="last_response_date">Ostatnia odpowiedź: %1$s</string> <string name="last_response_date">Ostatnia odpowiedź: %1$s</string>
<string name="last_response_duration">Ostatnia odpowiedź: %1$s temu</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> </resources>

View file

@ -267,4 +267,8 @@
<string name="last_response_duration">Última resposta: %1$s atrás</string> <string name="last_response_duration">Última resposta: %1$s atrás</string>
<string name="duration_ago">%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_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> </resources>

View file

@ -267,4 +267,8 @@
<string name="last_response_date">Última resposta: %1$s</string> <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="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_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> </resources>

View file

@ -108,7 +108,7 @@
<string name="not_found_yet">Ainda não encontrado</string> <string name="not_found_yet">Ainda não encontrado</string>
<string name="re_send_location">Reenvie o local</string> <string name="re_send_location">Reenvie o local</string>
<string name="last_available_location">Última localização disponível</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="location_sharing_status">Compartilhamento: %1$s</string>
<string name="shared_string_enabled">Ativado</string> <string name="shared_string_enabled">Ativado</string>
<string name="no_gps_connection">Sem conexão GPS</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_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="get_telegram_after_creating_account">Então pode usar esta app.</string>
<string name="shared_string_all">Todos</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="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="do_not_have_telegram">Não tenho uma conta do Telegram</string>
<string name="enter_phone_number">Digite o número de telefone</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="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="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="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="osmand_service_descr">OsmAnd Tracker é executado em segundo plano com o ecrã desligado.</string>
<string name="shared_string_distance">Distância</string> <string name="shared_string_distance">Distância</string>
<string name="share_location">Compartilhar localização</string> <string name="share_location">Compartilhar localização</string>
@ -230,15 +230,15 @@
<string name="m_s">m/s</string> <string name="m_s">m/s</string>
<string name="km_h">km/h</string> <string name="km_h">km/h</string>
<string name="mile_per_hour">mph</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_mph">Milhas por hora</string>
<string name="si_m_s">Metros por segundo</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_min_m">Minutos por milha</string>
<string name="si_nm_h">Milhas náuticas por hora (nó)</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_feet">Milhas/pés</string>
<string name="si_mi_yard">Milhas/jardas</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_nm">Milhas náuticas</string>
<string name="si_mi_meters">Milhas/metros</string> <string name="si_mi_meters">Milhas/metros</string>
<string name="shared_string_hour_short">h</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_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="time_zone">Fuso horário</string>
<string name="units_and_formats">Unidades e formatos</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_length">Unidades de comprimento</string>
<string name="unit_of_speed_system_descr">Definir unidade de velocidade.</string> <string name="unit_of_speed_system_descr">Definir unidade de velocidade.</string>
<string name="unit_of_speed_system">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_response_date">Última resposta: %1$s</string>
<string name="last_update_from_telegram_date">Última atualização do Telegram: %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_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> </resources>

View file

@ -75,7 +75,7 @@
<string name="by_distance">По расстоянию</string> <string name="by_distance">По расстоянию</string>
<string name="by_name">По имени</string> <string name="by_name">По имени</string>
<string name="by_group">По группе</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="shared_string_sort_by">Сортировать по</string>
<string name="turn_off_all">Отстановить все</string> <string name="turn_off_all">Отстановить все</string>
<string name="shared_string_exit">Выход</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_update_from_telegram_duration">Последнее обновление от Telegram: %1$s назад</string>
<string name="last_response_date">Последний ответ: %1$s</string> <string name="last_response_date">Последний ответ: %1$s</string>
<string name="last_update_from_telegram_date">Последнее обновление от Telegram: %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> </resources>

View file

@ -268,4 +268,8 @@
<string name="last_response_duration">Ùrtima risposta: %1$s a como</string> <string name="last_response_duration">Ùrtima risposta: %1$s a como</string>
<string name="duration_ago">%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_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> </resources>

View file

@ -267,4 +267,8 @@
<string name="last_response_date">Последњи одговор: %1$</string> <string name="last_response_date">Последњи одговор: %1$</string>
<string name="last_update_from_telegram_date">Последње ажурирање из Телеграма: %1$</string> <string name="last_update_from_telegram_date">Последње ажурирање из Телеграма: %1$</string>
<string name="shared_string_error_short">Грешка</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> </resources>

View file

@ -233,7 +233,7 @@
<string name="osmand_service_descr">OsmAnd Tracker, ekran kapalıyken arka planda çalışır.</string> <string name="osmand_service_descr">OsmAnd Tracker, ekran kapalıyken arka planda çalışır.</string>
<string name="share_location">Konumu paylaş</string> <string name="share_location">Konumu paylaş</string>
<string name="sharing_location">Konum paylaşılıyor</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="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_dialog_message">Önce OsmAnd\'ın ücretsiz veya ücretli sürümünü yüklemeniz gerekmektedir</string>
<string name="install_osmand">OsmAnd\'ı yükle</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="last_response_duration">Son cevap: %1$s önce</string>
<string name="duration_ago">%1$s önce</string> <string name="duration_ago">%1$s önce</string>
<string name="shared_string_error_short">HATA</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> </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="not_logged_in">Ви не увійшли до системи</string>
<string name="shared_string_continue">Продовжити</string> <string name="shared_string_continue">Продовжити</string>
<string name="shared_string_cancel">Скасувати</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="no_location_permission">Застосунок не має дозволу до отримання даних позиціювання.</string>
<string name="gps_not_available">Будь ласка, увімкніть «Позиціювання» у системних налаштуваннях</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="osmand_service_descr">OsmAnd Tracker працює у фоновому режимі з вимкненим екраном.</string>
<string name="shared_string_distance">Відстань</string> <string name="shared_string_distance">Відстань</string>
<string name="share_location">Поділитися позицією</string> <string name="share_location">Поділитися позицією</string>
@ -267,4 +267,8 @@
<string name="last_response_duration">Остання відповідь: %1$s тому</string> <string name="last_response_duration">Остання відповідь: %1$s тому</string>
<string name="duration_ago">%1$s тому</string> <string name="duration_ago">%1$s тому</string>
<string name="shared_string_error_short">ПМЛК</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> </resources>

View file

@ -270,4 +270,8 @@
<string name="last_response_duration">最後回應:%1$s 前</string> <string name="last_response_duration">最後回應:%1$s 前</string>
<string name="duration_ago">%1$s 前</string> <string name="duration_ago">%1$s 前</string>
<string name="shared_string_error_short">ERR</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> </resources>

View file

@ -27,6 +27,7 @@
<dimen name="dialog_welcome_title_top_margin">89dp</dimen> <dimen name="dialog_welcome_title_top_margin">89dp</dimen>
<dimen name="list_header_height">48dp</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_header_with_descr_height">42dp</dimen>
<dimen name="list_item_height">56dp</dimen> <dimen name="list_item_height">56dp</dimen>

View file

@ -1,5 +1,9 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <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="shared_string_error_short">ERR</string>
<string name="last_update_from_telegram_date">Last update from Telegram: %1$s</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> <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.app.Application
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager
import android.net.ConnectivityManager import android.net.ConnectivityManager
import android.net.NetworkInfo import android.net.NetworkInfo
import android.os.Build import android.os.Build
import android.os.Handler import android.os.Handler
import net.osmand.PlatformUtil
import net.osmand.telegram.ui.TrackerLogcatActivity
import net.osmand.telegram.helpers.* import net.osmand.telegram.helpers.*
import net.osmand.telegram.helpers.OsmandAidlHelper.OsmandHelperListener import net.osmand.telegram.helpers.OsmandAidlHelper.OsmandHelperListener
import net.osmand.telegram.helpers.OsmandAidlHelper.UpdatesListener import net.osmand.telegram.helpers.OsmandAidlHelper.UpdatesListener
import net.osmand.telegram.notifications.NotificationHelper import net.osmand.telegram.notifications.NotificationHelper
import net.osmand.telegram.utils.AndroidUtils import net.osmand.telegram.utils.AndroidUtils
import net.osmand.telegram.utils.UiUtils import net.osmand.telegram.utils.UiUtils
import java.io.File
class TelegramApplication : Application() { class TelegramApplication : Application() {
@ -200,4 +204,33 @@ class TelegramApplication : Application() {
fun runInUIThread(action: (() -> Unit), delay: Long) { fun runInUIThread(action: (() -> Unit), delay: Long) {
uiHandler.postDelayed(action, delay) 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.helpers.TelegramHelper.*
import net.osmand.telegram.notifications.TelegramNotification.NotificationType import net.osmand.telegram.notifications.TelegramNotification.NotificationType
import net.osmand.telegram.utils.AndroidUtils import net.osmand.telegram.utils.AndroidUtils
import net.osmand.telegram.utils.OsmandLocationUtils
import org.drinkless.td.libcore.telegram.TdApi import org.drinkless.td.libcore.telegram.TdApi
import java.util.* import java.util.*
@ -377,7 +376,10 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
Log.d(PlatformUtil.TAG, "Send live location error: $code - $message") Log.d(PlatformUtil.TAG, "Send live location error: $code - $message")
when (messageType) { when (messageType) {
TelegramHelper.MESSAGE_TYPE_TEXT -> shareInfo.pendingTdLibText-- 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 PROXY_PREFERENCES_KEY = "proxy_preferences"
private const val SHARING_INITIALIZATION_TIME = 60 * 2L // 2 minutes 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 private const val GPS_UPDATE_EXPIRED_TIME = 60 * 3L // 3 minutes
@ -304,27 +304,18 @@ class TelegramSettings(private val app: TelegramApplication) {
fun prepareForSharingNewMessages() { fun prepareForSharingNewMessages() {
shareChatsInfo.forEach { (_, shareInfo) -> shareChatsInfo.forEach { (_, shareInfo) ->
prepareForSharingNewMessages(shareInfo) shareInfo.resetMessagesInfo()
} }
} }
fun prepareForSharingNewMessages(chatsIds: List<Long>) { fun prepareForSharingNewMessages(chatsIds: List<Long>) {
chatsIds.forEach { chatsIds.forEach {
shareChatsInfo[it]?.also { shareInfo -> 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 getChatLivePeriod(chatId: Long) = shareChatsInfo[chatId]?.livePeriod
fun getChatsShareInfo() = shareChatsInfo fun getChatsShareInfo() = shareChatsInfo
@ -540,14 +531,24 @@ class TelegramSettings(private val app: TelegramApplication) {
if (initTime && initSending) { if (initTime && initSending) {
initializing = true initializing = true
} else { } else {
var waitingTimeError = false
val maxWaitingTime = WAITING_TDLIB_TIME * MAX_MESSAGES_IN_TDLIB_PER_CHAT * max(1, chatsCount) val maxWaitingTime = WAITING_TDLIB_TIME * MAX_MESSAGES_IN_TDLIB_PER_CHAT * max(1, chatsCount)
val textSharingError = !shareInfo.lastTextMessageHandled && currentTime - shareInfo.lastSendTextMessageTime > maxWaitingTime val textSharingWaitingTime = currentTime - shareInfo.lastSendTextMessageTime
val mapSharingError = !shareInfo.lastMapMessageHandled && currentTime - shareInfo.lastSendMapMessageTime > maxWaitingTime val mapSharingWaitingTime = currentTime - shareInfo.lastSendMapMessageTime
if (shareInfo.hasSharingError val textSharingError = !shareInfo.lastTextMessageHandled && textSharingWaitingTime > maxWaitingTime
|| (shareTypeValue == SHARE_TYPE_MAP_AND_TEXT && (textSharingError || mapSharingError)) val mapSharingError = !shareInfo.lastMapMessageHandled && mapSharingWaitingTime > maxWaitingTime
|| textSharingError && (shareTypeValue == SHARE_TYPE_TEXT) if ((shareTypeValue == SHARE_TYPE_MAP_AND_TEXT && (textSharingError || mapSharingError))
|| mapSharingError && (shareTypeValue == SHARE_TYPE_MAP) || textSharingError && (shareTypeValue == SHARE_TYPE_TEXT)
) { || 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 sendChatsErrors = true
locationTime = max(shareInfo.lastTextSuccessfulSendTime, shareInfo.lastMapSuccessfulSendTime) locationTime = max(shareInfo.lastTextSuccessfulSendTime, shareInfo.lastMapSuccessfulSendTime)
chatsIds.add(shareInfo.chatId) chatsIds.add(shareInfo.chatId)
@ -1487,6 +1488,27 @@ class TelegramSettings(private val app: TelegramApplication) {
fun isPendingMapMessagesLimitReached() = pendingTdLibMap >= MAX_MESSAGES_IN_TDLIB_PER_CHAT 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 { companion object {
internal const val CHAT_ID_KEY = "chatId" internal const val CHAT_ID_KEY = "chatId"

View file

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

View file

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

View file

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

View file

@ -213,6 +213,12 @@ class SettingsDialogFragment : BaseDialogFragment() {
DisconnectTelegramBottomSheet.showInstance(childFragmentManager) 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 return mainView
} }

View file

@ -72,7 +72,7 @@ class SharingStatusBottomSheet : DialogFragment() {
if (sharingStatusType.canResendLocation) { if (sharingStatusType.canResendLocation) {
if (i == 0) { if (i == 0) {
setOnClickListener { setOnClickListener {
app.shareLocationHelper.checkNetworkType() app.shareLocationHelper.updateNetworkType()
app.settings.prepareForSharingNewMessages(sharingStatus.chatsIds) app.settings.prepareForSharingNewMessages(sharingStatus.chatsIds)
app.shareLocationHelper.checkAndSendBufferMessages() app.shareLocationHelper.checkAndSendBufferMessages()
app.forceUpdateMyLocation() 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/commons-codec-commons-codec-1.11.jar
libs/OsmAndCore_android-0.1-SNAPSHOT.jar libs/OsmAndCore_android-0.1-SNAPSHOT.jar
# Huawei
libs/huawei-*.jar libs/huawei-*.jar
huaweidrmlib/ huaweidrmlib/
HwDRM_SDK_* HwDRM_SDK_*
drm_strings.xml drm_strings.xml
agconnect-services.json
OsmAndHms.jks
# copy_widget_icons.sh # copy_widget_icons.sh
res/drawable-large/map_* 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" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"> xmlns:tools="http://schemas.android.com/tools">
<application> <application
<activity android:name="com.huawei.android.sdk.drm.DrmDialogActivity" android:icon="@mipmap/icon_free"
android:configChanges="screenSize|orientation|keyboardHidden" android:label="@string/app_name_free"
android:exported="false" tools:replace="android:icon, android:label">
android:theme="@android:style/Theme.Translucent">
<meta-data <meta-data
android:name="hwc-theme" android:name="com.huawei.hms.client.appid"
android:value="androidhwext:style/Theme.Emui.Translucent" /> android:value="101486545" />
</activity> <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 <provider
android:name="androidx.core.content.FileProvider" android:name="androidx.core.content.FileProvider"
android:authorities="net.osmand.huawei.fileprovider" tools:replace="android:authorities"
tools:replace="android:authorities" /> android:authorities="net.osmand.huawei.fileprovider"/>
<service
android:name="net.osmand.plus.NavigationService"
android:process="net.osmand.huawei"
tools:replace="android:process" />
</application> </application>
</manifest> </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:icon="@mipmap/icon" android:label="@string/app_name"
android:name="net.osmand.plus.OsmandApplication" android:configChanges="locale" android:name="net.osmand.plus.OsmandApplication" android:configChanges="locale"
android:theme="@style/OsmandDarkTheme" android:restoreAnyVersion="true" android:largeHeap="true" 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.google.android.backup.api_key" android:value="AEdPqrEAAAAIqF3tNGT66etVBn_vgzpfAY1wmIzKV1Ss6Ku-2A" />
<meta-data android:name="com.sec.android.support.multiwindow" android:value="true" /> <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="" /> <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.HelpActivity" />
<activity android:name="net.osmand.plus.activities.ExitActivity" /> <activity android:name="net.osmand.plus.activities.ExitActivity" />
<activity android:name="net.osmand.plus.openplacereviews.OPRWebviewActivity" android:theme="@style/Theme.AppCompat.NoActionBar" />
<provider <provider
android:name="androidx.core.content.FileProvider" android:name="androidx.core.content.FileProvider"
@ -246,6 +248,7 @@
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="content"/>
<data android:scheme="file"/> <data android:scheme="file"/>
<data android:host="*"/> <data android:host="*"/>
<data android:pathPattern=".*\\.obf" /> <data android:pathPattern=".*\\.obf" />
@ -261,6 +264,7 @@
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="content"/>
<data android:scheme="file"/> <data android:scheme="file"/>
<data android:host="*"/> <data android:host="*"/>
<data android:mimeType="*/*"/> <data android:mimeType="*/*"/>
@ -371,6 +375,72 @@
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.xml" /> <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.xml" />
</intent-filter> </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--> <!--trying to handle emails-->
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
@ -399,6 +469,13 @@
<data android:mimeType="text/plain" /> <data android:mimeType="text/plain" />
</intent-filter> </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> </activity>
<receiver android:name="net.osmand.plus.audionotes.MediaRemoteControlReceiver"> <receiver android:name="net.osmand.plus.audionotes.MediaRemoteControlReceiver">
@ -408,22 +485,10 @@
</intent-filter> </intent-filter>
</receiver> </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.search.SearchActivity" android:label="@string/search_activity" />
<activity android:name="net.osmand.plus.activities.FavoritesListActivity" android:label="@string/favourites_list_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=".myplaces.FavoritesActivity" android:windowSoftInputMode="adjustPan" />
<activity android:name="net.osmand.plus.activities.TrackActivity"/> <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" /> <activity android:name="net.osmand.plus.activities.ContributionVersionActivity" android:configChanges="keyboardHidden|orientation" android:label="@string/contribution_activity" />
@ -484,11 +549,17 @@
<data android:host="map.wap.qq.com" /> <data android:host="map.wap.qq.com" />
<data android:host="map.qq.com" /> <data android:host="map.qq.com" />
<data android:host="maps.apple.com" /> <data android:host="maps.apple.com" />
<data android:host="ge0.me" />
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.BROWSABLE" />
</intent-filter> </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"/>
</intent-filter>
<intent-filter> <intent-filter>
<data android:scheme="http" android:host="openstreetmap.de" android:pathPrefix="/karte" /> <data android:scheme="http" android:host="openstreetmap.de" android:pathPrefix="/karte" />
<data android:scheme="https" android:host="openstreetmap.de" android:pathPrefix="/karte" /> <data android:scheme="https" android:host="openstreetmap.de" android:pathPrefix="/karte" />

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/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/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/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/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/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" /> <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