├── .gitignore
├── LICENSE.txt
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── graphhopper
│ │ └── navigation
│ │ └── example
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── ic_launcher-web.png
│ ├── java
│ │ └── com
│ │ │ └── graphhopper
│ │ │ └── navigation
│ │ │ └── example
│ │ │ ├── FetchGeocodingConfig.java
│ │ │ ├── FetchGeocodingTask.java
│ │ │ ├── FetchGeocodingTaskCallbackInterface.java
│ │ │ ├── FetchSolutionConfig.java
│ │ │ ├── FetchSolutionTask.java
│ │ │ ├── FetchSolutionTaskCallbackInterface.java
│ │ │ ├── GHAttributionDialogManager.java
│ │ │ ├── GeocodingInputDialog.java
│ │ │ ├── NavigationLauncherActivity.java
│ │ │ ├── NavigationViewSettingsActivity.java
│ │ │ ├── SimplifiedCallback.java
│ │ │ └── SolutionInputDialog.java
│ └── res
│ │ ├── drawable-hdpi
│ │ └── ic_map_marker.png
│ │ ├── drawable-mdpi
│ │ └── ic_map_marker.png
│ │ ├── drawable-v24
│ │ └── ic_launcher_foreground.xml
│ │ ├── drawable-xhdpi
│ │ └── ic_map_marker.png
│ │ ├── drawable-xxhdpi
│ │ └── ic_map_marker.png
│ │ ├── drawable-xxxhdpi
│ │ └── ic_map_marker.png
│ │ ├── drawable
│ │ ├── ic_cancel_black_24dp.xml
│ │ ├── ic_cloud_download_black_24dp.xml
│ │ ├── ic_help_black_24dp.xml
│ │ ├── ic_navigation_black_24dp.xml
│ │ ├── ic_search_black_24dp.xml
│ │ └── ic_settings_applications_black_24dp.xml
│ │ ├── layout
│ │ ├── activity_navigation_launcher.xml
│ │ ├── attribution_list_item.xml
│ │ ├── geocoding_input.xml
│ │ └── solution_input.xml
│ │ ├── menu
│ │ └── navigation_view_activity_menu.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── values
│ │ ├── .gitignore
│ │ ├── arrays.xml
│ │ ├── colors.xml
│ │ ├── developer-config.xml
│ │ ├── ic_launcher_background.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ │ └── xml
│ │ └── fragment_navigation_view_preferences.xml
│ └── test
│ └── java
│ └── com
│ └── graphhopper
│ └── navigation
│ └── ExampleUnitTest.java
├── build.gradle
├── files
├── gh-nav1.png
├── gh-nav2.png
├── gh-nav3.png
├── graphhopper-navigation-example.png
├── graphhopper-navigation-example.xcf
└── graphhopper.png
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 | *~
3 | TODO.txt
4 | nbactions*.xml
5 | maven/
6 | */nbactions.xml
7 | .idea/
8 | *.iml
9 | .*#
10 | /nbactions.xml
11 | tools/nb-configuration.xml
12 | .settings/
13 | .classpath
14 | .project
15 | .DS_Store
16 | package-lock.json
17 | .gradle
18 | /local.properties
19 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 |
2 |
3 | Apache License
4 | Version 2.0, January 2004
5 | http://www.apache.org/licenses/
6 |
7 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
8 |
9 | 1. Definitions.
10 |
11 | "License" shall mean the terms and conditions for use, reproduction,
12 | and distribution as defined by Sections 1 through 9 of this document.
13 |
14 | "Licensor" shall mean the copyright owner or entity authorized by
15 | the copyright owner that is granting the License.
16 |
17 | "Legal Entity" shall mean the union of the acting entity and all
18 | other entities that control, are controlled by, or are under common
19 | control with that entity. For the purposes of this definition,
20 | "control" means (i) the power, direct or indirect, to cause the
21 | direction or management of such entity, whether by contract or
22 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
23 | outstanding shares, or (iii) beneficial ownership of such entity.
24 |
25 | "You" (or "Your") shall mean an individual or Legal Entity
26 | exercising permissions granted by this License.
27 |
28 | "Source" form shall mean the preferred form for making modifications,
29 | including but not limited to software source code, documentation
30 | source, and configuration files.
31 |
32 | "Object" form shall mean any form resulting from mechanical
33 | transformation or translation of a Source form, including but
34 | not limited to compiled object code, generated documentation,
35 | and conversions to other media types.
36 |
37 | "Work" shall mean the work of authorship, whether in Source or
38 | Object form, made available under the License, as indicated by a
39 | copyright notice that is included in or attached to the work
40 | (an example is provided in the Appendix below).
41 |
42 | "Derivative Works" shall mean any work, whether in Source or Object
43 | form, that is based on (or derived from) the Work and for which the
44 | editorial revisions, annotations, elaborations, or other modifications
45 | represent, as a whole, an original work of authorship. For the purposes
46 | of this License, Derivative Works shall not include works that remain
47 | separable from, or merely link (or bind by name) to the interfaces of,
48 | the Work and Derivative Works thereof.
49 |
50 | "Contribution" shall mean any work of authorship, including
51 | the original version of the Work and any modifications or additions
52 | to that Work or Derivative Works thereof, that is intentionally
53 | submitted to Licensor for inclusion in the Work by the copyright owner
54 | or by an individual or Legal Entity authorized to submit on behalf of
55 | the copyright owner. For the purposes of this definition, "submitted"
56 | means any form of electronic, verbal, or written communication sent
57 | to the Licensor or its representatives, including but not limited to
58 | communication on electronic mailing lists, source code control systems,
59 | and issue tracking systems that are managed by, or on behalf of, the
60 | Licensor for the purpose of discussing and improving the Work, but
61 | excluding communication that is conspicuously marked or otherwise
62 | designated in writing by the copyright owner as "Not a Contribution."
63 |
64 | "Contributor" shall mean Licensor and any individual or Legal Entity
65 | on behalf of whom a Contribution has been received by Licensor and
66 | subsequently incorporated within the Work.
67 |
68 | 2. Grant of Copyright License. Subject to the terms and conditions of
69 | this License, each Contributor hereby grants to You a perpetual,
70 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
71 | copyright license to reproduce, prepare Derivative Works of,
72 | publicly display, publicly perform, sublicense, and distribute the
73 | Work and such Derivative Works in Source or Object form.
74 |
75 | 3. Grant of Patent License. Subject to the terms and conditions of
76 | this License, each Contributor hereby grants to You a perpetual,
77 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
78 | (except as stated in this section) patent license to make, have made,
79 | use, offer to sell, sell, import, and otherwise transfer the Work,
80 | where such license applies only to those patent claims licensable
81 | by such Contributor that are necessarily infringed by their
82 | Contribution(s) alone or by combination of their Contribution(s)
83 | with the Work to which such Contribution(s) was submitted. If You
84 | institute patent litigation against any entity (including a
85 | cross-claim or counterclaim in a lawsuit) alleging that the Work
86 | or a Contribution incorporated within the Work constitutes direct
87 | or contributory patent infringement, then any patent licenses
88 | granted to You under this License for that Work shall terminate
89 | as of the date such litigation is filed.
90 |
91 | 4. Redistribution. You may reproduce and distribute copies of the
92 | Work or Derivative Works thereof in any medium, with or without
93 | modifications, and in Source or Object form, provided that You
94 | meet the following conditions:
95 |
96 | (a) You must give any other recipients of the Work or
97 | Derivative Works a copy of this License; and
98 |
99 | (b) You must cause any modified files to carry prominent notices
100 | stating that You changed the files; and
101 |
102 | (c) You must retain, in the Source form of any Derivative Works
103 | that You distribute, all copyright, patent, trademark, and
104 | attribution notices from the Source form of the Work,
105 | excluding those notices that do not pertain to any part of
106 | the Derivative Works; and
107 |
108 | (d) If the Work includes a "NOTICE" text file as part of its
109 | distribution, then any Derivative Works that You distribute must
110 | include a readable copy of the attribution notices contained
111 | within such NOTICE file, excluding those notices that do not
112 | pertain to any part of the Derivative Works, in at least one
113 | of the following places: within a NOTICE text file distributed
114 | as part of the Derivative Works; within the Source form or
115 | documentation, if provided along with the Derivative Works; or,
116 | within a display generated by the Derivative Works, if and
117 | wherever such third-party notices normally appear. The contents
118 | of the NOTICE file are for informational purposes only and
119 | do not modify the License. You may add Your own attribution
120 | notices within Derivative Works that You distribute, alongside
121 | or as an addendum to the NOTICE text from the Work, provided
122 | that such additional attribution notices cannot be construed
123 | as modifying the License.
124 |
125 | You may add Your own copyright statement to Your modifications and
126 | may provide additional or different license terms and conditions
127 | for use, reproduction, or distribution of Your modifications, or
128 | for any such Derivative Works as a whole, provided Your use,
129 | reproduction, and distribution of the Work otherwise complies with
130 | the conditions stated in this License.
131 |
132 | 5. Submission of Contributions. Unless You explicitly state otherwise,
133 | any Contribution intentionally submitted for inclusion in the Work
134 | by You to the Licensor shall be under the terms and conditions of
135 | this License, without any additional terms or conditions.
136 | Notwithstanding the above, nothing herein shall supersede or modify
137 | the terms of any separate license agreement you may have executed
138 | with Licensor regarding such Contributions.
139 |
140 | 6. Trademarks. This License does not grant permission to use the trade
141 | names, trademarks, service marks, or product names of the Licensor,
142 | except as required for reasonable and customary use in describing the
143 | origin of the Work and reproducing the content of the NOTICE file.
144 |
145 | 7. Disclaimer of Warranty. Unless required by applicable law or
146 | agreed to in writing, Licensor provides the Work (and each
147 | Contributor provides its Contributions) on an "AS IS" BASIS,
148 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
149 | implied, including, without limitation, any warranties or conditions
150 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
151 | PARTICULAR PURPOSE. You are solely responsible for determining the
152 | appropriateness of using or redistributing the Work and assume any
153 | risks associated with Your exercise of permissions under this License.
154 |
155 | 8. Limitation of Liability. In no event and under no legal theory,
156 | whether in tort (including negligence), contract, or otherwise,
157 | unless required by applicable law (such as deliberate and grossly
158 | negligent acts) or agreed to in writing, shall any Contributor be
159 | liable to You for damages, including any direct, indirect, special,
160 | incidental, or consequential damages of any character arising as a
161 | result of this License or out of the use or inability to use the
162 | Work (including but not limited to damages for loss of goodwill,
163 | work stoppage, computer failure or malfunction, or any and all
164 | other commercial damages or losses), even if such Contributor
165 | has been advised of the possibility of such damages.
166 |
167 | 9. Accepting Warranty or Additional Liability. While redistributing
168 | the Work or Derivative Works thereof, You may choose to offer,
169 | and charge a fee for, acceptance of support, warranty, indemnity,
170 | or other liability obligations and/or rights consistent with this
171 | License. However, in accepting such obligations, You may act only
172 | on Your own behalf and on Your sole responsibility, not on behalf
173 | of any other Contributor, and only if You agree to indemnify,
174 | defend, and hold each Contributor harmless for any liability
175 | incurred by, or claims asserted against, such Contributor by reason
176 | of your accepting any such warranty or additional liability.
177 |
178 | END OF TERMS AND CONDITIONS
179 |
180 | APPENDIX: How to apply the Apache License to your work.
181 |
182 | To apply the Apache License to your work, attach the following
183 | boilerplate notice, with the fields enclosed by brackets "[]"
184 | replaced with your own identifying information. (Don't include
185 | the brackets!) The text should be enclosed in the appropriate
186 | comment syntax for the file format. We also recommend that a
187 | file or class name and description of purpose be included on the
188 | same "printed page" as the copyright notice for easier
189 | identification within third-party archives.
190 |
191 | Copyright [yyyy] [name of copyright owner]
192 |
193 | Licensed under the Apache License, Version 2.0 (the "License");
194 | you may not use this file except in compliance with the License.
195 | You may obtain a copy of the License at
196 |
197 | http://www.apache.org/licenses/LICENSE-2.0
198 |
199 | Unless required by applicable law or agreed to in writing, software
200 | distributed under the License is distributed on an "AS IS" BASIS,
201 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
202 | See the License for the specific language governing permissions and
203 | limitations under the License.
204 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Update to MapLibre Navigation SDK for Android
2 |
3 | We recommend that you use the successor of the GraphHopper Navigation SDK, which is the [MapLibre Navigation SDK](https://github.com/maplibre/maplibre-navigation-android).
4 | An example where GraphHopper routing is integration is available [here](https://github.com/graphhopper/graphhopper-navigation-example).
5 |
6 | ---------
7 |
8 | # Legacy Readme
9 |
10 | ## GraphHopper Navigation Sample
11 |
12 | This Android example application showcases navigation based on instructions returned from the [GraphHopper Navigation](https://github.com/graphhopper/graphhopper/tree/master/navigation) component.
13 |
14 | ## Try
15 |
16 | [Download from Google Play](https://play.google.com/store/apps/details?id=com.graphhopper.navigation.example).
17 |
18 | ## Features
19 |
20 | 
21 |
22 | - Turn-by-turn navigation including spoken turn instruction
23 | - Route planning (from A to B via intermediate points)
24 | - Load route optimization solutions from the [GraphHopper Route Optimization API](https://graphhopper.com/api/1/docs/route-optimization/)
25 | - Load routes planned on [GraphHopper Maps](https://graphhopper.com/maps/)
26 | - Search for places using the [GraphHopper Geocoding API](https://graphhopper.com/api/1/docs/geocoding/)
27 | - 100% open source
28 | - no dependency to Mapbox i.e. no Mapbox contract required. The Mapbox key can be a random string.
29 |
30 | ## Getting Started
31 |
32 | Building your own turn-by-turn navigation app based on GraphHopper is easy. Just sign up for the [GraphHopper Directions API](https://www.graphhopper.com/products/).
33 |
34 | GraphHopper does not provide map tiles. The navigation sdk is compatible with MVT vector tiles and raster tiles. There are several map providers, including:
35 | - [Mapilion](https://mapilion.com/)
36 | - [MapTiler](https://www.maptiler.com/cloud/)
37 | - [ThunderForest](http://thunderforest.com/)
38 |
39 | *Note: while it's possible to use raster tiles, we recommend vector tiles for mobile applications.*
40 |
41 | Enter your GraphHopper API key and map style url in the developer config: `app/src/main/res/values/developer-config.xml`
42 |
43 | You can fork this project and adapt it to your needs, or use it as orientation when developing your own application.
44 |
45 | ## License
46 |
47 | This project stands under the Apache License.
48 |
49 | It is a fork of the [Mapbox Sample App](https://github.com/mapbox/mapbox-navigation-android/tree/master/app),
50 | which is licensed under the [MIT](https://github.com/mapbox/mapbox-navigation-android/blob/master/LICENSE) license.
51 |
52 | ## Updating the developer-config file
53 |
54 | ```
55 | Ignore:
56 | git update-index --assume-unchanged app/src/main/res/values/developer-config.xml
57 | Unignore:
58 | git update-index --no-assume-unchanged app/src/main/res/values/developer-config.xml
59 | ```
60 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 |
4 |
5 | android {
6 | compileSdkVersion 27
7 | defaultConfig {
8 | applicationId "com.graphhopper.navigation.example"
9 | minSdkVersion 23
10 | targetSdkVersion 27
11 | versionCode 9
12 | versionName "1.0.0-pre5"
13 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
14 | }
15 | buildTypes {
16 | release {
17 | minifyEnabled true
18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
19 | }
20 | }
21 | compileOptions {
22 | targetCompatibility 1.8
23 | sourceCompatibility 1.8
24 | }
25 | }
26 |
27 | dependencies {
28 | implementation fileTree(include: ['*.jar'], dir: 'libs')
29 | implementation 'com.android.support:appcompat-v7:27.1.1'
30 | implementation 'com.android.support.constraint:constraint-layout:1.1.3'
31 | implementation 'com.graphhopper:graphhopper-navigation-android-ui:0.1.0-SNAPSHOT'
32 | implementation 'com.graphhopper:directions-api-client:0.10.1-4'
33 | implementation 'com.jakewharton:butterknife:8.8.1'
34 | annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
35 | testImplementation 'junit:junit:4.12'
36 | androidTestImplementation 'com.android.support.test:runner:1.0.2'
37 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
38 | }
39 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/graphhopper/navigation/example/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.graphhopper.navigation.example;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("graphhopper.com.graphhopper_navigation_example", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
12 |
13 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
40 |
41 |
42 |
43 |
46 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/app/src/main/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example-legacy/25fd91368a4c3b507eed0e9f323f6b818f0ddc46/app/src/main/ic_launcher-web.png
--------------------------------------------------------------------------------
/app/src/main/java/com/graphhopper/navigation/example/FetchGeocodingConfig.java:
--------------------------------------------------------------------------------
1 | package com.graphhopper.navigation.example;
2 |
3 | public class FetchGeocodingConfig {
4 |
5 | final String query;
6 | final String locale;
7 | final int limit;
8 | final boolean reverse;
9 | final String point;
10 | final String provider;
11 |
12 | FetchGeocodingConfig(String query, String locale, int limit, boolean reverse, String point, String provider) {
13 | this.query = query;
14 | this.locale = locale;
15 | this.limit = limit;
16 | this.reverse = reverse;
17 | this.point = point;
18 | this.provider = provider;
19 | }
20 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/graphhopper/navigation/example/FetchGeocodingTask.java:
--------------------------------------------------------------------------------
1 | package com.graphhopper.navigation.example;
2 |
3 | import android.os.AsyncTask;
4 |
5 | import com.graphhopper.directions.api.client.ApiException;
6 | import com.graphhopper.directions.api.client.api.GeocodingApi;
7 | import com.graphhopper.directions.api.client.model.GeocodingLocation;
8 | import com.graphhopper.directions.api.client.model.GeocodingResponse;
9 |
10 | import java.util.ArrayList;
11 | import java.util.List;
12 |
13 | import timber.log.Timber;
14 |
15 | public class FetchGeocodingTask extends AsyncTask> {
16 |
17 | private final String ghKey;
18 | private final FetchGeocodingTaskCallbackInterface callbackInterface;
19 |
20 | FetchGeocodingTask(FetchGeocodingTaskCallbackInterface callbackInterface, String ghKey) {
21 | this.callbackInterface = callbackInterface;
22 | this.ghKey = ghKey;
23 | }
24 |
25 | @Override
26 | protected List doInBackground(FetchGeocodingConfig... geocodingConfigs) {
27 |
28 | if (geocodingConfigs.length != 1)
29 | throw new IllegalArgumentException("It's only possible to fetch one geocoding at a time");
30 |
31 | List locations = new ArrayList<>();
32 | GeocodingApi api = new GeocodingApi();
33 |
34 | try {
35 | FetchGeocodingConfig geocodingConfig = geocodingConfigs[0];
36 | GeocodingResponse res = api.geocodeGet(ghKey, geocodingConfig.query, geocodingConfig.locale, geocodingConfig.limit, geocodingConfig.reverse, geocodingConfig.point, geocodingConfig.provider);
37 | locations = res.getHits();
38 |
39 | if (locations.isEmpty())
40 | callbackInterface.onError(R.string.error_location_not_found);
41 |
42 | } catch (ApiException e) {
43 | callbackInterface.onError(R.string.error_fetching_geocoding);
44 | Timber.e(e, "An exception occured when fetching geocoding results for %s", geocodingConfigs[0].query);
45 | }
46 |
47 | return locations;
48 | }
49 |
50 | @Override
51 | protected void onPostExecute(List locations) {
52 | callbackInterface.onPostExecuteGeocodingSearch(locations);
53 | }
54 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/graphhopper/navigation/example/FetchGeocodingTaskCallbackInterface.java:
--------------------------------------------------------------------------------
1 | package com.graphhopper.navigation.example;
2 |
3 | import com.graphhopper.directions.api.client.model.GeocodingLocation;
4 |
5 | import java.util.List;
6 |
7 | public interface FetchGeocodingTaskCallbackInterface {
8 |
9 | void onError(int message);
10 |
11 | void onPostExecuteGeocodingSearch(List points);
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/app/src/main/java/com/graphhopper/navigation/example/FetchSolutionConfig.java:
--------------------------------------------------------------------------------
1 | package com.graphhopper.navigation.example;
2 |
3 | public class FetchSolutionConfig {
4 |
5 | final String jobId;
6 | final String vehicleId;
7 |
8 | FetchSolutionConfig(String jobId, String vehicleId) {
9 | this.jobId = jobId;
10 | this.vehicleId = vehicleId;
11 | }
12 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/graphhopper/navigation/example/FetchSolutionTask.java:
--------------------------------------------------------------------------------
1 | package com.graphhopper.navigation.example;
2 |
3 | import android.os.AsyncTask;
4 |
5 | import com.graphhopper.directions.api.client.ApiException;
6 | import com.graphhopper.directions.api.client.api.SolutionApi;
7 | import com.graphhopper.directions.api.client.model.Activity;
8 | import com.graphhopper.directions.api.client.model.Address;
9 | import com.graphhopper.directions.api.client.model.Route;
10 | import com.mapbox.geojson.Point;
11 |
12 | import java.util.ArrayList;
13 | import java.util.List;
14 |
15 | import timber.log.Timber;
16 |
17 | public class FetchSolutionTask extends AsyncTask> {
18 |
19 | private final String ghKey;
20 | private final FetchSolutionTaskCallbackInterface callbackInterface;
21 |
22 | FetchSolutionTask(FetchSolutionTaskCallbackInterface callbackInterface, String ghKey) {
23 | this.callbackInterface = callbackInterface;
24 | this.ghKey = ghKey;
25 | }
26 |
27 | @Override
28 | protected List doInBackground(FetchSolutionConfig... solutions) {
29 |
30 | if (solutions.length != 1)
31 | throw new IllegalArgumentException("It's only possible to fetch one solution at a time");
32 |
33 | List points = new ArrayList<>();
34 | SolutionApi api = new SolutionApi();
35 |
36 | try {
37 | com.graphhopper.directions.api.client.model.Response res = api.getSolution(ghKey, solutions[0].jobId);
38 | List routes = res.getSolution().getRoutes();
39 |
40 | for (Route route : routes) {
41 | if (route.getVehicleId().equals(solutions[0].vehicleId) || solutions[0].vehicleId == null) {
42 | // Found the right vehicle
43 | List activities = route.getActivities();
44 | for (int i = 0; i < activities.size(); i++) {
45 | Activity activity = activities.get(i);
46 | Address address = activity.getAddress();
47 | points.add(Point.fromLngLat(address.getLon(), address.getLat()));
48 | }
49 | break;
50 | }
51 | }
52 |
53 | if (points.isEmpty())
54 | callbackInterface.onError(R.string.error_vehicle_not_found);
55 |
56 | } catch (ApiException e) {
57 | callbackInterface.onError(R.string.error_fetching_solution);
58 | Timber.e(e, "An exception occured when fetching a solution with jobId %s", solutions[0].jobId);
59 | }
60 |
61 | return points;
62 | }
63 |
64 | @Override
65 | protected void onPostExecute(List points) {
66 | callbackInterface.onPostExecute(points);
67 | }
68 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/graphhopper/navigation/example/FetchSolutionTaskCallbackInterface.java:
--------------------------------------------------------------------------------
1 | package com.graphhopper.navigation.example;
2 |
3 | import com.mapbox.geojson.Point;
4 |
5 | import java.util.List;
6 |
7 | public interface FetchSolutionTaskCallbackInterface {
8 |
9 | void onError(int message);
10 |
11 | void onPostExecute(List points);
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/app/src/main/java/com/graphhopper/navigation/example/GHAttributionDialogManager.java:
--------------------------------------------------------------------------------
1 | package com.graphhopper.navigation.example;
2 |
3 | import android.app.Activity;
4 | import android.app.AlertDialog;
5 | import android.content.ActivityNotFoundException;
6 | import android.content.Context;
7 | import android.content.DialogInterface;
8 | import android.content.Intent;
9 | import android.net.Uri;
10 | import android.support.annotation.NonNull;
11 | import android.view.View;
12 | import android.widget.ArrayAdapter;
13 | import android.widget.Toast;
14 |
15 | import com.mapbox.mapboxsdk.attribution.Attribution;
16 | import com.mapbox.mapboxsdk.attribution.AttributionParser;
17 | import com.mapbox.mapboxsdk.maps.AttributionDialogManager;
18 | import com.mapbox.mapboxsdk.maps.MapboxMap;
19 | import com.mapbox.mapboxsdk.style.sources.Source;
20 |
21 | import java.util.ArrayList;
22 | import java.util.List;
23 | import java.util.Set;
24 |
25 | /**
26 | * This class is mostly based on {@link AttributionDialogManager}, but adds GraphHopper as
27 | * additional attribution.
28 | */
29 | public class GHAttributionDialogManager extends AttributionDialogManager {
30 |
31 | private final Context context;
32 | private final MapboxMap mapboxMap;
33 | private Set attributionSet;
34 |
35 | public GHAttributionDialogManager(@NonNull Context context, @NonNull MapboxMap mapboxMap) {
36 | super(context, mapboxMap);
37 | this.context = context;
38 | this.mapboxMap = mapboxMap;
39 | }
40 |
41 | // Called when someone presses the attribution icon on the map
42 | @Override
43 | public void onClick(View view) {
44 | attributionSet = new GHAttributionDialogManager.AttributionBuilder(mapboxMap).build();
45 |
46 | boolean isActivityFinishing = false;
47 | if (context instanceof Activity) {
48 | isActivityFinishing = ((Activity) context).isFinishing();
49 | }
50 |
51 | // check is hosting activity isn't finishing
52 | // https://github.com/mapbox/mapbox-gl-native/issues/11238
53 | if (!isActivityFinishing) {
54 | showAttributionDialog(getAttributionTitles());
55 | }
56 | }
57 |
58 | // Called when someone selects an attribution or telemetry settings from the dialog
59 | @Override
60 | public void onClick(DialogInterface dialog, int which) {
61 | showMapFeedbackWebPage(which);
62 | }
63 |
64 | private void showMapFeedbackWebPage(int which) {
65 | Attribution[] attributions = attributionSet.toArray(new Attribution[attributionSet.size()]);
66 | String url = attributions[which].getUrl();
67 | showWebPage(url);
68 | }
69 |
70 | private void showWebPage(@NonNull String url) {
71 | try {
72 | Intent intent = new Intent(Intent.ACTION_VIEW);
73 | intent.setData(Uri.parse(url));
74 | context.startActivity(intent);
75 | } catch (ActivityNotFoundException exception) {
76 | // explicitly handling if the device hasn't have a web browser installed. #8899
77 | Toast.makeText(context, R.string.error_no_browser_installed, Toast.LENGTH_LONG).show();
78 | }
79 | }
80 |
81 |
82 | protected void showAttributionDialog(String[] attributionTitles) {
83 | AlertDialog.Builder builder = new AlertDialog.Builder(context);
84 | builder.setTitle(R.string.app_name);
85 | builder.setAdapter(new ArrayAdapter<>(context, R.layout.attribution_list_item, attributionTitles), this);
86 | builder.show();
87 | }
88 |
89 | private String[] getAttributionTitles() {
90 | List titles = new ArrayList<>();
91 | for (Attribution attribution : attributionSet) {
92 | titles.add(attribution.getTitle());
93 | }
94 | return titles.toArray(new String[titles.size()]);
95 | }
96 |
97 |
98 | private static class AttributionBuilder {
99 |
100 | private final MapboxMap mapboxMap;
101 |
102 | AttributionBuilder(MapboxMap mapboxMap) {
103 | this.mapboxMap = mapboxMap;
104 | }
105 |
106 | private Set build() {
107 | List attributions = new ArrayList<>();
108 | attributions.add("© GraphHopper API");
109 | for (Source source : mapboxMap.getSources()) {
110 | attributions.add(source.getAttribution());
111 | }
112 |
113 | return new AttributionParser.Options()
114 | .withCopyrightSign(true)
115 | // TODO when using Mapbox as Tilesource we should keep this, should we automatically remove it otherwise?
116 | .withImproveMap(true)
117 | .withAttributionData(attributions.toArray(new String[attributions.size()]))
118 | .build().getAttributions();
119 | }
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/app/src/main/java/com/graphhopper/navigation/example/GeocodingInputDialog.java:
--------------------------------------------------------------------------------
1 | package com.graphhopper.navigation.example;
2 |
3 | import android.app.Activity;
4 | import android.app.AlertDialog;
5 | import android.app.Dialog;
6 | import android.app.DialogFragment;
7 | import android.content.DialogInterface;
8 | import android.os.Bundle;
9 | import android.view.LayoutInflater;
10 | import android.view.View;
11 | import android.widget.EditText;
12 |
13 | public class GeocodingInputDialog extends DialogFragment {
14 |
15 | private String geocodingInput = "";
16 |
17 | public void setGeocodingInput(String geocodingInput) {
18 | this.geocodingInput = geocodingInput;
19 | }
20 |
21 | public interface NoticeDialogListener {
22 | public void onDialogPositiveClick(DialogFragment dialog);
23 | }
24 |
25 | NoticeDialogListener mListener;
26 |
27 | @Override
28 | public void onAttach(Activity activity) {
29 | super.onAttach(activity);
30 | // Verify that the host activity implements the callback interface
31 | try {
32 | // Instantiate the NoticeDialogListener so we can send events to the host
33 | mListener = (NoticeDialogListener) activity;
34 | } catch (ClassCastException e) {
35 | // The activity doesn't implement the interface, throw exception
36 | throw new ClassCastException(activity.toString()
37 | + " must implement NoticeDialogListener");
38 | }
39 | }
40 |
41 | @Override
42 | public Dialog onCreateDialog(Bundle savedInstanceState) {
43 | AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
44 | // Get the layout inflater
45 | LayoutInflater inflater = getActivity().getLayoutInflater();
46 |
47 | View modifiedView = inflater.inflate(R.layout.geocoding_input, null);
48 | if (!geocodingInput.isEmpty()) {
49 | EditText jobIdEditText = (EditText) modifiedView.findViewById(R.id.geocoding_input_id);
50 | jobIdEditText.setText(geocodingInput);
51 | }
52 |
53 | // Inflate and set the layout for the dialog
54 | // Pass null as the parent view because its going in the dialog layout
55 | builder.setView(modifiedView)
56 | // Add action buttons
57 | .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
58 | @Override
59 | public void onClick(DialogInterface dialog, int id) {
60 | mListener.onDialogPositiveClick(GeocodingInputDialog.this);
61 | }
62 | })
63 | .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
64 | public void onClick(DialogInterface dialog, int id) {
65 | GeocodingInputDialog.this.getDialog().cancel();
66 | }
67 | });
68 | return builder.create();
69 | }
70 |
71 | }
72 |
73 |
74 |
--------------------------------------------------------------------------------
/app/src/main/java/com/graphhopper/navigation/example/NavigationLauncherActivity.java:
--------------------------------------------------------------------------------
1 | package com.graphhopper.navigation.example;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.app.AlertDialog;
5 | import android.app.DialogFragment;
6 | import android.content.DialogInterface;
7 | import android.content.Intent;
8 | import android.content.SharedPreferences;
9 | import android.location.Location;
10 | import android.net.Uri;
11 | import android.os.Bundle;
12 | import android.preference.PreferenceManager;
13 | import android.support.annotation.NonNull;
14 | import android.support.annotation.Nullable;
15 | import android.support.design.widget.Snackbar;
16 | import android.support.v7.app.AppCompatActivity;
17 | import android.text.Html;
18 | import android.view.Menu;
19 | import android.view.MenuItem;
20 | import android.view.View;
21 | import android.widget.EditText;
22 | import android.widget.ProgressBar;
23 | import android.widget.Toast;
24 |
25 | import com.graphhopper.directions.api.client.model.GeocodingLocation;
26 | import com.graphhopper.directions.api.client.model.GeocodingPoint;
27 | import com.mapbox.android.core.permissions.PermissionsListener;
28 | import com.mapbox.android.core.permissions.PermissionsManager;
29 | import com.mapbox.api.directions.v5.DirectionsCriteria;
30 | import com.mapbox.api.directions.v5.models.DirectionsResponse;
31 | import com.mapbox.api.directions.v5.models.DirectionsRoute;
32 | import com.mapbox.core.constants.Constants;
33 | import com.mapbox.geojson.LineString;
34 | import com.mapbox.geojson.Point;
35 | import com.mapbox.mapboxsdk.Mapbox;
36 | import com.mapbox.mapboxsdk.annotations.IconFactory;
37 | import com.mapbox.mapboxsdk.annotations.Marker;
38 | import com.mapbox.mapboxsdk.annotations.MarkerOptions;
39 | import com.mapbox.mapboxsdk.camera.CameraPosition;
40 | import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
41 | import com.mapbox.mapboxsdk.exceptions.InvalidLatLngBoundsException;
42 | import com.mapbox.mapboxsdk.geometry.LatLng;
43 | import com.mapbox.mapboxsdk.geometry.LatLngBounds;
44 | import com.mapbox.mapboxsdk.maps.MapView;
45 | import com.mapbox.mapboxsdk.maps.MapboxMap;
46 | import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
47 | import com.mapbox.mapboxsdk.maps.Telemetry;
48 | import com.mapbox.mapboxsdk.plugins.locationlayer.LocationLayerPlugin;
49 | import com.mapbox.mapboxsdk.plugins.locationlayer.modes.RenderMode;
50 | import com.mapbox.services.android.navigation.ui.v5.NavigationLauncher;
51 | import com.mapbox.services.android.navigation.ui.v5.NavigationLauncherOptions;
52 | import com.mapbox.services.android.navigation.ui.v5.route.NavigationMapRoute;
53 | import com.mapbox.services.android.navigation.ui.v5.route.OnRouteSelectionChangeListener;
54 | import com.mapbox.services.android.navigation.v5.navigation.NavigationRoute;
55 | import com.mapbox.services.android.navigation.v5.utils.LocaleUtils;
56 |
57 | import java.util.ArrayList;
58 | import java.util.List;
59 | import java.util.Locale;
60 |
61 | import butterknife.BindView;
62 | import butterknife.ButterKnife;
63 | import retrofit2.Call;
64 | import retrofit2.Response;
65 |
66 | public class NavigationLauncherActivity extends AppCompatActivity implements OnMapReadyCallback,
67 | MapboxMap.OnMapLongClickListener, OnRouteSelectionChangeListener,
68 | SolutionInputDialog.NoticeDialogListener, FetchSolutionTaskCallbackInterface,
69 | FetchGeocodingTaskCallbackInterface, GeocodingInputDialog.NoticeDialogListener,
70 | PermissionsListener {
71 |
72 | private static final int CAMERA_ANIMATION_DURATION = 1000;
73 | private static final int DEFAULT_CAMERA_ZOOM = 16;
74 | private static final int CHANGE_SETTING_REQUEST_CODE = 1;
75 | // If you change the first start dialog (help message), increase this number, all users will be shown the message again
76 | private static final int FIRST_START_DIALOG_VERSION = 1;
77 | private static final int FIRST_NAVIGATION_DIALOG_VERSION = 1;
78 |
79 | private LocationLayerPlugin locationLayer;
80 | private NavigationMapRoute mapRoute;
81 | private MapboxMap mapboxMap;
82 | private PermissionsManager permissionsManager;
83 |
84 | @BindView(R.id.mapView)
85 | MapView mapView;
86 | @BindView(R.id.loading)
87 | ProgressBar loading;
88 |
89 | private Marker currentMarker;
90 | private List markers;
91 | private List waypoints = new ArrayList<>();
92 | private DirectionsRoute route;
93 | private LocaleUtils localeUtils;
94 |
95 | private final int[] padding = new int[]{50, 50, 50, 50};
96 |
97 | private String currentJobId = "";
98 | private String currentVehicleId = "";
99 | private String currentGeocodingInput = "";
100 |
101 | @Override
102 | protected void onCreate(@Nullable Bundle savedInstanceState) {
103 | super.onCreate(savedInstanceState);
104 | setContentView(R.layout.activity_navigation_launcher);
105 | Mapbox.getInstance(this.getApplicationContext(), getString(R.string.mapbox_access_token));
106 | Telemetry.disableOnUserRequest();
107 | ButterKnife.bind(this);
108 | mapView.setStyleUrl(getString(R.string.map_view_styleUrl));
109 | mapView.onCreate(savedInstanceState);
110 | mapView.getMapAsync(this);
111 | localeUtils = new LocaleUtils();
112 | if (getSupportActionBar() != null) {
113 | getSupportActionBar().setTitle("");
114 | }
115 | showFirstStartIfNecessary();
116 | }
117 |
118 | @Override
119 | public boolean onCreateOptionsMenu(Menu menu) {
120 | // Inflate the menu; this adds items to the action bar if it is present.
121 | getMenuInflater().inflate(R.menu.navigation_view_activity_menu, menu);
122 | return true;
123 | }
124 |
125 | @Override
126 | public boolean onOptionsItemSelected(MenuItem item) {
127 | switch (item.getItemId()) {
128 | case R.id.settings:
129 | showSettings();
130 | return true;
131 | case R.id.navigate_btn:
132 | launchNavigationWithRoute();
133 | return true;
134 | case R.id.reset_route_btn:
135 | clearRoute();
136 | return true;
137 | case R.id.fetch_solution_btn:
138 | showSolutionInputDialog();
139 | return true;
140 | case R.id.geocoding_search_btn:
141 | showGeocodingInputDialog();
142 | return true;
143 | case R.id.help:
144 | showHelpDialog();
145 | return true;
146 | default:
147 | return super.onOptionsItemSelected(item);
148 | }
149 | }
150 |
151 | private void showSettings() {
152 | startActivityForResult(new Intent(this, NavigationViewSettingsActivity.class), CHANGE_SETTING_REQUEST_CODE);
153 | }
154 |
155 | @Override
156 | protected void onActivityResult(int requestCode, int resultCode, Intent data) {
157 | super.onActivityResult(requestCode, resultCode, data);
158 | if (requestCode == CHANGE_SETTING_REQUEST_CODE && resultCode == RESULT_OK) {
159 | boolean shouldRefetch = data.getBooleanExtra(NavigationViewSettingsActivity.UNIT_TYPE_CHANGED, false)
160 | || data.getBooleanExtra(NavigationViewSettingsActivity.LANGUAGE_CHANGED, false)
161 | || data.getBooleanExtra(NavigationViewSettingsActivity.PROFILE_CHANGED, false);
162 | if (waypoints.size() > 0 && shouldRefetch) {
163 | fetchRoute();
164 | }
165 | }
166 | }
167 |
168 | @SuppressWarnings({"MissingPermission"})
169 | @Override
170 | protected void onStart() {
171 | super.onStart();
172 | mapView.onStart();
173 | if (locationLayer != null) {
174 | locationLayer.onStart();
175 | }
176 | }
177 |
178 | @SuppressWarnings({"MissingPermission"})
179 | @Override
180 | public void onResume() {
181 | super.onResume();
182 | mapView.onResume();
183 | handleIntent(getIntent());
184 | }
185 |
186 | @Override
187 | protected void onNewIntent(Intent intent) {
188 | super.onNewIntent(intent);
189 | // getIntent() should always return the most recent
190 | setIntent(intent);
191 | }
192 |
193 | private void handleIntent(Intent intent) {
194 | if (intent != null) {
195 | Uri data = intent.getData();
196 | if (data != null && "graphhopper.com".equals(data.getHost())) {
197 | if (data.getPath() != null) {
198 | if (this.mapboxMap == null) {
199 | //this happens when onResume is called at the initial start and we will call this method again in onMapReady
200 | return;
201 | }
202 | if (data.getPath().contains("maps")) {
203 | clearRoute();
204 | //Open Map Url
205 | setRouteProfileToSharedPreferences(data.getQueryParameter("vehicle"));
206 |
207 | List points = data.getQueryParameters("point");
208 | for (String point : points) {
209 | String[] pointArr = point.split(",");
210 | addPointToRoute(Double.parseDouble(pointArr[0]), Double.parseDouble(pointArr[1]));
211 | }
212 |
213 | setStartFromLocationToSharedPreferences(false);
214 | updateRouteAfterWaypointChange();
215 | }
216 | // https://graphhopper.com/api/1/vrp/solution/e7fb8a9b-e441-4ec2-a487-20788e591bb3?vehicle_id=1&key=[KEY]
217 | if (data.getPath().contains("api/1/vrp/solution")) {
218 | clearRoute();
219 | //Open Vrp Url
220 | List pathSegments = data.getPathSegments();
221 | fetchVrpSolution(pathSegments.get(pathSegments.size() - 1), data.getQueryParameter("vehicle_id"));
222 | }
223 | }
224 |
225 | }
226 | }
227 | }
228 |
229 | private void showFirstStartIfNecessary() {
230 | SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
231 | if (sharedPreferences.getInt(getString(R.string.first_start_dialog_key), -1) < FIRST_START_DIALOG_VERSION) {
232 | showHelpDialog();
233 | }
234 | }
235 |
236 | private void showHelpDialog() {
237 | AlertDialog.Builder builder = new AlertDialog.Builder(this);
238 | builder.setTitle(R.string.help_message_title);
239 | builder.setMessage(Html.fromHtml("1. Please note, this is a demo and not a full featured application. The purpose of this application is to provide an easy starting point for developers to create a navigation application with GraphHopper
2. You should enable your GPS/location
3.You can either search for a location using the magnifier icon or by long pressing on the map
4. Start the navigation by tapping the arrow button
This project is 100% open source, contributions are welcome.
Please drive carefully and always abide local law and signs. Roads might be impassible due to construction projects, traffic, weather, or other events."));
240 | SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
241 | builder.setPositiveButton(R.string.agree, new DialogInterface.OnClickListener() {
242 | public void onClick(DialogInterface dialog, int id) {
243 | SharedPreferences.Editor editor = sharedPreferences.edit();
244 | editor.putInt(getString(R.string.first_start_dialog_key), FIRST_START_DIALOG_VERSION);
245 | editor.apply();
246 | }
247 | });
248 | builder.setNeutralButton(R.string.github, new DialogInterface.OnClickListener() {
249 | public void onClick(DialogInterface dialog, int id) {
250 | startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/graphhopper/graphhopper-navigation-example")));
251 | }
252 | });
253 |
254 | AlertDialog dialog = builder.create();
255 | dialog.show();
256 | }
257 |
258 | private void showNavigationDialog() {
259 | AlertDialog.Builder builder = new AlertDialog.Builder(this);
260 | builder.setTitle(R.string.legal_title);
261 | builder.setMessage(Html.fromHtml("You are required to comply with applicable laws.
When using mapping data, directions or other data from GraphHopper / OpenStreetMap, it is possible that the results differ from the actual situation. You should therefore act at your own discretion. Use of GraphHopper / OpenStreetMap is at your own risk. You are responsible for your own behavior and consequences at all times."));
262 | SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
263 | builder.setPositiveButton(R.string.agree, new DialogInterface.OnClickListener() {
264 | public void onClick(DialogInterface dialog, int id) {
265 | SharedPreferences.Editor editor = sharedPreferences.edit();
266 | editor.putInt(getString(R.string.first_navigation_dialog_key), FIRST_NAVIGATION_DIALOG_VERSION);
267 | editor.apply();
268 | launchNavigationWithRoute();
269 | }
270 | });
271 |
272 | AlertDialog dialog = builder.create();
273 | dialog.show();
274 | }
275 |
276 | private void fetchVrpSolution(String jobId, String vehicleId) {
277 | currentJobId = jobId;
278 | currentVehicleId = vehicleId;
279 |
280 | showLoading();
281 | new FetchSolutionTask(this, getString(R.string.gh_key)).execute(new FetchSolutionConfig(currentJobId, currentVehicleId));
282 | }
283 |
284 | @Override
285 | public void onPause() {
286 | super.onPause();
287 | mapView.onPause();
288 | }
289 |
290 | @Override
291 | public void onLowMemory() {
292 | super.onLowMemory();
293 | mapView.onLowMemory();
294 | }
295 |
296 | @Override
297 | protected void onStop() {
298 | super.onStop();
299 | mapView.onStop();
300 | if (locationLayer != null) {
301 | locationLayer.onStop();
302 | }
303 | }
304 |
305 | @Override
306 | protected void onDestroy() {
307 | super.onDestroy();
308 | mapView.onDestroy();
309 | }
310 |
311 | @Override
312 | protected void onSaveInstanceState(Bundle outState) {
313 | super.onSaveInstanceState(outState);
314 | mapView.onSaveInstanceState(outState);
315 | }
316 |
317 | private void clearRoute() {
318 | waypoints.clear();
319 | mapRoute.removeRoute();
320 | route = null;
321 | if (currentMarker != null) {
322 | mapboxMap.removeMarker(currentMarker);
323 | currentMarker = null;
324 | }
325 | }
326 |
327 | private void clearGeocodingResults() {
328 | if (markers != null) {
329 | for (Marker marker : markers) {
330 | this.mapboxMap.removeMarker(marker);
331 | }
332 | markers.clear();
333 | }
334 | }
335 |
336 | @Override
337 | public void onMapReady(MapboxMap mapboxMap) {
338 | this.mapboxMap = mapboxMap;
339 | this.mapboxMap.getUiSettings().setAttributionDialogManager(new GHAttributionDialogManager(this.mapView.getContext(), this.mapboxMap));
340 | this.mapboxMap.addOnMapLongClickListener(this);
341 | initMapRoute();
342 |
343 | this.mapboxMap.setOnInfoWindowClickListener(new MapboxMap.OnInfoWindowClickListener() {
344 | @Override
345 | public boolean onInfoWindowClick(@NonNull Marker marker) {
346 | for (Marker geocodingMarker : markers) {
347 | if (geocodingMarker.getId() == marker.getId()) {
348 | LatLng position = geocodingMarker.getPosition();
349 | addPointToRoute(position.getLatitude(), position.getLongitude());
350 | updateRouteAfterWaypointChange();
351 | marker.hideInfoWindow();
352 | return true;
353 | }
354 | }
355 | return true;
356 | }
357 | });
358 |
359 | // Check for location permission
360 | permissionsManager = new PermissionsManager(this);
361 | if (!PermissionsManager.areLocationPermissionsGranted(this)) {
362 | permissionsManager.requestLocationPermissions(this);
363 | } else {
364 | initLocationLayer();
365 | }
366 |
367 | handleIntent(getIntent());
368 | }
369 |
370 | @Override
371 | public void onMapLongClick(@NonNull LatLng point) {
372 | addPointToRoute(point.getLatitude(), point.getLongitude());
373 | updateRouteAfterWaypointChange();
374 | }
375 |
376 | private void addPointToRoute(double lat, double lng) {
377 | waypoints.add(Point.fromLngLat(lng, lat));
378 | }
379 |
380 | @Override
381 | public void onNewPrimaryRouteSelected(DirectionsRoute directionsRoute) {
382 | route = directionsRoute;
383 | }
384 |
385 | @SuppressWarnings({"MissingPermission"})
386 | private void initLocationLayer() {
387 | locationLayer = new LocationLayerPlugin(mapView, mapboxMap);
388 | locationLayer.setRenderMode(RenderMode.COMPASS);
389 | Location lastKnownLocation = getLastKnownLocation();
390 | if (lastKnownLocation != null) {
391 | // TODO we could think about zoom to the user location later on as well
392 | animateCamera(new LatLng(lastKnownLocation.getLatitude(), lastKnownLocation.getLongitude()));
393 | }
394 | }
395 |
396 | private void initMapRoute() {
397 | mapRoute = new NavigationMapRoute(mapView, mapboxMap);
398 | mapRoute.setOnRouteSelectionChangeListener(this);
399 | }
400 |
401 | private void fetchRoute() {
402 | NavigationRoute.Builder builder = NavigationRoute.builder(this)
403 | .accessToken("pk." + getString(R.string.gh_key))
404 | .baseUrl(getString(R.string.base_url))
405 | .user("gh")
406 | .alternatives(true);
407 |
408 | boolean startFromLocation = getStartFromLocationFromSharedPreferences();
409 |
410 | if (!startFromLocation && waypoints.size() < 2 || startFromLocation && waypoints.size() < 1) {
411 | onError(R.string.error_not_enough_waypoints);
412 | return;
413 | }
414 |
415 | if (startFromLocation) {
416 | Location lastKnownLocation = getLastKnownLocation();
417 | if (lastKnownLocation == null) {
418 | onError(R.string.error_location_not_found);
419 | return;
420 | } else {
421 | Point location = Point.fromLngLat(lastKnownLocation.getLongitude(), lastKnownLocation.getLatitude());
422 | if (lastKnownLocation.hasBearing())
423 | // 90 seems to be the default tolerance of the SDK
424 | builder.origin(location, (double) lastKnownLocation.getBearing(), 90.0);
425 | else
426 | builder.origin(location);
427 | }
428 | }
429 |
430 | for (int i = 0; i < waypoints.size(); i++) {
431 | Point p = waypoints.get(i);
432 | if (i == 0 && !startFromLocation) {
433 | builder.origin(p);
434 | } else if (i < waypoints.size() - 1) {
435 | builder.addWaypoint(p);
436 | } else {
437 | builder.destination(p);
438 | }
439 | }
440 |
441 | showLoading();
442 |
443 | setFieldsFromSharedPreferences(builder);
444 | builder.build().getRoute(new SimplifiedCallback() {
445 | @Override
446 | public void onResponse(Call call, Response response) {
447 | if (validRouteResponse(response)) {
448 | route = response.body().routes().get(0);
449 | mapRoute.addRoutes(response.body().routes());
450 | boundCameraToRoute();
451 | } else {
452 | Snackbar.make(mapView, R.string.error_calculating_route, Snackbar.LENGTH_LONG).show();
453 | }
454 | hideLoading();
455 | }
456 |
457 | @Override
458 | public void onFailure(Call call, Throwable throwable) {
459 | super.onFailure(call, throwable);
460 | Snackbar.make(mapView, R.string.error_calculating_route, Snackbar.LENGTH_LONG).show();
461 | hideLoading();
462 | }
463 | });
464 | }
465 |
466 | @SuppressLint("MissingPermission")
467 | private Location getLastKnownLocation() {
468 | if (locationLayer != null) {
469 | return locationLayer.getLastKnownLocation();
470 | }
471 | return null;
472 | }
473 |
474 | private void updateRouteAfterWaypointChange() {
475 | if (this.waypoints.isEmpty()) {
476 | hideLoading();
477 | } else {
478 | Point lastPoint = this.waypoints.get(this.waypoints.size() - 1);
479 | LatLng latLng = new LatLng(lastPoint.latitude(), lastPoint.longitude());
480 | setCurrentMarkerPosition(latLng);
481 | if (this.waypoints.size() > 0) {
482 | fetchRoute();
483 | } else {
484 | hideLoading();
485 | }
486 | }
487 | }
488 |
489 | private void setFieldsFromSharedPreferences(NavigationRoute.Builder builder) {
490 | builder
491 | .language(getLanguageFromSharedPreferences())
492 | .voiceUnits(getUnitTypeFromSharedPreferences())
493 | .profile(getRouteProfileFromSharedPreferences());
494 | }
495 |
496 | private String getUnitTypeFromSharedPreferences() {
497 | SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
498 | String defaultUnitType = getString(R.string.default_unit_type);
499 | String unitType = sharedPreferences.getString(getString(R.string.unit_type_key), defaultUnitType);
500 | if (unitType.equals(defaultUnitType)) {
501 | unitType = localeUtils.getUnitTypeForDeviceLocale(this);
502 | }
503 |
504 | return unitType;
505 | }
506 |
507 | private Locale getLanguageFromSharedPreferences() {
508 | SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
509 | String defaultLanguage = getString(R.string.default_locale);
510 | String language = sharedPreferences.getString(getString(R.string.language_key), defaultLanguage);
511 | if (language.equals(defaultLanguage)) {
512 | return localeUtils.inferDeviceLocale(this);
513 | } else {
514 | return new Locale(language);
515 | }
516 | }
517 |
518 | private boolean getShouldSimulateRouteFromSharedPreferences() {
519 | SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
520 | return sharedPreferences.getBoolean(getString(R.string.simulate_route_key), false);
521 | }
522 |
523 | private boolean getStartFromLocationFromSharedPreferences() {
524 | SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
525 | return sharedPreferences.getBoolean(getString(R.string.start_from_location_key), true);
526 | }
527 |
528 | private void setStartFromLocationToSharedPreferences(boolean setStartFromLocation) {
529 | SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
530 | SharedPreferences.Editor editor = sharedPreferences.edit();
531 | editor.putBoolean(getString(R.string.start_from_location_key), setStartFromLocation);
532 | editor.apply();
533 | }
534 |
535 | private void setRouteProfileToSharedPreferences(String ghVehicle) {
536 | if (ghVehicle == null)
537 | return;
538 |
539 | SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
540 | SharedPreferences.Editor editor = sharedPreferences.edit();
541 | String routeProfile;
542 | switch (ghVehicle) {
543 | case "foot":
544 | case "hike":
545 | routeProfile = "walking";
546 | break;
547 | case "bike":
548 | case "mtb":
549 | case "racingbike":
550 | routeProfile = "cycling";
551 | break;
552 | default:
553 | routeProfile = "driving";
554 | }
555 | editor.putString(getString(R.string.route_profile_key), routeProfile);
556 | editor.apply();
557 | }
558 |
559 | private String getRouteProfileFromSharedPreferences() {
560 | SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
561 | return sharedPreferences.getString(
562 | getString(R.string.route_profile_key), DirectionsCriteria.PROFILE_DRIVING
563 | );
564 | }
565 |
566 | private void launchNavigationWithRoute() {
567 | if (route == null) {
568 | Snackbar.make(mapView, R.string.error_route_not_available, Snackbar.LENGTH_SHORT).show();
569 | return;
570 | }
571 |
572 | SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
573 | if (sharedPreferences.getInt(getString(R.string.first_navigation_dialog_key), -1) < FIRST_NAVIGATION_DIALOG_VERSION) {
574 | showNavigationDialog();
575 | return;
576 | }
577 |
578 | Location lastKnownLocation = getLastKnownLocation();
579 | if (lastKnownLocation != null && waypoints.size() > 1) {
580 | float[] distance = new float[1];
581 | Location.distanceBetween(lastKnownLocation.getLatitude(), lastKnownLocation.getLongitude(), waypoints.get(0).latitude(), waypoints.get(0).longitude(), distance);
582 |
583 | //Ask the user if he would like to recalculate the route from his current positions
584 | if (distance[0] > 100) {
585 | AlertDialog.Builder builder = new AlertDialog.Builder(this);
586 | builder.setTitle(R.string.error_too_far_from_start_title);
587 | builder.setMessage(R.string.error_too_far_from_start_message);
588 | builder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
589 | public void onClick(DialogInterface dialog, int id) {
590 | waypoints.set(0, Point.fromLngLat(lastKnownLocation.getLongitude(), lastKnownLocation.getLatitude()));
591 | fetchRoute();
592 | }
593 | });
594 | builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
595 | public void onClick(DialogInterface dialog, int id) {
596 | _launchNavigationWithRoute();
597 | }
598 | });
599 |
600 | AlertDialog dialog = builder.create();
601 | dialog.show();
602 | } else {
603 | _launchNavigationWithRoute();
604 | }
605 | } else {
606 | _launchNavigationWithRoute();
607 | }
608 |
609 | }
610 |
611 | private void _launchNavigationWithRoute() {
612 | NavigationLauncherOptions.Builder optionsBuilder = NavigationLauncherOptions.builder()
613 | .shouldSimulateRoute(getShouldSimulateRouteFromSharedPreferences())
614 | .directionsProfile(getRouteProfileFromSharedPreferences())
615 | .waynameChipEnabled(false);
616 |
617 | optionsBuilder.directionsRoute(route);
618 |
619 | NavigationLauncher.startNavigation(this, optionsBuilder.build());
620 | }
621 |
622 | private boolean validRouteResponse(Response response) {
623 | return response.body() != null && !response.body().routes().isEmpty();
624 | }
625 |
626 | private void hideLoading() {
627 | if (loading.getVisibility() == View.VISIBLE) {
628 | loading.setVisibility(View.INVISIBLE);
629 | }
630 | }
631 |
632 | private void showLoading() {
633 | if (loading.getVisibility() == View.INVISIBLE) {
634 | loading.setVisibility(View.VISIBLE);
635 | }
636 | }
637 |
638 | private void boundCameraToRoute() {
639 | if (route != null) {
640 | List routeCoords = LineString.fromPolyline(route.geometry(),
641 | Constants.PRECISION_6).coordinates();
642 | List bboxPoints = new ArrayList<>();
643 | for (Point point : routeCoords) {
644 | bboxPoints.add(new LatLng(point.latitude(), point.longitude()));
645 | }
646 | if (bboxPoints.size() > 1) {
647 | try {
648 | LatLngBounds bounds = new LatLngBounds.Builder().includes(bboxPoints).build();
649 | // left, top, right, bottom
650 | animateCameraBbox(bounds, CAMERA_ANIMATION_DURATION, padding);
651 | } catch (InvalidLatLngBoundsException exception) {
652 | Toast.makeText(this, R.string.error_valid_route_not_found, Toast.LENGTH_SHORT).show();
653 | }
654 | }
655 | }
656 | }
657 |
658 | private void animateCameraBbox(LatLngBounds bounds, int animationTime, int[] padding) {
659 | CameraPosition position = mapboxMap.getCameraForLatLngBounds(bounds, padding);
660 | mapboxMap.animateCamera(CameraUpdateFactory.newCameraPosition(position), animationTime);
661 | }
662 |
663 | private void animateCamera(LatLng point) {
664 | mapboxMap.animateCamera(CameraUpdateFactory.newLatLngZoom(point, DEFAULT_CAMERA_ZOOM), CAMERA_ANIMATION_DURATION);
665 | }
666 |
667 | private void setCurrentMarkerPosition(LatLng position) {
668 | if (position != null) {
669 | if (currentMarker == null) {
670 | MarkerOptions markerOptions = new MarkerOptions()
671 | .position(position);
672 | currentMarker = mapboxMap.addMarker(markerOptions);
673 | } else {
674 | currentMarker.setPosition(position);
675 | }
676 | }
677 | }
678 |
679 | private void updateWaypoints(List points) {
680 | if (points.size() > 24) {
681 | onError(R.string.error_too_many_waypoints);
682 | return;
683 | }
684 | clearRoute();
685 | this.waypoints = points;
686 | updateRouteAfterWaypointChange();
687 | }
688 |
689 | private void showSolutionInputDialog() {
690 | // Create an instance of the dialog fragment and show it
691 | SolutionInputDialog dialog = new SolutionInputDialog();
692 | dialog.setJobId(currentJobId);
693 | dialog.setVehicleId(currentVehicleId);
694 | dialog.show(getFragmentManager(), "gh-example");
695 | }
696 |
697 | private void showGeocodingInputDialog() {
698 | // Create an instance of the dialog fragment and show it
699 | GeocodingInputDialog dialog = new GeocodingInputDialog();
700 | dialog.setGeocodingInput(currentGeocodingInput);
701 | dialog.show(getFragmentManager(), "gh-example");
702 | }
703 |
704 | @Override
705 | public void onDialogPositiveClick(DialogFragment dialog) {
706 | EditText jobId = dialog.getDialog().findViewById(R.id.job_id);
707 | // Check if it's a solution fetch
708 | if (jobId != null) {
709 | EditText vehicleId = dialog.getDialog().findViewById(R.id.vehicle_id);
710 |
711 | fetchVrpSolution(jobId.getText().toString(), vehicleId.getText().toString());
712 | }
713 | // Check if it's a geocoding search
714 | EditText search = dialog.getDialog().findViewById(R.id.geocoding_input_id);
715 | if (search != null) {
716 | currentGeocodingInput = search.getText().toString();
717 |
718 | showLoading();
719 | String point = null;
720 | LatLng pointLatLng = this.mapboxMap.getCameraPosition().target;
721 | if (pointLatLng != null)
722 | point = pointLatLng.getLatitude() + "," + pointLatLng.getLongitude();
723 | new FetchGeocodingTask(this, getString(R.string.gh_key)).execute(new FetchGeocodingConfig(currentGeocodingInput, getLanguageFromSharedPreferences().getLanguage(), 5, false, point, "default"));
724 | }
725 |
726 | }
727 |
728 | @Override
729 | public void onError(int message) {
730 | Snackbar.make(mapView, message, Snackbar.LENGTH_LONG).show();
731 | }
732 |
733 | @Override
734 | public void onPostExecuteGeocodingSearch(List locations) {
735 | clearGeocodingResults();
736 | markers = new ArrayList<>(locations.size());
737 |
738 | if (locations.isEmpty()) {
739 | onError(R.string.error_geocoding_no_location);
740 | return;
741 | }
742 |
743 | List bounds = new ArrayList<>();
744 | Location lastKnownLocation = getLastKnownLocation();
745 | if (lastKnownLocation != null)
746 | bounds.add(new LatLng(lastKnownLocation.getLatitude(), lastKnownLocation.getLongitude()));
747 |
748 | for (GeocodingLocation location : locations) {
749 | GeocodingPoint point = location.getPoint();
750 | MarkerOptions markerOptions = new MarkerOptions();
751 | LatLng latLng = new LatLng(point.getLat(), point.getLng());
752 | markerOptions.position(latLng);
753 | bounds.add(latLng);
754 | markerOptions.title(location.getName());
755 | String snippet = "";
756 | if (location.getStreet() != null) {
757 | snippet += location.getStreet();
758 | if (location.getHousenumber() != null)
759 | snippet += " " + location.getHousenumber();
760 | snippet += "\n";
761 | }
762 | if (location.getCity() != null) {
763 | if (location.getPostcode() != null)
764 | snippet += location.getPostcode() + " ";
765 | snippet += location.getCity() + "\n";
766 | }
767 | if (location.getCountry() != null)
768 | snippet += location.getCountry() + "\n";
769 | if (location.getOsmId() != null) {
770 | snippet += "OSM-Id: " + location.getOsmId() + "\n";
771 | if (location.getOsmKey() != null)
772 | snippet += "OSM-Key: " + location.getOsmKey() + "\n";
773 | if (location.getOsmType() != null)
774 | snippet += "OSM-Type: " + location.getOsmType() + "\n";
775 | }
776 | snippet += "\n\n Tap on info window\n to add point to route";
777 | if (!snippet.isEmpty())
778 | markerOptions.snippet(snippet);
779 | markerOptions.icon(IconFactory.getInstance(this.getApplicationContext()).fromResource(R.drawable.ic_map_marker));
780 | markers.add(mapboxMap.addMarker(markerOptions));
781 | }
782 |
783 | // For bounds we need at least 2 entries
784 | if (bounds.size() >= 2) {
785 | LatLngBounds.Builder boundsBuilder = new LatLngBounds.Builder();
786 | boundsBuilder.includes(bounds);
787 | animateCameraBbox(boundsBuilder.build(), CAMERA_ANIMATION_DURATION, padding);
788 | } else if (bounds.size() == 1) {
789 | // If there is only 1 result (=>current location unknown), we just zoom to that result
790 | animateCamera(bounds.get(0));
791 | }
792 | hideLoading();
793 | }
794 |
795 | @Override
796 | public void onPostExecute(List points) {
797 | if (getStartFromLocationFromSharedPreferences() && !points.isEmpty()) {
798 | // Remove the first point if we want to start from the current location
799 | points.remove(0);
800 | }
801 | updateWaypoints(points);
802 | }
803 |
804 | @Override
805 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
806 | @NonNull int[] grantResults) {
807 | permissionsManager.onRequestPermissionsResult(requestCode, permissions, grantResults);
808 | }
809 |
810 | @Override
811 | public void onExplanationNeeded(List permissionsToExplain) {
812 | Toast.makeText(this, "This app needs location permissions to work properly.",
813 | Toast.LENGTH_LONG).show();
814 | }
815 |
816 | @Override
817 | public void onPermissionResult(boolean granted) {
818 | if (granted) {
819 | initLocationLayer();
820 | } else {
821 | Toast.makeText(this, "You didn't grant location permissions.",
822 | Toast.LENGTH_LONG).show();
823 | }
824 | }
825 | }
826 |
--------------------------------------------------------------------------------
/app/src/main/java/com/graphhopper/navigation/example/NavigationViewSettingsActivity.java:
--------------------------------------------------------------------------------
1 | package com.graphhopper.navigation.example;
2 |
3 |
4 | import android.content.Intent;
5 | import android.content.SharedPreferences;
6 | import android.os.Bundle;
7 | import android.preference.PreferenceActivity;
8 | import android.preference.PreferenceFragment;
9 | import android.preference.PreferenceManager;
10 |
11 | public class NavigationViewSettingsActivity extends PreferenceActivity {
12 | private SharedPreferences.OnSharedPreferenceChangeListener listener;
13 | static final String UNIT_TYPE_CHANGED = "unit_type_changed";
14 | static final String LANGUAGE_CHANGED = "language_changed";
15 | static final String PROFILE_CHANGED = "profile_changed";
16 |
17 | @Override
18 | public void onCreate(Bundle savedInstanceState) {
19 | super.onCreate(savedInstanceState);
20 | listener = (sharedPreferences, key) -> {
21 | Intent resultIntent = new Intent();
22 | resultIntent.putExtra(UNIT_TYPE_CHANGED, key.equals(getString(R.string.unit_type_key)));
23 | resultIntent.putExtra(LANGUAGE_CHANGED, key.equals(getString(R.string.language_key)));
24 | resultIntent.putExtra(PROFILE_CHANGED, key.equals(getString(R.string.route_profile_key)));
25 | setResult(RESULT_OK, resultIntent);
26 | };
27 | PreferenceManager.getDefaultSharedPreferences(this).registerOnSharedPreferenceChangeListener(listener);
28 | getFragmentManager().beginTransaction().replace(
29 | android.R.id.content, new NavigationViewPreferenceFragment()).commit();
30 | }
31 |
32 | @Override
33 | protected boolean isValidFragment(String fragmentName) {
34 | return super.isValidFragment(fragmentName);
35 | }
36 |
37 | public static class NavigationViewPreferenceFragment extends PreferenceFragment {
38 | @Override
39 | public void onCreate(final Bundle savedInstanceState) {
40 | super.onCreate(savedInstanceState);
41 | addPreferencesFromResource(R.xml.fragment_navigation_view_preferences);
42 | PreferenceManager.setDefaultValues(getActivity(), R.xml.fragment_navigation_view_preferences, false);
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/app/src/main/java/com/graphhopper/navigation/example/SimplifiedCallback.java:
--------------------------------------------------------------------------------
1 | package com.graphhopper.navigation.example;
2 |
3 | import com.mapbox.api.directions.v5.models.DirectionsResponse;
4 |
5 | import retrofit2.Call;
6 | import retrofit2.Callback;
7 | import timber.log.Timber;
8 |
9 | /**
10 | * Helper class to reduce redundant logging code when no other action is taken in onFailure
11 | */
12 | public abstract class SimplifiedCallback implements Callback {
13 | @Override
14 | public void onFailure(Call call, Throwable throwable) {
15 | Timber.e(throwable, throwable.getMessage());
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/app/src/main/java/com/graphhopper/navigation/example/SolutionInputDialog.java:
--------------------------------------------------------------------------------
1 | package com.graphhopper.navigation.example;
2 |
3 | import android.app.Activity;
4 | import android.app.AlertDialog;
5 | import android.app.Dialog;
6 | import android.app.DialogFragment;
7 | import android.content.DialogInterface;
8 | import android.os.Bundle;
9 | import android.view.LayoutInflater;
10 | import android.view.View;
11 | import android.widget.EditText;
12 |
13 | public class SolutionInputDialog extends DialogFragment {
14 |
15 | private String jobId = "";
16 | private String vehicleId = "";
17 |
18 | public void setVehicleId(String vehicleId) {
19 | this.vehicleId = vehicleId;
20 | }
21 |
22 | public void setJobId(String jobId) {
23 | this.jobId = jobId;
24 | }
25 |
26 | public interface NoticeDialogListener {
27 | public void onDialogPositiveClick(DialogFragment dialog);
28 | }
29 |
30 | NoticeDialogListener mListener;
31 |
32 | @Override
33 | public void onAttach(Activity activity) {
34 | super.onAttach(activity);
35 | // Verify that the host activity implements the callback interface
36 | try {
37 | // Instantiate the NoticeDialogListener so we can send events to the host
38 | mListener = (NoticeDialogListener) activity;
39 | } catch (ClassCastException e) {
40 | // The activity doesn't implement the interface, throw exception
41 | throw new ClassCastException(activity.toString()
42 | + " must implement NoticeDialogListener");
43 | }
44 | }
45 |
46 | @Override
47 | public Dialog onCreateDialog(Bundle savedInstanceState) {
48 | AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
49 | // Get the layout inflater
50 | LayoutInflater inflater = getActivity().getLayoutInflater();
51 |
52 | View modifiedView = inflater.inflate(R.layout.solution_input, null);
53 | if (!jobId.isEmpty()) {
54 | EditText jobIdEditText = (EditText) modifiedView.findViewById(R.id.job_id);
55 | jobIdEditText.setText(jobId);
56 | }
57 | if (!vehicleId.isEmpty()) {
58 | EditText vehicleIdEditText = (EditText) modifiedView.findViewById(R.id.vehicle_id);
59 | vehicleIdEditText.setText(vehicleId);
60 | }
61 |
62 |
63 | // Inflate and set the layout for the dialog
64 | // Pass null as the parent view because its going in the dialog layout
65 | builder.setView(modifiedView)
66 | // Add action buttons
67 | .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
68 | @Override
69 | public void onClick(DialogInterface dialog, int id) {
70 | mListener.onDialogPositiveClick(SolutionInputDialog.this);
71 | }
72 | })
73 | .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
74 | public void onClick(DialogInterface dialog, int id) {
75 | SolutionInputDialog.this.getDialog().cancel();
76 | }
77 | });
78 |
79 | return builder.create();
80 | }
81 |
82 | }
83 |
84 |
85 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_map_marker.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example-legacy/25fd91368a4c3b507eed0e9f323f6b818f0ddc46/app/src/main/res/drawable-hdpi/ic_map_marker.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_map_marker.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example-legacy/25fd91368a4c3b507eed0e9f323f6b818f0ddc46/app/src/main/res/drawable-mdpi/ic_map_marker.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_map_marker.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example-legacy/25fd91368a4c3b507eed0e9f323f6b818f0ddc46/app/src/main/res/drawable-xhdpi/ic_map_marker.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_map_marker.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example-legacy/25fd91368a4c3b507eed0e9f323f6b818f0ddc46/app/src/main/res/drawable-xxhdpi/ic_map_marker.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/ic_map_marker.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example-legacy/25fd91368a4c3b507eed0e9f323f6b818f0ddc46/app/src/main/res/drawable-xxxhdpi/ic_map_marker.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_cancel_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_cloud_download_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_help_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_navigation_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_search_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_settings_applications_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_navigation_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
15 |
16 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/attribution_list_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/geocoding_input.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
13 |
14 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/solution_input.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
13 |
14 |
24 |
25 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/navigation_view_activity_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example-legacy/25fd91368a4c3b507eed0e9f323f6b818f0ddc46/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example-legacy/25fd91368a4c3b507eed0e9f323f6b818f0ddc46/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example-legacy/25fd91368a4c3b507eed0e9f323f6b818f0ddc46/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example-legacy/25fd91368a4c3b507eed0e9f323f6b818f0ddc46/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example-legacy/25fd91368a4c3b507eed0e9f323f6b818f0ddc46/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example-legacy/25fd91368a4c3b507eed0e9f323f6b818f0ddc46/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example-legacy/25fd91368a4c3b507eed0e9f323f6b818f0ddc46/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example-legacy/25fd91368a4c3b507eed0e9f323f6b818f0ddc46/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example-legacy/25fd91368a4c3b507eed0e9f323f6b818f0ddc46/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example-legacy/25fd91368a4c3b507eed0e9f323f6b818f0ddc46/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example-legacy/25fd91368a4c3b507eed0e9f323f6b818f0ddc46/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example-legacy/25fd91368a4c3b507eed0e9f323f6b818f0ddc46/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example-legacy/25fd91368a4c3b507eed0e9f323f6b818f0ddc46/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example-legacy/25fd91368a4c3b507eed0e9f323f6b818f0ddc46/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example-legacy/25fd91368a4c3b507eed0e9f323f6b818f0ddc46/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/.gitignore:
--------------------------------------------------------------------------------
1 | developer-config.xml
2 |
--------------------------------------------------------------------------------
/app/src/main/res/values/arrays.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | - Default for Device
6 | - English
7 | - French
8 | - German
9 | - Indonesian
10 |
11 |
12 |
13 | - @string/default_locale
14 | - en
15 | - fr
16 | - de
17 | - in
18 |
19 |
20 |
21 | - Default for Device
22 | - Metric
23 | - Imperial
24 |
25 |
26 |
27 | - @string/default_unit_type
28 | - metric
29 | - imperial
30 |
31 |
32 |
33 | - Driving
34 | - Cycling
35 | - MTB
36 | - Racing bike
37 | - Walking
38 | - Hike
39 | - Scooter
40 | - Small truck
41 | - Truck
42 |
43 |
44 |
45 | - driving
46 | - cycling
47 | - mtb
48 | - racingbike
49 | - walking
50 | - hike
51 | - scooter
52 | - small_truck
53 | - truck
54 |
55 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #2F2F2F
4 | #2F2F2F
5 | #00f148
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/developer-config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | pk.test
5 |
6 | [GH_API_KEY]
7 |
8 | https://graphhopper.com/api/1/navigate/
9 |
10 |
11 |
12 | https://tiles.mapilion.com/assets/osm-bright/style.json?key=[MAP_API_KEY]
13 |
14 | https://tiles.mapilion.com/assets/osm-bright/style.json?key=[MAP_API__KEY]
15 |
16 | https://tiles.mapilion.com/assets/osm-bright/style.json?key=[MAP_API_KEY]
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/values/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #00F148
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | GraphHopper Demo
3 |
4 | Settings
5 | Help
6 | Simulate Route
7 | Start route from current location
8 | Language
9 | Unit Type
10 | Route Profile
11 |
12 | JobId
13 | VehicleId
14 | Search…
15 | OK
16 | Cancel
17 |
18 | unit_type
19 | simulate_route
20 | start_from_location
21 | language
22 | route_profile
23 | first_start_dialog
24 | first_navigation_dialog
25 | default_for_device
26 | default_for_device
27 | current_night_mode
28 |
29 | Current route is not available
30 | Please select a longer route
31 | Valid route not found.
32 | There was an error calculating the route
33 | There was an error fetching the solution
34 | There was an error fetching results from the geocoding API
35 | Vehicle not found
36 | Location not found
37 | No location found
38 | A route cannot have more than 25 waypoints
39 | A route needs at least 2 waypoints
40 | No browser installed
41 | Too far from start
42 | Would you like to recalculate the route from your current location?
43 | Long press map to place waypoint
44 | Launch Navigation
45 | Reset Route
46 | Fetch Solution
47 | Search
48 | Getting Started
49 | Legal Notice
50 | I agree
51 | Contribute on Github
52 |
53 | Open Route from GH Maps
54 | Open VRP Solution
55 |
56 |
57 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/fragment_navigation_view_preferences.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
9 |
13 |
19 |
25 |
30 |
--------------------------------------------------------------------------------
/app/src/test/java/com/graphhopper/navigation/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.graphhopper.navigation;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 |
5 | repositories {
6 | google()
7 | jcenter()
8 | mavenCentral()
9 | }
10 | dependencies {
11 | classpath 'com.android.tools.build:gradle:3.3.0'
12 |
13 | // NOTE: Do not place your application dependencies here; they belong
14 | // in the individual module build.gradle files
15 | }
16 | }
17 |
18 | allprojects {
19 | repositories {
20 | google()
21 | jcenter()
22 | maven { url "https://oss.sonatype.org/content/repositories/snapshots" }
23 | }
24 | }
25 |
26 | task clean(type: Delete) {
27 | delete rootProject.buildDir
28 | }
29 |
--------------------------------------------------------------------------------
/files/gh-nav1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example-legacy/25fd91368a4c3b507eed0e9f323f6b818f0ddc46/files/gh-nav1.png
--------------------------------------------------------------------------------
/files/gh-nav2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example-legacy/25fd91368a4c3b507eed0e9f323f6b818f0ddc46/files/gh-nav2.png
--------------------------------------------------------------------------------
/files/gh-nav3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example-legacy/25fd91368a4c3b507eed0e9f323f6b818f0ddc46/files/gh-nav3.png
--------------------------------------------------------------------------------
/files/graphhopper-navigation-example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example-legacy/25fd91368a4c3b507eed0e9f323f6b818f0ddc46/files/graphhopper-navigation-example.png
--------------------------------------------------------------------------------
/files/graphhopper-navigation-example.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example-legacy/25fd91368a4c3b507eed0e9f323f6b818f0ddc46/files/graphhopper-navigation-example.xcf
--------------------------------------------------------------------------------
/files/graphhopper.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example-legacy/25fd91368a4c3b507eed0e9f323f6b818f0ddc46/files/graphhopper.png
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx1536m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example-legacy/25fd91368a4c3b507eed0e9f323f6b818f0ddc46/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Nov 14 11:23:19 CET 2018
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------