16
.github/ISSUE_TEMPLATE/1-support-request.md
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
---
|
||||
name: "❓ Support request"
|
||||
about: Questions and requests for support
|
||||
---
|
||||
|
||||
🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑
|
||||
|
||||
Please do not file questions or support requests on the GitHub issues tracker.
|
||||
|
||||
In case you aren't sure whether to open an issue or not, please send your request to support@osmand.net.
|
||||
|
||||
You can get your questions answered using the [Google group](https://groups.google.com/forum/#!forum/osmand) or chat in real-time via our Telegram instances: [English](https://t.me/OsmAndMaps), [German](https://t.me/deosmand), [French](https://t.me/frosmand), [Ukrainian](https://t.me/uaosmand), [Italian](https://t.me/itosmand), [Russian](https://t.me/ruosmand).
|
||||
|
||||
Thank you!
|
||||
|
||||
🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑
|
12
.github/ISSUE_TEMPLATE/2-faq-report.md
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
name: "📚 Outdated FAQ"
|
||||
about: Report an issue in FAQ
|
||||
|
||||
---
|
||||
🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑
|
||||
|
||||
Please do not file FAQ issues on the GitHub issues tracker.
|
||||
|
||||
Instead use the [Google group](https://groups.google.com/forum/#!forum/osmand) to fix wrong or outdated FAQ.
|
||||
|
||||
🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑
|
69
.github/ISSUE_TEMPLATE/3-bug-report.md
vendored
Normal file
|
@ -0,0 +1,69 @@
|
|||
---
|
||||
name: "\U0001F41E Bug report"
|
||||
about: Report a bug in OsmAnd
|
||||
---
|
||||
<!--🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅
|
||||
|
||||
Oh hi there! 😄
|
||||
|
||||
To expedite issue processing please search open and closed issues before submitting a new one.
|
||||
Existing issues often contain information about workarounds, resolution, or progress updates.
|
||||
|
||||
GitHub is our main development tool for our developers. There are hundreds of requests a month and there are relatively few developers.
|
||||
So by opening an issue, please know that your issue will be sent out to all developers and acknowledge that it could be closed without explanation or with just a brief message.
|
||||
Comments on the closed issues are also sent to all developers, so you will definitely will be heard.
|
||||
However, there is no guarantee that a developer will pick up the issue to work on it.
|
||||
|
||||
Please be sure to read our [FAQ](https://osmand.net/help-online) before creating an issue here.
|
||||
|
||||
The best way to get help about an OsmAnd issue is to create a valid and detailed issue.
|
||||
Please give us the following information so that we can try to **reproduce** your issue:
|
||||
|
||||
🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅-->
|
||||
|
||||
# 🐞 bug report
|
||||
|
||||
### Is this a regression?
|
||||
|
||||
<!-- Did this behavior use to work in the previous version? -->
|
||||
<!-- ✍️--> Yes, the previous version in which this bug was not present was: ....
|
||||
|
||||
|
||||
### Description
|
||||
|
||||
<!-- ✍️--> A clear and concise description of the problem...
|
||||
|
||||
|
||||
## 🔬 Minimal Reproduction
|
||||
<!--
|
||||
If the bug is reproducible, please describe steps below:
|
||||
-->
|
||||
<!-- ✍️--> 1. Open app, and click on ...
|
||||
|
||||
## 🔥 Exception or Error
|
||||
<pre><code>
|
||||
<!-- If the issue is accompanied by an exception or an error, please share it below: -->
|
||||
<!-- ✍️-->
|
||||
|
||||
</code></pre>
|
||||
|
||||
|
||||
## 🌍 Your Environment
|
||||
|
||||
**OsmAnd Version:**
|
||||
<pre><code>
|
||||
<!-- paste version below -->
|
||||
<!-- ✍️-->
|
||||
|
||||
</code></pre>
|
||||
|
||||
**Device and Android/iOS version:**
|
||||
|
||||
**Maps used (online or offline):**
|
||||
<!-- Please tick the correct box [x] (or both) -->
|
||||
- [ ] Offline maps offered within the OsmAnd app for download.
|
||||
<!-- If you have an issue related to offline maps, tell us the exact name of the map file where the issue occurs and its edition date. -->
|
||||
- [ ] Online (tile / raster) maps <!-- Please name it -->
|
||||
|
||||
|
||||
**Anything else relevant?**
|
66
.github/ISSUE_TEMPLATE/4-routing-report.md
vendored
Normal file
|
@ -0,0 +1,66 @@
|
|||
---
|
||||
name: "\U0001F6A9 Routing report"
|
||||
about: Report a routing issue 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:
|
||||
|
||||
🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅-->
|
||||
|
||||
# 🐞 routing report
|
||||
|
||||
### Routing engine
|
||||
|
||||
<!-- Which routing provider was used? (please tick the proper box [x]) -->
|
||||
- [ ] OsmAnd's in-app offline routing
|
||||
- [ ] Any online routing provider (YOURS, OpenRouteService, OSRM, etc.)
|
||||
|
||||
### Routing Profile
|
||||
<!-- What routing profile is chosen in the OsmAnd app? (car, bike, pedestrian, fastest or shortest, etc.) -->
|
||||
|
||||
### Start and end points
|
||||
|
||||
<!-- Please specify (as exactly as possible) the start and endpoint of your route by telling us the city and street name so that we can find it via the in-app address search easily.
|
||||
Also, a permalink from [openstreetmap.org](https://www.openstreetmap.org/) can be helpful. -->
|
||||
|
||||
### Actual and expected routes
|
||||
<!-- Tell us your expected routing and how OsmAnd routes, or add screenshots here. -->
|
||||
|
||||
### Is this a regression?
|
||||
|
||||
<!-- Did this behavior use to work in the previous version? -->
|
||||
<!-- ✍️--> Yes, the previous version in which this bug was not present was: ....
|
||||
|
||||
## 🌍 Your Environment
|
||||
|
||||
**OsmAnd Version:**
|
||||
<pre><code>
|
||||
<!-- paste version below -->
|
||||
<!-- ✍️-->
|
||||
|
||||
</code></pre>
|
||||
|
||||
**Device and Android/iOS version:**
|
||||
|
||||
**Maps used (online or offline):**
|
||||
<!-- Please tick the correct box [x] (or both) -->
|
||||
- [ ] Offline maps offered within the OsmAnd app for download.
|
||||
<!-- If you have an issue related to offline maps, tell us the exact name of the map file where the issue occurs and its edition date. -->
|
||||
- [ ] Online (tile / raster) maps <!-- Please name it -->
|
||||
|
||||
|
||||
**Anything else relevant?**
|
33
.github/ISSUE_TEMPLATE/5-feature-request.md
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
---
|
||||
name: "\U0001F680 Feature request"
|
||||
about: Suggest a feature for 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.
|
||||
|
||||
🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅-->
|
||||
|
||||
# 🚀 feature request
|
||||
|
||||
### Description
|
||||
<!-- ✍️--> A clear and concise description of the problem or missing capability...
|
||||
|
||||
|
||||
### Describe the solution you'd like
|
||||
<!-- ✍️--> If you have a solution in mind, please describe it.
|
||||
|
||||
|
||||
### Describe alternatives you've considered
|
||||
<!-- ✍️--> Have you considered any alternative solutions or workarounds?
|
10
.github/workflows/gradle-wrapper-validation.yml
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
name: "Validate Gradle Wrapper"
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
validation:
|
||||
name: "Validation"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: gradle/wrapper-validation-action@v1
|
|
@ -1,7 +1,7 @@
|
|||
### Credits to all major contributors/developers:
|
||||
Major contributors /developers listed here https://github.com/osmandapp/osmandapp.github.io/blob/master/website/help/about.html#L8
|
||||
### Credits to all major contributors / developers:
|
||||
Major contributors / developers listed here https://github.com/osmandapp/osmandapp.github.io/blob/master/website/help/about.html#L8
|
||||
|
||||
### Other Pull requests
|
||||
Copyright © All authors of translations and pull requests could be found in commits history:
|
||||
Copyright © All authors of translations and pull requests can be found in the commit history:
|
||||
- Translations are under special “contributor” name ‘weblate’
|
||||
- Pull requests have two committers, first is original contributor and second is project maintainer
|
||||
- Pull requests have two committers: first is original contributor, and second is project maintainer
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
Before entering an issue, please read the information below.
|
||||
|
||||
```GitHub is a main development tool for developers. There are hundreds requests a month and there are only 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 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.```
|
||||
|
||||
In case you are not sure to open issue or not, please send your request to support support@osmand.net. For **general questions** about OsmAnd, please use the [Google group](https://groups.google.com/forum/#!forum/osmand).
|
||||
|
||||
Please be sure to have read our [FAQ](http://osmand.net/help-online) before creating an issue here. (Also, tell us in Google Groups when the FAQ is wrong or outdated.)
|
||||
|
||||
The best way to get help about an OsmAnd issue is to create a valid and detailed issue content.
|
||||
Please give us the following information so that we can try to **reproduce** your issue:
|
||||
|
||||
What version of OsmAnd are you using, on what device and Android/iOS version?
|
||||
|
||||
Do you use the offline maps offered within the OsmAnd app for download, or online (tile / raster) maps?
|
||||
|
||||
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.
|
||||
|
||||
__*In case of wrong routing:*__
|
||||
|
||||
Tell us whether you have used OsmAnd's in-app offline routing, or any online routing provider like YOURS, OpenRouteService or OSRM.
|
||||
|
||||
What routing profile is chosen in OsmAnd app? (car, bike, pedestrian, fastest or shortest)
|
||||
|
||||
Please specify as exactly as possible the start and end point of your route by telling us city name and street name so that we can find it via in-app address search easily. Also, a permalink from openstreetmap.org can be helpful.
|
||||
|
||||
Tell us your expected routing, and how OsmAnd routes, or add screenshots here.
|
70
LICENSE
|
@ -1,11 +1,11 @@
|
|||
|
||||
OsmAnd – OSM Automated Navigation Directions – navigation software based on OpenStreetMap.
|
||||
Copyright © 2010–2018 OsmAnd BV (Amstelveen, Netherlands - KvK 62066714, BTW 854627704B01).
|
||||
Copyright © 2010–2020 OsmAnd BV (Amstelveen, Netherlands - KvK 62066714, BTW 854627704B01).
|
||||
|
||||
The code in this repository is covered by *GPLv3* (for code) and the artwork is covered by [ CC-BY-NC-ND 4.0 ](https://creativecommons.org/licenses/by-nc-nd/4.0/) (for artwork), except some 3rd party libs and resources.
|
||||
ATTENTION: please be aware that some artwork has proprietary license.
|
||||
The code in this repository is covered by *GPLv3* (for code) and the artwork is covered by [CC-BY-NC-ND 4.0](https://creativecommons.org/licenses/by-nc-nd/4.0/) (for artwork), except for some third-party libraries and resources.
|
||||
ATTENTION: Please be aware that some artwork uses a proprietary license.
|
||||
|
||||
Main AUTHORS (more detailed list in AUTHORS):
|
||||
Main AUTHORS (more detailed list in AUTHORS.md):
|
||||
Victor Shcherb – all parts of the project, originator
|
||||
Alexey Pelykh – rendering and core parts
|
||||
Hardy Mueller – main parts of the project, mostly rendering, UI interaction design
|
||||
|
@ -30,33 +30,33 @@
|
|||
* Source code in main repositories is covered by GPLv3 (license exceptions below):
|
||||
- https://github.com/osmandapp/Osmand/tree/master/OsmAnd
|
||||
- https://github.com/osmandapp/Osmand/tree/master/OsmAnd-java
|
||||
- https://github.com/osmandapp/Osmand-core/tree/legacy_core
|
||||
- https://github.com/osmandapp/Osmand-core/
|
||||
- https://github.com/osmandapp/OsmAnd-core/tree/legacy_core
|
||||
- https://github.com/osmandapp/OsmAnd-core
|
||||
- https://github.com/osmandapp/OsmAnd-misc
|
||||
- https://github.com/osmandapp/OsmAnd-tools
|
||||
- https://github.com/osmandapp/OsmAnd-resources
|
||||
|
||||
* UI Design and UX work, such as layout, icons is covered by CC-BY-NC-ND
|
||||
* UI Design and UX work, such as layout and icons, are covered by [CC-BY-NC-ND 4.0](https://creativecommons.org/licenses/by-nc-nd/4.0/)
|
||||
- https://github.com/osmandapp/Osmand/tree/master/OsmAnd/res and others
|
||||
Restriction to UI/UX CC-BY-NC-ND:
|
||||
* Publishing applications using the OsmAnd UI/UX code to Google Play, Amazon Market or Apple Store must be done with written permission*
|
||||
* Publishing applications using the OsmAnd UI/UX code to Google Play, Amazon Market, or Apple Store must be done with written permission.*
|
||||
|
||||
|
||||
* Map icons are taken from sjjb and some are drawn and distributed under Public Domain (except icons8)
|
||||
- https://github.com/osmandapp/OsmAnd-resources/tree/master/icons/svg
|
||||
- some icons are from http://osm-icons.org/wiki/Icons (CC-0 by Markus59, CC BY-SA 2.0)
|
||||
|
||||
* Integration with Qt library in (https://github.com/osmandapp/Osmand-core/) - dynamic linking
|
||||
- LGPL (http://www.qt.io/qt-licensing-terms/)
|
||||
* Integration with Qt library in (https://github.com/osmandapp/OsmAnd-core) - dynamic linking
|
||||
- LGPL (https://www.qt.io/terms-conditions/)
|
||||
|
||||
* Map icons and their derived primitives are covered by proprietary license:
|
||||
* Map icons and their derived primitives are covered by a proprietary license:
|
||||
- © icons8.com (https://github.com/osmandapp/OsmAnd-resources/tree/master/icons/svg/icons8)
|
||||
|
||||
* Generated voice files from TTS files are covered by proprietary license:
|
||||
* Generated voice files from TTS files are covered by a proprietary license:
|
||||
- Voice files (https://github.com/osmandapp/OsmAnd-resources/tree/master/voice)
|
||||
|
||||
* Fonts (https://github.com/osmandapp/OsmAnd-resources/tree/master/rendering_styles/fonts)
|
||||
- Google Fonts (Apache License 2)
|
||||
- Google Fonts (Apache License 2.0)
|
||||
|
||||
* Map icons (Mapnik):
|
||||
- Open-SVG-Map-Icons - Public Domain
|
||||
|
@ -65,49 +65,27 @@
|
|||
- SherlockBar - Apache License - https://github.com/osmandapp/Osmand/tree/master/SherlockBar (https://github.com/JakeWharton/ActionBarSherlock/blob/master/LICENSE.txt)
|
||||
|
||||
* Patched libraries:
|
||||
- Protobuf - New BSD License (patches - https://github.com/osmandapp/Osmand/tree/master/OsmAnd-java/protobuf-src, https://github.com/osmandapp/OsmAnd-core/tree/legacy_core/externals/protobuf)
|
||||
- Expat - (https://github.com/osmandapp/OsmAnd-core/tree/legacy_core/externals/expat)
|
||||
- Freetype - (https://github.com/osmandapp/OsmAnd-core/tree/legacy_core/externals/freetype)
|
||||
- Giflib - (https://github.com/osmandapp/OsmAnd-core/tree/legacy_core/externals/giflib)
|
||||
- Protobuf - New BSD License (patches - https://github.com/osmandapp/Osmand/tree/master/OsmAnd-java/src/main/java/com/google/protobuf, https://github.com/osmandapp/OsmAnd-core/tree/legacy_core/externals/protobuf)
|
||||
- Jpeg - (https://github.com/osmandapp/OsmAnd-core/tree/legacy_core/externals/jpeg)
|
||||
- Libpng - (https://github.com/osmandapp/OsmAnd-core/tree/legacy_core/externals/libpng)
|
||||
- Skia - (https://github.com/osmandapp/OsmAnd-core/tree/legacy_core/externals/skia)
|
||||
- ZLib - (https://github.com/osmandapp/OsmAnd-core/tree/legacy_core/externals/zlib)
|
||||
- android-openmap-framework - (https://github.com/osmandapp/Osmand/tree/master/OsmAnd-java/src/main/java/com/jwetherell/openmap/common)
|
||||
- mapbox-vector-tile - (https://github.com/osmandapp/Osmand/tree/master/OsmAnd-java/src/main/java/com/wdtinc/mapbox_vector_tile)
|
||||
|
||||
* 3rd party libraries present in the libs folder (https://github.com/osmandapp/Osmand/tree/master/OsmAnd-java/libs):
|
||||
- bzip2-20090327.jar Bzip2 - Apache License
|
||||
- commons-logging-1.1.1.jar - Apache License
|
||||
- gnu-trove-osmand.jar GNU trove - LGPL
|
||||
- icu4j-49_1.jar - ICU license (http://source.icu-project.org/repos/icu/icu/trunk/license.html)
|
||||
- json-20090211.jar - BSD alike (http://www.json.org/license.html)
|
||||
- junidecode-0.1.jar - BSD-4-Clause-UC (http://sourceforge.net/projects/junidecode/)
|
||||
- kxml2-2.3.0.jar - BSD license (http://www.kxml.org/)
|
||||
- tuprolog.jar - LGPL (http://apice.unibo.it/xwiki/bin/view/Tuprolog/)
|
||||
- OpenMap framework - Apache License (https://code.google.com/p/android-openmap-framework/)
|
||||
- icu4j-49_1_patched.jar - ICU license (https://home.unicode.org/basic-info/projects/#/icu/icu/trunk/license.html)
|
||||
|
||||
* Pull-requests and translations:
|
||||
- All pull requests are accepted under MIT License (most honorable contributors are mentioned in AUTHORS list)
|
||||
|
||||
* Libraries not used in final product (https://github.com/osmandapp/OsmAnd-tools/tree/master/OsmAndMapCreator/libi)
|
||||
- Ant libraries - (tools) https://github.com/osmandapp/Osmand/tree/master/OsmAnd/ant-lib
|
||||
- jleveldb-v01.jar
|
||||
- jsch-20120101.jar
|
||||
- junit-4.10.jar
|
||||
- mysql-connector-java-5.1.18-bin.jar
|
||||
- sqlite-jdbc-3.7.6.3-20110609.081603-3.jar
|
||||
- h2-latest.jar
|
||||
- All pull requests are accepted under MIT License (most honorable contributors are mentioned in AUTHORS list).
|
||||
|
||||
* Special tools for new rendering (GPLv3)
|
||||
- https://github.com/osmandapp/OsmAnd-tools/tree/master/obf-inspector
|
||||
- https://github.com/osmandapp/OsmAnd-tools/tree/master/obf-verifier
|
||||
- https://github.com/osmandapp/OsmAnd-tools/tree/master/route-tester
|
||||
- https://github.com/osmandapp/OsmAnd-tools
|
||||
|
||||
* OSM data 2014
|
||||
- Extracts - https://github.com/osmandapp/OsmAnd-misc/blob/master/osm-planet/osm-data/
|
||||
* OSM data
|
||||
- Extracts - https://github.com/osmandapp/OsmAnd-misc/tree/master/osm-planet/osm-data
|
||||
|
||||
* Data files
|
||||
- Country boundaries - https://github.com/osmandapp/OsmAnd-misc/tree/master/osm-planet/geo-polygons © by Geofabrik - data free to use
|
||||
- Country boundaries - https://github.com/osmandapp/OsmAnd-misc/tree/master/osm-planet/gislab-polygons © by http://be.gis-lab.info - data free to use
|
||||
- Country boundaries - https://github.com/osmandapp/OsmAnd-misc/tree/master/osm-planet/polygons © by Geofabrik - data free to use
|
||||
|
||||
* Subway icons
|
||||
- Moscow: Art Lebedev Studio (http://www.artlebedev.ru/everything/metro/logo/) [Public domain], undefined
|
||||
|
@ -119,7 +97,7 @@
|
|||
- Kazan: «Kazan-metro-Logo» (Россиянин) - own work. Under Public domain Commons license from the site - https://commons.wikimedia.org/wiki/File:Kazan-metro-Logo.svg#/media/File:Kazan-metro-Logo.svg
|
||||
- Tbilisi: «Metro Tbilisi logo» (Carnby) - own work. Under CC BY-SA 3.0 license from site - https://commons.wikimedia.org/wiki/File:Metro_Tbilisi_logo.svg#/media/File:Metro_Tbilisi_logo.svg
|
||||
- Minsk: «Minsk metro logo» (Skip405) - own work. Under Public domain Commons license from the site - https://commons.wikimedia.org/wiki/File:Minsk_metro_logo.svg#/media/File:Minsk_metro_logo.svg
|
||||
- Nizhny Novgorod: «NNMetro» (AlexTref871) - own work. This vector image includes elements borrowed from another image: Coat of arms of Nizhny Novgorod Region.svg.. Under Public domain Commons licensefrom the site - https://commons.wikimedia.org/wiki/File:NNMetro.svg#/media/File:NNMetro.svg
|
||||
- Nizhny Novgorod: «NNMetro» (AlexTref871) - own work. This vector image includes elements borrowed from another image: Coat of arms of Nizhny Novgorod Region.svg.. Under Public domain Commons licensefrom the site - https://commons.wikimedia.org/wiki/File:NNMetro.svg#/media/File:NNMetro.svg
|
||||
- Novosibirsk: «Logo-Nsk-Metro» (AlexTref871) - own work. Under Public domain Commons license from the site - https://commons.wikimedia.org/wiki/File:Logo-Nsk-Metro.svg#/media/File:Logo-Nsk-Metro.svg
|
||||
- Yekaterinburg: «Ekt-metro-logo-01» (AlexTref871) - own work. Under CC BY-SA 4.0 license from site - https://commons.wikimedia.org/wiki/File:Ekt-metro-logo-01.svg#/media/File:Ekt-metro-logo-01.svg
|
||||
- New York: «MTA New York City Subway logo» (Metropolitan Transportation Authority) - http://mta.info/. Under Public domain Commons license from the site - https://commons.wikimedia.org/wiki/File:MTA_New_York_City_Subway_logo.svg#/media/File:MTA_New_York_City_Subway_logo.svg
|
||||
|
@ -152,7 +130,7 @@
|
|||
- Los Angeles: "Lametro" by Los Angeles County Metropolitan Transportation Authority. Original uploader was Cheeselouise at en.wikipedia - Metro materials at http://www.metro.net/riding_metro/pocket_guide_cambodian_printers.pdf. Licensed under Public Domain via Commons - https://commons.wikimedia.org/wiki/File:Lametro.svg#/media/File:Lametro.svg
|
||||
|
||||
* Depth maps
|
||||
- The GEBCO_2014 Grid, version 20150318, www.gebco.net
|
||||
- The GEBCO_2020 Grid, www.gebco.net
|
||||
- U.S. Bureau of Ocean Energy Management (24 may 2017,12m per pixel)
|
||||
- South_Padre_Island_DEM_4133: Grothe, P.G., L.A. Taylor, B.W. Eakins, K.S. Carignan, D.Z. Friday, and M. Love, 2012. Digital Elevation Models of South Padre Island, Texas: Procedures, Data Sources and Analysis, NOAA National Geophysical Data Center technical report, Boulder, CO, 15 pp.
|
||||
- Corpus_Christi_DEM_1035: Taylor, L.A., B.W. Eakins, K.S. Carignan, R.R. Warnken, T. Sazonova, and D.C. Schoolcraft, 2008. Digital Elevation Model of Corpus Christi, Texas: Procedures, Data Sources and Analysis, NOAA Technical Memorandum NESDIS NGDC-11, National Geophysical Data Center, Boulder, CO, 19 pp.
|
||||
|
|
|
@ -51,4 +51,9 @@ interface IOsmAndAidlCallback {
|
|||
* Callback for {@link IOsmAndAidlInterface} registerForVoiceRouterMessages() method.
|
||||
*/
|
||||
void onVoiceRouterNotify(in OnVoiceNavigationParams params);
|
||||
|
||||
/**
|
||||
* Callback for {@link IOsmAndAidlInterface} registerForKeyEvents() method.
|
||||
*/
|
||||
void onKeyEvent(in KeyEvent params);
|
||||
}
|
|
@ -74,6 +74,7 @@ import net.osmand.aidlapi.customization.OsmandSettingsParams;
|
|||
import net.osmand.aidlapi.customization.OsmandSettingsInfoParams;
|
||||
import net.osmand.aidlapi.customization.CustomizationInfoParams;
|
||||
import net.osmand.aidlapi.customization.ProfileSettingsParams;
|
||||
import net.osmand.aidlapi.customization.MapMarginsParams;
|
||||
|
||||
import net.osmand.aidlapi.gpx.AGpxFile;
|
||||
import net.osmand.aidlapi.gpx.AGpxFileDetails;
|
||||
|
@ -96,6 +97,12 @@ import net.osmand.aidlapi.mapmarker.RemoveMapMarkersParams;
|
|||
import net.osmand.aidlapi.quickaction.QuickActionParams;
|
||||
import net.osmand.aidlapi.quickaction.QuickActionInfoParams;
|
||||
|
||||
import net.osmand.aidlapi.lock.SetLockStateParams;
|
||||
|
||||
import net.osmand.aidlapi.events.AKeyEventsParams;
|
||||
|
||||
import net.osmand.aidlapi.info.AppInfoParams;
|
||||
|
||||
// NOTE: Add new methods at the end of file!!!
|
||||
|
||||
interface IOsmAndAidlInterface {
|
||||
|
@ -841,4 +848,23 @@ interface IOsmAndAidlInterface {
|
|||
boolean executeQuickAction(in QuickActionParams params);
|
||||
|
||||
boolean getQuickActionsInfo(out List<QuickActionInfoParams> quickActions);
|
||||
|
||||
/**
|
||||
* Toggle Lock/Unlock screen.
|
||||
*/
|
||||
boolean setLockState(in SetLockStateParams params);
|
||||
|
||||
/**
|
||||
* Method to register for key events.
|
||||
*
|
||||
* @params subscribeToUpdates (boolean) - boolean flag to subscribe or unsubscribe from key events
|
||||
* @params callbackId (long) - id of callback, needed to unsubscribe key events
|
||||
* @params callback (IOsmAndAidlCallback) - callback to notify user on key event
|
||||
* @params keyEventList (List<Integer>) - list of requested key events
|
||||
*/
|
||||
long registerForKeyEvents(in AKeyEventsParams params, IOsmAndAidlCallback callback);
|
||||
|
||||
AppInfoParams getAppInfo();
|
||||
|
||||
boolean setMapMargins(in MapMarginsParams params);
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
package net.osmand.aidlapi.customization;
|
||||
|
||||
parcelable MapMarginsParams;
|
|
@ -0,0 +1,77 @@
|
|||
package net.osmand.aidlapi.customization;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcel;
|
||||
|
||||
import net.osmand.aidlapi.AidlParams;
|
||||
|
||||
public class MapMarginsParams extends AidlParams {
|
||||
|
||||
private String appModeKey;
|
||||
private int leftMargin;
|
||||
private int topMargin;
|
||||
private int rightMargin;
|
||||
private int bottomMargin;
|
||||
|
||||
public MapMarginsParams(String appModeKey, int leftMargin, int topMargin, int rightMargin, int bottomMargin) {
|
||||
this.appModeKey = appModeKey;
|
||||
this.leftMargin = leftMargin;
|
||||
this.topMargin = topMargin;
|
||||
this.rightMargin = rightMargin;
|
||||
this.bottomMargin = bottomMargin;
|
||||
}
|
||||
|
||||
public MapMarginsParams(Parcel in) {
|
||||
readFromParcel(in);
|
||||
}
|
||||
|
||||
public static final Creator<MapMarginsParams> CREATOR = new Creator<MapMarginsParams>() {
|
||||
@Override
|
||||
public MapMarginsParams createFromParcel(Parcel in) {
|
||||
return new MapMarginsParams(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapMarginsParams[] newArray(int size) {
|
||||
return new MapMarginsParams[size];
|
||||
}
|
||||
};
|
||||
|
||||
public String getAppModeKey() {
|
||||
return appModeKey;
|
||||
}
|
||||
|
||||
public int getLeftMargin() {
|
||||
return leftMargin;
|
||||
}
|
||||
|
||||
public int getTopMargin() {
|
||||
return topMargin;
|
||||
}
|
||||
|
||||
public int getRightMargin() {
|
||||
return rightMargin;
|
||||
}
|
||||
|
||||
public int getBottomMargin() {
|
||||
return bottomMargin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToBundle(Bundle bundle) {
|
||||
bundle.putString("appModeKey", appModeKey);
|
||||
bundle.putInt("leftMargin", leftMargin);
|
||||
bundle.putInt("topMargin", topMargin);
|
||||
bundle.putInt("rightMargin", rightMargin);
|
||||
bundle.putInt("bottomMargin", bottomMargin);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void readFromBundle(Bundle bundle) {
|
||||
appModeKey = bundle.getString("appModeKey");
|
||||
leftMargin = bundle.getInt("leftMargin");
|
||||
topMargin = bundle.getInt("topMargin");
|
||||
rightMargin = bundle.getInt("rightMargin");
|
||||
bottomMargin = bundle.getInt("bottomMargin");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
package net.osmand.aidlapi.events;
|
||||
parcelable AKeyEventsParams;
|
|
@ -0,0 +1,73 @@
|
|||
package net.osmand.aidlapi.events;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import net.osmand.aidlapi.AidlParams;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class AKeyEventsParams extends AidlParams {
|
||||
|
||||
private long callbackId = -1L;
|
||||
private boolean subscribeToUpdates = true;
|
||||
private ArrayList<Integer> keyEventList;
|
||||
|
||||
public AKeyEventsParams() {
|
||||
}
|
||||
|
||||
protected AKeyEventsParams(Parcel in) {
|
||||
readFromParcel(in);
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<AKeyEventsParams> CREATOR = new Parcelable.Creator<AKeyEventsParams>() {
|
||||
@Override
|
||||
public AKeyEventsParams createFromParcel(Parcel in) {
|
||||
return new AKeyEventsParams(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AKeyEventsParams[] newArray(int size) {
|
||||
return new AKeyEventsParams[size];
|
||||
}
|
||||
};
|
||||
|
||||
public long getCallbackId() {
|
||||
return callbackId;
|
||||
}
|
||||
|
||||
public void setCallbackId(long callbackId) {
|
||||
this.callbackId = callbackId;
|
||||
}
|
||||
|
||||
public void setSubscribeToUpdates(boolean subscribeToUpdates) {
|
||||
this.subscribeToUpdates = subscribeToUpdates;
|
||||
}
|
||||
|
||||
public boolean isSubscribeToUpdates() {
|
||||
return subscribeToUpdates;
|
||||
}
|
||||
|
||||
public void setKeyEventList(ArrayList<Integer> keyEventList) {
|
||||
this.keyEventList = keyEventList;
|
||||
}
|
||||
|
||||
public ArrayList<Integer> getKeyEventList() {
|
||||
return keyEventList;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void readFromBundle(Bundle bundle) {
|
||||
callbackId = bundle.getLong("callbackId");
|
||||
subscribeToUpdates = bundle.getBoolean("subscribeToUpdates");
|
||||
keyEventList = bundle.getIntegerArrayList("keyEventList");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToBundle(Bundle bundle) {
|
||||
bundle.putLong("callbackId", callbackId);
|
||||
bundle.putBoolean("subscribeToUpdates", subscribeToUpdates);
|
||||
bundle.putIntegerArrayList("keyEventList", keyEventList);
|
||||
}
|
||||
}
|
|
@ -11,16 +11,18 @@ public class AFavorite extends AidlParams {
|
|||
private double lon;
|
||||
private String name;
|
||||
private String description;
|
||||
private String address;
|
||||
private String category;
|
||||
private String color;
|
||||
private boolean visible;
|
||||
|
||||
public AFavorite(double lat, double lon, String name, String description,
|
||||
public AFavorite(double lat, double lon, String name, String description, String address,
|
||||
String category, String color, boolean visible) {
|
||||
this.lat = lat;
|
||||
this.lon = lon;
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
this.address = address;
|
||||
this.category = category;
|
||||
this.color = color;
|
||||
this.visible = visible;
|
||||
|
@ -58,6 +60,8 @@ public class AFavorite extends AidlParams {
|
|||
return description;
|
||||
}
|
||||
|
||||
public String getAddress() { return address; }
|
||||
|
||||
public String getCategory() {
|
||||
return category;
|
||||
}
|
||||
|
@ -76,6 +80,7 @@ public class AFavorite extends AidlParams {
|
|||
bundle.putDouble("lon", lon);
|
||||
bundle.putString("name", name);
|
||||
bundle.putString("description", description);
|
||||
bundle.putString("address", address);
|
||||
bundle.putString("category", category);
|
||||
bundle.putString("color", color);
|
||||
bundle.putBoolean("visible", visible);
|
||||
|
@ -87,6 +92,7 @@ public class AFavorite extends AidlParams {
|
|||
lon = bundle.getDouble("lon");
|
||||
name = bundle.getString("name");
|
||||
description = bundle.getString("description");
|
||||
address = bundle.getString("address");
|
||||
category = bundle.getString("category");
|
||||
color = bundle.getString("color");
|
||||
visible = bundle.getBoolean("visible");
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
package net.osmand.aidlapi.info;
|
||||
|
||||
parcelable AppInfoParams;
|
95
OsmAnd-api/src/net/osmand/aidlapi/info/AppInfoParams.java
Normal file
|
@ -0,0 +1,95 @@
|
|||
package net.osmand.aidlapi.info;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcel;
|
||||
|
||||
import net.osmand.aidlapi.AidlParams;
|
||||
import net.osmand.aidlapi.map.ALatLon;
|
||||
|
||||
public class AppInfoParams extends AidlParams {
|
||||
|
||||
private ALatLon lastKnownLocation;
|
||||
private ALatLon mapLocation;
|
||||
|
||||
private Bundle turnInfo;
|
||||
private int leftTime;
|
||||
private int leftDistance;
|
||||
private long arrivalTime;
|
||||
private boolean mapVisible;
|
||||
|
||||
public AppInfoParams(ALatLon lastKnownLocation, ALatLon mapLocation, Bundle turnInfo, int leftTime, int leftDistance, long arrivalTime, boolean mapVisible) {
|
||||
this.lastKnownLocation = lastKnownLocation;
|
||||
this.mapLocation = mapLocation;
|
||||
this.leftTime = leftTime;
|
||||
this.leftDistance = leftDistance;
|
||||
this.arrivalTime = arrivalTime;
|
||||
this.turnInfo = turnInfo;
|
||||
this.mapVisible = mapVisible;
|
||||
}
|
||||
|
||||
public AppInfoParams(Parcel in) {
|
||||
readFromParcel(in);
|
||||
}
|
||||
|
||||
public static final Creator<AppInfoParams> CREATOR = new Creator<AppInfoParams>() {
|
||||
@Override
|
||||
public AppInfoParams createFromParcel(Parcel in) {
|
||||
return new AppInfoParams(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AppInfoParams[] newArray(int size) {
|
||||
return new AppInfoParams[size];
|
||||
}
|
||||
};
|
||||
|
||||
public ALatLon getLastKnownLocation() {
|
||||
return lastKnownLocation;
|
||||
}
|
||||
|
||||
public ALatLon getMapLocation() {
|
||||
return mapLocation;
|
||||
}
|
||||
|
||||
public int getLeftTime() {
|
||||
return leftTime;
|
||||
}
|
||||
|
||||
public long getArrivalTime() {
|
||||
return arrivalTime;
|
||||
}
|
||||
|
||||
public int getLeftDistance() {
|
||||
return leftDistance;
|
||||
}
|
||||
|
||||
public boolean isMapVisible() {
|
||||
return mapVisible;
|
||||
}
|
||||
|
||||
public Bundle getTurnInfo() {
|
||||
return turnInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToBundle(Bundle bundle) {
|
||||
bundle.putParcelable("lastKnownLocation", lastKnownLocation);
|
||||
bundle.putParcelable("mapLocation", mapLocation);
|
||||
bundle.putInt("leftTime", leftTime);
|
||||
bundle.putLong("arrivalTime", arrivalTime);
|
||||
bundle.putInt("leftDistance", leftDistance);
|
||||
bundle.putBundle("turnInfo", turnInfo);
|
||||
bundle.putBoolean("mapVisible", mapVisible);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void readFromBundle(Bundle bundle) {
|
||||
lastKnownLocation = bundle.getParcelable("lastKnownLocation");
|
||||
mapLocation = bundle.getParcelable("mapLocation");
|
||||
leftTime = bundle.getInt("leftTime");
|
||||
arrivalTime = bundle.getLong("arrivalTime");
|
||||
leftDistance = bundle.getInt("leftDistance");
|
||||
turnInfo = bundle.getBundle("turnInfo");
|
||||
mapVisible = bundle.getBoolean("mapVisible");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
package net.osmand.aidlapi.lock;
|
||||
|
||||
parcelable SetLockStateParams;
|
|
@ -0,0 +1,45 @@
|
|||
package net.osmand.aidlapi.lock;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcel;
|
||||
|
||||
import net.osmand.aidlapi.AidlParams;
|
||||
|
||||
public class SetLockStateParams extends AidlParams {
|
||||
|
||||
private boolean lock;
|
||||
|
||||
public SetLockStateParams(boolean lock) {
|
||||
this.lock = lock;
|
||||
}
|
||||
|
||||
public SetLockStateParams(Parcel in) {
|
||||
readFromParcel(in);
|
||||
}
|
||||
|
||||
public static final Creator<SetLockStateParams> CREATOR = new Creator<SetLockStateParams>() {
|
||||
@Override
|
||||
public SetLockStateParams createFromParcel(Parcel in) {
|
||||
return new SetLockStateParams(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SetLockStateParams[] newArray(int size) {
|
||||
return new SetLockStateParams[size];
|
||||
}
|
||||
};
|
||||
|
||||
public boolean getLockState() {
|
||||
return lock;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToBundle(Bundle bundle) {
|
||||
bundle.putBoolean("lock", this.lock);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void readFromBundle(Bundle bundle) {
|
||||
lock = bundle.getBoolean("lock");
|
||||
}
|
||||
}
|
|
@ -10,12 +10,14 @@ public class SetMapLocationParams extends AidlParams {
|
|||
private double latitude;
|
||||
private double longitude;
|
||||
private int zoom;
|
||||
private float rotation;
|
||||
private boolean animated;
|
||||
|
||||
public SetMapLocationParams(double latitude, double longitude, int zoom, boolean animated) {
|
||||
public SetMapLocationParams(double latitude, double longitude, int zoom, float rotation, boolean animated) {
|
||||
this.latitude = latitude;
|
||||
this.longitude = longitude;
|
||||
this.zoom = zoom;
|
||||
this.rotation = rotation;
|
||||
this.animated = animated;
|
||||
}
|
||||
|
||||
|
@ -47,6 +49,10 @@ public class SetMapLocationParams extends AidlParams {
|
|||
return zoom;
|
||||
}
|
||||
|
||||
public float getRotation() {
|
||||
return rotation;
|
||||
}
|
||||
|
||||
public boolean isAnimated() {
|
||||
return animated;
|
||||
}
|
||||
|
@ -56,6 +62,7 @@ public class SetMapLocationParams extends AidlParams {
|
|||
bundle.putDouble("latitude", latitude);
|
||||
bundle.putDouble("longitude", longitude);
|
||||
bundle.putInt("zoom", zoom);
|
||||
bundle.putFloat("rotation", rotation);
|
||||
bundle.putBoolean("animated", animated);
|
||||
}
|
||||
|
||||
|
@ -64,6 +71,7 @@ public class SetMapLocationParams extends AidlParams {
|
|||
latitude = bundle.getDouble("latitude");
|
||||
longitude = bundle.getDouble("longitude");
|
||||
zoom = bundle.getInt("zoom");
|
||||
rotation = bundle.getFloat("rotation");
|
||||
animated = bundle.getBoolean("animated");
|
||||
}
|
||||
}
|
|
@ -2,6 +2,9 @@
|
|||
package net.osmand;
|
||||
|
||||
|
||||
import net.osmand.binary.StringBundle;
|
||||
import net.osmand.binary.StringBundleWriter;
|
||||
import net.osmand.binary.StringBundleXmlWriter;
|
||||
import net.osmand.data.QuadRect;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
||||
|
@ -13,7 +16,6 @@ import org.xmlpull.v1.XmlSerializer;
|
|||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
@ -49,6 +51,8 @@ public class GPXUtilities {
|
|||
private static final String ICON_NAME_EXTENSION = "icon";
|
||||
private static final String DEFAULT_ICON_NAME = "special_star";
|
||||
private static final String BACKGROUND_TYPE_EXTENSION = "background";
|
||||
private static final String PROFILE_TYPE_EXTENSION = "profile";
|
||||
private static final String TRKPT_INDEX_EXTENSION = "trkpt_idx";
|
||||
|
||||
private 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$
|
||||
|
@ -125,6 +129,13 @@ public class GPXUtilities {
|
|||
return extensions;
|
||||
}
|
||||
|
||||
public void copyExtensions(GPXExtensions e) {
|
||||
Map<String, String> extensionsToRead = e.getExtensionsToRead();
|
||||
if (!extensionsToRead.isEmpty()) {
|
||||
getExtensionsToWrite().putAll(extensionsToRead);
|
||||
}
|
||||
}
|
||||
|
||||
public GPXExtensionsWriter getExtensionsWriter() {
|
||||
return extensionsWriter;
|
||||
}
|
||||
|
@ -305,6 +316,30 @@ public class GPXUtilities {
|
|||
getExtensionsToWrite().put(BACKGROUND_TYPE_EXTENSION, backType);
|
||||
}
|
||||
|
||||
public String getProfileType() {
|
||||
return getExtensionsToRead().get(PROFILE_TYPE_EXTENSION);
|
||||
}
|
||||
|
||||
public void setProfileType(String profileType) {
|
||||
getExtensionsToWrite().put(PROFILE_TYPE_EXTENSION, profileType);
|
||||
}
|
||||
|
||||
public void removeProfileType() {
|
||||
getExtensionsToWrite().remove(PROFILE_TYPE_EXTENSION);
|
||||
}
|
||||
|
||||
public int getTrkPtIndex() {
|
||||
try {
|
||||
return Integer.parseInt(getExtensionsToRead().get(TRKPT_INDEX_EXTENSION));
|
||||
} catch (NumberFormatException e) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public void setTrkPtIndex(int index) {
|
||||
getExtensionsToWrite().put(TRKPT_INDEX_EXTENSION, String.valueOf(index));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
|
@ -415,6 +450,65 @@ public class GPXUtilities {
|
|||
public double maxlon;
|
||||
}
|
||||
|
||||
public static class RouteSegment {
|
||||
public String id;
|
||||
public String length;
|
||||
public String segmentTime;
|
||||
public String speed;
|
||||
public String turnType;
|
||||
public String turnAngle;
|
||||
public String types;
|
||||
public String pointTypes;
|
||||
public String names;
|
||||
|
||||
public static RouteSegment fromStringBundle(StringBundle bundle) {
|
||||
RouteSegment s = new RouteSegment();
|
||||
s.id = bundle.getString("id", null);
|
||||
s.length = bundle.getString("length", null);
|
||||
s.segmentTime = bundle.getString("segmentTime", null);
|
||||
s.speed = bundle.getString("speed", null);
|
||||
s.turnType = bundle.getString("turnType", null);
|
||||
s.turnAngle = bundle.getString("turnAngle", null);
|
||||
s.types = bundle.getString("types", null);
|
||||
s.pointTypes = bundle.getString("pointTypes", null);
|
||||
s.names = bundle.getString("names", null);
|
||||
return s;
|
||||
}
|
||||
|
||||
public StringBundle toStringBundle() {
|
||||
StringBundle bundle = new StringBundle();
|
||||
bundle.putString("id", id);
|
||||
bundle.putString("length", length);
|
||||
bundle.putString("segmentTime", segmentTime);
|
||||
bundle.putString("speed", speed);
|
||||
bundle.putString("turnType", turnType);
|
||||
bundle.putString("turnAngle", turnAngle);
|
||||
bundle.putString("types", types);
|
||||
bundle.putString("pointTypes", pointTypes);
|
||||
bundle.putString("names", names);
|
||||
return bundle;
|
||||
}
|
||||
}
|
||||
|
||||
public static class RouteType {
|
||||
public String tag;
|
||||
public String value;
|
||||
|
||||
public static RouteType fromStringBundle(StringBundle bundle) {
|
||||
RouteType t = new RouteType();
|
||||
t.tag = bundle.getString("t", null);
|
||||
t.value = bundle.getString("v", null);
|
||||
return t;
|
||||
}
|
||||
|
||||
public StringBundle toStringBundle() {
|
||||
StringBundle bundle = new StringBundle();
|
||||
bundle.putString("t", tag);
|
||||
bundle.putString("v", value);
|
||||
return bundle;
|
||||
}
|
||||
}
|
||||
|
||||
public static class GPXTrackAnalysis {
|
||||
public float totalDistance = 0;
|
||||
public float totalDistanceWithoutGaps = 0;
|
||||
|
@ -984,6 +1078,9 @@ public class GPXUtilities {
|
|||
private List<WptPt> points = new ArrayList<>();
|
||||
public List<Route> routes = new ArrayList<>();
|
||||
|
||||
public List<RouteSegment> routeSegments = new ArrayList<>();
|
||||
public List<RouteType> routeTypes = new ArrayList<>();
|
||||
|
||||
public Exception error = null;
|
||||
public String path = "";
|
||||
public boolean showCurrentTrack;
|
||||
|
@ -1010,6 +1107,10 @@ public class GPXUtilities {
|
|||
}
|
||||
}
|
||||
|
||||
public boolean hasRoute() {
|
||||
return !routeSegments.isEmpty() && !routeTypes.isEmpty();
|
||||
}
|
||||
|
||||
public List<WptPt> getPoints() {
|
||||
return Collections.unmodifiableList(points);
|
||||
}
|
||||
|
@ -1217,6 +1318,17 @@ public class GPXUtilities {
|
|||
return pt;
|
||||
}
|
||||
|
||||
public TrkSegment getNonEmptyTrkSegment() {
|
||||
for (GPXUtilities.Track t : tracks) {
|
||||
for (TrkSegment s : t.segments) {
|
||||
if (s.points.size() > 0) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void addTrkSegment(List<WptPt> points) {
|
||||
removeGeneralTrackIfExists();
|
||||
|
||||
|
@ -1514,52 +1626,42 @@ public class GPXUtilities {
|
|||
return new QuadRect(left, top, right, bottom);
|
||||
}
|
||||
|
||||
public int getGradientScaleColor(GradientScaleType gradientScaleType, int defColor) {
|
||||
public int getGradientScaleColor(String gradientScaleType, int defColor) {
|
||||
String clrValue = null;
|
||||
if (extensions != null) {
|
||||
clrValue = extensions.get(gradientScaleType.getTypeName());
|
||||
clrValue = extensions.get(gradientScaleType);
|
||||
}
|
||||
return parseColor(clrValue, defColor);
|
||||
}
|
||||
|
||||
public void setGradientScaleColor(GradientScaleType gradientScaleType, int gradientScaleColor) {
|
||||
getExtensionsToWrite().put(gradientScaleType.getTypeName(), Algorithms.colorToString(gradientScaleColor));
|
||||
public void setGradientScaleColor(String gradientScaleType, int gradientScaleColor) {
|
||||
getExtensionsToWrite().put(gradientScaleType, Algorithms.colorToString(gradientScaleColor));
|
||||
}
|
||||
|
||||
public GradientScaleType getGradientScaleType() {
|
||||
public String getGradientScaleType() {
|
||||
if (extensions != null) {
|
||||
String gradientScaleTypeName = extensions.get("gradient_scale_type");
|
||||
if (!Algorithms.isEmpty(gradientScaleTypeName)) {
|
||||
try {
|
||||
return GradientScaleType.valueOf(gradientScaleTypeName);
|
||||
} catch (IllegalArgumentException e) {
|
||||
log.error("Error reading gradientScaleType", e);
|
||||
}
|
||||
}
|
||||
return extensions.get("gradient_scale_type");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setGradientScaleType(GradientScaleType gradientScaleType) {
|
||||
getExtensionsToWrite().put("gradient_scale_type", gradientScaleType.name());
|
||||
public void setGradientScaleType(String gradientScaleType) {
|
||||
getExtensionsToWrite().put("gradient_scale_type", gradientScaleType);
|
||||
}
|
||||
|
||||
public GpxSplitType getSplitType() {
|
||||
public void removeGradientScaleType() {
|
||||
getExtensionsToWrite().remove("gradient_scale_type");
|
||||
}
|
||||
|
||||
public String getSplitType() {
|
||||
if (extensions != null) {
|
||||
String gradientScaleTypeName = extensions.get("split_type");
|
||||
if (!Algorithms.isEmpty(gradientScaleTypeName)) {
|
||||
try {
|
||||
return GpxSplitType.valueOf(gradientScaleTypeName);
|
||||
} catch (IllegalArgumentException e) {
|
||||
log.error("Error reading GpxSplitType", e);
|
||||
}
|
||||
}
|
||||
return extensions.get("split_type");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setSplitType(GpxSplitType gpxSplitType) {
|
||||
getExtensionsToWrite().put("split_type", gpxSplitType.name());
|
||||
public void setSplitType(String gpxSplitType) {
|
||||
getExtensionsToWrite().put("split_type", gpxSplitType);
|
||||
}
|
||||
|
||||
public double getSplitInterval() {
|
||||
|
@ -1614,38 +1716,6 @@ public class GPXUtilities {
|
|||
public void setShowStartFinish(boolean showStartFinish) {
|
||||
getExtensionsToWrite().put("show_start_finish", String.valueOf(showStartFinish));
|
||||
}
|
||||
|
||||
public enum GradientScaleType {
|
||||
SPEED("gradient_speed_color"),
|
||||
ALTITUDE("gradient_altitude_color"),
|
||||
SLOPE("gradient_slope_color");
|
||||
|
||||
private String typeName;
|
||||
|
||||
GradientScaleType(String typeName) {
|
||||
this.typeName = typeName;
|
||||
}
|
||||
|
||||
public String getTypeName() {
|
||||
return typeName;
|
||||
}
|
||||
}
|
||||
|
||||
public enum GpxSplitType {
|
||||
NO_SPLIT(-1),
|
||||
DISTANCE(1),
|
||||
TIME(2);
|
||||
|
||||
private int type;
|
||||
|
||||
GpxSplitType(int type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static String asString(GPXFile file) {
|
||||
|
@ -1764,6 +1834,7 @@ public class GPXUtilities {
|
|||
serializer.endTag(null, "wpt"); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
assignRouteExtensionWriter(file);
|
||||
writeExtensions(serializer, file);
|
||||
|
||||
serializer.endTag(null, "gpx"); //$NON-NLS-1$
|
||||
|
@ -1776,6 +1847,29 @@ public class GPXUtilities {
|
|||
return null;
|
||||
}
|
||||
|
||||
private static void assignRouteExtensionWriter(final GPXFile gpxFile) {
|
||||
if (gpxFile.hasRoute() && gpxFile.getExtensionsWriter() == null) {
|
||||
gpxFile.setExtensionsWriter(new GPXExtensionsWriter() {
|
||||
@Override
|
||||
public void writeExtensions(XmlSerializer serializer) {
|
||||
StringBundle bundle = new StringBundle();
|
||||
List<StringBundle> segmentsBundle = new ArrayList<>();
|
||||
for (RouteSegment segment : gpxFile.routeSegments) {
|
||||
segmentsBundle.add(segment.toStringBundle());
|
||||
}
|
||||
bundle.putBundleList("route", "segment", segmentsBundle);
|
||||
List<StringBundle> typesBundle = new ArrayList<>();
|
||||
for (RouteType routeType : gpxFile.routeTypes) {
|
||||
typesBundle.add(routeType.toStringBundle());
|
||||
}
|
||||
bundle.putBundleList("types", "type", typesBundle);
|
||||
StringBundleWriter bundleWriter = new StringBundleXmlWriter(bundle, serializer);
|
||||
bundleWriter.writeBundle();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static String getFilename(String path) {
|
||||
if(path != null) {
|
||||
int i = path.lastIndexOf('/');
|
||||
|
@ -1993,23 +2087,7 @@ public class GPXUtilities {
|
|||
}
|
||||
|
||||
public static GPXFile loadGPXFile(InputStream f) {
|
||||
return loadGPXFile(f, null, null);
|
||||
}
|
||||
|
||||
public static GPXFile loadGPXFile(InputStream f, GPXFile gpxFile, GPXExtensionsReader extensionsReader) {
|
||||
boolean readExtensionsOnly = false;
|
||||
if (gpxFile == null) {
|
||||
gpxFile = new GPXFile(null);
|
||||
} else {
|
||||
if (f == null) {
|
||||
try {
|
||||
f = new FileInputStream(new File(gpxFile.path));
|
||||
} catch (FileNotFoundException e) {
|
||||
return gpxFile;
|
||||
}
|
||||
}
|
||||
readExtensionsOnly = extensionsReader != null;
|
||||
}
|
||||
GPXFile gpxFile = new GPXFile(null);
|
||||
SimpleDateFormat format = new SimpleDateFormat(GPX_TIME_FORMAT, Locale.US);
|
||||
format.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
SimpleDateFormat formatMillis = new SimpleDateFormat(GPX_TIME_FORMAT_MILLIS, Locale.US);
|
||||
|
@ -2023,6 +2101,10 @@ public class GPXUtilities {
|
|||
Stack<GPXExtensions> parserState = new Stack<>();
|
||||
boolean extensionReadMode = false;
|
||||
boolean routePointExtension = false;
|
||||
List<RouteSegment> routeSegments = gpxFile.routeSegments;
|
||||
List<RouteType> routeTypes = gpxFile.routeTypes;
|
||||
boolean routeExtension = false;
|
||||
boolean typesExtension = false;
|
||||
parserState.push(gpxFile);
|
||||
int tok;
|
||||
while ((tok = parser.next()) != XmlPullParser.END_DOCUMENT) {
|
||||
|
@ -2031,37 +2113,50 @@ public class GPXUtilities {
|
|||
String tag = parser.getName();
|
||||
if (extensionReadMode && parse != null && !routePointExtension) {
|
||||
String tagName = tag.toLowerCase();
|
||||
boolean extensionsRead = false;
|
||||
if (extensionsReader != null) {
|
||||
extensionsRead = extensionsReader.readExtensions(gpxFile, parser);
|
||||
if (routeExtension) {
|
||||
if (tagName.equals("segment")) {
|
||||
RouteSegment segment = parseRouteSegmentAttributes(parser);
|
||||
routeSegments.add(segment);
|
||||
}
|
||||
} else if (typesExtension) {
|
||||
if (tagName.equals("type")) {
|
||||
RouteType type = parseRouteTypeAttributes(parser);
|
||||
routeTypes.add(type);
|
||||
}
|
||||
}
|
||||
if (!readExtensionsOnly && !extensionsRead) {
|
||||
switch (tagName) {
|
||||
case "routepointextension":
|
||||
routePointExtension = true;
|
||||
if (parse instanceof WptPt) {
|
||||
parse.getExtensionsToWrite().put("offset", routeTrackSegment.points.size() + "");
|
||||
}
|
||||
break;
|
||||
switch (tagName) {
|
||||
case "routepointextension":
|
||||
routePointExtension = true;
|
||||
if (parse instanceof WptPt) {
|
||||
parse.getExtensionsToWrite().put("offset", routeTrackSegment.points.size() + "");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
Map<String, String> values = readTextMap(parser, tag);
|
||||
if (values.size() > 0) {
|
||||
for (Entry<String, String> entry : values.entrySet()) {
|
||||
String t = entry.getKey().toLowerCase();
|
||||
String value = entry.getValue();
|
||||
parse.getExtensionsToWrite().put(t, value);
|
||||
if (tag.equals("speed") && parse instanceof WptPt) {
|
||||
try {
|
||||
((WptPt) parse).speed = Float.parseFloat(value);
|
||||
} catch (NumberFormatException e) {
|
||||
log.debug(e.getMessage(), e);
|
||||
}
|
||||
case "route":
|
||||
routeExtension = true;
|
||||
break;
|
||||
|
||||
case "types":
|
||||
typesExtension = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
Map<String, String> values = readTextMap(parser, tag);
|
||||
if (values.size() > 0) {
|
||||
for (Entry<String, String> entry : values.entrySet()) {
|
||||
String t = entry.getKey().toLowerCase();
|
||||
String value = entry.getValue();
|
||||
parse.getExtensionsToWrite().put(t, value);
|
||||
if (tag.equals("speed") && parse instanceof WptPt) {
|
||||
try {
|
||||
((WptPt) parse).speed = Float.parseFloat(value);
|
||||
} catch (NumberFormatException e) {
|
||||
log.debug(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else if (parse != null && tag.equals("extensions")) {
|
||||
extensionReadMode = true;
|
||||
|
@ -2071,7 +2166,7 @@ public class GPXUtilities {
|
|||
routeTrackSegment.points.add(wptPt);
|
||||
parserState.push(wptPt);
|
||||
}
|
||||
} else if (!readExtensionsOnly) {
|
||||
} else {
|
||||
if (parse instanceof GPXFile) {
|
||||
if (tag.equals("gpx")) {
|
||||
((GPXFile) parse).author = parser.getAttributeValue("", "creator");
|
||||
|
@ -2267,7 +2362,12 @@ public class GPXUtilities {
|
|||
if (parse != null && tag.equals("extensions")) {
|
||||
extensionReadMode = false;
|
||||
}
|
||||
if (readExtensionsOnly) {
|
||||
if (extensionReadMode && tag.equals("route")) {
|
||||
routeExtension = false;
|
||||
continue;
|
||||
}
|
||||
if (extensionReadMode && tag.equals("types")) {
|
||||
typesExtension = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -2347,6 +2447,27 @@ public class GPXUtilities {
|
|||
return wpt;
|
||||
}
|
||||
|
||||
private static RouteSegment parseRouteSegmentAttributes(XmlPullParser parser) {
|
||||
RouteSegment segment = new RouteSegment();
|
||||
segment.id = parser.getAttributeValue("", "id");
|
||||
segment.length = parser.getAttributeValue("", "length");
|
||||
segment.segmentTime = parser.getAttributeValue("", "segmentTime");
|
||||
segment.speed = parser.getAttributeValue("", "speed");
|
||||
segment.turnType = parser.getAttributeValue("", "turnType");
|
||||
segment.turnAngle = parser.getAttributeValue("", "turnAngle");
|
||||
segment.types = parser.getAttributeValue("", "types");
|
||||
segment.pointTypes = parser.getAttributeValue("", "pointTypes");
|
||||
segment.names = parser.getAttributeValue("", "names");
|
||||
return segment;
|
||||
}
|
||||
|
||||
private static RouteType parseRouteTypeAttributes(XmlPullParser parser) {
|
||||
RouteType type = new RouteType();
|
||||
type.tag = parser.getAttributeValue("", "t");
|
||||
type.value = parser.getAttributeValue("", "v");
|
||||
return type;
|
||||
}
|
||||
|
||||
private static Bounds parseBoundsAttributes(XmlPullParser parser) {
|
||||
Bounds bounds = new Bounds();
|
||||
try {
|
||||
|
|
|
@ -45,6 +45,9 @@ public class IndexConstants {
|
|||
|
||||
public static final String GPX_FILE_EXT = ".gpx"; //$NON-NLS-1$
|
||||
|
||||
public static final String WPT_CHART_FILE_EXT = ".wpt.chart";
|
||||
public static final String SQLITE_CHART_FILE_EXT = ".3d.chart";
|
||||
|
||||
public final static String POI_TABLE = "poi"; //$NON-NLS-1$
|
||||
|
||||
public static final String INDEX_DOWNLOAD_DOMAIN = "download.osmand.net";
|
||||
|
|
159
OsmAnd-java/src/main/java/net/osmand/LocationsHolder.java
Normal file
|
@ -0,0 +1,159 @@
|
|||
package net.osmand;
|
||||
|
||||
import net.osmand.GPXUtilities.WptPt;
|
||||
import net.osmand.data.LatLon;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class LocationsHolder {
|
||||
|
||||
private static final int LOCATION_TYPE_UNKNOWN = -1;
|
||||
private static final int LOCATION_TYPE_LATLON = 0;
|
||||
private static final int LOCATION_TYPE_LOCATION = 1;
|
||||
private static final int LOCATION_TYPE_WPTPT = 2;
|
||||
|
||||
private List<LatLon> latLonList;
|
||||
private List<Location> locationList;
|
||||
private List<WptPt> wptPtList;
|
||||
private int locationType;
|
||||
private int size;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public LocationsHolder(List<?> locations) {
|
||||
this.locationType = resolveLocationType(locations);
|
||||
switch (locationType) {
|
||||
case LOCATION_TYPE_LATLON:
|
||||
latLonList = new ArrayList<>((List<LatLon>) locations);
|
||||
size = locations.size();
|
||||
break;
|
||||
case LOCATION_TYPE_LOCATION:
|
||||
locationList = new ArrayList<>((List<Location>) locations);
|
||||
size = locations.size();
|
||||
break;
|
||||
case LOCATION_TYPE_WPTPT:
|
||||
wptPtList = new ArrayList<>((List<WptPt>) locations);
|
||||
size = locations.size();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private int resolveLocationType(List<?> locations) {
|
||||
if (!Algorithms.isEmpty(locations)) {
|
||||
Object locationObj = locations.get(0);
|
||||
if (locationObj instanceof LatLon) {
|
||||
return LOCATION_TYPE_LATLON;
|
||||
} else if (locationObj instanceof WptPt) {
|
||||
return LOCATION_TYPE_WPTPT;
|
||||
} else if (locationObj instanceof Location) {
|
||||
return LOCATION_TYPE_LOCATION;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported location type: " + locationObj.getClass().getSimpleName());
|
||||
}
|
||||
}
|
||||
return LOCATION_TYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
public double getLatitude(int index) {
|
||||
switch (locationType) {
|
||||
case LOCATION_TYPE_LATLON:
|
||||
return latLonList.get(index).getLatitude();
|
||||
case LOCATION_TYPE_LOCATION:
|
||||
return locationList.get(index).getLatitude();
|
||||
case LOCATION_TYPE_WPTPT:
|
||||
return wptPtList.get(index).getLatitude();
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public double getLongitude(int index) {
|
||||
switch (locationType) {
|
||||
case LOCATION_TYPE_LATLON:
|
||||
return latLonList.get(index).getLongitude();
|
||||
case LOCATION_TYPE_LOCATION:
|
||||
return locationList.get(index).getLongitude();
|
||||
case LOCATION_TYPE_WPTPT:
|
||||
return wptPtList.get(index).getLongitude();
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> List<T> getList(int locationType) {
|
||||
List<T> res = new ArrayList<>();
|
||||
if (size > 0) {
|
||||
for (int i = 0; i < size; i++) {
|
||||
switch (locationType) {
|
||||
case LOCATION_TYPE_LATLON:
|
||||
res.add((T) getLatLon(i));
|
||||
break;
|
||||
case LOCATION_TYPE_LOCATION:
|
||||
res.add((T) getLocation(i));
|
||||
break;
|
||||
case LOCATION_TYPE_WPTPT:
|
||||
res.add((T) getWptPt(i));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public List<LatLon> getLatLonList() {
|
||||
if (this.locationType == LOCATION_TYPE_LATLON) {
|
||||
return latLonList;
|
||||
} else {
|
||||
return getList(LOCATION_TYPE_LATLON);
|
||||
}
|
||||
}
|
||||
|
||||
public List<WptPt> getWptPtList() {
|
||||
if (this.locationType == LOCATION_TYPE_WPTPT) {
|
||||
return wptPtList;
|
||||
} else {
|
||||
return getList(LOCATION_TYPE_WPTPT);
|
||||
}
|
||||
}
|
||||
|
||||
public List<Location> getLocationsList() {
|
||||
if (this.locationType == LOCATION_TYPE_LOCATION) {
|
||||
return locationList;
|
||||
} else {
|
||||
return getList(LOCATION_TYPE_LOCATION);
|
||||
}
|
||||
}
|
||||
|
||||
public LatLon getLatLon(int index) {
|
||||
if (this.locationType == LOCATION_TYPE_LATLON) {
|
||||
return latLonList.get(index);
|
||||
} else {
|
||||
return new LatLon(getLatitude(index), getLongitude(index));
|
||||
}
|
||||
}
|
||||
|
||||
public WptPt getWptPt(int index) {
|
||||
if (this.locationType == LOCATION_TYPE_WPTPT) {
|
||||
return wptPtList.get(index);
|
||||
} else {
|
||||
WptPt wptPt = new WptPt();
|
||||
wptPt.lat = getLatitude(index);
|
||||
wptPt.lon = getLongitude(index);
|
||||
return wptPt;
|
||||
}
|
||||
}
|
||||
|
||||
public Location getLocation(int index) {
|
||||
if (this.locationType == LOCATION_TYPE_LOCATION) {
|
||||
return locationList.get(index);
|
||||
} else {
|
||||
return new Location("", getLatitude(index), getLongitude(index));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -696,6 +696,7 @@ public class BinaryMapIndexReader {
|
|||
private void readMapIndex(MapIndex index, boolean onlyInitEncodingRules) throws IOException {
|
||||
int defaultId = 1;
|
||||
int oldLimit;
|
||||
int encodingRulesSize = 0;
|
||||
while (true) {
|
||||
int t = codedIS.readTag();
|
||||
int tag = WireFormat.getTagFieldNumber(t);
|
||||
|
@ -712,10 +713,14 @@ public class BinaryMapIndexReader {
|
|||
break;
|
||||
case OsmandOdb.OsmAndMapIndex.RULES_FIELD_NUMBER :
|
||||
if (onlyInitEncodingRules) {
|
||||
if(encodingRulesSize == 0) {
|
||||
encodingRulesSize = codedIS.getTotalBytesRead();
|
||||
}
|
||||
int len = codedIS.readInt32();
|
||||
oldLimit = codedIS.pushLimit(len);
|
||||
readMapEncodingRule(index, defaultId++);
|
||||
codedIS.popLimit(oldLimit);
|
||||
index.encodingRulesSizeBytes = (codedIS.getTotalBytesRead() - encodingRulesSize);
|
||||
} else {
|
||||
skipUnknownField(t);
|
||||
}
|
||||
|
@ -1829,10 +1834,13 @@ public class BinaryMapIndexReader {
|
|||
public int onewayReverseAttribute = -1;
|
||||
public TIntHashSet positiveLayers = new TIntHashSet(2);
|
||||
public TIntHashSet negativeLayers = new TIntHashSet(2);
|
||||
public int encodingRulesSizeBytes;
|
||||
|
||||
// to speed up comparision
|
||||
private MapIndex referenceMapIndex;
|
||||
|
||||
|
||||
|
||||
public Integer getRule(String t, String v) {
|
||||
Map<String, Integer> m = encodingRules.get(t);
|
||||
if (m != null) {
|
||||
|
|
|
@ -292,6 +292,7 @@ public class BinaryMapRouteReaderAdapter {
|
|||
public static class RouteRegion extends BinaryIndexPart {
|
||||
public int regionsRead;
|
||||
public List<RouteTypeRule> routeEncodingRules = new ArrayList<BinaryMapRouteReaderAdapter.RouteTypeRule>();
|
||||
public int routeEncodingRulesBytes = 0;
|
||||
public Map<String, Integer> decodingRules = null;
|
||||
List<RouteSubregion> subregions = new ArrayList<RouteSubregion>();
|
||||
List<RouteSubregion> basesubregions = new ArrayList<RouteSubregion>();
|
||||
|
@ -614,6 +615,7 @@ public class BinaryMapRouteReaderAdapter {
|
|||
|
||||
protected void readRouteIndex(RouteRegion region) throws IOException {
|
||||
int routeEncodingRule = 1;
|
||||
int routeEncodingRulesSize = 0;
|
||||
while(true){
|
||||
int t = codedIS.readTag();
|
||||
int tag = WireFormat.getTagFieldNumber(t);
|
||||
|
@ -626,10 +628,13 @@ public class BinaryMapRouteReaderAdapter {
|
|||
break;
|
||||
case OsmandOdb.OsmAndRoutingIndex.RULES_FIELD_NUMBER: {
|
||||
int len = codedIS.readInt32();
|
||||
if(routeEncodingRulesSize == 0) {
|
||||
routeEncodingRulesSize = codedIS.getTotalBytesRead();
|
||||
}
|
||||
int oldLimit = codedIS.pushLimit(len);
|
||||
readRouteEncodingRule(region, routeEncodingRule++);
|
||||
codedIS.skipRawBytes(codedIS.getBytesUntilLimit());
|
||||
codedIS.popLimit(oldLimit);
|
||||
region.routeEncodingRulesBytes = codedIS.getTotalBytesRead() - routeEncodingRulesSize;
|
||||
} break;
|
||||
case OsmandOdb.OsmAndRoutingIndex.ROOTBOXES_FIELD_NUMBER :
|
||||
case OsmandOdb.OsmAndRoutingIndex.BASEMAPBOXES_FIELD_NUMBER :{
|
||||
|
|
|
@ -21,7 +21,7 @@ public class StringBundle {
|
|||
private static final DecimalFormat FIVE_DIGITS_FORMATTER = new DecimalFormat("#.#####");
|
||||
private static final DecimalFormat SIX_DIGITS_FORMATTER = new DecimalFormat("#.######");
|
||||
|
||||
private Map<String, Item> map = new LinkedHashMap<>();
|
||||
private Map<String, Item<?>> map = new LinkedHashMap<>();
|
||||
|
||||
public enum ItemType {
|
||||
STRING,
|
||||
|
@ -32,7 +32,7 @@ public class StringBundle {
|
|||
public StringBundle() {
|
||||
}
|
||||
|
||||
protected StringBundle(Map<String, Item> map) {
|
||||
protected StringBundle(Map<String, Item<?>> map) {
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
|
@ -156,16 +156,16 @@ public class StringBundle {
|
|||
}
|
||||
}
|
||||
|
||||
public static class StringListItem extends Item<List<Item>> {
|
||||
public static class StringListItem extends Item<List<Item<?>>> {
|
||||
|
||||
private StringListItem(String name, List<Item> list) {
|
||||
private StringListItem(String name, List<Item<?>> list) {
|
||||
super(name, ItemType.LIST, list);
|
||||
}
|
||||
}
|
||||
|
||||
public static class StringMapItem extends Item<Map<String, Item>> {
|
||||
public static class StringMapItem extends Item<Map<String, Item<?>>> {
|
||||
|
||||
private StringMapItem(String name, Map<String, Item> map) {
|
||||
private StringMapItem(String name, Map<String, Item<?>> map) {
|
||||
super(name, ItemType.MAP, map);
|
||||
}
|
||||
}
|
||||
|
@ -177,11 +177,11 @@ public class StringBundle {
|
|||
}
|
||||
}
|
||||
|
||||
public Map<String, Item> getMap() {
|
||||
public Map<String, Item<?>> getMap() {
|
||||
return Collections.unmodifiableMap(map);
|
||||
}
|
||||
|
||||
public Item getItem(String key) {
|
||||
public Item<?> getItem(String key) {
|
||||
return map.get(key);
|
||||
}
|
||||
|
||||
|
@ -190,7 +190,7 @@ public class StringBundle {
|
|||
}
|
||||
|
||||
public int getInt(String key, int defaultValue) {
|
||||
Item item = map.get(key);
|
||||
Item<?> item = map.get(key);
|
||||
return item instanceof StringItem ? ((StringItem) item).asInt(defaultValue) : defaultValue;
|
||||
}
|
||||
|
||||
|
@ -199,7 +199,7 @@ public class StringBundle {
|
|||
}
|
||||
|
||||
public long getLong(String key, long defaultValue) {
|
||||
Item item = map.get(key);
|
||||
Item<?> item = map.get(key);
|
||||
return item instanceof StringItem ? ((StringItem) item).asLong(defaultValue) : defaultValue;
|
||||
}
|
||||
|
||||
|
@ -212,7 +212,7 @@ public class StringBundle {
|
|||
}
|
||||
|
||||
public float getFloat(String key, float defaultValue) {
|
||||
Item item = map.get(key);
|
||||
Item<?> item = map.get(key);
|
||||
return item instanceof StringItem ? ((StringItem) item).asFloat(defaultValue) : defaultValue;
|
||||
}
|
||||
|
||||
|
@ -221,7 +221,7 @@ public class StringBundle {
|
|||
}
|
||||
|
||||
public boolean getBoolean(String key, boolean defaultValue) {
|
||||
Item item = map.get(key);
|
||||
Item<?> item = map.get(key);
|
||||
return item instanceof StringItem ? ((StringItem) item).asBoolean(defaultValue) : defaultValue;
|
||||
}
|
||||
|
||||
|
@ -232,35 +232,13 @@ public class StringBundle {
|
|||
}
|
||||
|
||||
public String getString(String key, String defaultValue) {
|
||||
Item item = map.get(key);
|
||||
Item<?> item = map.get(key);
|
||||
return item instanceof StringItem ? ((StringItem) item).getValue() : defaultValue;
|
||||
}
|
||||
|
||||
public void putObject(String key, StringExternalizable object) {
|
||||
if (object != null) {
|
||||
StringBundle bundle = newInstance();
|
||||
object.writeToBundle(bundle);
|
||||
map.put(key, new StringBundleItem(key, bundle));
|
||||
}
|
||||
}
|
||||
|
||||
public void putList(String key, String itemName, List<? extends StringExternalizable> list) {
|
||||
if (list != null) {
|
||||
List<Item> itemList = new ArrayList<>();
|
||||
for (StringExternalizable ex : list) {
|
||||
if (ex != null) {
|
||||
StringBundle bundle = newInstance();
|
||||
ex.writeToBundle(bundle);
|
||||
itemList.add(new StringBundleItem(itemName, bundle));
|
||||
}
|
||||
}
|
||||
map.put(key, new StringListItem(key, itemList));
|
||||
}
|
||||
}
|
||||
|
||||
public void putBundleList(String key, String itemName, List<StringBundle> list) {
|
||||
if (list != null) {
|
||||
List<Item> itemList = new ArrayList<>();
|
||||
List<Item<?>> itemList = new ArrayList<>();
|
||||
for (StringBundle bundle : list) {
|
||||
itemList.add(new StringBundleItem(itemName, bundle));
|
||||
}
|
||||
|
@ -279,7 +257,7 @@ public class StringBundle {
|
|||
}
|
||||
|
||||
public int[] getIntArray(String key, int[] defaultValue) {
|
||||
Item item = map.get(key);
|
||||
Item<?> item = map.get(key);
|
||||
return item instanceof StringItem ? ((StringItem) item).asIntArray(defaultValue) : defaultValue;
|
||||
}
|
||||
|
||||
|
@ -290,7 +268,7 @@ public class StringBundle {
|
|||
}
|
||||
|
||||
public int[][] getIntIntArray(String key, int[][] defaultValue) {
|
||||
Item item = map.get(key);
|
||||
Item<?> item = map.get(key);
|
||||
return item instanceof StringItem ? ((StringItem) item).asIntIntArray(defaultValue) : defaultValue;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,10 +16,10 @@ public abstract class StringBundleWriter {
|
|||
return bundle;
|
||||
}
|
||||
|
||||
protected abstract void writeItem(String name, Item item);
|
||||
protected abstract void writeItem(String name, Item<?> item);
|
||||
|
||||
public void writeBundle() {
|
||||
for (Entry<String, Item> entry : bundle.getMap().entrySet()) {
|
||||
for (Entry<String, Item<?>> entry : bundle.getMap().entrySet()) {
|
||||
writeItem(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ public class StringBundleXmlWriter extends StringBundleWriter {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void writeItem(String name, Item item) {
|
||||
protected void writeItem(String name, Item<?> item) {
|
||||
if (serializer != null) {
|
||||
try {
|
||||
writeItemImpl(name, item);
|
||||
|
@ -47,7 +47,7 @@ public class StringBundleXmlWriter extends StringBundleWriter {
|
|||
}
|
||||
}
|
||||
|
||||
private void writeItemImpl(String name, Item item) throws IOException {
|
||||
private void writeItemImpl(String name, Item<?> item) throws IOException {
|
||||
if (serializer != null && item != null) {
|
||||
switch (item.getType()) {
|
||||
case STRING: {
|
||||
|
@ -58,13 +58,13 @@ public class StringBundleXmlWriter extends StringBundleWriter {
|
|||
case LIST: {
|
||||
StringListItem listItem = (StringListItem) item;
|
||||
serializer.startTag(null, name);
|
||||
List<Item> list = listItem.getValue();
|
||||
for (Item i : list) {
|
||||
List<Item<?>> list = listItem.getValue();
|
||||
for (Item<?> i : list) {
|
||||
if (i.getType() == StringBundle.ItemType.STRING) {
|
||||
writeItemImpl(i.getName(), i);
|
||||
}
|
||||
}
|
||||
for (Item i : list) {
|
||||
for (Item<?> i : list) {
|
||||
if (i.getType() != StringBundle.ItemType.STRING) {
|
||||
writeItemImpl(i.getName(), i);
|
||||
}
|
||||
|
@ -75,14 +75,14 @@ public class StringBundleXmlWriter extends StringBundleWriter {
|
|||
case MAP: {
|
||||
StringMapItem mapItem = (StringMapItem) item;
|
||||
serializer.startTag(null, name);
|
||||
for (Entry<String, Item> entry : mapItem.getValue().entrySet()) {
|
||||
Item i = entry.getValue();
|
||||
for (Entry<String, Item<?>> entry : mapItem.getValue().entrySet()) {
|
||||
Item<?> i = entry.getValue();
|
||||
if (i.getType() == StringBundle.ItemType.STRING) {
|
||||
writeItemImpl(entry.getKey(), i);
|
||||
}
|
||||
}
|
||||
for (Entry<String, Item> entry : mapItem.getValue().entrySet()) {
|
||||
Item i = entry.getValue();
|
||||
for (Entry<String, Item<?>> entry : mapItem.getValue().entrySet()) {
|
||||
Item<?> i = entry.getValue();
|
||||
if (i.getType() != StringBundle.ItemType.STRING) {
|
||||
writeItemImpl(entry.getKey(), i);
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ public class Amenity extends MapObject {
|
|||
public static final String CONTENT = "content";
|
||||
public static final String CUISINE = "cuisine";
|
||||
public static final String WIKIDATA = "wikidata";
|
||||
public static final String WIKIMEDIA_COMMONS = "wikimedia_commons";
|
||||
public static final String DISH = "dish";
|
||||
public static final String REF = "ref";
|
||||
public static final String OSM_DELETE_VALUE = "delete";
|
||||
|
|
|
@ -32,6 +32,8 @@ public interface ITileSource {
|
|||
|
||||
public String getReferer();
|
||||
|
||||
public String getUserAgent();
|
||||
|
||||
public void deleteTiles(String path);
|
||||
|
||||
public int getAvgSize();
|
||||
|
|
|
@ -7,7 +7,6 @@ import java.io.IOException;
|
|||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
|
@ -91,6 +90,7 @@ public class MapTileDownloader {
|
|||
public final int yTile;
|
||||
public String url;
|
||||
public String referer = null;
|
||||
public String userAgent = null;
|
||||
public boolean error;
|
||||
|
||||
public DownloadRequest(String url, File fileToSave, int xTile, int yTile, int zoom) {
|
||||
|
@ -267,7 +267,7 @@ public class MapTileDownloader {
|
|||
request.setError(false);
|
||||
try {
|
||||
URLConnection connection = NetworkUtils.getHttpURLConnection(request.url);
|
||||
connection.setRequestProperty("User-Agent", USER_AGENT); //$NON-NLS-1$
|
||||
connection.setRequestProperty("User-Agent", Algorithms.isEmpty(request.userAgent) ? USER_AGENT : request.userAgent); //$NON-NLS-1$
|
||||
if (request.referer != null)
|
||||
connection.setRequestProperty("Referer", request.referer); //$NON-NLS-1$
|
||||
connection.setConnectTimeout(CONNECTION_TIMEOUT);
|
||||
|
|
|
@ -68,6 +68,7 @@ public class TileSourceManager {
|
|||
private String[] randomsArray;
|
||||
private String rule;
|
||||
private String referer;
|
||||
private String userAgent;
|
||||
private boolean hidden; // if hidden in configure map settings, for example mapillary sources
|
||||
|
||||
private boolean isRuleAcceptable = true;
|
||||
|
@ -261,6 +262,14 @@ public class TileSourceManager {
|
|||
this.referer = referer;
|
||||
}
|
||||
|
||||
public String getUserAgent() {
|
||||
return userAgent;
|
||||
}
|
||||
|
||||
public void setUserAgent(String userAgent) {
|
||||
this.userAgent = userAgent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTileSize() {
|
||||
return tileSize;
|
||||
|
@ -484,6 +493,9 @@ public class TileSourceManager {
|
|||
if (!Algorithms.isEmpty(tm.getReferer())) {
|
||||
properties.put("referer", tm.getReferer());
|
||||
}
|
||||
if (!Algorithms.isEmpty(tm.getUserAgent())) {
|
||||
properties.put("user_agent", tm.getUserAgent());
|
||||
}
|
||||
|
||||
properties.put("ext", tm.getTileFormat());
|
||||
properties.put("min_zoom", tm.getMinimumZoomSupported() + "");
|
||||
|
@ -708,6 +720,12 @@ public class TileSourceManager {
|
|||
}
|
||||
String randoms = attributes.get("randoms");
|
||||
TileSourceTemplate templ = new TileSourceTemplate(name, urlTemplate, ext, maxZoom, minZoom, tileSize, bitDensity, avgTileSize);
|
||||
if (attributes.get("referer") != null) {
|
||||
templ.setReferer(attributes.get("referer"));
|
||||
}
|
||||
if (attributes.get("user_agent") != null) {
|
||||
templ.setUserAgent(attributes.get("user_agent"));
|
||||
}
|
||||
if(expirationTime >= 0) {
|
||||
templ.setExpirationTimeMinutes(expirationTime);
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import java.io.FileInputStream;
|
|||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
|
@ -153,6 +154,34 @@ public abstract class MapRenderingTypes {
|
|||
return a;
|
||||
}
|
||||
|
||||
protected MapRulType checkOrCreateTextRule(String targetTag, MapRulType ref) {
|
||||
MapRulType mt = types.get(constructRuleKey(targetTag, null));
|
||||
if (mt == null) {
|
||||
MapRulType ct = MapRulType.createText(targetTag, ref);
|
||||
mt = registerRuleType(ct);
|
||||
}
|
||||
return mt;
|
||||
}
|
||||
|
||||
protected MapRulType checkOrMainRule(String tag, String value, int minzoom) {
|
||||
MapRulType mt = types.get(constructRuleKey(tag, value));
|
||||
if (mt == null) {
|
||||
mt = registerRuleType(MapRulType.createMainEntity(tag, value));
|
||||
mt.minzoom = minzoom;
|
||||
mt.maxzoom = 21;
|
||||
}
|
||||
return mt;
|
||||
}
|
||||
|
||||
protected MapRulType checkOrCreateAdditional(String tag, String value, MapRulType ref) {
|
||||
MapRulType mt = types.get(constructRuleKey(tag, value));
|
||||
if (mt == null) {
|
||||
MapRulType ct = MapRulType.createAdditional(tag, value, ref);
|
||||
mt = registerRuleType(ct);
|
||||
}
|
||||
return mt;
|
||||
}
|
||||
|
||||
protected MapRulType getRuleType(String tag, String val, boolean poi, boolean map) {
|
||||
Map<String, MapRulType> types = getEncodingRuleTypes();
|
||||
tag = lc(tag);
|
||||
|
@ -171,7 +200,6 @@ public abstract class MapRenderingTypes {
|
|||
rType.map = parent.map;
|
||||
rType.poi = parent.poi;
|
||||
rType.onlyPoint = parent.onlyPoint;
|
||||
rType.namePrefix = parent.namePrefix;
|
||||
rType = registerRuleType(rType);
|
||||
}
|
||||
return rType;
|
||||
|
@ -266,36 +294,111 @@ public abstract class MapRenderingTypes {
|
|||
rtype.relation = Boolean.parseBoolean(parser.getAttributeValue("", "relation")); //$NON-NLS-1$
|
||||
rtype.relationGroup = Boolean.parseBoolean(parser.getAttributeValue("", "relationGroup")); //$NON-NLS-1$
|
||||
if (rtype.isMain()) {
|
||||
rtype.namePrefix = parser.getAttributeValue("", "namePrefix"); //$NON-NLS-1$
|
||||
if (rtype.namePrefix == null) {
|
||||
rtype.namePrefix = "";
|
||||
if (rtype.relationGroup) {
|
||||
MapRulType mrt = MapRulType.createMainEntity(tag + "_" + value, null);
|
||||
mrt.order = rtype.order;
|
||||
mrt.category = rtype.category;
|
||||
mrt.poi = rtype.poi;
|
||||
mrt.map = rtype.map;
|
||||
registerMapRule(parser, mrt);
|
||||
}
|
||||
|
||||
String v = parser.getAttributeValue("", "nameTags");
|
||||
if (v != null) {
|
||||
String[] names = v.split(",");
|
||||
rtype.names = new MapRulType[names.length * (langs.length + 1)];
|
||||
int j = 0;
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
String tagName = names[i];
|
||||
if (rtype.namePrefix.length() > 0) {
|
||||
tagName = rtype.namePrefix + tagName;
|
||||
String groupSort = parser.getAttributeValue("", "relationGroupSort");
|
||||
if (groupSort != null) {
|
||||
rtype.relationSortTags = new LinkedHashMap<String, List<String>>();
|
||||
String[] ls = groupSort.split(";");
|
||||
for(String l : ls) {
|
||||
int sp = l.indexOf('=');
|
||||
String key = l;
|
||||
String[] values = new String[0];
|
||||
if(sp >= 0) {
|
||||
key = l.substring(0, sp);
|
||||
values = l.substring(sp +1).split(",");
|
||||
}
|
||||
MapRulType mt = MapRulType.createText(tagName);
|
||||
mt = registerRuleType(mt);
|
||||
rtype.names[j++] = mt;
|
||||
for(String lng : langs) {
|
||||
mt = MapRulType.createText(tagName + ":" + lng);
|
||||
mt = registerRuleType(mt);
|
||||
rtype.names[j++] = mt;
|
||||
rtype.relationSortTags.put(key, Arrays.asList(values));
|
||||
}
|
||||
}
|
||||
|
||||
String additionalTags = parser.getAttributeValue("", "additionalTags");
|
||||
String additionalPrefix = parser.getAttributeValue("", "additionalPrefix");
|
||||
if (additionalTags != null) {
|
||||
rtype.additionalTags = new LinkedHashMap<String, String>();
|
||||
for(String tg : additionalTags.split(",")) {
|
||||
String targetTag = tg;
|
||||
if(!Algorithms.isEmpty(additionalPrefix)) {
|
||||
targetTag = additionalPrefix + tg;
|
||||
}
|
||||
rtype.additionalTags.put(tg, targetTag);
|
||||
}
|
||||
}
|
||||
rtype.relationGroupPrefix = parser.getAttributeValue("", "relationGroupPrefix"); //$NON-NLS-1$
|
||||
String relationGroupAdditionalTags = parser.getAttributeValue("", "relationGroupAdditionalTags");
|
||||
if (relationGroupAdditionalTags != null) {
|
||||
rtype.relationGroupAdditionalTags = new LinkedHashMap<String, String>();
|
||||
for(String tg : relationGroupAdditionalTags.split(",")) {
|
||||
rtype.relationGroupAdditionalTags.put(tg, tg);
|
||||
}
|
||||
}
|
||||
|
||||
String nmts = parser.getAttributeValue("", "nameTags");
|
||||
if (nmts != null) {
|
||||
if (rtype.relation || rtype.relationGroup) {
|
||||
String namePrefix = parser.getAttributeValue("", "namePrefix"); //$NON-NLS-1$
|
||||
if (namePrefix == null) {
|
||||
namePrefix = "";
|
||||
}
|
||||
rtype.relationNames = new LinkedHashMap<String, String>();
|
||||
putNameTags(nmts, rtype.relationNames, namePrefix);
|
||||
} else {
|
||||
String[] nameSplit = nmts.split(",");
|
||||
for (String nameTag : nameSplit) {
|
||||
checkOrCreateTextRule(nameTag, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
String rnmts = parser.getAttributeValue("", "relationGroupNameTags");
|
||||
if (rnmts != null) {
|
||||
rtype.relationGroupNameTags = new LinkedHashMap<String, String>();
|
||||
putNameTags(rnmts, rtype.relationGroupNameTags, "");
|
||||
}
|
||||
}
|
||||
return rtype;
|
||||
|
||||
}
|
||||
|
||||
private void putNameTags(String namesList, Map<String, String> names, String namePrefix) {
|
||||
if (namesList != null) {
|
||||
String[] nameSplit = namesList.split(",");
|
||||
for (int i = 0; i < nameSplit.length; i++) {
|
||||
String tagName = nameSplit[i];
|
||||
String tagTargetName = tagName;
|
||||
if (namePrefix.length() > 0) {
|
||||
tagTargetName = namePrefix + tagName;
|
||||
}
|
||||
names.put(tagName, tagTargetName);
|
||||
for (String lng : langs) {
|
||||
names.put(tagName + ":" + lng, tagTargetName + ":" + lng);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void registerMapRule(XmlPullParser parser, MapRulType rtype) {
|
||||
String val = parser.getAttributeValue("", "minzoom"); //$NON-NLS-1$
|
||||
if (rtype.isMain()) {
|
||||
rtype.minzoom = 15;
|
||||
}
|
||||
if (val != null) {
|
||||
rtype.minzoom = Integer.parseInt(val);
|
||||
}
|
||||
val = parser.getAttributeValue("", "maxzoom"); //$NON-NLS-1$
|
||||
rtype.maxzoom = 31;
|
||||
if (val != null) {
|
||||
rtype.maxzoom = Integer.parseInt(val);
|
||||
}
|
||||
registerRuleType(rtype);
|
||||
}
|
||||
|
||||
protected MapRulType registerRuleType(MapRulType rt) {
|
||||
String tag = rt.tagValuePattern.tag;
|
||||
String val = rt.tagValuePattern.value;
|
||||
|
@ -422,7 +525,14 @@ public abstract class MapRenderingTypes {
|
|||
}
|
||||
|
||||
public static class MapRulType {
|
||||
protected MapRulType[] names;
|
||||
// relation part
|
||||
protected Map<String, String> relationNames;
|
||||
protected Map<String, String> additionalTags;
|
||||
protected Map<String, List<String>> relationSortTags;
|
||||
protected String relationGroupPrefix;
|
||||
protected Map<String, String> relationGroupNameTags;
|
||||
protected Map<String, String> relationGroupAdditionalTags;
|
||||
|
||||
protected TagValuePattern tagValuePattern;
|
||||
protected boolean additional;
|
||||
protected boolean additionalText;
|
||||
|
@ -440,7 +550,6 @@ public abstract class MapRenderingTypes {
|
|||
protected int minzoom;
|
||||
protected int maxzoom;
|
||||
protected boolean onlyPoint;
|
||||
protected String namePrefix ="";
|
||||
|
||||
|
||||
// inner id
|
||||
|
@ -452,6 +561,16 @@ public abstract class MapRenderingTypes {
|
|||
private MapRulType(){
|
||||
}
|
||||
|
||||
|
||||
private void copyMetadata(MapRulType ref) {
|
||||
minzoom = ref.minzoom;
|
||||
maxzoom = ref.maxzoom;
|
||||
order = ref.order;
|
||||
category = ref.category;
|
||||
onlyPoint = ref.onlyPoint;
|
||||
}
|
||||
|
||||
|
||||
public boolean isPOI(){
|
||||
return poi;
|
||||
}
|
||||
|
@ -471,24 +590,37 @@ public abstract class MapRenderingTypes {
|
|||
return rt;
|
||||
}
|
||||
|
||||
public static MapRulType createText(String tag) {
|
||||
public static MapRulType createText(String tag, MapRulType ref) {
|
||||
MapRulType rt = new MapRulType();
|
||||
rt.additionalText = true;
|
||||
rt.minzoom = 2;
|
||||
rt.maxzoom = 31;
|
||||
if (ref != null) {
|
||||
rt.copyMetadata(ref);
|
||||
}
|
||||
rt.additionalText = true;
|
||||
rt.tagValuePattern = new TagValuePattern(tag, null);
|
||||
return rt;
|
||||
}
|
||||
|
||||
public static MapRulType createAdditional(String tag, String value) {
|
||||
public static MapRulType createAdditional(String tag, String value, MapRulType ref) {
|
||||
MapRulType rt = new MapRulType();
|
||||
rt.additional = true;
|
||||
rt.minzoom = 2;
|
||||
rt.maxzoom = 31;
|
||||
if (ref != null) {
|
||||
rt.copyMetadata(ref);
|
||||
}
|
||||
rt.additional = true;
|
||||
rt.tagValuePattern = new TagValuePattern(tag, value);
|
||||
return rt;
|
||||
}
|
||||
|
||||
public static MapRulType createText(String tag) {
|
||||
return createText(tag, null);
|
||||
}
|
||||
|
||||
public static MapRulType createAdditional(String tag, String value) {
|
||||
return createAdditional(tag, value, null);
|
||||
}
|
||||
|
||||
public String getTag() {
|
||||
return tagValuePattern.tag;
|
||||
|
@ -549,14 +681,6 @@ public abstract class MapRenderingTypes {
|
|||
return onlyPoint;
|
||||
}
|
||||
|
||||
public boolean isRelation() {
|
||||
return relation;
|
||||
}
|
||||
|
||||
public boolean isRelationGroup() {
|
||||
return relationGroup;
|
||||
}
|
||||
|
||||
|
||||
public int getFreq() {
|
||||
return freq;
|
||||
|
|
|
@ -556,6 +556,9 @@ public class OsmMapUtils {
|
|||
|
||||
// take centroid as the first best guess
|
||||
Cell bestCell = getCentroidCell(rings);
|
||||
if(bestCell == null) {
|
||||
return new LatLon(minX, minY);
|
||||
}
|
||||
|
||||
// special case for rectangular polygons
|
||||
Cell bboxCell = new Cell(minX + width / 2, minY + height / 2, 0, rings);
|
||||
|
@ -606,10 +609,13 @@ public class OsmMapUtils {
|
|||
area += f * 3;
|
||||
}
|
||||
|
||||
if (area == 0) {
|
||||
LatLon p = points.get(0);
|
||||
return new Cell(p.getLatitude(), p.getLongitude(), 0, rings);
|
||||
}
|
||||
if (area == 0) {
|
||||
if (points.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
LatLon p = points.get(0);
|
||||
return new Cell(p.getLatitude(), p.getLongitude(), 0, rings);
|
||||
}
|
||||
|
||||
return new Cell(x / area, y / area, 0, rings);
|
||||
}
|
||||
|
|
|
@ -1,93 +1,104 @@
|
|||
package net.osmand.osm.io;
|
||||
|
||||
|
||||
/**
|
||||
* @source http://www.javaworld.com/javaworld/javatips/jw-javatip47.html -- 24.11.2008, (mb)
|
||||
*/
|
||||
public class Base64 {
|
||||
/*******************************************************************************************************************
|
||||
* BASE 64 encoding of a String or an array of bytes. See also RFC 1421.
|
||||
*
|
||||
* @author Unknown
|
||||
* @author David W. Croft
|
||||
* @version 1998-06-08
|
||||
******************************************************************************************************************/
|
||||
/*******************************************************************************************************************
|
||||
* BASE 64 encoding of a String or an array of bytes. See also RFC 1421.
|
||||
*
|
||||
* @author Unknown
|
||||
* @author David W. Croft
|
||||
* @version 1998-06-08
|
||||
******************************************************************************************************************/
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
public static final char[] alphabet = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', // 0 to 7
|
||||
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', // 8 to 15
|
||||
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', // 16 to 23
|
||||
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', // 24 to 31
|
||||
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', // 32 to 39
|
||||
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', // 40 to 47
|
||||
'w', 'x', 'y', 'z', '0', '1', '2', '3', // 48 to 55
|
||||
'4', '5', '6', '7', '8', '9', '+', '/' }; // 56 to 63
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
public static final char[] alphabet = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', // 0 to 7
|
||||
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', // 8 to 15
|
||||
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', // 16 to 23
|
||||
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', // 24 to 31
|
||||
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', // 32 to 39
|
||||
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', // 40 to 47
|
||||
'w', 'x', 'y', 'z', '0', '1', '2', '3', // 48 to 55
|
||||
'4', '5', '6', '7', '8', '9', '+', '/' }; // 56 to 63
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
public static String encode(final String s)
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
{
|
||||
return encode(s.getBytes());
|
||||
}
|
||||
public static int indexOf(char c) {
|
||||
for (int i = 0; i < alphabet.length; i++) {
|
||||
if (alphabet[i] == c) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static String encode(final byte[] octetString)
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
{
|
||||
int bits24;
|
||||
int bits6;
|
||||
|
||||
final char[] out = new char[((octetString.length - 1) / 3 + 1) * 4];
|
||||
public static String encode(final String s)
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
{
|
||||
return encode(s.getBytes());
|
||||
}
|
||||
|
||||
int outIndex = 0;
|
||||
int i = 0;
|
||||
public static String encode(final byte[] octetString)
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
{
|
||||
int bits24;
|
||||
int bits6;
|
||||
|
||||
while ((i + 3) <= octetString.length) {
|
||||
// store the octets
|
||||
bits24 = (octetString[i++] & 0xFF) << 16;
|
||||
bits24 |= (octetString[i++] & 0xFF) << 8;
|
||||
bits24 |= (octetString[i++] & 0xFF);
|
||||
final char[] out = new char[((octetString.length - 1) / 3 + 1) * 4];
|
||||
|
||||
bits6 = (bits24 & 0x00FC0000) >> 18;
|
||||
out[outIndex++] = alphabet[bits6];
|
||||
bits6 = (bits24 & 0x0003F000) >> 12;
|
||||
out[outIndex++] = alphabet[bits6];
|
||||
bits6 = (bits24 & 0x00000FC0) >> 6;
|
||||
out[outIndex++] = alphabet[bits6];
|
||||
bits6 = (bits24 & 0x0000003F);
|
||||
out[outIndex++] = alphabet[bits6];
|
||||
}
|
||||
int outIndex = 0;
|
||||
int i = 0;
|
||||
|
||||
if (octetString.length - i == 2) {
|
||||
// store the octets
|
||||
bits24 = (octetString[i] & 0xFF) << 16;
|
||||
bits24 |= (octetString[i + 1] & 0xFF) << 8;
|
||||
while ((i + 3) <= octetString.length) {
|
||||
// store the octets
|
||||
bits24 = (octetString[i++] & 0xFF) << 16;
|
||||
bits24 |= (octetString[i++] & 0xFF) << 8;
|
||||
bits24 |= (octetString[i++] & 0xFF);
|
||||
|
||||
bits6 = (bits24 & 0x00FC0000) >> 18;
|
||||
out[outIndex++] = alphabet[bits6];
|
||||
bits6 = (bits24 & 0x0003F000) >> 12;
|
||||
out[outIndex++] = alphabet[bits6];
|
||||
bits6 = (bits24 & 0x00000FC0) >> 6;
|
||||
out[outIndex++] = alphabet[bits6];
|
||||
bits6 = (bits24 & 0x00FC0000) >> 18;
|
||||
out[outIndex++] = alphabet[bits6];
|
||||
bits6 = (bits24 & 0x0003F000) >> 12;
|
||||
out[outIndex++] = alphabet[bits6];
|
||||
bits6 = (bits24 & 0x00000FC0) >> 6;
|
||||
out[outIndex++] = alphabet[bits6];
|
||||
bits6 = (bits24 & 0x0000003F);
|
||||
out[outIndex++] = alphabet[bits6];
|
||||
}
|
||||
|
||||
// padding
|
||||
out[outIndex++] = '=';
|
||||
} else if (octetString.length - i == 1) {
|
||||
// store the octets
|
||||
bits24 = (octetString[i] & 0xFF) << 16;
|
||||
if (octetString.length - i == 2) {
|
||||
// store the octets
|
||||
bits24 = (octetString[i] & 0xFF) << 16;
|
||||
bits24 |= (octetString[i + 1] & 0xFF) << 8;
|
||||
|
||||
bits6 = (bits24 & 0x00FC0000) >> 18;
|
||||
out[outIndex++] = alphabet[bits6];
|
||||
bits6 = (bits24 & 0x0003F000) >> 12;
|
||||
out[outIndex++] = alphabet[bits6];
|
||||
bits6 = (bits24 & 0x00FC0000) >> 18;
|
||||
out[outIndex++] = alphabet[bits6];
|
||||
bits6 = (bits24 & 0x0003F000) >> 12;
|
||||
out[outIndex++] = alphabet[bits6];
|
||||
bits6 = (bits24 & 0x00000FC0) >> 6;
|
||||
out[outIndex++] = alphabet[bits6];
|
||||
|
||||
// padding
|
||||
out[outIndex++] = '=';
|
||||
out[outIndex++] = '=';
|
||||
}
|
||||
// padding
|
||||
out[outIndex++] = '=';
|
||||
} else if (octetString.length - i == 1) {
|
||||
// store the octets
|
||||
bits24 = (octetString[i] & 0xFF) << 16;
|
||||
|
||||
return new String(out);
|
||||
}
|
||||
bits6 = (bits24 & 0x00FC0000) >> 18;
|
||||
out[outIndex++] = alphabet[bits6];
|
||||
bits6 = (bits24 & 0x0003F000) >> 12;
|
||||
out[outIndex++] = alphabet[bits6];
|
||||
|
||||
// padding
|
||||
out[outIndex++] = '=';
|
||||
out[outIndex++] = '=';
|
||||
}
|
||||
|
||||
return new String(out);
|
||||
}
|
||||
|
||||
}
|
|
@ -7,7 +7,6 @@ import java.io.IOException;
|
|||
import java.io.InputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
|
@ -18,6 +17,7 @@ import java.util.Map.Entry;
|
|||
import java.util.Stack;
|
||||
|
||||
import net.osmand.PlatformUtil;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
|
@ -26,7 +26,7 @@ import org.xmlpull.v1.XmlPullParserException;
|
|||
public class RenderingRulesStorage {
|
||||
|
||||
private final static Log log = PlatformUtil.getLog(RenderingRulesStorage.class);
|
||||
static boolean STORE_ATTTRIBUTES = false;
|
||||
static boolean STORE_ATTRIBUTES = false;
|
||||
|
||||
// keep sync !
|
||||
// keep sync ! not change values
|
||||
|
@ -40,6 +40,10 @@ public class RenderingRulesStorage {
|
|||
|
||||
private final static int SHIFT_TAG_VAL = 16;
|
||||
|
||||
|
||||
private final static String SEQ_ATTR_KEY = "seq";
|
||||
private final static String SEQ_PLACEHOLDER = "#SEQ";
|
||||
|
||||
// C++
|
||||
List<String> dictionary = new ArrayList<String>();
|
||||
Map<String, Integer> dictionaryMap = new LinkedHashMap<String, Integer>();
|
||||
|
@ -183,31 +187,86 @@ public class RenderingRulesStorage {
|
|||
}
|
||||
}
|
||||
|
||||
private class XmlTreeSequence {
|
||||
XmlTreeSequence parent;
|
||||
String seqOrder;
|
||||
Map<String, String> attrsMap = new LinkedHashMap<String, String>();
|
||||
String name;
|
||||
List<XmlTreeSequence> children = new ArrayList<RenderingRulesStorage.XmlTreeSequence>();
|
||||
|
||||
private void process(RenderingRulesHandler handler, int el) throws XmlPullParserException, IOException {
|
||||
Map<String, String> seqAttrsMap = new HashMap<String, String>(attrsMap);
|
||||
if (attrsMap.containsKey(SEQ_ATTR_KEY)) {
|
||||
attrsMap.remove(SEQ_ATTR_KEY);
|
||||
}
|
||||
|
||||
for (Entry<String, String> attr: attrsMap.entrySet()) {
|
||||
if (attr.getValue().contains(SEQ_PLACEHOLDER)) {
|
||||
seqAttrsMap.put(attr.getKey(), attr.getValue().replace(SEQ_PLACEHOLDER, el+""));
|
||||
} else {
|
||||
seqAttrsMap.put(attr.getKey(), attr.getValue());
|
||||
}
|
||||
}
|
||||
handler.startElement(seqAttrsMap, name);
|
||||
for(XmlTreeSequence s : children) {
|
||||
s.process(handler, el);
|
||||
}
|
||||
handler.endElement(name);
|
||||
}
|
||||
}
|
||||
|
||||
private class RenderingRulesHandler {
|
||||
private final XmlPullParser parser;
|
||||
private int state;
|
||||
|
||||
Stack<RenderingRule> stack = new Stack<RenderingRule>();
|
||||
|
||||
Map<String, String> attrsMap = new LinkedHashMap<String, String>();
|
||||
private final RenderingRulesStorageResolver resolver;
|
||||
private RenderingRulesStorage dependsStorage;
|
||||
|
||||
|
||||
|
||||
public RenderingRulesHandler(XmlPullParser parser, RenderingRulesStorageResolver resolver){
|
||||
this.parser = parser;
|
||||
this.resolver = resolver;
|
||||
}
|
||||
|
||||
public void parse(InputStream is) throws XmlPullParserException, IOException {
|
||||
XmlPullParser parser = this.parser;
|
||||
Map<String, String> attrsMap = new LinkedHashMap<String, String>();
|
||||
parser.setInput(is, "UTF-8");
|
||||
int tok;
|
||||
XmlTreeSequence currentSeqElement = null;
|
||||
while ((tok = parser.next()) != XmlPullParser.END_DOCUMENT) {
|
||||
if (tok == XmlPullParser.START_TAG) {
|
||||
startElement(parser.getName());
|
||||
attrsMap.clear();
|
||||
parseAttributes(parser, attrsMap);
|
||||
String name = parser.getName();
|
||||
if (!Algorithms.isEmpty(parser.getAttributeValue("", SEQ_ATTR_KEY)) || currentSeqElement != null) {
|
||||
XmlTreeSequence seq = new XmlTreeSequence();
|
||||
seq.name = name;
|
||||
seq.attrsMap = new HashMap<String, String>(attrsMap);
|
||||
seq.parent = currentSeqElement;
|
||||
if (currentSeqElement == null) {
|
||||
seq.seqOrder = parser.getAttributeValue("", SEQ_ATTR_KEY);
|
||||
} else {
|
||||
currentSeqElement.children.add(seq);
|
||||
seq.seqOrder = currentSeqElement.seqOrder;
|
||||
}
|
||||
currentSeqElement = seq;
|
||||
} else {
|
||||
startElement(attrsMap, name);
|
||||
}
|
||||
} else if (tok == XmlPullParser.END_TAG) {
|
||||
endElement(parser.getName());
|
||||
if(currentSeqElement == null) {
|
||||
endElement(parser.getName());
|
||||
} else {
|
||||
XmlTreeSequence process = currentSeqElement;
|
||||
currentSeqElement = currentSeqElement.parent;
|
||||
if (currentSeqElement == null) {
|
||||
// Here we process sequence element
|
||||
int seqEnd = Integer.parseInt(process.seqOrder.substring(process.seqOrder.indexOf(':') + 1, process.seqOrder.length()));
|
||||
for(int i = 1; i < seqEnd; i++) {
|
||||
process.process(this, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -226,16 +285,14 @@ public class RenderingRulesStorage {
|
|||
return true;
|
||||
}
|
||||
|
||||
public void startElement(String name) throws XmlPullParserException, IOException {
|
||||
public void startElement(Map<String, String> attrsMap, String name) throws XmlPullParserException, IOException {
|
||||
boolean stateChanged = false;
|
||||
final boolean isCase = isCase(name);
|
||||
final boolean isSwitch = isSwitch(name);
|
||||
if(isCase || isSwitch){ //$NON-NLS-1$
|
||||
attrsMap.clear();
|
||||
boolean top = stack.size() == 0 || isTopCase();
|
||||
parseAttributes(attrsMap);
|
||||
RenderingRule renderingRule = new RenderingRule(attrsMap, isSwitch, RenderingRulesStorage.this);
|
||||
if(top || STORE_ATTTRIBUTES){
|
||||
if(top || STORE_ATTRIBUTES){
|
||||
renderingRule.storeAttributes(attrsMap);
|
||||
}
|
||||
if (stack.size() > 0 && stack.peek() instanceof RenderingRule) {
|
||||
|
@ -244,10 +301,8 @@ public class RenderingRulesStorage {
|
|||
}
|
||||
stack.push(renderingRule);
|
||||
} else if(isApply(name)){ //$NON-NLS-1$
|
||||
attrsMap.clear();
|
||||
parseAttributes(attrsMap);
|
||||
RenderingRule renderingRule = new RenderingRule(attrsMap, false, RenderingRulesStorage.this);
|
||||
if(STORE_ATTTRIBUTES) {
|
||||
if(STORE_ATTRIBUTES) {
|
||||
renderingRule.storeAttributes(attrsMap);
|
||||
}
|
||||
if (stack.size() > 0 && stack.peek() instanceof RenderingRule) {
|
||||
|
@ -272,14 +327,14 @@ public class RenderingRulesStorage {
|
|||
state = POLYGON_RULES;
|
||||
stateChanged = true;
|
||||
} else if("renderingAttribute".equals(name)){ //$NON-NLS-1$
|
||||
String attr = parser.getAttributeValue("", "name");
|
||||
String attr = attrsMap.get("name");
|
||||
RenderingRule root = new RenderingRule(new HashMap<String, String>(), false, RenderingRulesStorage.this);
|
||||
renderingAttributes.put(attr, root);
|
||||
stack.push(root);
|
||||
} else if("renderingProperty".equals(name)){ //$NON-NLS-1$
|
||||
String attr = parser.getAttributeValue("", "attr");
|
||||
String attr = attrsMap.get("attr");
|
||||
RenderingRuleProperty prop;
|
||||
String type = parser.getAttributeValue("", "type");
|
||||
String type = attrsMap.get("type");
|
||||
if("boolean".equalsIgnoreCase(type)){
|
||||
prop = RenderingRuleProperty.createInputBooleanProperty(attr);
|
||||
} else if("string".equalsIgnoreCase(type)){
|
||||
|
@ -287,20 +342,20 @@ public class RenderingRulesStorage {
|
|||
} else {
|
||||
prop = RenderingRuleProperty.createInputIntProperty(attr);
|
||||
}
|
||||
prop.setDescription(parser.getAttributeValue("", "description"));
|
||||
prop.setDefaultValueDescription(parser.getAttributeValue("", "defaultValueDescription"));
|
||||
prop.setCategory(parser.getAttributeValue("", "category"));
|
||||
prop.setName(parser.getAttributeValue("", "name"));
|
||||
if(parser.getAttributeValue("", "possibleValues") != null){
|
||||
prop.setPossibleValues(parser.getAttributeValue("", "possibleValues").split(","));
|
||||
prop.setDescription(attrsMap.get("description"));
|
||||
prop.setDefaultValueDescription(attrsMap.get("defaultValueDescription"));
|
||||
prop.setCategory(attrsMap.get("category"));
|
||||
prop.setName(attrsMap.get("name"));
|
||||
if (attrsMap.get("possibleValues") != null) {
|
||||
prop.setPossibleValues(attrsMap.get("possibleValues").split(","));
|
||||
}
|
||||
PROPS.registerRule(prop);
|
||||
} else if("renderingConstant".equals(name)){ //$NON-NLS-1$
|
||||
if(!renderingConstants.containsKey(parser.getAttributeValue("", "name"))){
|
||||
renderingConstants.put(parser.getAttributeValue("", "name"), parser.getAttributeValue("", "value"));
|
||||
if(!renderingConstants.containsKey(attrsMap.get("name"))){
|
||||
renderingConstants.put(attrsMap.get("name"), attrsMap.get("value"));
|
||||
}
|
||||
} else if("renderingStyle".equals(name)){ //$NON-NLS-1$
|
||||
String depends = parser.getAttributeValue("", "depends");
|
||||
String depends = attrsMap.get("depends");
|
||||
if(depends != null && depends.length()> 0){
|
||||
this.dependsStorage = resolver.resolve(depends, resolver);
|
||||
}
|
||||
|
@ -311,7 +366,7 @@ public class RenderingRulesStorage {
|
|||
PROPS = new RenderingRuleStorageProperties(dependsStorage.PROPS);
|
||||
|
||||
}
|
||||
internalRenderingName = parser.getAttributeValue("", "name");
|
||||
internalRenderingName = attrsMap.get("name");
|
||||
|
||||
} else if("renderer".equals(name)){ //$NON-NLS-1$
|
||||
throw new XmlPullParserException("Rendering style is deprecated and no longer supported.");
|
||||
|
@ -337,7 +392,7 @@ public class RenderingRulesStorage {
|
|||
return "group".equals(name) || "switch".equals(name);
|
||||
}
|
||||
|
||||
private Map<String, String> parseAttributes(Map<String, String> m) {
|
||||
private Map<String, String> parseAttributes(XmlPullParser parser, Map<String, String> m) {
|
||||
for (int i = 0; i < parser.getAttributeCount(); i++) {
|
||||
String name = parser.getAttributeName(i);
|
||||
String vl = parser.getAttributeValue(i);
|
||||
|
@ -396,7 +451,7 @@ public class RenderingRulesStorage {
|
|||
vl = ns.remove("value");
|
||||
// reset rendering rule attributes
|
||||
renderingRule.init(ns);
|
||||
if(STORE_ATTTRIBUTES) {
|
||||
if(STORE_ATTRIBUTES) {
|
||||
renderingRule.storeAttributes(ns);
|
||||
}
|
||||
|
||||
|
@ -469,7 +524,7 @@ public class RenderingRulesStorage {
|
|||
|
||||
|
||||
public static void main(String[] args) throws XmlPullParserException, IOException {
|
||||
STORE_ATTTRIBUTES = true;
|
||||
STORE_ATTRIBUTES = true;
|
||||
// InputStream is = RenderingRulesStorage.class.getResourceAsStream("default.render.xml");
|
||||
final String loc = "/Users/victorshcherb/osmand/repos/resources/rendering_styles/";
|
||||
String defaultFile = loc + "UniRS.render.xml";
|
||||
|
|
|
@ -21,7 +21,7 @@ import org.xmlpull.v1.XmlPullParserException;
|
|||
public class RenderingRulesStoragePrinter {
|
||||
|
||||
public static void main(String[] args) throws XmlPullParserException, IOException {
|
||||
RenderingRulesStorage.STORE_ATTTRIBUTES = true;
|
||||
RenderingRulesStorage.STORE_ATTRIBUTES = true;
|
||||
// InputStream is = RenderingRulesStorage.class.getResourceAsStream("default.render.xml");
|
||||
String defaultFile = "/Users/victorshcherb/osmand/repos/resources/rendering_styles/default.render.xml";
|
||||
if(args.length > 0) {
|
||||
|
|
|
@ -49,14 +49,16 @@ public class RouteCalculationProgress {
|
|||
pr = Math.min(p * p / (all * all), 1);
|
||||
}
|
||||
float progress = INITIAL_PROGRESS;
|
||||
if (totalIterations > 1) {
|
||||
if (totalIterations <= 1) {
|
||||
progress = INITIAL_PROGRESS + pr * (1 - INITIAL_PROGRESS);
|
||||
} else if (totalIterations <= 2) {
|
||||
if (iteration < 1) {
|
||||
progress = pr * FIRST_ITERATION + INITIAL_PROGRESS;
|
||||
} else {
|
||||
progress = (INITIAL_PROGRESS + FIRST_ITERATION) + pr * (1 - FIRST_ITERATION - INITIAL_PROGRESS);
|
||||
}
|
||||
} else {
|
||||
progress = INITIAL_PROGRESS + pr * (1 - INITIAL_PROGRESS);
|
||||
progress = (float) ((iteration + Math.min(pr, 0.7)) / totalIterations);
|
||||
}
|
||||
return Math.min(progress * 100f, 99);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
package net.osmand.router;
|
||||
|
||||
import net.osmand.GPXUtilities.GPXExtensionsWriter;
|
||||
import net.osmand.GPXUtilities.GPXFile;
|
||||
import net.osmand.GPXUtilities.RouteSegment;
|
||||
import net.osmand.GPXUtilities.RouteType;
|
||||
import net.osmand.GPXUtilities.Track;
|
||||
import net.osmand.GPXUtilities.TrkSegment;
|
||||
import net.osmand.GPXUtilities.WptPt;
|
||||
|
@ -9,12 +10,8 @@ import net.osmand.Location;
|
|||
import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteTypeRule;
|
||||
import net.osmand.binary.RouteDataBundle;
|
||||
import net.osmand.binary.StringBundle;
|
||||
import net.osmand.binary.StringBundleWriter;
|
||||
import net.osmand.binary.StringBundleXmlWriter;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
||||
import org.xmlpull.v1.XmlSerializer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -37,8 +34,7 @@ public class RouteExporter {
|
|||
|
||||
public GPXFile exportRoute() {
|
||||
RouteDataResources resources = new RouteDataResources(locations);
|
||||
final RouteDataBundle bundle = new RouteDataBundle(resources);
|
||||
|
||||
List<StringBundle> routeItems = new ArrayList<>();
|
||||
if (!Algorithms.isEmpty(route)) {
|
||||
for (RouteSegmentResult sr : route) {
|
||||
sr.collectTypes(resources);
|
||||
|
@ -47,15 +43,12 @@ public class RouteExporter {
|
|||
sr.collectNames(resources);
|
||||
}
|
||||
|
||||
List<StringBundle> routeItems = new ArrayList<>();
|
||||
for (RouteSegmentResult sr : route) {
|
||||
RouteDataBundle itemBundle = new RouteDataBundle(resources);
|
||||
sr.writeToBundle(itemBundle);
|
||||
routeItems.add(itemBundle);
|
||||
}
|
||||
bundle.putBundleList("route", "segment", routeItems);
|
||||
}
|
||||
|
||||
List<StringBundle> typeList = new ArrayList<>();
|
||||
Map<RouteTypeRule, Integer> rules = resources.getRules();
|
||||
for (RouteTypeRule rule : rules.keySet()) {
|
||||
|
@ -63,7 +56,6 @@ public class RouteExporter {
|
|||
rule.writeToBundle(typeBundle);
|
||||
typeList.add(typeBundle);
|
||||
}
|
||||
bundle.putBundleList("types", "type", typeList);
|
||||
|
||||
GPXFile gpx = new GPXFile(OSMAND_ROUTER_V2);
|
||||
Track track = new Track();
|
||||
|
@ -75,7 +67,6 @@ public class RouteExporter {
|
|||
if (locations == null || locations.isEmpty()) {
|
||||
return gpx;
|
||||
}
|
||||
|
||||
for (int i = 0; i < locations.size(); i++) {
|
||||
Location loc = locations.get(i);
|
||||
WptPt pt = new WptPt();
|
||||
|
@ -92,21 +83,22 @@ public class RouteExporter {
|
|||
}
|
||||
trkSegment.points.add(pt);
|
||||
}
|
||||
|
||||
if (points != null) {
|
||||
for (WptPt pt : points) {
|
||||
gpx.addPoint(pt);
|
||||
}
|
||||
}
|
||||
|
||||
GPXExtensionsWriter extensionsWriter = new GPXExtensionsWriter() {
|
||||
@Override
|
||||
public void writeExtensions(XmlSerializer serializer) {
|
||||
StringBundleWriter bundleWriter = new StringBundleXmlWriter(bundle, serializer);
|
||||
bundleWriter.writeBundle();
|
||||
}
|
||||
};
|
||||
gpx.setExtensionsWriter(extensionsWriter);
|
||||
List<RouteSegment> routeSegments = new ArrayList<>();
|
||||
for (StringBundle item : routeItems) {
|
||||
routeSegments.add(RouteSegment.fromStringBundle(item));
|
||||
}
|
||||
gpx.routeSegments = routeSegments;
|
||||
List<RouteType> routeTypes = new ArrayList<>();
|
||||
for (StringBundle item : typeList) {
|
||||
routeTypes.add(RouteType.fromStringBundle(item));
|
||||
}
|
||||
gpx.routeTypes = routeTypes;
|
||||
|
||||
return gpx;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
package net.osmand.router;
|
||||
|
||||
import net.osmand.GPXUtilities;
|
||||
import net.osmand.GPXUtilities.GPXExtensionsReader;
|
||||
import net.osmand.GPXUtilities.GPXFile;
|
||||
import net.osmand.GPXUtilities.RouteSegment;
|
||||
import net.osmand.GPXUtilities.RouteType;
|
||||
import net.osmand.GPXUtilities.WptPt;
|
||||
import net.osmand.Location;
|
||||
import net.osmand.PlatformUtil;
|
||||
|
@ -10,11 +11,8 @@ import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteRegion;
|
|||
import net.osmand.binary.RouteDataBundle;
|
||||
import net.osmand.binary.RouteDataObject;
|
||||
import net.osmand.binary.StringBundle;
|
||||
import net.osmand.binary.StringBundleReader;
|
||||
import net.osmand.binary.StringBundleXmlReader;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
|
@ -31,6 +29,10 @@ public class RouteImporter {
|
|||
private File file;
|
||||
private GPXFile gpxFile;
|
||||
|
||||
private List<RouteSegmentResult> route = new ArrayList<>();
|
||||
private RouteRegion region = new RouteRegion();
|
||||
private RouteDataResources resources = new RouteDataResources();
|
||||
|
||||
public RouteImporter(File file) {
|
||||
this.file = file;
|
||||
}
|
||||
|
@ -40,90 +42,14 @@ public class RouteImporter {
|
|||
}
|
||||
|
||||
public List<RouteSegmentResult> importRoute() {
|
||||
|
||||
final List<RouteSegmentResult> route = new ArrayList<>();
|
||||
final RouteRegion region = new RouteRegion();
|
||||
final RouteDataResources resources = new RouteDataResources();
|
||||
|
||||
GPXExtensionsReader extensionsReader = new GPXExtensionsReader() {
|
||||
@Override
|
||||
public boolean readExtensions(GPXFile res, XmlPullParser parser) throws Exception {
|
||||
if (!resources.hasLocations()) {
|
||||
List<Location> locations = resources.getLocations();
|
||||
double lastElevation = HEIGHT_UNDEFINED;
|
||||
if (res.tracks.size() > 0 && res.tracks.get(0).segments.size() > 0 && res.tracks.get(0).segments.get(0).points.size() > 0) {
|
||||
for (WptPt point : res.tracks.get(0).segments.get(0).points) {
|
||||
Location loc = new Location("", point.getLatitude(), point.getLongitude());
|
||||
if (!Double.isNaN(point.ele)) {
|
||||
loc.setAltitude(point.ele);
|
||||
lastElevation = point.ele;
|
||||
} else if (lastElevation != HEIGHT_UNDEFINED) {
|
||||
loc.setAltitude(lastElevation);
|
||||
}
|
||||
locations.add(loc);
|
||||
}
|
||||
}
|
||||
}
|
||||
String tag = parser.getName();
|
||||
if ("route".equals(tag)) {
|
||||
int tok;
|
||||
while ((tok = parser.next()) != XmlPullParser.END_DOCUMENT) {
|
||||
if (tok == XmlPullParser.START_TAG) {
|
||||
tag = parser.getName();
|
||||
if ("segment".equals(tag)) {
|
||||
StringBundleReader bundleReader = new StringBundleXmlReader(parser);
|
||||
RouteDataObject object = new RouteDataObject(region);
|
||||
RouteSegmentResult segment = new RouteSegmentResult(object);
|
||||
bundleReader.readBundle();
|
||||
segment.readFromBundle(new RouteDataBundle(resources, bundleReader.getBundle()));
|
||||
route.add(segment);
|
||||
}
|
||||
} else if (tok == XmlPullParser.END_TAG) {
|
||||
tag = parser.getName();
|
||||
if ("route".equals(tag)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if ("types".equals(tag)) {
|
||||
int tok;
|
||||
int i = 0;
|
||||
while ((tok = parser.next()) != XmlPullParser.END_DOCUMENT) {
|
||||
if (tok == XmlPullParser.START_TAG) {
|
||||
tag = parser.getName();
|
||||
if ("type".equals(tag)) {
|
||||
StringBundleReader bundleReader = new StringBundleXmlReader(parser);
|
||||
bundleReader.readBundle();
|
||||
StringBundle bundle = bundleReader.getBundle();
|
||||
String t = bundle.getString("t", null);
|
||||
String v = bundle.getString("v", null);
|
||||
region.initRouteEncodingRule(i++, t, v);
|
||||
}
|
||||
} else if (tok == XmlPullParser.END_TAG) {
|
||||
tag = parser.getName();
|
||||
if ("types".equals(tag)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
if (gpxFile != null) {
|
||||
GPXUtilities.loadGPXFile(null, gpxFile, extensionsReader);
|
||||
for (RouteSegmentResult segment : route) {
|
||||
segment.fillNames(resources);
|
||||
}
|
||||
parseRoute();
|
||||
} else if (file != null) {
|
||||
FileInputStream fis = null;
|
||||
try {
|
||||
fis = new FileInputStream(file);
|
||||
GPXFile gpxFile = GPXUtilities.loadGPXFile(fis, null, extensionsReader);
|
||||
for (RouteSegmentResult segment : route) {
|
||||
segment.fillNames(resources);
|
||||
}
|
||||
gpxFile = GPXUtilities.loadGPXFile(fis);
|
||||
parseRoute();
|
||||
gpxFile.path = file.getAbsolutePath();
|
||||
gpxFile.modifiedTime = file.lastModified();
|
||||
} catch (IOException e) {
|
||||
|
@ -139,7 +65,51 @@ public class RouteImporter {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
return route;
|
||||
}
|
||||
|
||||
private void parseRoute() {
|
||||
collectLocations();
|
||||
collectSegments();
|
||||
collectTypes();
|
||||
for (RouteSegmentResult segment : route) {
|
||||
segment.fillNames(resources);
|
||||
}
|
||||
}
|
||||
|
||||
private void collectLocations() {
|
||||
List<Location> locations = resources.getLocations();
|
||||
double lastElevation = HEIGHT_UNDEFINED;
|
||||
if (gpxFile.tracks.size() > 0 && gpxFile.tracks.get(0).segments.size() > 0 && gpxFile.tracks.get(0).segments.get(0).points.size() > 0) {
|
||||
for (WptPt point : gpxFile.tracks.get(0).segments.get(0).points) {
|
||||
Location loc = new Location("", point.getLatitude(), point.getLongitude());
|
||||
if (!Double.isNaN(point.ele)) {
|
||||
loc.setAltitude(point.ele);
|
||||
lastElevation = point.ele;
|
||||
} else if (lastElevation != HEIGHT_UNDEFINED) {
|
||||
loc.setAltitude(lastElevation);
|
||||
}
|
||||
locations.add(loc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void collectSegments() {
|
||||
for (RouteSegment segment : gpxFile.routeSegments) {
|
||||
RouteDataObject object = new RouteDataObject(region);
|
||||
RouteSegmentResult segmentResult = new RouteSegmentResult(object);
|
||||
segmentResult.readFromBundle(new RouteDataBundle(resources, segment.toStringBundle()));
|
||||
route.add(segmentResult);
|
||||
}
|
||||
}
|
||||
|
||||
private void collectTypes() {
|
||||
int i = 0;
|
||||
for (RouteType routeType : gpxFile.routeTypes) {
|
||||
StringBundle bundle = routeType.toStringBundle();
|
||||
String t = bundle.getString("t", null);
|
||||
String v = bundle.getString("v", null);
|
||||
region.initRouteEncodingRule(i++, t, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +1,10 @@
|
|||
package net.osmand.router;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
||||
import net.osmand.LocationsHolder;
|
||||
import net.osmand.NativeLibrary;
|
||||
import net.osmand.PlatformUtil;
|
||||
import net.osmand.ResultMatcher;
|
||||
import net.osmand.binary.BinaryMapIndexReader;
|
||||
import net.osmand.binary.BinaryMapRouteReaderAdapter;
|
||||
import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteRegion;
|
||||
|
@ -23,6 +17,14 @@ import net.osmand.util.MapUtils;
|
|||
|
||||
import org.apache.commons.logging.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
||||
import gnu.trove.list.array.TIntArrayList;
|
||||
|
||||
public class RoutePlannerFrontEnd {
|
||||
|
@ -56,15 +58,22 @@ public class RoutePlannerFrontEnd {
|
|||
public int routeCalculations = 0;
|
||||
public int routePointsSearched = 0;
|
||||
public int routeDistCalculations = 0;
|
||||
public List<RouteSegmentResult> res = new ArrayList<RouteSegmentResult>();
|
||||
public List<GpxPoint> finalPoints = new ArrayList<GpxPoint>();
|
||||
public List<RouteSegmentResult> result = new ArrayList<RouteSegmentResult>();
|
||||
public int routeDistance;
|
||||
public int routeGapDistance;
|
||||
public int routeDistanceUnmatched;
|
||||
|
||||
|
||||
public GpxRouteApproximation(RoutingContext ctx) {
|
||||
this.ctx = ctx;
|
||||
}
|
||||
|
||||
public GpxRouteApproximation(GpxRouteApproximation gctx) {
|
||||
this.ctx = gctx.ctx;
|
||||
this.routeDistance = gctx.routeDistance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format(">> GPX approximation (%d of %d m route calcs, %d route points searched) for %d m: %d m umatched",
|
||||
|
@ -72,21 +81,21 @@ public class RoutePlannerFrontEnd {
|
|||
}
|
||||
|
||||
public double distFromLastPoint(LatLon startPoint) {
|
||||
if(res.size() > 0) {
|
||||
if (result.size() > 0) {
|
||||
return MapUtils.getDistance(getLastPoint(), startPoint);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public LatLon getLastPoint() {
|
||||
if(res.size() > 0) {
|
||||
return res.get(res.size() - 1).getEndPoint();
|
||||
if (result.size() > 0) {
|
||||
return result.get(result.size() - 1).getEndPoint();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static class GpxPoint {
|
||||
public static class GpxPoint {
|
||||
public int ind;
|
||||
public LatLon loc;
|
||||
public double cumDist;
|
||||
|
@ -94,6 +103,16 @@ public class RoutePlannerFrontEnd {
|
|||
public List<RouteSegmentResult> routeToTarget;
|
||||
public List<RouteSegmentResult> stepBackRoute;
|
||||
public int targetInd = -1;
|
||||
public boolean straightLine = false;
|
||||
|
||||
public GpxPoint() {
|
||||
}
|
||||
|
||||
public GpxPoint(GpxPoint point) {
|
||||
this.ind = point.ind;
|
||||
this.loc = point.loc;
|
||||
this.cumDist = point.cumDist;
|
||||
}
|
||||
}
|
||||
|
||||
public RoutingContext buildRoutingContext(RoutingConfiguration config, NativeLibrary nativeLibrary, BinaryMapIndexReader[] map, RouteCalculationMode rm) {
|
||||
|
@ -203,7 +222,6 @@ public class RoutePlannerFrontEnd {
|
|||
return null;
|
||||
}
|
||||
|
||||
|
||||
public List<RouteSegmentResult> searchRoute(final RoutingContext ctx, LatLon start, LatLon end, List<LatLon> intermediates) throws IOException, InterruptedException {
|
||||
return searchRoute(ctx, start, end, intermediates, null);
|
||||
}
|
||||
|
@ -212,25 +230,25 @@ public class RoutePlannerFrontEnd {
|
|||
useSmartRouteRecalculation = use;
|
||||
}
|
||||
|
||||
public GpxRouteApproximation searchGpxRoute(GpxRouteApproximation gctx, List<LatLon> points) throws IOException, InterruptedException {
|
||||
public GpxRouteApproximation searchGpxRoute(GpxRouteApproximation gctx, List<GpxPoint> gpxPoints, ResultMatcher<GpxRouteApproximation> resultMatcher) throws IOException, InterruptedException {
|
||||
long timeToCalculate = System.nanoTime();
|
||||
gctx.ctx.keepNativeRoutingContext = true;
|
||||
if (gctx.ctx.calculationProgress == null) {
|
||||
gctx.ctx.calculationProgress = new RouteCalculationProgress();
|
||||
}
|
||||
gctx.ctx.keepNativeRoutingContext = true;
|
||||
List<GpxPoint> gpxPoints = generageGpxPoints(points, gctx);
|
||||
GpxPoint start = null;
|
||||
GpxPoint prev = null;
|
||||
if(gpxPoints.size() > 0) {
|
||||
if (gpxPoints.size() > 0) {
|
||||
gctx.ctx.calculationProgress.totalIterations = (int) (gpxPoints.get(gpxPoints.size() - 1).cumDist / gctx.MAXIMUM_STEP_APPROXIMATION + 1);
|
||||
start = gpxPoints.get(0);
|
||||
}
|
||||
while (start != null) {
|
||||
while (start != null && !gctx.ctx.calculationProgress.isCancelled) {
|
||||
double routeDist = gctx.MAXIMUM_STEP_APPROXIMATION;
|
||||
GpxPoint next = findNextGpxPointWithin(gctx, gpxPoints, start, routeDist);
|
||||
boolean routeFound = false;
|
||||
gctx.ctx.calculationProgress.nextIteration();
|
||||
if (next != null && initRoutingPoint(start, gctx, gctx.MINIMUM_POINT_APPROXIMATION)) {
|
||||
gctx.ctx.calculationProgress.totalEstimatedDistance = 0;
|
||||
gctx.ctx.calculationProgress.iteration = (int) (next.cumDist / gctx.MAXIMUM_STEP_APPROXIMATION);
|
||||
while (routeDist >= gctx.MINIMUM_STEP_APPROXIMATION && !routeFound) {
|
||||
routeFound = initRoutingPoint(next, gctx, gctx.MINIMUM_POINT_APPROXIMATION);
|
||||
if (routeFound) {
|
||||
|
@ -279,16 +297,19 @@ public class RoutePlannerFrontEnd {
|
|||
}
|
||||
start = next;
|
||||
}
|
||||
if(gctx.ctx.calculationProgress != null) {
|
||||
gctx.ctx.calculationProgress.timeToCalculate = System.nanoTime() - timeToCalculate;
|
||||
if (gctx.ctx.calculationProgress != null) {
|
||||
gctx.ctx.calculationProgress.timeToCalculate = System.nanoTime() - timeToCalculate;
|
||||
}
|
||||
gctx.ctx.deleteNativeRoutingContext();
|
||||
BinaryRoutePlanner.printDebugMemoryInformation(gctx.ctx);
|
||||
calculateGpxRoute(gctx, gpxPoints);
|
||||
if (!gctx.res.isEmpty()) {
|
||||
new RouteResultPreparation().printResults(gctx.ctx, points.get(0), points.get(points.size() - 1), gctx.res);
|
||||
if (!gctx.result.isEmpty() && !gctx.ctx.calculationProgress.isCancelled) {
|
||||
new RouteResultPreparation().printResults(gctx.ctx, gpxPoints.get(0).loc, gpxPoints.get(gpxPoints.size() - 1).loc, gctx.result);
|
||||
System.out.println(gctx);
|
||||
}
|
||||
if (resultMatcher != null) {
|
||||
resultMatcher.publish(gctx.ctx.calculationProgress.isCancelled ? null : gctx);
|
||||
}
|
||||
return gctx;
|
||||
}
|
||||
|
||||
|
@ -340,13 +361,14 @@ public class RoutePlannerFrontEnd {
|
|||
RouteRegion reg = new RouteRegion();
|
||||
reg.initRouteEncodingRule(0, "highway", RouteResultPreparation.UNMATCHED_HIGHWAY_TYPE);
|
||||
List<LatLon> lastStraightLine = null;
|
||||
for (int i = 0; i < gpxPoints.size(); ) {
|
||||
GpxPoint straightPointStart = null;
|
||||
for (int i = 0; i < gpxPoints.size() && !gctx.ctx.calculationProgress.isCancelled; ) {
|
||||
GpxPoint pnt = gpxPoints.get(i);
|
||||
if (pnt.routeToTarget != null && !pnt.routeToTarget.isEmpty()) {
|
||||
LatLon startPoint = pnt.routeToTarget.get(0).getStartPoint();
|
||||
if (lastStraightLine != null) {
|
||||
lastStraightLine.add(startPoint);
|
||||
addStraightLine(gctx.res, lastStraightLine, reg, gctx);
|
||||
addStraightLine(gctx, lastStraightLine, straightPointStart, reg);
|
||||
lastStraightLine = null;
|
||||
}
|
||||
if (gctx.distFromLastPoint(startPoint) > 1) {
|
||||
|
@ -354,14 +376,16 @@ public class RoutePlannerFrontEnd {
|
|||
System.out.println(String.format("????? gap of route point = %f, gap of actual gpxPoint = %f, %s ",
|
||||
gctx.distFromLastPoint(startPoint), gctx.distFromLastPoint(pnt.loc), pnt.loc));
|
||||
}
|
||||
gctx.res.addAll(pnt.routeToTarget);
|
||||
gctx.finalPoints.add(pnt);
|
||||
gctx.result.addAll(pnt.routeToTarget);
|
||||
i = pnt.targetInd;
|
||||
} else {
|
||||
// add straight line from i -> i+1
|
||||
if (lastStraightLine == null) {
|
||||
lastStraightLine = new ArrayList<LatLon>();
|
||||
straightPointStart = pnt;
|
||||
// make smooth connection
|
||||
if(gctx.distFromLastPoint(pnt.loc) > 1) {
|
||||
if (gctx.distFromLastPoint(pnt.loc) > 1) {
|
||||
lastStraightLine.add(gctx.getLastPoint());
|
||||
}
|
||||
}
|
||||
|
@ -370,20 +394,55 @@ public class RoutePlannerFrontEnd {
|
|||
}
|
||||
}
|
||||
if (lastStraightLine != null) {
|
||||
addStraightLine(gctx.res, lastStraightLine, reg, gctx);
|
||||
addStraightLine(gctx, lastStraightLine, straightPointStart, reg);
|
||||
lastStraightLine = null;
|
||||
}
|
||||
// clean turns to recaculate them
|
||||
cleanupResultAndAddTurns(gctx);
|
||||
}
|
||||
|
||||
private List<GpxPoint> generageGpxPoints(List<LatLon> points, GpxRouteApproximation gctx) {
|
||||
List<GpxPoint> gpxPoints = new ArrayList<>(points.size());
|
||||
public static RouteSegmentResult generateStraightLineSegment(float averageSpeed, List<LatLon> points) {
|
||||
RouteRegion reg = new RouteRegion();
|
||||
reg.initRouteEncodingRule(0, "highway", RouteResultPreparation.UNMATCHED_HIGHWAY_TYPE);
|
||||
RouteDataObject rdo = new RouteDataObject(reg);
|
||||
int size = points.size();
|
||||
TIntArrayList x = new TIntArrayList(size);
|
||||
TIntArrayList y = new TIntArrayList(size);
|
||||
double distance = 0;
|
||||
double distOnRoadToPass = 0;
|
||||
LatLon prev = null;
|
||||
for (int i = 0; i < size; i++) {
|
||||
LatLon l = points.get(i);
|
||||
if (l != null) {
|
||||
x.add(MapUtils.get31TileNumberX(l.getLongitude()));
|
||||
y.add(MapUtils.get31TileNumberY(l.getLatitude()));
|
||||
if (prev != null) {
|
||||
double d = MapUtils.getDistance(l, prev);
|
||||
distance += d;
|
||||
distOnRoadToPass += d / averageSpeed;
|
||||
}
|
||||
}
|
||||
prev = l;
|
||||
}
|
||||
rdo.pointsX = x.toArray();
|
||||
rdo.pointsY = y.toArray();
|
||||
rdo.types = new int[] { 0 } ;
|
||||
rdo.id = -1;
|
||||
RouteSegmentResult segment = new RouteSegmentResult(rdo, 0, rdo.getPointsLength() - 1);
|
||||
segment.setSegmentTime((float) distOnRoadToPass);
|
||||
segment.setSegmentSpeed(averageSpeed);
|
||||
segment.setDistance((float) distance);
|
||||
segment.setTurnType(TurnType.straight());
|
||||
return segment;
|
||||
}
|
||||
|
||||
public List<GpxPoint> generateGpxPoints(GpxRouteApproximation gctx, LocationsHolder locationsHolder) {
|
||||
List<GpxPoint> gpxPoints = new ArrayList<>(locationsHolder.getSize());
|
||||
GpxPoint prev = null;
|
||||
for(int i = 0; i < points.size(); i++) {
|
||||
for(int i = 0; i < locationsHolder.getSize(); i++) {
|
||||
GpxPoint p = new GpxPoint();
|
||||
p.ind = i;
|
||||
p.loc = points.get(i);
|
||||
p.loc = locationsHolder.getLatLon(i);
|
||||
if (prev != null) {
|
||||
p.cumDist = MapUtils.getDistance(p.loc, prev.loc) + prev.cumDist;
|
||||
}
|
||||
|
@ -397,27 +456,29 @@ public class RoutePlannerFrontEnd {
|
|||
private void cleanupResultAndAddTurns(GpxRouteApproximation gctx) {
|
||||
// cleanup double joints
|
||||
int LOOK_AHEAD = 4;
|
||||
for(int i = 0; i < gctx.res.size(); i++) {
|
||||
RouteSegmentResult s = gctx.res.get(i);
|
||||
for(int j = i + 2; j <= i + LOOK_AHEAD && j < gctx.res.size(); j++) {
|
||||
RouteSegmentResult e = gctx.res.get(j);
|
||||
if(e.getStartPoint().equals(s.getEndPoint())) {
|
||||
while((--j) != i) {
|
||||
gctx.res.remove(j);
|
||||
for(int i = 0; i < gctx.result.size() && !gctx.ctx.calculationProgress.isCancelled; i++) {
|
||||
RouteSegmentResult s = gctx.result.get(i);
|
||||
for(int j = i + 2; j <= i + LOOK_AHEAD && j < gctx.result.size(); j++) {
|
||||
RouteSegmentResult e = gctx.result.get(j);
|
||||
if (e.getStartPoint().equals(s.getEndPoint())) {
|
||||
while ((--j) != i) {
|
||||
gctx.result.remove(j);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
RouteResultPreparation preparation = new RouteResultPreparation();
|
||||
for (RouteSegmentResult r : gctx.res) {
|
||||
for (RouteSegmentResult r : gctx.result) {
|
||||
r.setTurnType(null);
|
||||
r.setDescription("");
|
||||
}
|
||||
preparation.prepareTurnResults(gctx.ctx, gctx.res);
|
||||
if (!gctx.ctx.calculationProgress.isCancelled) {
|
||||
preparation.prepareTurnResults(gctx.ctx, gctx.result);
|
||||
}
|
||||
}
|
||||
|
||||
private void addStraightLine(List<RouteSegmentResult> res, List<LatLon> lastStraightLine, RouteRegion reg, GpxRouteApproximation gctx) {
|
||||
private void addStraightLine(GpxRouteApproximation gctx, List<LatLon> lastStraightLine, GpxPoint strPnt, RouteRegion reg) {
|
||||
RouteDataObject rdo = new RouteDataObject(reg);
|
||||
if(gctx.SMOOTHEN_POINTS_NO_ROUTE > 0) {
|
||||
simplifyDouglasPeucker(lastStraightLine, gctx.SMOOTHEN_POINTS_NO_ROUTE, 0, lastStraightLine.size() - 1);
|
||||
|
@ -441,17 +502,19 @@ public class RoutePlannerFrontEnd {
|
|||
rdo.pointsY = y.toArray();
|
||||
rdo.types = new int[] { 0 } ;
|
||||
rdo.id = -1;
|
||||
List<RouteSegmentResult> rts = new ArrayList<>();
|
||||
rts.add(new RouteSegmentResult(rdo, 0, rdo.getPointsLength() - 1));
|
||||
strPnt.routeToTarget = new ArrayList<>();
|
||||
strPnt.straightLine = true;
|
||||
strPnt.routeToTarget.add(new RouteSegmentResult(rdo, 0, rdo.getPointsLength() - 1));
|
||||
RouteResultPreparation preparation = new RouteResultPreparation();
|
||||
try {
|
||||
preparation.prepareResult(gctx.ctx, rts, false);
|
||||
preparation.prepareResult(gctx.ctx, strPnt.routeToTarget, false);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
|
||||
// VIEW: comment to see road without straight connections
|
||||
res.addAll(rts);
|
||||
gctx.finalPoints.add(strPnt);
|
||||
gctx.result.addAll(strPnt.routeToTarget);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -327,6 +327,9 @@ public class RouteSegmentResult implements StringExternalizable<RouteDataBundle>
|
|||
Location prevLocation = null;
|
||||
for (int i = 0; i < length; i++) {
|
||||
Location location = resources.getLocation(index);
|
||||
if (location == null) {
|
||||
break;
|
||||
}
|
||||
double dist = 0;
|
||||
if (prevLocation != null) {
|
||||
dist = MapUtils.getDistance(prevLocation.getLatitude(), prevLocation.getLongitude(), location.getLatitude(), location.getLongitude());
|
||||
|
|
|
@ -2,27 +2,16 @@ package net.osmand.router;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Locale;
|
||||
import java.util.PriorityQueue;
|
||||
|
||||
|
||||
import gnu.trove.iterator.TIntIterator;
|
||||
import gnu.trove.list.array.TIntArrayList;
|
||||
import gnu.trove.map.hash.TIntObjectHashMap;
|
||||
import gnu.trove.map.hash.TLongObjectHashMap;
|
||||
import net.osmand.NativeLibrary;
|
||||
import net.osmand.binary.BinaryMapIndexReader;
|
||||
import net.osmand.binary.BinaryMapIndexReader.SearchRequest;
|
||||
import net.osmand.data.IncompleteTransportRoute;
|
||||
|
||||
import net.osmand.data.LatLon;
|
||||
import net.osmand.data.QuadRect;
|
||||
import net.osmand.data.TransportRoute;
|
||||
|
@ -31,9 +20,6 @@ import net.osmand.data.TransportStop;
|
|||
import net.osmand.data.TransportStopExit;
|
||||
import net.osmand.osm.edit.Node;
|
||||
import net.osmand.osm.edit.Way;
|
||||
import net.osmand.router.TransportRoutePlanner.TransportRouteResult;
|
||||
import net.osmand.router.TransportRoutePlanner.TransportRouteResultSegment;
|
||||
import net.osmand.router.TransportRoutePlanner.TransportRouteSegment;
|
||||
import net.osmand.util.MapUtils;
|
||||
|
||||
public class TransportRoutePlanner {
|
||||
|
@ -224,11 +210,10 @@ public class TransportRoutePlanner {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private List<TransportRouteResult> prepareResults(TransportRoutingContext ctx, List<TransportRouteSegment> results) {
|
||||
Collections.sort(results, new SegmentsComparator(ctx));
|
||||
List<TransportRouteResult> lst = new ArrayList<TransportRouteResult>();
|
||||
System.out.println(String.format("Calculated %.1f seconds, found %d results, visited %d routes / %d stops, loaded %d tiles (%d ms read, %d ms total), loaded ways %d (%d wrong)",
|
||||
System.out.println(String.format(Locale.US, "Calculated %.1f seconds, found %d results, visited %d routes / %d stops, loaded %d tiles (%d ms read, %d ms total), loaded ways %d (%d wrong)",
|
||||
(System.currentTimeMillis() - ctx.startCalcTime) / 1000.0, results.size(),
|
||||
ctx.visitedRoutesCount, ctx.visitedStops,
|
||||
ctx.quadTree.size(), ctx.readTime / (1000 * 1000), ctx.loadTime / (1000 * 1000),
|
||||
|
@ -314,7 +299,6 @@ public class TransportRoutePlanner {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
public static class TransportRouteResultSegment {
|
||||
|
||||
private static final boolean DISPLAY_FULL_SEGMENT_ROUTE = false;
|
||||
|
@ -487,156 +471,12 @@ public class TransportRoutePlanner {
|
|||
}
|
||||
}
|
||||
|
||||
public static class TransportRouteResult {
|
||||
|
||||
List<TransportRouteResultSegment> segments = new ArrayList<TransportRouteResultSegment>(4);
|
||||
double finishWalkDist;
|
||||
double routeTime;
|
||||
private final TransportRoutingConfiguration cfg;
|
||||
|
||||
public TransportRouteResult(TransportRoutingContext ctx) {
|
||||
cfg = ctx.cfg;
|
||||
}
|
||||
|
||||
public TransportRouteResult(TransportRoutingConfiguration cfg) {
|
||||
this.cfg = cfg;
|
||||
}
|
||||
|
||||
public List<TransportRouteResultSegment> getSegments() {
|
||||
return segments;
|
||||
}
|
||||
|
||||
public void setFinishWalkDist(double finishWalkDist) {
|
||||
this.finishWalkDist = finishWalkDist;
|
||||
}
|
||||
|
||||
public void setRouteTime(double routeTime) {
|
||||
this.routeTime = routeTime;
|
||||
}
|
||||
|
||||
public void addSegment(TransportRouteResultSegment seg) {
|
||||
segments.add(seg);
|
||||
}
|
||||
|
||||
public double getWalkDist() {
|
||||
double d = finishWalkDist;
|
||||
for (TransportRouteResultSegment s : segments) {
|
||||
d += s.walkDist;
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
public double getFinishWalkDist() {
|
||||
return finishWalkDist;
|
||||
}
|
||||
|
||||
public double getWalkSpeed() {
|
||||
return cfg.walkSpeed;
|
||||
}
|
||||
|
||||
public double getRouteTime() {
|
||||
return routeTime;
|
||||
}
|
||||
|
||||
public int getStops() {
|
||||
int stops = 0;
|
||||
for(TransportRouteResultSegment s : segments) {
|
||||
stops += (s.end - s.start);
|
||||
}
|
||||
return stops;
|
||||
}
|
||||
|
||||
public boolean isRouteStop(TransportStop stop) {
|
||||
for(TransportRouteResultSegment s : segments) {
|
||||
if (s.getTravelStops().contains(stop)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public TransportRouteResultSegment getRouteStopSegment(TransportStop stop) {
|
||||
for(TransportRouteResultSegment s : segments) {
|
||||
if (s.getTravelStops().contains(stop)) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public double getTravelDist() {
|
||||
double d = 0;
|
||||
for (TransportRouteResultSegment s : segments) {
|
||||
d += s.getTravelDist();
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
public double getTravelTime() {
|
||||
double t = 0;
|
||||
for (TransportRouteResultSegment s : segments) {
|
||||
if (cfg.useSchedule) {
|
||||
TransportSchedule sts = s.route.getSchedule();
|
||||
for (int k = s.start; k < s.end; k++) {
|
||||
t += sts.getAvgStopIntervals()[k] * 10;
|
||||
}
|
||||
} else {
|
||||
t += cfg.getBoardingTime();
|
||||
t += s.getTravelTime();
|
||||
}
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
public double getWalkTime() {
|
||||
return getWalkDist() / cfg.walkSpeed;
|
||||
}
|
||||
|
||||
public double getChangeTime() {
|
||||
return cfg.getChangeTime();
|
||||
}
|
||||
|
||||
public double getBoardingTime() {
|
||||
return cfg.getBoardingTime();
|
||||
}
|
||||
|
||||
public int getChanges() {
|
||||
return segments.size() - 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder bld = new StringBuilder();
|
||||
bld.append(String.format("Route %d stops, %d changes, %.2f min: %.2f m (%.1f min) to walk, %.2f m (%.1f min) to travel\n",
|
||||
getStops(), getChanges(), routeTime / 60, getWalkDist(), getWalkTime() / 60.0,
|
||||
getTravelDist(), getTravelTime() / 60.0));
|
||||
for(int i = 0; i < segments.size(); i++) {
|
||||
TransportRouteResultSegment s = segments.get(i);
|
||||
String time = "";
|
||||
String arriveTime = "";
|
||||
if(s.depTime != -1) {
|
||||
time = String.format("at %s", formatTransporTime(s.depTime));
|
||||
}
|
||||
int aTime = s.getArrivalTime();
|
||||
if(aTime != -1) {
|
||||
arriveTime = String.format("and arrive at %s", formatTransporTime(aTime));
|
||||
}
|
||||
bld.append(String.format(" %d. %s [%d]: walk %.1f m to '%s' and travel %s to '%s' by %s %d stops %s\n",
|
||||
i + 1, s.route.getRef(), s.route.getId() / 2, s.walkDist, s.getStart().getName(),
|
||||
time, s.getEnd().getName(),s.route.getName(), (s.end - s.start), arriveTime));
|
||||
}
|
||||
bld.append(String.format(" F. Walk %.1f m to reach your destination", finishWalkDist));
|
||||
return bld.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public static String formatTransporTime(int i) {
|
||||
public static String formatTransportTime(int i) {
|
||||
int h = i / 60 / 6;
|
||||
int mh = i - h * 60 * 6;
|
||||
int m = mh / 6;
|
||||
int s = (mh - m * 6) * 10;
|
||||
String tm = String.format("%02d:%02d:%02d ", h, m, s);
|
||||
return tm;
|
||||
return String.format(Locale.US, "%02d:%02d:%02d ", h, m, s);
|
||||
}
|
||||
|
||||
public static class TransportRouteSegment {
|
||||
|
@ -653,13 +493,9 @@ public class TransportRoutePlanner {
|
|||
double parentTravelDist; // travel distance for parent route (inaccurate)
|
||||
// walk distance to start route location (or finish in case last segment)
|
||||
double walkDist = 0;
|
||||
|
||||
// main field accumulated all time spent from beginning of journey
|
||||
double distFromStart = 0;
|
||||
|
||||
|
||||
|
||||
|
||||
public TransportRouteSegment(TransportRoute road, int stopIndex) {
|
||||
this.road = road;
|
||||
this.segStart = (short) stopIndex;
|
||||
|
@ -678,7 +514,6 @@ public class TransportRoutePlanner {
|
|||
this.departureTime = c.departureTime;
|
||||
}
|
||||
|
||||
|
||||
public boolean wasVisited(TransportRouteSegment rrs) {
|
||||
if (rrs.road.getId().longValue() == road.getId().longValue() &&
|
||||
rrs.departureTime == departureTime) {
|
||||
|
@ -690,22 +525,18 @@ public class TransportRoutePlanner {
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
public TransportStop getStop(int i) {
|
||||
return road.getForwardStops().get(i);
|
||||
}
|
||||
|
||||
|
||||
public LatLon getLocation() {
|
||||
return road.getForwardStops().get(segStart).getLocation();
|
||||
}
|
||||
|
||||
|
||||
public int getLength() {
|
||||
return road.getForwardStops().size();
|
||||
}
|
||||
|
||||
|
||||
public long getId() {
|
||||
long l = road.getId();
|
||||
|
||||
|
@ -727,7 +558,6 @@ public class TransportRoutePlanner {
|
|||
return l ;
|
||||
}
|
||||
|
||||
|
||||
public int getDepth() {
|
||||
if(parentRoute != null) {
|
||||
return parentRoute.getDepth() + 1;
|
||||
|
@ -738,162 +568,7 @@ public class TransportRoutePlanner {
|
|||
@Override
|
||||
public String toString() {
|
||||
return String.format("Route: %s, stop: %s %s", road.getName(), road.getForwardStops().get(segStart).getName(),
|
||||
departureTime == -1 ? "" : formatTransporTime(departureTime) );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class TransportRoutingContext {
|
||||
|
||||
public NativeLibrary library;
|
||||
public RouteCalculationProgress calculationProgress;
|
||||
public TLongObjectHashMap<TransportRouteSegment> visitedSegments = new TLongObjectHashMap<TransportRouteSegment>();
|
||||
public TransportRoutingConfiguration cfg;
|
||||
public TLongObjectHashMap<TransportRoute> combinedRoutesCache = new TLongObjectHashMap<TransportRoute>();
|
||||
public Map<TransportStop, List<TransportRoute>> missingStopsCache = new HashMap<TransportStop, List<TransportRoute>>();
|
||||
|
||||
public TLongObjectHashMap<List<TransportRouteSegment>> quadTree;
|
||||
// Here we don't limit files by bbox, so it could be an issue while searching for multiple unused files
|
||||
// Incomplete routes usually don't need more files than around Max-BBOX of start/end,
|
||||
// so here an improvement could be introduced
|
||||
final TransportStopsRouteReader transportStopsReader;
|
||||
public int finishTimeSeconds;
|
||||
|
||||
// stats
|
||||
public long startCalcTime;
|
||||
public int visitedRoutesCount;
|
||||
public int visitedStops;
|
||||
public int wrongLoadedWays;
|
||||
public int loadedWays;
|
||||
public long loadTime;
|
||||
public long readTime;
|
||||
|
||||
|
||||
|
||||
private final int walkRadiusIn31;
|
||||
private final int walkChangeRadiusIn31;
|
||||
|
||||
|
||||
|
||||
public TransportRoutingContext(TransportRoutingConfiguration cfg, NativeLibrary library, BinaryMapIndexReader... readers) {
|
||||
this.cfg = cfg;
|
||||
walkRadiusIn31 = (int) (cfg.walkRadius / MapUtils.getTileDistanceWidth(31));
|
||||
walkChangeRadiusIn31 = (int) (cfg.walkChangeRadius / MapUtils.getTileDistanceWidth(31));
|
||||
quadTree = new TLongObjectHashMap<List<TransportRouteSegment>>();
|
||||
this.library = library;
|
||||
transportStopsReader = new TransportStopsRouteReader(Arrays.asList(readers));
|
||||
}
|
||||
|
||||
public List<TransportRouteSegment> getTransportStops(LatLon loc) throws IOException {
|
||||
int y = MapUtils.get31TileNumberY(loc.getLatitude());
|
||||
int x = MapUtils.get31TileNumberX(loc.getLongitude());
|
||||
return getTransportStops(x, y, false, new ArrayList<TransportRouteSegment>());
|
||||
}
|
||||
|
||||
public List<TransportRouteSegment> getTransportStops(int x, int y, boolean change, List<TransportRouteSegment> res) throws IOException {
|
||||
return loadNativeTransportStops(x, y, change, res);
|
||||
}
|
||||
|
||||
private List<TransportRouteSegment> loadNativeTransportStops(int sx, int sy, boolean change, List<TransportRouteSegment> res) throws IOException {
|
||||
long nanoTime = System.nanoTime();
|
||||
int d = change ? walkChangeRadiusIn31 : walkRadiusIn31;
|
||||
int lx = (sx - d ) >> (31 - cfg.ZOOM_TO_LOAD_TILES);
|
||||
int rx = (sx + d ) >> (31 - cfg.ZOOM_TO_LOAD_TILES);
|
||||
int ty = (sy - d ) >> (31 - cfg.ZOOM_TO_LOAD_TILES);
|
||||
int by = (sy + d ) >> (31 - cfg.ZOOM_TO_LOAD_TILES);
|
||||
for(int x = lx; x <= rx; x++) {
|
||||
for(int y = ty; y <= by; y++) {
|
||||
long tileId = (((long)x) << (cfg.ZOOM_TO_LOAD_TILES + 1)) + y;
|
||||
List<TransportRouteSegment> list = quadTree.get(tileId);
|
||||
if(list == null) {
|
||||
list = loadTile(x, y);
|
||||
quadTree.put(tileId, list);
|
||||
}
|
||||
for(TransportRouteSegment r : list) {
|
||||
TransportStop st = r.getStop(r.segStart);
|
||||
if (Math.abs(st.x31 - sx) > walkRadiusIn31 || Math.abs(st.y31 - sy) > walkRadiusIn31) {
|
||||
wrongLoadedWays++;
|
||||
} else {
|
||||
loadedWays++;
|
||||
res.add(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
loadTime += System.nanoTime() - nanoTime;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
private List<TransportRouteSegment> loadTile(int x, int y) throws IOException {
|
||||
long nanoTime = System.nanoTime();
|
||||
List<TransportRouteSegment> lst = new ArrayList<TransportRouteSegment>();
|
||||
int pz = (31 - cfg.ZOOM_TO_LOAD_TILES);
|
||||
SearchRequest<TransportStop> sr = BinaryMapIndexReader.buildSearchTransportRequest(x << pz, (x + 1) << pz,
|
||||
y << pz, (y + 1) << pz, -1, null);
|
||||
Collection<TransportStop> stops = transportStopsReader.readMergedTransportStops(sr);
|
||||
loadTransportSegments(stops, lst);
|
||||
readTime += System.nanoTime() - nanoTime;
|
||||
return lst;
|
||||
}
|
||||
|
||||
private void loadTransportSegments(Collection<TransportStop> stops, List<TransportRouteSegment> lst) throws IOException {
|
||||
for(TransportStop s : stops) {
|
||||
if (s.isDeleted() || s.getRoutes() == null) {
|
||||
continue;
|
||||
}
|
||||
for (TransportRoute route : s.getRoutes()) {
|
||||
int stopIndex = -1;
|
||||
double dist = TransportRoute.SAME_STOP;
|
||||
for (int k = 0; k < route.getForwardStops().size(); k++) {
|
||||
TransportStop st = route.getForwardStops().get(k);
|
||||
if(st.getId().longValue() == s.getId().longValue() ) {
|
||||
stopIndex = k;
|
||||
break;
|
||||
}
|
||||
double d = MapUtils.getDistance(st.getLocation(), s.getLocation());
|
||||
if (d < dist) {
|
||||
stopIndex = k;
|
||||
dist = d;
|
||||
}
|
||||
}
|
||||
if (stopIndex != -1) {
|
||||
if (cfg != null && cfg.useSchedule) {
|
||||
loadScheduleRouteSegment(lst, route, stopIndex);
|
||||
} else {
|
||||
TransportRouteSegment segment = new TransportRouteSegment(route, stopIndex);
|
||||
lst.add(segment);
|
||||
}
|
||||
} else {
|
||||
System.err.println(String.format("Routing error: missing stop '%s' in route '%s' id: %d",
|
||||
s.toString(), route.getRef(), route.getId() / 2));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void loadScheduleRouteSegment(List<TransportRouteSegment> lst, TransportRoute route, int stopIndex) {
|
||||
if(route.getSchedule() != null) {
|
||||
TIntArrayList ti = route.getSchedule().tripIntervals;
|
||||
int cnt = ti.size();
|
||||
int t = 0;
|
||||
// improve by using exact data
|
||||
int stopTravelTime = 0;
|
||||
TIntArrayList avgStopIntervals = route.getSchedule().avgStopIntervals;
|
||||
for (int i = 0; i < stopIndex; i++) {
|
||||
if (avgStopIntervals.size() > i) {
|
||||
stopTravelTime += avgStopIntervals.getQuick(i);
|
||||
}
|
||||
}
|
||||
for(int i = 0; i < cnt; i++) {
|
||||
t += ti.getQuick(i);
|
||||
int startTime = t + stopTravelTime;
|
||||
if(startTime >= cfg.scheduleTimeOfDay && startTime <= cfg.scheduleTimeOfDay + cfg.scheduleMaxTime ) {
|
||||
TransportRouteSegment segment = new TransportRouteSegment(route, stopIndex, startTime);
|
||||
lst.add(segment);
|
||||
}
|
||||
}
|
||||
}
|
||||
departureTime == -1 ? "" : formatTransportTime(departureTime) );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,151 @@
|
|||
package net.osmand.router;
|
||||
|
||||
import net.osmand.data.TransportSchedule;
|
||||
import net.osmand.data.TransportStop;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public class TransportRouteResult {
|
||||
|
||||
List<TransportRoutePlanner.TransportRouteResultSegment> segments = new ArrayList<TransportRoutePlanner.TransportRouteResultSegment>(4);
|
||||
double finishWalkDist;
|
||||
double routeTime;
|
||||
private final TransportRoutingConfiguration cfg;
|
||||
|
||||
public TransportRouteResult(TransportRoutingContext ctx) {
|
||||
cfg = ctx.cfg;
|
||||
}
|
||||
|
||||
public TransportRouteResult(TransportRoutingConfiguration cfg) {
|
||||
this.cfg = cfg;
|
||||
}
|
||||
|
||||
public List<TransportRoutePlanner.TransportRouteResultSegment> getSegments() {
|
||||
return segments;
|
||||
}
|
||||
|
||||
public void setFinishWalkDist(double finishWalkDist) {
|
||||
this.finishWalkDist = finishWalkDist;
|
||||
}
|
||||
|
||||
public void setRouteTime(double routeTime) {
|
||||
this.routeTime = routeTime;
|
||||
}
|
||||
|
||||
public void addSegment(TransportRoutePlanner.TransportRouteResultSegment seg) {
|
||||
segments.add(seg);
|
||||
}
|
||||
|
||||
public double getWalkDist() {
|
||||
double d = finishWalkDist;
|
||||
for (TransportRoutePlanner.TransportRouteResultSegment s : segments) {
|
||||
d += s.walkDist;
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
public double getFinishWalkDist() {
|
||||
return finishWalkDist;
|
||||
}
|
||||
|
||||
public double getWalkSpeed() {
|
||||
return cfg.walkSpeed;
|
||||
}
|
||||
|
||||
public double getRouteTime() {
|
||||
return routeTime;
|
||||
}
|
||||
|
||||
public int getStops() {
|
||||
int stops = 0;
|
||||
for(TransportRoutePlanner.TransportRouteResultSegment s : segments) {
|
||||
stops += (s.end - s.start);
|
||||
}
|
||||
return stops;
|
||||
}
|
||||
|
||||
public boolean isRouteStop(TransportStop stop) {
|
||||
for(TransportRoutePlanner.TransportRouteResultSegment s : segments) {
|
||||
if (s.getTravelStops().contains(stop)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public TransportRoutePlanner.TransportRouteResultSegment getRouteStopSegment(TransportStop stop) {
|
||||
for(TransportRoutePlanner.TransportRouteResultSegment s : segments) {
|
||||
if (s.getTravelStops().contains(stop)) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public double getTravelDist() {
|
||||
double d = 0;
|
||||
for (TransportRoutePlanner.TransportRouteResultSegment s : segments) {
|
||||
d += s.getTravelDist();
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
public double getTravelTime() {
|
||||
double t = 0;
|
||||
for (TransportRoutePlanner.TransportRouteResultSegment s : segments) {
|
||||
if (cfg.useSchedule) {
|
||||
TransportSchedule sts = s.route.getSchedule();
|
||||
for (int k = s.start; k < s.end; k++) {
|
||||
t += sts.getAvgStopIntervals()[k] * 10;
|
||||
}
|
||||
} else {
|
||||
t += cfg.getBoardingTime();
|
||||
t += s.getTravelTime();
|
||||
}
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
public double getWalkTime() {
|
||||
return getWalkDist() / cfg.walkSpeed;
|
||||
}
|
||||
|
||||
public double getChangeTime() {
|
||||
return cfg.getChangeTime();
|
||||
}
|
||||
|
||||
public double getBoardingTime() {
|
||||
return cfg.getBoardingTime();
|
||||
}
|
||||
|
||||
public int getChanges() {
|
||||
return segments.size() - 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder bld = new StringBuilder();
|
||||
bld.append(String.format(Locale.US, "Route %d stops, %d changes, %.2f min: %.2f m (%.1f min) to walk, %.2f m (%.1f min) to travel\n",
|
||||
getStops(), getChanges(), routeTime / 60, getWalkDist(), getWalkTime() / 60.0,
|
||||
getTravelDist(), getTravelTime() / 60.0));
|
||||
for(int i = 0; i < segments.size(); i++) {
|
||||
TransportRoutePlanner.TransportRouteResultSegment s = segments.get(i);
|
||||
String time = "";
|
||||
String arriveTime = "";
|
||||
if(s.depTime != -1) {
|
||||
time = String.format("at %s", TransportRoutePlanner.formatTransportTime(s.depTime));
|
||||
}
|
||||
int aTime = s.getArrivalTime();
|
||||
if(aTime != -1) {
|
||||
arriveTime = String.format("and arrive at %s", TransportRoutePlanner.formatTransportTime(aTime));
|
||||
}
|
||||
bld.append(String.format(Locale.US, " %d. %s [%d]: walk %.1f m to '%s' and travel %s to '%s' by %s %d stops %s\n",
|
||||
i + 1, s.route.getRef(), s.route.getId() / 2, s.walkDist, s.getStart().getName(),
|
||||
time, s.getEnd().getName(),s.route.getName(), (s.end - s.start), arriveTime));
|
||||
}
|
||||
bld.append(String.format(" F. Walk %.1f m to reach your destination", finishWalkDist));
|
||||
return bld.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,171 @@
|
|||
package net.osmand.router;
|
||||
|
||||
import net.osmand.NativeLibrary;
|
||||
import net.osmand.binary.BinaryMapIndexReader;
|
||||
import net.osmand.data.LatLon;
|
||||
import net.osmand.data.TransportRoute;
|
||||
import net.osmand.data.TransportStop;
|
||||
import net.osmand.router.TransportRoutePlanner.TransportRouteSegment;
|
||||
import net.osmand.util.MapUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import gnu.trove.list.array.TIntArrayList;
|
||||
import gnu.trove.map.hash.TLongObjectHashMap;
|
||||
|
||||
public class TransportRoutingContext {
|
||||
|
||||
public NativeLibrary library;
|
||||
public RouteCalculationProgress calculationProgress;
|
||||
public TLongObjectHashMap<TransportRouteSegment> visitedSegments = new TLongObjectHashMap<TransportRouteSegment>();
|
||||
public TransportRoutingConfiguration cfg;
|
||||
public TLongObjectHashMap<TransportRoute> combinedRoutesCache = new TLongObjectHashMap<TransportRoute>();
|
||||
public Map<TransportStop, List<TransportRoute>> missingStopsCache = new HashMap<TransportStop, List<TransportRoute>>();
|
||||
|
||||
public TLongObjectHashMap<List<TransportRouteSegment>> quadTree;
|
||||
// Here we don't limit files by bbox, so it could be an issue while searching for multiple unused files
|
||||
// Incomplete routes usually don't need more files than around Max-BBOX of start/end,
|
||||
// so here an improvement could be introduced
|
||||
final TransportStopsRouteReader transportStopsReader;
|
||||
public int finishTimeSeconds;
|
||||
|
||||
// stats
|
||||
public long startCalcTime;
|
||||
public int visitedRoutesCount;
|
||||
public int visitedStops;
|
||||
public int wrongLoadedWays;
|
||||
public int loadedWays;
|
||||
public long loadTime;
|
||||
public long readTime;
|
||||
|
||||
private final int walkRadiusIn31;
|
||||
private final int walkChangeRadiusIn31;
|
||||
|
||||
public TransportRoutingContext(TransportRoutingConfiguration cfg, NativeLibrary library, BinaryMapIndexReader... readers) {
|
||||
this.cfg = cfg;
|
||||
walkRadiusIn31 = (int) (cfg.walkRadius / MapUtils.getTileDistanceWidth(31));
|
||||
walkChangeRadiusIn31 = (int) (cfg.walkChangeRadius / MapUtils.getTileDistanceWidth(31));
|
||||
quadTree = new TLongObjectHashMap<List<TransportRouteSegment>>();
|
||||
this.library = library;
|
||||
transportStopsReader = new TransportStopsRouteReader(Arrays.asList(readers));
|
||||
}
|
||||
|
||||
public List<TransportRouteSegment> getTransportStops(LatLon loc) throws IOException {
|
||||
int y = MapUtils.get31TileNumberY(loc.getLatitude());
|
||||
int x = MapUtils.get31TileNumberX(loc.getLongitude());
|
||||
return getTransportStops(x, y, false, new ArrayList<TransportRouteSegment>());
|
||||
}
|
||||
|
||||
public List<TransportRouteSegment> getTransportStops(int x, int y, boolean change, List<TransportRouteSegment> res) throws IOException {
|
||||
return loadNativeTransportStops(x, y, change, res);
|
||||
}
|
||||
|
||||
private List<TransportRouteSegment> loadNativeTransportStops(int sx, int sy, boolean change, List<TransportRouteSegment> res) throws IOException {
|
||||
long nanoTime = System.nanoTime();
|
||||
int d = change ? walkChangeRadiusIn31 : walkRadiusIn31;
|
||||
int lx = (sx - d ) >> (31 - cfg.ZOOM_TO_LOAD_TILES);
|
||||
int rx = (sx + d ) >> (31 - cfg.ZOOM_TO_LOAD_TILES);
|
||||
int ty = (sy - d ) >> (31 - cfg.ZOOM_TO_LOAD_TILES);
|
||||
int by = (sy + d ) >> (31 - cfg.ZOOM_TO_LOAD_TILES);
|
||||
for(int x = lx; x <= rx; x++) {
|
||||
for(int y = ty; y <= by; y++) {
|
||||
long tileId = (((long)x) << (cfg.ZOOM_TO_LOAD_TILES + 1)) + y;
|
||||
List<TransportRouteSegment> list = quadTree.get(tileId);
|
||||
if(list == null) {
|
||||
list = loadTile(x, y);
|
||||
quadTree.put(tileId, list);
|
||||
}
|
||||
for(TransportRouteSegment r : list) {
|
||||
TransportStop st = r.getStop(r.segStart);
|
||||
if (Math.abs(st.x31 - sx) > walkRadiusIn31 || Math.abs(st.y31 - sy) > walkRadiusIn31) {
|
||||
wrongLoadedWays++;
|
||||
} else {
|
||||
loadedWays++;
|
||||
res.add(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
loadTime += System.nanoTime() - nanoTime;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
private List<TransportRouteSegment> loadTile(int x, int y) throws IOException {
|
||||
long nanoTime = System.nanoTime();
|
||||
List<TransportRouteSegment> lst = new ArrayList<TransportRouteSegment>();
|
||||
int pz = (31 - cfg.ZOOM_TO_LOAD_TILES);
|
||||
BinaryMapIndexReader.SearchRequest<TransportStop> sr = BinaryMapIndexReader.buildSearchTransportRequest(x << pz, (x + 1) << pz,
|
||||
y << pz, (y + 1) << pz, -1, null);
|
||||
Collection<TransportStop> stops = transportStopsReader.readMergedTransportStops(sr);
|
||||
loadTransportSegments(stops, lst);
|
||||
readTime += System.nanoTime() - nanoTime;
|
||||
return lst;
|
||||
}
|
||||
|
||||
private void loadTransportSegments(Collection<TransportStop> stops, List<TransportRouteSegment> lst) throws IOException {
|
||||
for(TransportStop s : stops) {
|
||||
if (s.isDeleted() || s.getRoutes() == null) {
|
||||
continue;
|
||||
}
|
||||
for (TransportRoute route : s.getRoutes()) {
|
||||
int stopIndex = -1;
|
||||
double dist = TransportRoute.SAME_STOP;
|
||||
for (int k = 0; k < route.getForwardStops().size(); k++) {
|
||||
TransportStop st = route.getForwardStops().get(k);
|
||||
if(st.getId().longValue() == s.getId().longValue() ) {
|
||||
stopIndex = k;
|
||||
break;
|
||||
}
|
||||
double d = MapUtils.getDistance(st.getLocation(), s.getLocation());
|
||||
if (d < dist) {
|
||||
stopIndex = k;
|
||||
dist = d;
|
||||
}
|
||||
}
|
||||
if (stopIndex != -1) {
|
||||
if (cfg != null && cfg.useSchedule) {
|
||||
loadScheduleRouteSegment(lst, route, stopIndex);
|
||||
} else {
|
||||
TransportRouteSegment segment = new TransportRouteSegment(route, stopIndex);
|
||||
lst.add(segment);
|
||||
}
|
||||
} else {
|
||||
System.err.println(String.format(Locale.US, "Routing error: missing stop '%s' in route '%s' id: %d",
|
||||
s.toString(), route.getRef(), route.getId() / 2));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void loadScheduleRouteSegment(List<TransportRouteSegment> lst, TransportRoute route, int stopIndex) {
|
||||
if(route.getSchedule() != null) {
|
||||
TIntArrayList ti = route.getSchedule().tripIntervals;
|
||||
int cnt = ti.size();
|
||||
int t = 0;
|
||||
// improve by using exact data
|
||||
int stopTravelTime = 0;
|
||||
TIntArrayList avgStopIntervals = route.getSchedule().avgStopIntervals;
|
||||
for (int i = 0; i < stopIndex; i++) {
|
||||
if (avgStopIntervals.size() > i) {
|
||||
stopTravelTime += avgStopIntervals.getQuick(i);
|
||||
}
|
||||
}
|
||||
for(int i = 0; i < cnt; i++) {
|
||||
t += ti.getQuick(i);
|
||||
int startTime = t + stopTravelTime;
|
||||
if(startTime >= cfg.scheduleTimeOfDay && startTime <= cfg.scheduleTimeOfDay + cfg.scheduleMaxTime ) {
|
||||
TransportRouteSegment segment = new TransportRouteSegment(route, stopIndex, startTime);
|
||||
lst.add(segment);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -145,7 +145,7 @@ public class SearchCoreFactory {
|
|||
}
|
||||
|
||||
protected void subSearchApiOrPublish(SearchPhrase phrase, SearchResultMatcher resultMatcher, SearchResult res, SearchBaseAPI api,
|
||||
boolean publish)
|
||||
boolean publish)
|
||||
throws IOException {
|
||||
phrase.countUnknownWordsMatchMainResult(res);
|
||||
boolean firstUnknownWordMatches = res.firstUnknownWordMatches;
|
||||
|
@ -206,9 +206,9 @@ public class SearchCoreFactory {
|
|||
if (!leftUnknownSearchWords.isEmpty() && api != null && api.isSearchAvailable(phrase)) {
|
||||
SearchPhrase nphrase = phrase.selectWord(res, leftUnknownSearchWords,
|
||||
phrase.isLastUnknownSearchWordComplete() ||
|
||||
!leftUnknownSearchWords.contains(phrase.getLastUnknownSearchWord()));
|
||||
!leftUnknownSearchWords.contains(phrase.getLastUnknownSearchWord()));
|
||||
SearchResult prev = resultMatcher.setParentSearchResult(publish ? res :
|
||||
resultMatcher.getParentSearchResult());
|
||||
resultMatcher.getParentSearchResult());
|
||||
api.search(nphrase, resultMatcher);
|
||||
resultMatcher.setParentSearchResult(prev);
|
||||
}
|
||||
|
@ -764,7 +764,7 @@ public class SearchCoreFactory {
|
|||
} else {
|
||||
String enTranslation = a.getEnTranslation().toLowerCase();
|
||||
if (!"no".equals(enTranslation) // && !"yes".equals(enTranslation)
|
||||
) {
|
||||
) {
|
||||
PoiTypeResult ptr = checkPoiType(nm, a);
|
||||
if (ptr != null) {
|
||||
results.put(a.getKeyName(), ptr);
|
||||
|
@ -869,7 +869,7 @@ public class SearchCoreFactory {
|
|||
}
|
||||
|
||||
private void addPoiTypeResult(SearchPhrase phrase, SearchResultMatcher resultMatcher, boolean showTopFiltersOnly,
|
||||
String stdFilterId, SearchResult res) {
|
||||
String stdFilterId, SearchResult res) {
|
||||
res.priorityDistance = 0;
|
||||
res.objectType = ObjectType.POI_TYPE;
|
||||
res.firstUnknownWordMatches = true;
|
||||
|
|
|
@ -160,7 +160,7 @@ public class SearchPhrase {
|
|||
|
||||
|
||||
public SearchPhrase generateNewPhrase(String text, SearchSettings settings) {
|
||||
String textToSearch = text;
|
||||
String textToSearch = Algorithms.normalizeSearchText(text);
|
||||
List<SearchWord> leftWords = this.words;
|
||||
String thisTxt = getText(true);
|
||||
List<SearchWord> foundWords = new ArrayList<>();
|
||||
|
@ -183,6 +183,7 @@ public class SearchPhrase {
|
|||
}
|
||||
|
||||
|
||||
|
||||
public static SearchPhrase emptyPhrase() {
|
||||
return emptyPhrase(null);
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ import java.util.Comparator;
|
|||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
@ -41,11 +42,34 @@ public class Algorithms {
|
|||
private static final int BUFFER_SIZE = 1024;
|
||||
private static final Log log = PlatformUtil.getLog(Algorithms.class);
|
||||
|
||||
public static boolean isEmpty(Collection c) {
|
||||
public static boolean isEmpty(Collection<?> c) {
|
||||
return c == null || c.size() == 0;
|
||||
}
|
||||
|
||||
public static boolean isEmpty(Map map) {
|
||||
private static char[] CHARS_TO_NORMALIZE_KEY = new char['’'];
|
||||
private static char[] CHARS_TO_NORMALIZE_VALUE = new char['\''];
|
||||
|
||||
public static String normalizeSearchText(String s) {
|
||||
boolean norm = false;
|
||||
for (int i = 0; i < s.length() && !norm; i++) {
|
||||
char ch = s.charAt(i);
|
||||
for (int j = 0; j < CHARS_TO_NORMALIZE_KEY.length; j++) {
|
||||
if (ch == CHARS_TO_NORMALIZE_KEY[j]) {
|
||||
norm = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!norm) {
|
||||
return s;
|
||||
}
|
||||
for (int k = 0; k < CHARS_TO_NORMALIZE_KEY.length; k++) {
|
||||
s = s.replace(CHARS_TO_NORMALIZE_KEY[k], CHARS_TO_NORMALIZE_VALUE[k]);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
public static boolean isEmpty(Map<?, ?> map) {
|
||||
return map == null || map.size() == 0;
|
||||
}
|
||||
|
||||
|
@ -116,6 +140,26 @@ public class Algorithms {
|
|||
return name;
|
||||
}
|
||||
|
||||
public static List<File> collectDirs(File parentDir, List<File> dirs) {
|
||||
return collectDirs(parentDir, dirs, null);
|
||||
}
|
||||
|
||||
public static List<File> collectDirs(File parentDir, List<File> dirs, File exclDir) {
|
||||
File[] listFiles = parentDir.listFiles();
|
||||
if (listFiles != null) {
|
||||
Arrays.sort(listFiles);
|
||||
for (File f : listFiles) {
|
||||
if (f.isDirectory()) {
|
||||
if (!f.equals(exclDir)) {
|
||||
dirs.add(f);
|
||||
}
|
||||
Algorithms.collectDirs(f, dirs);
|
||||
}
|
||||
}
|
||||
}
|
||||
return dirs;
|
||||
}
|
||||
|
||||
public static File[] getSortedFilesVersions(File dir) {
|
||||
File[] listFiles = dir.listFiles();
|
||||
if (listFiles != null) {
|
||||
|
@ -320,10 +364,8 @@ public class Algorithms {
|
|||
* exception. Supported formats are:
|
||||
* #RRGGBB
|
||||
* #AARRGGBB
|
||||
* 'red', 'blue', 'green', 'black', 'white', 'gray', 'cyan', 'magenta',
|
||||
* 'yellow', 'lightgray', 'darkgray'
|
||||
*/
|
||||
public static int parseColor(String colorString) {
|
||||
public static int parseColor(String colorString) throws IllegalArgumentException {
|
||||
if (colorString.charAt(0) == '#') {
|
||||
// Use a long to avoid rollovers on #ffXXXXXX
|
||||
if (colorString.length() == 4) {
|
||||
|
@ -484,6 +526,10 @@ public class Algorithms {
|
|||
}
|
||||
|
||||
public static StringBuilder readFromInputStream(InputStream i) throws IOException {
|
||||
return readFromInputStream(i, true);
|
||||
}
|
||||
|
||||
public static StringBuilder readFromInputStream(InputStream i, boolean autoclose) throws IOException {
|
||||
StringBuilder responseBody = new StringBuilder();
|
||||
responseBody.setLength(0);
|
||||
if (i != null) {
|
||||
|
@ -498,6 +544,9 @@ public class Algorithms {
|
|||
}
|
||||
responseBody.append(s);
|
||||
}
|
||||
if (autoclose) {
|
||||
i.close();
|
||||
}
|
||||
}
|
||||
return responseBody;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@ package net.osmand.util;
|
|||
import java.net.URI;
|
||||
import java.net.URLDecoder;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.Arrays;
|
||||
import java.util.Base64;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Locale;
|
||||
|
@ -11,6 +13,9 @@ import java.util.Set;
|
|||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import net.osmand.data.LatLon;
|
||||
import net.osmand.util.GeoPointParserUtil.GeoParsedPoint;
|
||||
|
||||
public class GeoPointParserUtil {
|
||||
|
||||
|
||||
|
@ -70,6 +75,31 @@ public class GeoPointParserUtil {
|
|||
return map;
|
||||
}
|
||||
|
||||
private static int kMaxPointBytes = 10;
|
||||
private static int kMaxCoordBits = kMaxPointBytes * 3;
|
||||
public static LatLon decodeMapsMeLatLonToInt(String s) {
|
||||
// 44TvlEGXf-
|
||||
int lat = 0, lon = 0;
|
||||
int shift = kMaxCoordBits - 3;
|
||||
for (int i = 0; i < s.length(); ++i, shift -= 3) {
|
||||
int a = net.osmand.osm.io.Base64.indexOf(s.charAt(i));
|
||||
if (a < 0)
|
||||
return null;
|
||||
|
||||
int lat1 = (((a >> 5) & 1) << 2 | ((a >> 3) & 1) << 1 | ((a >> 1) & 1));
|
||||
int lon1 = (((a >> 4) & 1) << 2 | ((a >> 2) & 1) << 1 | (a & 1));
|
||||
lat |= lat1 << shift;
|
||||
lon |= lon1 << shift;
|
||||
}
|
||||
double middleOfSquare = 1 << (3 * (kMaxPointBytes - s.length()) - 1);
|
||||
lat += middleOfSquare;
|
||||
lon += middleOfSquare;
|
||||
|
||||
double dlat = ((double) lat) / ((1 << kMaxCoordBits) - 1) * 180 - 90;
|
||||
double dlon = ((double) lon) / ((1 << kMaxCoordBits) - 1 + 1) * 360.0 - 180;
|
||||
return new LatLon(dlat, dlon);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses geo and map intents:
|
||||
*
|
||||
|
@ -181,7 +211,7 @@ public class GeoPointParserUtil {
|
|||
}
|
||||
} else if (host.startsWith("map.baidu.")) { // .com and .cn both work
|
||||
/* Baidu Map uses a custom format for lat/lon., it is basically standard lat/lon
|
||||
* multiplied by 100,000, then rounded to an integer */
|
||||
* multiplied by 100,000, then rounded to an integer */
|
||||
String zm = params.get("l");
|
||||
String[] vls = silentSplit(params.get("c"), ",");
|
||||
if (vls != null && vls.length >= 2) {
|
||||
|
@ -190,6 +220,31 @@ public class GeoPointParserUtil {
|
|||
int zoom = parseZoom(zm);
|
||||
return new GeoParsedPoint(lat, lon, zoom);
|
||||
}
|
||||
} else if (host.equals("ge0.me")) {
|
||||
// http:///44TvlEGXf-/Kyiv
|
||||
if (path.startsWith("/")) {
|
||||
path = path.substring(1);
|
||||
}
|
||||
String[] pms = path.split("/");
|
||||
String label = "";
|
||||
if (pms.length > 1) {
|
||||
label = pms[1];
|
||||
}
|
||||
String qry = pms[0];
|
||||
if (qry.length() < 10) {
|
||||
return null;
|
||||
}
|
||||
int indZoom = net.osmand.osm.io.Base64.indexOf(qry.charAt(0));
|
||||
int zoom = 15;
|
||||
if (indZoom >= 0) {
|
||||
zoom = indZoom / 4 + 4;
|
||||
}
|
||||
LatLon l = decodeMapsMeLatLonToInt(qry.substring(1).replace('-', '/'));
|
||||
if (l == null) {
|
||||
return null;
|
||||
}
|
||||
return new GeoParsedPoint(l.getLatitude(), l.getLongitude(), zoom, label);
|
||||
|
||||
} else if (simpleDomains.contains(host)) {
|
||||
if (uri.getQuery() == null && params.size() == 0) {
|
||||
// DOUBLE check this may be wrong test of openstreetmap.de (looks very weird url and server doesn't respond)
|
||||
|
@ -221,7 +276,6 @@ public class GeoPointParserUtil {
|
|||
String z = String.valueOf(GeoParsedPoint.NO_ZOOM);
|
||||
|
||||
if (params.containsKey("q")) {
|
||||
System.out.println("q=" + params.get("q"));
|
||||
Matcher matcher = commaSeparatedPairPattern.matcher(params.get("q"));
|
||||
if (matcher.matches()) {
|
||||
latString = matcher.group(1);
|
||||
|
@ -252,7 +306,6 @@ public class GeoPointParserUtil {
|
|||
}
|
||||
final String postf = "\\s\\((\\p{L}|\\p{M}|\\p{Z}|\\p{S}|\\p{N}|\\p{P}|\\p{C})*\\)$";
|
||||
opath = opath.replaceAll(postf, "");
|
||||
System.out.println("opath=" + opath);
|
||||
return parseGoogleMapsPath(opath, params);
|
||||
}
|
||||
if (fragment != null) {
|
||||
|
@ -262,13 +315,32 @@ public class GeoPointParserUtil {
|
|||
return new GeoParsedPoint(m.group(1));
|
||||
}
|
||||
}
|
||||
|
||||
String DATA_PREFIX = "/data=";
|
||||
String[] pathPrefixes = new String[]{"/@", "/ll=",
|
||||
"loc:", "/"};
|
||||
"loc:", DATA_PREFIX, "/"};
|
||||
for (String pref : pathPrefixes) {
|
||||
if (path.contains(pref)) {
|
||||
path = path.substring(path.lastIndexOf(pref) + pref.length());
|
||||
return parseGoogleMapsPath(path, params);
|
||||
if (path.contains("/")) {
|
||||
path = path.substring(0, path.indexOf('/'));
|
||||
}
|
||||
if (pref.equals(DATA_PREFIX)) {
|
||||
String[] vls = path.split("!");
|
||||
String lat = null;
|
||||
String lon = null;
|
||||
for (String v : vls) {
|
||||
if (v.startsWith("3d")) {
|
||||
lat = v.substring(2);
|
||||
} else if (v.startsWith("4d")) {
|
||||
lon = v.substring(2);
|
||||
}
|
||||
}
|
||||
if (lat != null && lon != null) {
|
||||
return new GeoParsedPoint(Double.valueOf(lat), Double.valueOf(lon));
|
||||
}
|
||||
} else {
|
||||
return parseGoogleMapsPath(path, params);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (host.endsWith(".amap.com")) {
|
||||
|
@ -279,7 +351,7 @@ public class GeoPointParserUtil {
|
|||
Pattern p;
|
||||
Matcher matcher;
|
||||
final String[] patterns = {
|
||||
/* though this looks like Query String, it is also used as part of the Fragment */
|
||||
/* though this looks like Query String, it is also used as part of the Fragment */
|
||||
".*q=([+-]?\\d+(?:\\.\\d+)?),([+-]?\\d+(?:\\.\\d+)?).*&radius=(\\d+).*",
|
||||
".*q=([+-]?\\d+(?:\\.\\d+)?),([+-]?\\d+(?:\\.\\d+)?).*",
|
||||
".*p=(?:[A-Z0-9]+),([+-]?\\d+(?:\\.\\d+)?),([+-]?\\d+(?:\\.\\d+)?).*",};
|
||||
|
@ -474,7 +546,7 @@ public class GeoPointParserUtil {
|
|||
}
|
||||
|
||||
if ("z".equals(paramName) && paramValue != null) {
|
||||
zoom = Integer.parseInt(paramValue);
|
||||
zoom = (int) Float.parseFloat(paramValue);
|
||||
} else if ("q".equals(paramName) && paramValue != null) {
|
||||
searchRequest = URLDecoder.decode(paramValue);
|
||||
}
|
||||
|
@ -569,7 +641,7 @@ public class GeoPointParserUtil {
|
|||
private static int parseZoom(String zoom) {
|
||||
try {
|
||||
if (zoom != null) {
|
||||
return Integer.valueOf(zoom);
|
||||
return (int) Float.parseFloat(zoom);
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
}
|
||||
|
@ -756,7 +828,7 @@ public class GeoPointParserUtil {
|
|||
public String toString() {
|
||||
return isGeoPoint() ?
|
||||
String.format("GeoParsedPoint [lat=%.5f, lon=%.5f, zoom=%d, label=%s]", lat, lon, zoom, label) :
|
||||
String.format("GeoParsedPoint [query=%s]",query);
|
||||
String.format("GeoParsedPoint [query=%s]",query);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,24 @@ public class GeoPointParserUtilTest {
|
|||
assertGeoPoint(actual, new GeoParsedPoint(46.853582, 9.529903));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGoogleMapsData() {
|
||||
// https://www.google.com/maps?daddr=Bahnhofplatz+3,+7000+Chur@46.853582,9.529903
|
||||
GeoParsedPoint actual = GeoPointParserUtil.parse(
|
||||
"https://www.google.co.in/maps/place/10%C2%B007'16.8%22N+76%C2%B020'54.2%22E/@10.1213253,76.3478427,247m/data=!3m2!1e3!4b1!4m6!3m5!1s0x0:0x0!7e2!8m2!3d10.1213237!4d76.348392?shorturl=1");
|
||||
assertGeoPoint(actual, new GeoParsedPoint(10.1213253, 76.3478427));
|
||||
actual = GeoPointParserUtil.parse(
|
||||
"https://www.google.co.in/maps/place/data=!3m2!1e3!4b1!4m6!3m5!1s0x0:0x0!7e2!8m2!3d10.1213237!4d76.348392?shorturl=1");
|
||||
assertGeoPoint(actual, new GeoParsedPoint(10.1213237, 76.348392));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapsMeParser() {
|
||||
GeoParsedPoint actual = GeoPointParserUtil.parse(
|
||||
"http://ge0.me/44TvlEGXf-/Kyiv");
|
||||
assertGeoPoint(actual, new GeoParsedPoint(50.45003, 30.52414, 18, "Kyiv"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGeoPoint() {
|
||||
final int ilat = 34, ilon = -106;
|
||||
|
@ -438,21 +456,21 @@ public class GeoPointParserUtilTest {
|
|||
actual = GeoPointParserUtil.parse(url);
|
||||
assertGeoPoint(actual, new GeoParsedPoint("paris"));
|
||||
|
||||
// TODO this URL does not work, where is it used?
|
||||
// LEGACY this URL does not work, where is it used?
|
||||
// http://maps.google.com/maps/q=loc:34,-106&z=11
|
||||
url = "http://maps.google.com/maps/q=loc:" + ilat + "," + ilon + "&z=" + z;
|
||||
System.out.println("url: " + url);
|
||||
actual = GeoPointParserUtil.parse(url);
|
||||
assertGeoPoint(actual, new GeoParsedPoint(ilat, ilon, z));
|
||||
|
||||
// TODO this URL does not work, where is it used?
|
||||
// LEGACY this URL does not work, where is it used?
|
||||
// http://maps.google.com/maps/q=loc:34.99393,-106.61568&z=11
|
||||
url = "http://maps.google.com/maps/q=loc:" + dlat + "," + dlon + "&z=" + z;
|
||||
System.out.println("url: " + url);
|
||||
actual = GeoPointParserUtil.parse(url);
|
||||
assertGeoPoint(actual, new GeoParsedPoint(dlat, dlon, z));
|
||||
|
||||
// TODO this URL does not work, where is it used?
|
||||
// LEGACY this URL does not work, where is it used?
|
||||
// whatsapp
|
||||
// http://maps.google.com/maps/q=loc:34,-106 (You)
|
||||
z = GeoParsedPoint.NO_ZOOM;
|
||||
|
@ -461,7 +479,7 @@ public class GeoPointParserUtilTest {
|
|||
actual = GeoPointParserUtil.parse(url);
|
||||
assertGeoPoint(actual, new GeoParsedPoint(ilat, ilon, z));
|
||||
|
||||
// TODO this URL does not work, where is it used?
|
||||
// LEGACY this URL does not work, where is it used?
|
||||
// whatsapp
|
||||
// http://maps.google.com/maps/q=loc:34.99393,-106.61568 (You)
|
||||
z = GeoParsedPoint.NO_ZOOM;
|
||||
|
@ -705,7 +723,7 @@ public class GeoPointParserUtilTest {
|
|||
actual = GeoPointParserUtil.parse(url);
|
||||
assertGeoPoint(actual, new GeoParsedPoint(dlat, dlon, z));
|
||||
|
||||
/* URLs straight from various services, instead of generated here */
|
||||
/* URLs straight from various services, instead of generated here */
|
||||
|
||||
String urls[] = {
|
||||
"https://openstreetmap.org/go/0LQ127-?m",
|
||||
|
|
|
@ -67,7 +67,7 @@
|
|||
<string name="shared_string_apply">تطبيق</string>
|
||||
<string name="shared_string_enabled">مفعل</string>
|
||||
<string name="units_and_formats">الوحدات والأشكال</string>
|
||||
<string name="unit_of_length_descr">اختيار الوحدات: كم، ميل، ميل بحري.. إلخ.</string>
|
||||
<string name="unit_of_length_descr">اختيار الوحدات: كم، ميل، ميلٌ بحري.. إلخ.</string>
|
||||
<string name="unit_of_length">وحدات الطول</string>
|
||||
<string name="last_update_from_telegram_date">آخر تحديث من تيليجرام: %1$s</string>
|
||||
<string name="last_response_date">الرد الأخير:٪ 1 $ s</string>
|
||||
|
|
|
@ -64,7 +64,7 @@
|
|||
<string name="disconnect_from_telegram">Як выключыць назіральнік OsmAnd праз Telegram</string>
|
||||
<string name="logout_help_desc">Як выключыць назіральнік OsmAnd праз Тэлеграм</string>
|
||||
<string name="connected_account">Падлучаны акаўнт</string>
|
||||
<string name="shared_string_account">Рахунак</string>
|
||||
<string name="shared_string_account">Акаўнт</string>
|
||||
<string name="in_time">у %1$s</string>
|
||||
<string name="osmand_connect_desc">Абраць версію OsmAnd, якую OsmAnd Tracker будзе выкарыстоўваць для адлюстравання пазіцыі.</string>
|
||||
<string name="osmand_connect">Злучэнне з OsmAnd</string>
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
<string name="add_device">Tilføj enhed</string>
|
||||
<string name="share_location_as">Del placering som</string>
|
||||
<string name="live_now_description">Kontakter og grupper som der deles placering med.</string>
|
||||
<string name="logout_from_osmand_telegram_descr">"Bekræft log af OsmAnd Tracker, der kan ikke deles placering eller se placering af andre\?"</string>
|
||||
<string name="logout_from_osmand_telegram_descr">"Bekræft log af OsmAnd Tracker, der kan ikke deles placering eller se placering af andre\?"</string>
|
||||
<string name="logout_from_osmand_telegram">Log ud af OsmAnd Tracker\?</string>
|
||||
<string name="shared_string_name">Navn</string>
|
||||
<string name="by_distance">Efter afstand</string>
|
||||
|
|
|
@ -206,7 +206,7 @@
|
|||
<string name="shared_string_appearance">Aspecto</string>
|
||||
<string name="show_gps_points">Mostrar puntos GPS</string>
|
||||
<string name="show_gps_points_descr">Muestra la cantidad de puntos GPS recibidos y enviados.</string>
|
||||
<string name="shared_string_ok">Aplicar</string>
|
||||
<string name="shared_string_ok">Aceptar</string>
|
||||
<string name="timeline_available_for_free_now">La línea de tiempo es una función disponible ahora de forma gratuita.</string>
|
||||
<string name="disable_monitoring">Desactivar la monitorización</string>
|
||||
<string name="location_recording_enabled">Grabación de ubicación activada</string>
|
||||
|
|
|
@ -210,7 +210,7 @@
|
|||
<string name="osmand_service_descr">OsmAnd aztarnaria atzeko planoan exekutatzen da pantaila itzalita dagoenean.</string>
|
||||
<string name="location_service_no_gps_available">Hautatu kokapen-hornitzaileetako bat zure kokapena partekatzeko.</string>
|
||||
<string name="no_location_permission">Aplikazioak ez du kokapena atzitzeko baimenik.</string>
|
||||
<string name="authentication_code_descr">"Telegramek kode bat bidali dizu OsmAnd-ek zure kontuan saioa hasteko."</string>
|
||||
<string name="authentication_code_descr">Telegramek kode bat bidali dizu OsmAnd-ek zure kontuan saioa hasteko.</string>
|
||||
<string name="my_location_search_hint">Bilaketa: Taldea edo kontaktua</string>
|
||||
<string name="location_sharing_description">Hautatu kokapena partekatzeko kontaktuak eta taldeak.</string>
|
||||
<string name="set_time">Ezarri denbora</string>
|
||||
|
@ -232,14 +232,14 @@
|
|||
<string name="send_my_location_desc">Ezarri kokapena partekatzeko gutxieneko tartea.</string>
|
||||
<string name="stale_location">Ez da mugitzen</string>
|
||||
<string name="stale_location_desc">Kontaktu bat mugitu zen azken aldia.</string>
|
||||
<string name="location_history_desc">Ezkutatu denbora jakin batean mugitu ez diren kontaktuak</string>
|
||||
<string name="location_history_desc">Ezkutatu denbora jakin batean mugitu ez diren kontaktuak.</string>
|
||||
<string name="osmand_connect">OsmAnd konexioa</string>
|
||||
<string name="osmand_connect_desc">Aukeratu OsmAnd aztarnariak posizioak bistaratzeko erabiliko duen OsmAnd bertsioa.</string>
|
||||
<string name="in_time">%1$s-n</string>
|
||||
<string name="logout_help_desc">Nola itzali OsmAnd aztarnaria Telegram-etik</string>
|
||||
<string name="disconnect_from_telegram">Nola itzali OsmAnd aztarnaria Telegram-etik</string>
|
||||
<string name="disconnect_from_telegram_desc">Kokapena partekatzeko sarbidea baliogabetzeko. Ireki Telegram, joan Ezarpenak → Pribatutasuna eta segurtasuna → Saioak eta amaitu OsmAnd aztarnariaren saioa atalera.</string>
|
||||
<string name="logout_no_internet_msg">"Konektatu Internetera Telegram saioa behar bezala amaiatzeko."</string>
|
||||
<string name="logout_no_internet_msg">Konektatu Internetera Telegram saioa behar bezala amaiatzeko.</string>
|
||||
<string name="last_response">Azken erantzuna</string>
|
||||
<string name="disable_all_sharing_desc">Kokapena partekatzea itzaltzen du hautatutako txat guztietan (%1$d).</string>
|
||||
<string name="choose_osmand_desc">Hautatu kontaktuak mapan bistaratzeko OsmAnd bertsioa.</string>
|
||||
|
|
|
@ -264,4 +264,6 @@
|
|||
<string name="send_my_location_desc">Définir l\'intervalle minimum pour partager sa position.</string>
|
||||
<string name="stale_location_desc">La dernière fois qu\'un contact s\'est déplacé.</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="osmand_connect">OsmAnd connect</string>
|
||||
</resources>
|
|
@ -267,4 +267,5 @@
|
|||
<string name="last_update_from_telegram_duration">Utolsó frissítés a Telegramtól: %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="shared_string_error_short">HIBA</string>
|
||||
</resources>
|
|
@ -196,7 +196,7 @@
|
|||
<string name="shared_string_telegram">Telegram</string>
|
||||
<string name="privacy_policy_use_telegram">Telegram (l\'applicazione di messaggistica) viene usato per connettersi e comunicare con le persone.</string>
|
||||
<string name="privacy_policy_telegram_client">Il tracker OsmAnd è uno dei client utilizzati dalla piattaforma aperta Telegram. I tuoi contatti possono usare un qualsiasi cliente Telegram.</string>
|
||||
<string name="privacy_policy_agree">Cliccando continua tu sottoscrivi le condizioni di Privacy di Telegram e quelle di OsmAnd.</string>
|
||||
<string name="privacy_policy_agree">Cliccando \"Continua\" tu sottoscrivi le condizioni di privacy di Telegram e quelle di OsmAnd.</string>
|
||||
<string name="shared_string_accept">Accettazione</string>
|
||||
<string name="how_it_works">Come funziona</string>
|
||||
<string name="telegram_privacy_policy">Informativa sulla privacy di Telegram</string>
|
||||
|
@ -257,4 +257,12 @@
|
|||
<string name="time_zone">Fuso orario</string>
|
||||
<string name="unit_of_speed_system">Unità di misura della velocità</string>
|
||||
<string name="back_to_osmand">Torna a OsmAnd</string>
|
||||
<string name="status_widget_title">Stato di OsmAnd Tracker</string>
|
||||
<string name="shared_string_suggested">Suggerito</string>
|
||||
<string name="duration_ago">%1$s fa</string>
|
||||
<string name="last_response_duration">Ultima risposta: %1$s fa</string>
|
||||
<string name="last_update_from_telegram_duration">Ultimo aggiornamento da Telegram: %1$s fa</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="shared_string_error_short">ERR</string>
|
||||
</resources>
|
|
@ -221,8 +221,8 @@
|
|||
<string name="yard">ヤード</string>
|
||||
<string name="foot">フィート</string>
|
||||
<string name="mile">マイル</string>
|
||||
<string name="km">キロメートル</string>
|
||||
<string name="m">メートル</string>
|
||||
<string name="km">km</string>
|
||||
<string name="m">m</string>
|
||||
<string name="nm">海里</string>
|
||||
<string name="min_mile">min/m</string>
|
||||
<string name="min_km">min/km</string>
|
||||
|
|
|
@ -70,7 +70,7 @@
|
|||
<string name="saved_messages">Iznan yettwaskelsen</string>
|
||||
<string name="unit_of_speed_system">Tayunt n urured</string>
|
||||
<string name="unit_of_speed_system_descr">Ad isbadu tayunt n urured.</string>
|
||||
<string name="unit_of_length">Tayunin n umeccaq</string>
|
||||
<string name="unit_of_length">Tayunin n teɣzef</string>
|
||||
<string name="unit_of_length_descr">Beddel tayunt n uktili n umeccaq.</string>
|
||||
<string name="units_and_formats">Tayunin d yimasalen</string>
|
||||
<string name="time_zone_descr">Fren izḍi usrig ara d-tsekneḍ deg yiznan-ik n usideg.</string>
|
||||
|
@ -137,7 +137,7 @@
|
|||
<string name="shared_string_group">Agraw</string>
|
||||
<string name="last_response">Dernier temps de réponse</string>
|
||||
<string name="time_ago">aya</string>
|
||||
<string name="shared_string_exit">Tufɣa</string>
|
||||
<string name="shared_string_exit">Tuffɣa</string>
|
||||
<string name="shared_string_sort">Smizzwer</string>
|
||||
<string name="by_name">S yisem</string>
|
||||
<string name="share_location_as">Bḍu adɣar</string>
|
||||
|
|
|
@ -102,7 +102,7 @@
|
|||
<string name="minutes_format">%1$d m</string>
|
||||
<string name="hours_format">%1$d h</string>
|
||||
<string name="shared_string_install">Instalar</string>
|
||||
<string name="shared_string_share">Enviar</string>
|
||||
<string name="shared_string_share">Compartilhe</string>
|
||||
<string name="shared_string_back">Voltar</string>
|
||||
<string name="visible_time_for_all">Hora visível para todos</string>
|
||||
<string name="set_time_description">Defina a hora em que seus contatos e grupos selecionados verão sua localização em tempo real.</string>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<resources>
|
||||
<string name="searching_for_gps">Posicionando…</string>
|
||||
<string name="si_nm_h">Milhas náuticas por hora (nó)</string>
|
||||
<string name="install_osmand_dialog_message">Você precisa instalar a versão gratuita ou paga do OsmAnd primeiro</string>
|
||||
<string name="install_osmand_dialog_message">Precisa instalar a versão gratuita ou paga do OsmAnd primeiro</string>
|
||||
<string name="shared_string_telegram">Telegram</string>
|
||||
<string name="shared_string_login">Entrar</string>
|
||||
<string name="start_end_date">Data de início - fim</string>
|
||||
|
@ -10,7 +10,7 @@
|
|||
<string name="gps_not_available">Por favor, ligue \"Localização\" nas configurações do sistema</string>
|
||||
<string name="timeline_no_data">Sem dados</string>
|
||||
<string name="sending_location_messages">enviando localização</string>
|
||||
<string name="location_sharing_description">Selecione os contatos e grupos com os quais você deseja compartilhar sua localização.</string>
|
||||
<string name="location_sharing_description">Selecione os contactos e grupos com os quais deseja compartilhar sua localização.</string>
|
||||
<string name="waiting_for_response_from_telegram">Aguardando resposta do Telegram</string>
|
||||
<string name="connected_account">Conta conectada</string>
|
||||
<string name="osmand_privacy_policy">Política de privacidade do OsmAnd</string>
|
||||
|
@ -25,15 +25,15 @@
|
|||
<string name="active_chats">Bate-papos ativos</string>
|
||||
<string name="si_min_km">Minutos por quilômetro</string>
|
||||
<string name="background_work">Funcionamento em segundo plano</string>
|
||||
<string name="location_history_desc">Ocultar contatos que não foram movidos em um determinado momento.</string>
|
||||
<string name="location_history_desc">Ocultar contactos que não foram movidos num determinado momento.</string>
|
||||
<string name="gpx_settings">Configurações de GPX</string>
|
||||
<string name="type_contact_or_group_name">Digite o nome do contato ou do grupo</string>
|
||||
<string name="min_mile">min/m</string>
|
||||
<string name="password_descr">Senha do telegrama</string>
|
||||
<string name="password_descr">Palavra-passe do telegrama</string>
|
||||
<string name="last_updated_location">Última localização atualizada:</string>
|
||||
<string name="stale_location">Parado</string>
|
||||
<string name="show_gps_points_descr">Mostrar quantidade de pontos de GPS coletados e enviados.</string>
|
||||
<string name="already_registered_in_telegram">Você precisa de uma conta e número de telefone registrados no Telegram</string>
|
||||
<string name="already_registered_in_telegram">Precisa de uma conta e número de telefone registados no Telegram</string>
|
||||
<string name="min_logging_speed_descr">Filtro: sem registro abaixo da velocidade selecionada</string>
|
||||
<string name="shared_string_sort_by">Ordenar por</string>
|
||||
<string name="shared_string_sent">Enviado</string>
|
||||
|
@ -42,7 +42,7 @@
|
|||
<string name="successfully_sent_and_updated">Enviado e atualizado com sucesso</string>
|
||||
<string name="send_location_as_descr">Escolha como as mensagens com sua localização serão exibidas.</string>
|
||||
<string name="shared_string_connection">Conexão</string>
|
||||
<string name="share_location_as_description">Se você deseja conectar vários aparelhos a uma conta de telegrama, é necessário usar um aparelho diferente para compartilhar sua localização.</string>
|
||||
<string name="share_location_as_description">Se deseja conectar vários aparelhos a uma conta de telegrama, é necessário usar um aparelho diferente para compartilhar a sua localização.</string>
|
||||
<string name="proxy_password">Palavra-passe</string>
|
||||
<string name="shared_string_authorization">Autorização</string>
|
||||
<string name="shared_string_select">Selecionar</string>
|
||||
|
@ -51,7 +51,7 @@
|
|||
<string name="shared_string_bot">Robô</string>
|
||||
<string name="average_altitude">Altitude média</string>
|
||||
<string name="start_date">Data de início</string>
|
||||
<string name="live_now_description">Contatos e grupos compartilhando o local para você.</string>
|
||||
<string name="live_now_description">Contatos e grupos compartilhando o local consigo.</string>
|
||||
<string name="shared_string_all">Todos</string>
|
||||
<string name="received_gps_points">Pontos GPX recebidos: %1$s</string>
|
||||
<string name="shared_string_appearance">Aparência</string>
|
||||
|
@ -59,7 +59,7 @@
|
|||
<string name="by_distance">Pela distância</string>
|
||||
<string name="turn_off_location_sharing">Desativar o compartilhamento de local</string>
|
||||
<string name="shared_string_collected">Coletado</string>
|
||||
<string name="enter_another_device_name">Escolha um nome que você ainda não usou</string>
|
||||
<string name="enter_another_device_name">Escolha um nome que ainda não usou</string>
|
||||
<string name="shared_string_add">Adicionar</string>
|
||||
<string name="show_users_on_map">Mostrar utilitadoes no mapa</string>
|
||||
<string name="enter_authentication_code">Digite o código de autenticação</string>
|
||||
|
@ -71,7 +71,7 @@
|
|||
<string name="osmand_connect">Conectar OsmAnd</string>
|
||||
<string name="get_telegram_description_continue">Por favor, instale o Telegram e configure uma conta.</string>
|
||||
<string name="si_kmh">Quilômetros por hora</string>
|
||||
<string name="shared_string_password">Senha</string>
|
||||
<string name="shared_string_password">Palavra-passe</string>
|
||||
<string name="min_logging_distance">Distância mínima de registro</string>
|
||||
<string name="shared_string_save">Gravar</string>
|
||||
<string name="shared_string_start">Iniciar</string>
|
||||
|
@ -81,8 +81,8 @@
|
|||
<string name="proxy_connected">Conectado</string>
|
||||
<string name="m">m</string>
|
||||
<string name="stop_sharing_all">O compartilhamento está ativado (desativado)</string>
|
||||
<string name="do_not_have_telegram">Eu não tenho conta Telegram</string>
|
||||
<string name="get_telegram_account_first">Você precisa de uma conta do Telegram para usar o compartilhamento de local.</string>
|
||||
<string name="do_not_have_telegram">Não tenho uma conta do Telegram</string>
|
||||
<string name="get_telegram_account_first">Precisa de uma conta do Telegram para usar o compartilhamento de local.</string>
|
||||
<string name="disable_all_sharing">Desativar todo o compartilhamento</string>
|
||||
<string name="sharing_status">Status de compartilhamento</string>
|
||||
<string name="shared_string_end">Fim</string>
|
||||
|
@ -92,11 +92,11 @@
|
|||
<string name="shared_string_later">Mais tarde</string>
|
||||
<string name="my_location">Minha localização</string>
|
||||
<string name="install_osmand">Instalar OsmAnd</string>
|
||||
<string name="privacy_policy_use_telegram">Telegrama (o aplicativo de mensagens) é usado para conectar e se comunicar com as pessoas.</string>
|
||||
<string name="privacy_policy_use_telegram">Telegram (a app de mensagens) é usado para conectar e comunicar com as pessoas.</string>
|
||||
<string name="not_possible_to_send_to_telegram_chats">Não é possível enviar para bate-papo do Telegram:</string>
|
||||
<string name="not_sent_yet">Ainda não enviado</string>
|
||||
<string name="points_size">%1$d pontos</string>
|
||||
<string name="welcome_descr"><b>OsmAnd Tracker</b> permite que partilhe a sua localização e veja a dos outros no OsmAnd.<br/> <br/>O app usa a API Telegram e você precisa de uma conta do Telegram.</string>
|
||||
<string name="welcome_descr"><b>OsmAnd Tracker</b> permite que partilhe a sua localização e veja a dos outros no OsmAnd.<br/> <br/>O app usa a API Telegram e precisa de uma conta do Telegram.</string>
|
||||
<string name="min_logging_distance_descr">Filtro: distância mínima para registrar um novo ponto</string>
|
||||
<string name="device_name_cannot_be_empty">O nome do aparelho não pode estar vazio</string>
|
||||
<string name="yard">yd</string>
|
||||
|
@ -108,7 +108,7 @@
|
|||
<string name="expire_at">Expira</string>
|
||||
<string name="send_location_as">Enviar localização como</string>
|
||||
<string name="shared_string_exit">Sair</string>
|
||||
<string name="no_location_permission">O aplicativo 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="si_mph">Milhas por hora</string>
|
||||
<string name="share_location_as_description_second_line">Pode criar e visualizar o ID do aparelho no cliente de telegrama usando o bot de bate-papo %1$s. %2$s</string>
|
||||
<string name="shared_string_back">Voltar</string>
|
||||
|
@ -152,7 +152,7 @@
|
|||
<string name="hours_and_minutes_format">%1$d h %2$d m</string>
|
||||
<string name="device_name_is_too_long">Nome do aparelho muito longo</string>
|
||||
<string name="gps_points">Pontos de GPS</string>
|
||||
<string name="timeline_description">Ative o monitoramento para salvar todos os locais no histórico.</string>
|
||||
<string name="timeline_description">Ative o monitoramento para gravar todos os locais no histórico.</string>
|
||||
<string name="show_on_map">Mostrar no mapa</string>
|
||||
<string name="send_my_location">Enviar minha localização</string>
|
||||
<string name="share_location_as">Compartilhar localização como</string>
|
||||
|
@ -160,7 +160,7 @@
|
|||
<string name="mile_per_hour">mph</string>
|
||||
<string name="si_min_m">Minutos por milha</string>
|
||||
<string name="last_update_from_telegram">Última atualização do Telegram</string>
|
||||
<string name="logout_from_osmand_telegram_descr">Tem certeza de que deseja sair do OsmAnd Tracker para que você não possa compartilhar o local ou ver a localização de outras pessoas\?</string>
|
||||
<string name="logout_from_osmand_telegram_descr">Tem certeza de que deseja sair do OsmAnd Tracker para que não possa compartilhar o local ou ver a localização de outras pessoas\?</string>
|
||||
<string name="proxy_server">Servidor</string>
|
||||
<string name="si_m_s">Metros por segundo</string>
|
||||
<string name="location_sharing_status">Compartilhamento: %1$s</string>
|
||||
|
@ -199,7 +199,7 @@
|
|||
<string name="shared_string_authorization_descr">Por favor, insira o número de telefone do seu Telegram em formato internacional</string>
|
||||
<string name="set_visible_time_for_all">Definir tempo visível para todos</string>
|
||||
<string name="phone_number_title">Número de telefone</string>
|
||||
<string name="privacy_policy_agree">Ao clicar em \"Continuar\" você concorda com as condições da política de privacidade do Telegram e OsmAnd.</string>
|
||||
<string name="privacy_policy_agree">Ao clicar em \"Continuar\" concorda com as condições da política de privacidade do Telegram e OsmAnd.</string>
|
||||
<string name="si_mi_feet">Milhas/pés</string>
|
||||
<string name="monitoring_is_enabled">Monitoramento está ativado</string>
|
||||
<string name="osmand_connect_desc">Escolha a versão OsmAnd que OsmAnd Tracker usa para exibir posições.</string>
|
||||
|
@ -208,7 +208,7 @@
|
|||
<string name="average_speed">Velocidade média</string>
|
||||
<string name="shared_string_status">Situação</string>
|
||||
<string name="km_h">km/h</string>
|
||||
<string name="get_telegram_after_creating_account">Então você pode usar este aplicativo.</string>
|
||||
<string name="get_telegram_after_creating_account">Então pode usar esta app.</string>
|
||||
<string name="shared_string_settings">Configurações</string>
|
||||
<string name="go_to_settings">Vá para as configurações</string>
|
||||
<string name="authentication_code_descr">Uma faixa GPX é salva automaticamente durante a navegação.</string>
|
||||
|
|
|
@ -57,10 +57,10 @@
|
|||
<string name="timeline_available_for_free_now">Linha do tempo é um recurso disponível agora gratuitamente.</string>
|
||||
<string name="disable_monitoring">Desativar monitoramento</string>
|
||||
<string name="location_recording_enabled">Gravação de localização ativada</string>
|
||||
<string name="timeline_description">Ative o monitoramento para salvar todos os locais no histórico.</string>
|
||||
<string name="privacy_policy_use_telegram">Telegrama (o aplicativo de mensagens) é usado para conectar e se comunicar com as pessoas.</string>
|
||||
<string name="timeline_description">Ative o monitoramento para gravar todos os locais no histórico.</string>
|
||||
<string name="privacy_policy_use_telegram">Telegram (a app de mensagens) é usado para conectar e comunicar com as pessoas.</string>
|
||||
<string name="privacy_policy_telegram_client">OsmAnd tracker é um dos clientes que usam a Plataforma aberta do Telegram . Seus contatos podem usar qualquer outro cliente Telegram.</string>
|
||||
<string name="privacy_policy_agree">Ao clicar em \"Continuar\" você concorda com as condições da política de privacidade do Telegram e OsmAnd.</string>
|
||||
<string name="privacy_policy_agree">Ao clicar em \"Continuar\" concorda com as condições da política de privacidade do Telegram e OsmAnd.</string>
|
||||
<string name="shared_string_accept">Aceitar</string>
|
||||
<string name="telegram_privacy_policy">Política de privacidade do Telegram</string>
|
||||
<string name="osmand_privacy_policy">Política de privacidade do OsmAnd</string>
|
||||
|
@ -82,7 +82,7 @@
|
|||
<string name="send_location_as_descr">Escolha como as mensagens com sua localização serão exibidas.</string>
|
||||
<string name="map_and_text">Mapa e texto</string>
|
||||
<string name="last_update_from_telegram">Última atualização do Telegram</string>
|
||||
<string name="enter_another_device_name">Escolha um nome que você ainda não usou</string>
|
||||
<string name="enter_another_device_name">Escolha um nome que ainda não usou</string>
|
||||
<string name="device_added_successfully">%1$s adicionado.</string>
|
||||
<string name="error_adding_new_device">Não foi possível adicionar novo aparelho</string>
|
||||
<string name="enter_device_name_description">Nomeie seu novo aparelho no máximo 200 símbolos.</string>
|
||||
|
@ -90,7 +90,7 @@
|
|||
<string name="device_name_cannot_be_empty">O nome do aparelho não pode estar vazio</string>
|
||||
<string name="device_name">Nome do aparelho</string>
|
||||
<string name="share_location_as_description_second_line">Pode criar e visualizar o ID do aparelho no cliente de telegrama usando o bot de bate-papo %1$s. %2$s</string>
|
||||
<string name="share_location_as_description">Se você deseja conectar vários aparelhos a uma conta de telegrama, é necessário usar um aparelho diferente para compartilhar sua localização.</string>
|
||||
<string name="share_location_as_description">Se deseja conectar vários aparelhos a uma conta de telegrama, é necessário usar um aparelho diferente para compartilhar a sua localização.</string>
|
||||
<string name="last_updated_location">Última localização atualizada:</string>
|
||||
<string name="successfully_sent_and_updated">Enviado e atualizado com sucesso</string>
|
||||
<string name="not_possible_to_send_to_telegram_chats">Não é possível enviar para bate-papo do Telegram:</string>
|
||||
|
@ -117,8 +117,8 @@
|
|||
<string name="shared_string_save">Gravar</string>
|
||||
<string name="add_device">Adicionar aparelho</string>
|
||||
<string name="share_location_as">Compartilhar localização como</string>
|
||||
<string name="live_now_description">Contatos e grupos compartilhando o local para você.</string>
|
||||
<string name="logout_from_osmand_telegram_descr">Tem certeza de que deseja sair do OsmAnd Tracker para que você não possa compartilhar o local ou ver a localização de outras pessoas\?</string>
|
||||
<string name="live_now_description">Contatos e grupos compartilhando o local consigo.</string>
|
||||
<string name="logout_from_osmand_telegram_descr">Tem certeza de que deseja sair do OsmAnd Tracker para que não possa compartilhar o local ou ver a localização de outras pessoas\?</string>
|
||||
<string name="logout_from_osmand_telegram">Sair do OsmAnd Tracker\?</string>
|
||||
<string name="shared_string_name">Nome</string>
|
||||
<string name="by_distance">Pela distância</string>
|
||||
|
@ -144,7 +144,7 @@
|
|||
<string name="in_time">no %1$s</string>
|
||||
<string name="osmand_connect_desc">Escolha a versão OsmAnd que OsmAnd Tracker usa para exibir posições.</string>
|
||||
<string name="osmand_connect">Conectar OsmAnd</string>
|
||||
<string name="location_history_desc">Ocultar contatos que não foram movidos em um determinado momento.</string>
|
||||
<string name="location_history_desc">Ocultar contactos que não foram movidos num determinado momento.</string>
|
||||
<string name="location_history">Histórico de localização</string>
|
||||
<string name="stale_location_desc">A última vez que um contato foi movido.</string>
|
||||
<string name="stale_location">Parado</string>
|
||||
|
@ -159,13 +159,13 @@
|
|||
<string name="shared_string_live">Vivo</string>
|
||||
<string name="shared_string_bot">Robô</string>
|
||||
<string name="get_telegram_title">Registro no Telegram</string>
|
||||
<string name="get_telegram_account_first">Você precisa de uma conta do Telegram para usar o compartilhamento de local.</string>
|
||||
<string name="get_telegram_account_first">Precisa de uma conta do Telegram para usar o compartilhamento de local.</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 você pode usar este aplicativo.</string>
|
||||
<string name="get_telegram_after_creating_account">Então pode usar esta app.</string>
|
||||
<string name="shared_string_all">Todos</string>
|
||||
<string name="shared_string_off">Desligado</string>
|
||||
<string name="already_registered_in_telegram">Você precisa de uma conta e número de telefone registrados no Telegram</string>
|
||||
<string name="do_not_have_telegram">Eu não tenho conta 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="enter_phone_number">Digite o número de telefone</string>
|
||||
<string name="enter_authentication_code">Digite o código de autenticação</string>
|
||||
<string name="set_visible_time_for_all">Definir tempo visível para todos</string>
|
||||
|
@ -173,12 +173,12 @@
|
|||
<string name="minutes_format">%1$d m</string>
|
||||
<string name="hours_format">%1$d h</string>
|
||||
<string name="shared_string_install">Instalar</string>
|
||||
<string name="shared_string_share">Partilhar</string>
|
||||
<string name="shared_string_share">Compartilhar</string>
|
||||
<string name="shared_string_back">Voltar</string>
|
||||
<string name="visible_time_for_all">Hora visível para todos</string>
|
||||
<string name="set_time_description">Defina a hora em que seus contatos e grupos selecionados verão sua localização em tempo real.</string>
|
||||
<string name="set_time">Definir tempo</string>
|
||||
<string name="location_sharing_description">Selecione os contatos e grupos com os quais você deseja compartilhar sua localização.</string>
|
||||
<string name="location_sharing_description">Selecione os contactos e grupos com os quais deseja compartilhar sua localização.</string>
|
||||
<string name="my_location_search_hint">Pesquisa: Grupo ou contato</string>
|
||||
<string name="start_location_sharing">Compartilhar localização</string>
|
||||
<string name="show_on_map">Mostrar no mapa</string>
|
||||
|
@ -190,7 +190,7 @@
|
|||
<string name="authentication_code">Código de Autenticação</string>
|
||||
<string name="authentication_code_descr">Uma faixa GPX é salva automaticamente durante a navegação.</string>
|
||||
<string name="enter_password">Digite a palavra-passe</string>
|
||||
<string name="password_descr">Senha do telegrama</string>
|
||||
<string name="password_descr">Palavra-passe do telegrama</string>
|
||||
<string name="shared_string_login">Entrar</string>
|
||||
<string name="shared_string_logout">Sair</string>
|
||||
<string name="initialization">Iniciando</string>
|
||||
|
@ -201,7 +201,7 @@
|
|||
<string name="shared_string_continue">Continuar</string>
|
||||
<string name="shared_string_cancel">Cancelar</string>
|
||||
<string name="shared_string_settings">Configurações</string>
|
||||
<string name="no_location_permission">O aplicativo 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="location_service_no_gps_available">Selecione um dos provedores de localização para compartilhar sua localização.</string>
|
||||
<string name="osmand_service">Modo de fundo</string>
|
||||
|
@ -211,7 +211,7 @@
|
|||
<string name="sharing_location">Compartilhando localização</string>
|
||||
<string name="process_service">Serviço OsmAnd Tracker</string>
|
||||
<string name="osmand_logo">Logotipo do OsmAnd</string>
|
||||
<string name="install_osmand_dialog_message">Você precisa instalar a versão gratuita ou paga do OsmAnd primeiro</string>
|
||||
<string name="install_osmand_dialog_message">Precisa instalar a versão gratuita ou paga do OsmAnd primeiro</string>
|
||||
<string name="install_osmand">Instalar OsmAnd</string>
|
||||
<string name="show_users_on_map">Mostrar utilitadoes no mapa</string>
|
||||
<string name="active_chats">Bate-papos ativos</string>
|
||||
|
@ -244,16 +244,15 @@
|
|||
<string name="shared_string_hour_short">h</string>
|
||||
<string name="shared_string_minute_short">min</string>
|
||||
<string name="shared_string_second_short">seg</string>
|
||||
<string name="welcome_descr">O <b>OsmAnd Tracker</b> permite que partilhe sua localização e veja a dos outros no OsmAnd.<br/>
|
||||
<br/>O app usa a API Telegram e você precisa de uma conta da Telegram.</string>
|
||||
<string name="welcome_descr"><b>OsmAnd Tracker</b> permite que partilhe a sua localização e veja a dos outros no OsmAnd.<br/> <br/>O app usa a API Telegram e precisa de uma conta do Telegram.</string>
|
||||
<string name="my_location">Minha localização</string>
|
||||
<string name="live_now">Ao vivo agora</string>
|
||||
<string name="timeline">Cronologia</string>
|
||||
<string name="saved_messages">Mensagens gravadas</string>
|
||||
<string name="time_zone_descr">Selecione o fuso horário para 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="units_and_formats">Unidades e formatos</string>
|
||||
<string name="unit_of_length_descr">Alterar unidade de medida de distância.</string>
|
||||
<string name="unit_of_length_descr">Alterar a unidade de medida de distância.</string>
|
||||
<string name="unit_of_length">Unidades de comprimento</string>
|
||||
<string name="unit_of_speed_system_descr">Definir unidade de velocidade.</string>
|
||||
<string name="unit_of_speed_system">Unidade de velocidade</string>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<resources>
|
||||
<string name="timeline_available_for_free_now">Хронология теперь доступна бесплатно.</string>
|
||||
<string name="location_recording_enabled">Запись местоположений включена</string>
|
||||
<string name="privacy_policy_use_telegram">Telegram (менеджер сообщений) используется для связи и общения с людьми.</string>
|
||||
<string name="privacy_policy_use_telegram">Telegram (мессенджер) используется для связи и общения с людьми.</string>
|
||||
<string name="privacy_policy_telegram_client">OsmAnd Tracker является одним из клиентов, использующих открытую платформу Telegram. Ваши контакты могут использовать любой другой клиент Telegram.</string>
|
||||
<string name="privacy_policy_agree">Нажимая \"Продолжить\", вы соглашаетесь с условиями политики конфиденциальности Telegram и OsmAnd.</string>
|
||||
<string name="timeline_description">Включите мониторинг, чтобы сохранять все местоположения в истории.</string>
|
||||
|
@ -63,7 +63,7 @@
|
|||
<string name="do_not_have_telegram">У меня нет учетной записи Telegram</string>
|
||||
<string name="enter_phone_number">Введите номер телефона</string>
|
||||
<string name="enter_authentication_code">Введите код аутентификации</string>
|
||||
<string name="shared_string_add">Добавить</string>
|
||||
<string name="shared_string_add">Сохранить</string>
|
||||
<string name="enter_device_name_description">Назовите новое устройство макс. 200 символов.</string>
|
||||
<string name="shared_string_distance">Расстояние</string>
|
||||
<string name="my_location">Моя локация</string>
|
||||
|
@ -106,7 +106,7 @@
|
|||
<string name="last_updated_location">Последнее обновление локации:</string>
|
||||
<string name="successfully_sent_and_updated">Успешно отправлено и обновлено</string>
|
||||
<string name="not_possible_to_send_to_telegram_chats">Невозможно отправить Telegram чаты:</string>
|
||||
<string name="waiting_for_response_from_telegram">Ожидание ответа от Telegram</string>
|
||||
<string name="waiting_for_response_from_telegram">Ожидание ответа Telegram</string>
|
||||
<string name="searching_for_gps">Поиск GPS…</string>
|
||||
<string name="connecting_to_the_internet">Подключение к Интернету</string>
|
||||
<string name="background_work_description">Измените настройки оптимизации батареи, чтобы обеспечить стабильную отправку местоположения.</string>
|
||||
|
@ -122,7 +122,7 @@
|
|||
<string name="osmand_connect_desc">Выберите версию OsmAnd которую OsmAnd Tracker использует для отображения положений на карте.</string>
|
||||
<string name="osmand_connect">OsmAnd подключение</string>
|
||||
<string name="connected_account">Связанная учетная запись</string>
|
||||
<string name="shared_string_account">Учетная запись</string>
|
||||
<string name="shared_string_account">Учётная запись</string>
|
||||
<string name="start_location_sharing">Начать отправку локации</string>
|
||||
<string name="install_osmand_dialog_message">Вам необходимо сначала установить бесплатную или платную версию OsmAnd</string>
|
||||
<string name="disconnect_from_telegram">Как отключить OsmAnd Tracker от Telegram</string>
|
||||
|
@ -156,7 +156,7 @@
|
|||
<string name="telegram_privacy_policy">Политика конфиденциальности Telegram</string>
|
||||
<string name="osmand_privacy_policy">Политика конфиденциальности OsmAnd</string>
|
||||
<string name="received_gps_points">Получено точек GPX: %1$s</string>
|
||||
<string name="shared_string_appearance">Вид</string>
|
||||
<string name="shared_string_appearance">Внешний вид</string>
|
||||
<string name="show_gps_points_descr">Показать количество собранных и отправленных точек GPS.</string>
|
||||
<string name="please_update_osmand">Обновите OsmAnd для просмотра данных на карте</string>
|
||||
<string name="shared_string_update">Обновить</string>
|
||||
|
@ -166,8 +166,8 @@
|
|||
<string name="shared_string_collected">Собрано</string>
|
||||
<string name="gps_points">Точки GPS</string>
|
||||
<string name="shared_string_sent">Отправлено</string>
|
||||
<string name="monitoring_is_enabled">Мониторинг включен</string>
|
||||
<string name="monitoring_is_disabled">Мониторинг отключен</string>
|
||||
<string name="monitoring_is_enabled">Мониторинг включён</string>
|
||||
<string name="monitoring_is_disabled">Мониторинг отключён</string>
|
||||
<string name="time_on_the_move">Время в движении</string>
|
||||
<string name="average_altitude">Средняя высота</string>
|
||||
<string name="average_speed">Средняя скорость</string>
|
||||
|
@ -211,7 +211,7 @@
|
|||
<string name="timeline">Хронология</string>
|
||||
<string name="search_contacts">Искать контакты</string>
|
||||
<string name="search_contacts_descr">Поиск среди всех ваших групп и контактов.</string>
|
||||
<string name="type_contact_or_group_name">Введите контакт или название группы</string>
|
||||
<string name="type_contact_or_group_name">Имя контакта или название группы</string>
|
||||
<string name="shared_string_search">Поиск</string>
|
||||
<string name="direction">Направление</string>
|
||||
<string name="precision">Точность</string>
|
||||
|
@ -220,8 +220,8 @@
|
|||
<string name="proxy_server">Сервер</string>
|
||||
<string name="shared_string_connection">Соединение</string>
|
||||
<string name="proxy_type">Тип прокси</string>
|
||||
<string name="proxy_connected">Соединено</string>
|
||||
<string name="proxy_disconnected">Разъединено</string>
|
||||
<string name="proxy_connected">Подключено</string>
|
||||
<string name="proxy_disconnected">Отключено</string>
|
||||
<string name="proxy_settings">Настройки прокси</string>
|
||||
<string name="proxy">Прокси</string>
|
||||
<string name="gpx_settings">Настройки GPX</string>
|
||||
|
@ -233,7 +233,7 @@
|
|||
<string name="mile">миля</string>
|
||||
<string name="mile_per_hour">миль/ч</string>
|
||||
<string name="altitude">Высота</string>
|
||||
<string name="bearing">Ориентация</string>
|
||||
<string name="bearing">Пеленг</string>
|
||||
<string name="proxy_key">Ключ</string>
|
||||
<string name="proxy_password">Пароль</string>
|
||||
<string name="proxy_username">Имя пользователя</string>
|
||||
|
@ -246,7 +246,7 @@
|
|||
<string name="min_logging_speed">Минимальная скорость регистрации</string>
|
||||
<string name="min_logging_speed_descr">Фильтр: не регистрировать, пока не достигнута необходимая скорость</string>
|
||||
<string name="shared_string_end">Конец</string>
|
||||
<string name="shared_string_start">Начало</string>
|
||||
<string name="shared_string_start">Старт</string>
|
||||
<string name="set_time_timeline_descr">Выберите время для отображения</string>
|
||||
<string name="saved_messages">Сохраненные сообщения</string>
|
||||
<string name="time_zone_descr">Выберите часовой пояс, чтобы показывать время вашего местоположения в сообщениях.</string>
|
||||
|
|
4
OsmAnd-telegram/res/values-sv/strings.xml
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="last_update_from_telegram_date">Senaste uppdatering från Telegram: %1$s</string>
|
||||
</resources>
|
|
@ -251,7 +251,7 @@
|
|||
<string name="saved_messages">Збережені повідомлення</string>
|
||||
<string name="time_zone_descr">Оберіть часовий пояс щоб відобразити повідомлення у вашому розташуванні.</string>
|
||||
<string name="time_zone">Часовий пояс</string>
|
||||
<string name="units_and_formats">Одиниця вимірювання та формати</string>
|
||||
<string name="units_and_formats">Одиниці виміру й формати</string>
|
||||
<string name="unit_of_length">Одиниці вимірювання довжини</string>
|
||||
<string name="unit_of_length_descr">Змінити одиницю вимірювання відстані.</string>
|
||||
<string name="unit_of_speed_system_descr">Визначити одиницю швидкості.</string>
|
||||
|
|
|
@ -8,12 +8,15 @@ public class SetMapLocationParams implements Parcelable {
|
|||
private double latitude;
|
||||
private double longitude;
|
||||
private int zoom;
|
||||
private float rotation;
|
||||
|
||||
private boolean animated;
|
||||
|
||||
public SetMapLocationParams(double latitude, double longitude, int zoom, boolean animated) {
|
||||
public SetMapLocationParams(double latitude, double longitude, int zoom, float rotation, boolean animated) {
|
||||
this.latitude = latitude;
|
||||
this.longitude = longitude;
|
||||
this.zoom = zoom;
|
||||
this.rotation = rotation;
|
||||
this.animated = animated;
|
||||
}
|
||||
|
||||
|
@ -44,6 +47,10 @@ public class SetMapLocationParams implements Parcelable {
|
|||
return zoom;
|
||||
}
|
||||
|
||||
public float getRotation() {
|
||||
return rotation;
|
||||
}
|
||||
|
||||
public boolean isAnimated() {
|
||||
return animated;
|
||||
}
|
||||
|
@ -53,6 +60,7 @@ public class SetMapLocationParams implements Parcelable {
|
|||
out.writeDouble(longitude);
|
||||
out.writeInt(zoom);
|
||||
out.writeByte((byte) (animated ? 1 : 0));
|
||||
out.writeFloat(rotation);
|
||||
}
|
||||
|
||||
private void readFromParcel(Parcel in) {
|
||||
|
@ -60,6 +68,7 @@ public class SetMapLocationParams implements Parcelable {
|
|||
longitude = in.readDouble();
|
||||
zoom = in.readInt();
|
||||
animated = in.readByte() != 0;
|
||||
rotation = in.readFloat();
|
||||
}
|
||||
|
||||
public int describeContents() {
|
||||
|
|
|
@ -939,7 +939,7 @@ class OsmandAidlHelper(private val app: TelegramApplication) {
|
|||
if (mIOsmAndAidlInterface != null) {
|
||||
try {
|
||||
return mIOsmAndAidlInterface!!.setMapLocation(
|
||||
SetMapLocationParams(latitude, longitude, zoom, animated))
|
||||
SetMapLocationParams(latitude, longitude, zoom, Float.NaN, animated))
|
||||
} catch (e: RemoteException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
|
|
@ -371,6 +371,72 @@
|
|||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.xml" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter
|
||||
android:label="@string/app_name"
|
||||
android:priority="50">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="file"/>
|
||||
<data android:scheme="content"/>
|
||||
<data android:host="*"/>
|
||||
<data android:pathPattern=".*\\.wpt.chart" />
|
||||
<data android:pathPattern=".*\\..*\\.wpt.chart" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\.wpt.chart" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\.wpt.chart" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.wpt.chart" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter
|
||||
android:label="@string/app_name"
|
||||
android:priority="50">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="file"/>
|
||||
<data android:scheme="content"/>
|
||||
<data android:host="*"/>
|
||||
<data android:mimeType="*/*"/>
|
||||
<data android:pathPattern=".*\\.wpt.chart" />
|
||||
<data android:pathPattern=".*\\..*\\.wpt.chart" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\.wpt.chart" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\.wpt.chart" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.wpt.chart" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter
|
||||
android:label="@string/app_name"
|
||||
android:priority="50">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="file"/>
|
||||
<data android:scheme="content"/>
|
||||
<data android:host="*"/>
|
||||
<data android:pathPattern=".*\\.3d.chart" />
|
||||
<data android:pathPattern=".*\\..*\\.3d.chart" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\.3d.chart" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\.3d.chart" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.3d.chart" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter
|
||||
android:label="@string/app_name"
|
||||
android:priority="50">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="file"/>
|
||||
<data android:scheme="content"/>
|
||||
<data android:host="*"/>
|
||||
<data android:mimeType="*/*"/>
|
||||
<data android:pathPattern=".*\\.3d.chart" />
|
||||
<data android:pathPattern=".*\\..*\\.3d.chart" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\.3d.chart" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\.3d.chart" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.3d.chart" />
|
||||
</intent-filter>
|
||||
|
||||
<!--trying to handle emails-->
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
@ -488,6 +554,13 @@
|
|||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<data android:host="ge0.me" android:scheme="https"/>
|
||||
<data android:host="ge0.me" android:scheme="http"/>
|
||||
<action android:name="android.intent.action.VIEW"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
<category android:name="android.intent.category.BROWSABLE"/>
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<data android:scheme="http" android:host="openstreetmap.de" android:pathPrefix="/karte" />
|
||||
<data android:scheme="https" android:host="openstreetmap.de" android:pathPrefix="/karte" />
|
||||
|
|
|
@ -566,6 +566,7 @@ dependencies {
|
|||
implementation ("com.github.HITGIF:TextFieldBoxes:1.4.5"){
|
||||
exclude group: 'com.android.support'
|
||||
}
|
||||
implementation 'com.jaredrummler:colorpicker:1.1.0'
|
||||
|
||||
huaweiImplementation files('libs/huawei-android-drm_v2.5.2.300.jar')
|
||||
freehuaweiImplementation files('libs/huawei-android-drm_v2.5.2.300.jar')
|
||||
|
|
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 5 KiB |
Before Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 5.2 KiB |
BIN
OsmAnd/res/drawable-hdpi/map_track_point_start_finish.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 3.9 KiB |
BIN
OsmAnd/res/drawable-mdpi/map_track_point_start_finish.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:opacity="opaque">
|
||||
<item android:drawable="@color/map_background_color_light"/>
|
||||
<item android:drawable="@color/splash_screen_background_color"/>
|
||||
<item android:top="@dimen/splash_screen_logo_top">
|
||||
<bitmap
|
||||
android:gravity="center"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:opacity="opaque">
|
||||
<item android:drawable="@color/map_background_color_light"/>
|
||||
<item android:drawable="@color/splash_screen_background_color"/>
|
||||
<item android:top="@dimen/splash_screen_logo_top">
|
||||
<bitmap
|
||||
android:gravity="center"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:opacity="opaque">
|
||||
<item android:drawable="@color/map_background_color_light"/>
|
||||
<item android:drawable="@color/splash_screen_background_color"/>
|
||||
<item android:top="@dimen/splash_screen_logo_top">
|
||||
<bitmap
|
||||
android:gravity="center"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="@color/map_background_color_light"/>
|
||||
<solid android:color="@color/splash_screen_background_color"/>
|
||||
</shape>
|
|
@ -1,4 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="@color/map_background_color_light"/>
|
||||
<solid android:color="@color/splash_screen_background_color"/>
|
||||
</shape>
|
|
@ -1,4 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="@color/map_background_color_light"/>
|
||||
<solid android:color="@color/splash_screen_background_color"/>
|
||||
</shape>
|
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:color="@color/active_color_primary_dark">
|
||||
<item>
|
||||
<shape>
|
||||
<solid android:color="@color/switch_button_active_dark" />
|
||||
<corners android:radius="@dimen/dlg_button_rect_rad" />
|
||||
<stroke
|
||||
android:width="1dp"
|
||||
android:color="@color/active_color_primary_dark" />
|
||||
</shape>
|
||||
</item>
|
||||
<item
|
||||
android:id="@android:id/mask"
|
||||
android:state_pressed="true">
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="@color/switch_button_active_stroke_dark" />
|
||||
<corners android:radius="@dimen/dlg_button_rect_rad" />
|
||||
</shape>
|
||||
</item>
|
||||
</ripple>
|