Is it possible using custom OSRM server (Docker) for routing in navigation SDK? If i have custom streets in postgrey db, how can i calculate route on this streets?
Something as
NavigationRoute.builder(this)
.baseUrl("my server url")
does make request to my server but with additional params in query which i dont want :
/route/v1/driving/directions/v5/mapbox/driving-traffic/
I need just
/route/v1/driving/
Is it possible or exist some lib which converts osrm format to mapbox format?
I've found that it's reasonably trivial to use OSRM as a backing server for the Graphhopper Navigation API (which was forked from Mapbox I believe). I haven't tried using it directly with the Mapbox SDKs, but it might be worth a shot. Basically all I had to do was start up a forwarding server that would grab the coordinates and route parameters and pass them to OSRM, then add a request UUID on the way back to stop the SDK from complaining. I implemented the server in Ruby using Sinatra, and the code is below:
require 'net/http'
require 'sinatra'
require 'sinatra/json'
get '/directions/v5/:user/driving/:coordinates' do
uri = URI("http://router.project-osrm.org/route/v1/driving/#{params['coordinates']}")
uri.query = URI.encode_www_form({
alternatives: params['alternatives'],
continue_straight: params['continue_straight'],
geometries: params['geometries'],
overview: params['overview'],
steps: params['steps']
})
res = JSON.parse(Net::HTTP.get_response(uri).body)
res["uuid"] = SecureRandom.uuid
json(res)
end
Related
I am creating an android app to record a user's activity using Google Maps SDK and the Google Play Services Location API. I am attempting to retrieve the user's elevation based on a given latitude and longitude. I originally used Location#getAltitude() but then realised that does not give the elevation above sea level.
I proceeded to use the open elevation API using the following query string:
String url = "https://api.open-elevation.com/api/v1/lookup?locations=" + latLng.latitude + "," + latLng.longitude;
However, that API appears to be much too slow in generating a response. I then found the Google Maps Elevation API which we can make a request using a URL also. However, we need to pass an API key and I do not want to pass this API key in the URL string and end up committing it to the remote repository.
In this repo (https://github.com/googlemaps/google-maps-services-java) I found the class:
/src/main/java/com/google/maps/ElevationApi.java which I thought I could use to avoid messing around with http requests.
In my gradle, I included this dependency:
implementation 'com.google.maps:google-maps-services:0.18.0'
At the moment, the code to retrieve the elevation is as follows:
ElevationApi.getByPoint(new GeoApiContext.Builder().apiKey(API_KEY).build(), latLng)
.setCallback(new PendingResult.Callback<ElevationResult>() {
#Override
public void onResult(ElevationResult result) {
consumer.doAction(result.elevation);
}
#Override
public void onFailure(Throwable e) {
e.printStackTrace();
}
});
What do I pass in for API_KEY here since I don't want to commit it to the repository? I have an api key defined in local.properties for maps, however, like so:
MAPS_API_KEY=<API_KEY_HERE>
Basically, my question is, can I define an API key in a properties file that is not committed to GitHub and then reference it in the code?
Thanks for any help.
Update:
I have managed to read the API key from local.properties using gradle but got an exception from the ElevationApi saying API 21+ expected, but was 30...strange. So I went back to the open-elevation API with the following Volley request:
/**
* Calculates elevation gain for the provided recording service
* #param recordingService the recording service to calculate elevation gain for
* #param response the handler to consume the elevation gain with
*/
public static void calculateElevationGain(RecordingService recordingService, ActionHandlerConsumer<Double> response) {
ArrayList<Location> locations = recordingService.getLocations();
JSONArray array = constructLocations(locations);
try {
if (array != null) {
RequestQueue requestQueue = Volley.newRequestQueue(recordingService);
String url = "https://api.open-elevation.com/api/v1/lookup";
JSONObject requestHeader = new JSONObject(); // TODO this seems very slow
requestHeader.put("locations", array);
JsonObjectRequest request = new JsonObjectRequest(Request.Method.POST, url, requestHeader,
response1 -> handleSuccessfulResponse(response1, response), RecordingUtils::handleErrorResponse);
request.setRetryPolicy(new DefaultRetryPolicy(500000, DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
requestQueue.add(request);
}
} catch (JSONException ex) {
ex.printStackTrace();
}
}
I had to set the timeout to a high number not sure how hight it should be because I was getting Volley timeout errors due to the slow response times.
Are there any other ways I can retrieve elevation about sea level?
Yeah, open-elevation.com has intermittent issues with timeouts and latency.
There are some alternatives listed on this GIS stack exchange question Seeking alternative to Google Maps Elevation API. I'm the developer of Open Topo Data which is the most-voted answer over there. You can host your own server with docker, and I also have a free public API which has pretty good latency and uptime.
There's also GPXZ as an alternative to the Google Elevation API with higher-quality data, but it requires an API key so would have the same issue as with Google Maps.
I advise a different direction: stay with the Google and the API key, but employ best practices regarding secrets and source repositories. Since you are dealing with an Android app and not a webapp your key can be somewhat safe inside your app binary (versus a key in a web deployed app is exposed).
Bets practices:
Do not commit the API key. The best to achieve this is to exclude the file which contains the key from the source control repo. That can simply be done with .gitignore. For example this Codelab has a file with the secret, but it has a dummy value and normally this file should be excluded from the source. It is only there because that is an educational code lab.
As a security measure take advantage of GitGuardian to scan your repos in case you'd accidentally push an API key. In such events you'd get a notification. As for me I forked that Geospatial API codelab and saw the key file was in the gitignore and I accidentally pushed a key.
In case you accidentally push a key in a commit it's not enough to reverse the commit and delete the file! Scavenger bots will still find the information in your git history. Rather immediately disable the key and generate another one.
If you are dealing with a webapp you can restrict the API key usage to your webapp's domain. Similarly you can restrict the key to specific Android app signatures (don't forget to add your developer environment's signature) too. This guarantees that even if someone steals the key they probably won't be able to use it.
I used StartApplicationRequest to create a sample request to start the application as given below:
StartApplicationRequest request = StartApplicationRequest.builder()
.applicationId("test-app-name")
.build();
Then, I used the ReactorCloudFoundryClient to start the application as shown below:
cloudFoundryClient.applicationsV3().start(request);
But my test application test-app-name is not getting started. I'm using latest Java CF client version (v4.5.0 RELEASE), but not seeing a way around to start the application.
Quite surprisingly, the outdated version seems to be working with the below code:
cfstatus = cfClient.startApplication("test-app-name"); //start app
cfstatus = cfClient.stopApplication("test-app-name"); //stop app
cfstatus = cfClient.restartApplication("test-app-name"); //stop app
I want to do the same with latest CF client library, but I don't see any useful reference. I referred to test cases written at CloudFoundry official Github repo. I derived to the below code after checking out a lot of docs:
StartApplicationRequest request = StartApplicationRequest.builder()
.applicationId("test-app-name")
.build();
cloudFoundryClient.applicationsV3().start(request);
Note that cloudFoundryClient is ReactorCloudFoundryClient instance as the latest library doesn't support the client class used with outdated code. I would like to do all operations (start/stop/restart) with latest library. The above code isn't working.
A couple things here...
Using the reactor based client, your call to cloudFoundryClient.applicationsV3().start(request) returns a Mono<StartApplicationResponse>. That's not the actual response, it's the possibility of one. You need to do something to get the response. See here for more details.
If you would like similar behavior to the original cf-java-client, you can call .block() on the Mono<StartApplicationResponse> and it will wait and turn into a response.
Ex:
client.applicationsV3()
.start(StartApplicationRequest.builder()
.applicationId("test-app-name")
.build())
.block()
The second thing is that it's .applicationId not applicationName. You need to pass in an application guid, not the name. As it is, you're going to get a 404 saying the application doesn't exist. You can use the client to fetch the guid, or you can use CloudFoundryOperations instead (see #3).
The CloudFoundryOperations interface is a higher-level API. It's easier to use, in general, and supports things like starting an app based on the name instead of the guid.
Ex:
ops.applications()
.start(StartApplicationRequest.builder()
.name("test-app-name").build())
.block();
I'm using Spark Java to create a simple API.
Furthermore I've been using spark-authentication for basic authentication.
webSocket(ROUTE_WS, GarageWebsocket.class);
get(ROUTE_GARAGE_DOOR_STATE, GarageDoorController::getGarageDoorState);
put(ROUTE_GARAGE_DOOR_COMMAND_OPEN, GarageDoorController::openGarageDoor);
put(ROUTE_GARAGE_DOOR_COMMAND_CLOSE, GarageDoorController::closeGarageDoor);
put(ROUTE_GARAGE_DOOR_COMMAND_TOGGLE, GarageDoorController::toggleGarageDoor);
put(ROUTE_GARAGE_DOOR_COMMAND_STOP, GarageDoorController::stopGarageDoor);
before(new BasicAuthenticationFilter("/garage/*", new AuthenticationDetails(USERNAME, PASSWORD)));
The problem seems to be, that the before filter also applies to the websocket route.
Which is /ws.
The PUT routes starts with /garage/....
Any ideas?
I am developing an Android app which takes the current location of the user and displays a list of restaurants close to his/her location. The restaurants' data is available to me (i.e I do have the lat/long of each restaurant I want to display in the search results). I can't use Google Places API, because I need to show only those restaurants that are available in our database(in our website). My question is how do I access my database(or even an URL),which is on a computer, to extract the restaurants' data and display as search results in my android app?
I am actually making a Seamless ( http://bit.ly/Jp7pUN ) type application for my company.
I am a complete newbie to android app development. So, pardon me if this is really a very broad or a stupid question. Please just tell me what topics I need to study to implement this. I would study and do it myself.
Thanks.
You will need:
a Sqlite database to store the restaurants and their longitude/latitude
a MapView to display the map (Don't forget to register your Google Maps API key)
a map overlay to show the markers on the map
GPS access to get the user's location (needs the appropriate Android permission)
a simple search algorithm that retrieves a result set of restaurants within x distance of the user's location
EDIT
If your database is stored on a server, you will need a way to query the server, preferably using an HTTP-based protocol such as REST. It is useful (but not required) to cache the restaurant locations on the Android device (using Sqlite), in case the user is offline (The good news: Since you can use Java both on Android and the server, 90% of your data access layer you will only need to write once).
For the data transfer from server to the Android client, JSON is a popular format.
To acces database on your computer (not SQLite on Android) you should use url for your database server changing localhost to: 10.0.2.2. But in case your database will be on the Internet - you should create maybe some REST API to get the data you need. Then use HttpClient to fetch the data from server.
Everything that you need is in Developer Guide: MapView
And for retrieving current location I advice using MyLocationOverlay
For example (url to server):
//public static final String SERVER_ADDRESS = "http://10.0.2.2:3000"; // for localhost server
public static final String SERVER_ADDRESS = "http://railsserver.herokuapp.com"; //for remote server
Accessing data on your server - this depends on that how you implement (and using what thechnology) your server (REST API?, WebService?, Plain HTML?) and what will be the format of the response from server (JSON? XML?, etc.)
I suggest using JSON because it is easy to parse using included classes in Android SDK:
String json = execute(new HttpGet(Constants.SERVER_URL + "/fetchData"));
JSONObject responseJSON = new JSONObject(json);
if(responseJSON.has("auth_error")) {
throw new IOException("fetchData_error");
}
Greetings,
I am creating a Java based server to create push notifications for Apple's iOS APNs service. I have found Javapns on google code which seems to provide a simple basic framework to communicate with APNs, and which seems to be fairly wide used.
http://code.google.com/p/javapns/
However, reading Apple's docs, there is an "enhanced format" for notifications which supports "expiry" i.e. setting a time (well, in seconds) for a notification to expire if it hasn't yet been delivered. I do not see any way to set this using Javapns, and I am unsure how the APNs service handles expiry of notifications if you do not explicitly set it. So,
Does anyone know how to support the enhanced notification format of APNs specifically how to set the expiry?
Does anyone know how Apple handles notification expiry if it isn't explicitly set?
Does anyone have any suggestions that don't require me to start from scratch, as the server is currently functional as is?
Thanks in advance.
Andrew
I have recently made substantial contributions to the JavaPNS project, which lead to the release of JavaPNS 2.0 a few days ago. That version provides full support for the enhanced notification format, including the ability to set your own expiry.
Sylvain
Nice that you found the java library... to bad you didn't read the docs there.
I'll post some of the highlights below:
The existing code uses the 'Simple notification format' which does not return an error EVER.
See docs at:
http://developer.apple.com/library/ios/#documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CommunicatingWIthAPS/CommunicatingWIthAPS.html
I've tried updating to the 'Enhanced notification format' which is supposed to return an error, but I'm unable to get any errors back from the APNS. (also in the link above)
With the Enhanced format, the connection isn't being dropped immediately after sending data, but I'm not getting anything back from my socket.getInputSocket.read() call.
This issue will have to be tabled until I have more time to troubleshoot.
(Someone else commented)
Thanks a lot for looking into it.
I got the same result as yours. Maybe it has something to do with Apple Gateway.
So... you could:
1) Build your own
2) Help improve the existing library
3) Try another library like: https://github.com/notnoop/java-apns
4) Do nothing
Enhanced ios push here.
To send a notification, you can do it in three steps:
Setup the connection
ApnsService service =
APNS.newService()
.withCert("/path/to/certificate.p12", "MyCertPassword")
.withSandboxDestination()
.build();
Create and send the message
String payload = APNS.newPayload().alertBody("Can't be simpler than this!").build();
String token = "fedfbcfb....";
service.push(token, payload);
To query the feedback service for inactive devices:
Map<String, Date> inactiveDevices = service.getInactiveDevices();
for (String deviceToken : inactiveDevices.keySet()) {
Date inactiveAsOf = inactiveDevices.get(deviceToken);
...
}