DirectionResult has null routes and waypoints - Google Directions API - android

My goal for this program was to poll the Google Directions API and plot the course by Polyline on a MapView in an Android app.
However, when I get the DirectionsResult back from the API call, trying to access directionsResult.routes[0] or directionsResult.geocodedWaypoints[0] results in a NullPointerException.
I am currently importing the following libraries using maven repositories (excerpt from my build.gradle):
compile 'com.android.support:appcompat-v7:23.1.1'
compile 'com.google.http-client:google-http-client-android:1.21.0'
compile 'com.google.http-client:google-http-client-jackson:1.21.0'
compile 'com.google.http-client:google-http-client-jackson2:1.21.0'
compile 'com.google.http-client:google-http-client-gson:1.21.0'
compile 'com.google.http-client:google-http-client-protobuf:1.21.0'
compile 'com.google.http-client:google-http-client:1.21.0'
compile 'com.google.maps:google-maps-services:0.1.10'
compile 'com.google.android.gms:play-services:8.4.0'
My current code inside an AsyncTask implementation with debugging calls commented out:
#Override
protected synchronized String doInBackground(URL... params)
{
try {
HttpRequestFactory requestFactory = HTTP_TRANSPORT.createRequestFactory(new HttpRequestInitializer() {
#Override
public void initialize(HttpRequest request) throws IOException {
request.setParser(new JsonObjectParser(JSON_FACTORY));
}
});
GenericUrl url = new GenericUrl("http://maps.googleapis.com/maps/api/directions/json");
// to and from are both LatLng's
url.put("origin", from.toUrlValue());
url.put("destination", to.toUrlValue());
url.put("sensor", true);
HttpRequest request = requestFactory.buildGetRequest(url);
//wait(1000);
HttpResponse httpResponse = request.execute();
//Log.i(TAG, httpResponse.parseAsString());
//wait(1000);
DirectionsResult directionsResult = httpResponse.parseAs(DirectionsResult.class);
//wait(1000);
//Log.i(TAG, Integer.toString(httpResponse.getStatusCode()));
//Log.i(TAG, httpResponse.getStatusMessage());
latlngs = directionsResult.routes[0].overviewPolyline.decodePath();
} catch (IOException ioe) {
ioe.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
My Debugging Process:
This is my printed request url:
http://maps.googleapis.com/maps/api/directions/json?origin=40.426870,-86.925083&destination=40.430092,-86.921679&sensor=true
Obviously it is a short but complete call. With elements of legs containing polyline points (which is what I assume I'm after). This JSON is the same as the response I got from reading httpResponse.parseAsString().
Looking at some StackExchange questions, I saw some people suggested waiting for data to be received. I put 1 second delays between all integral parts of request cycle with no results.
None of the other parts of the call were null.
httpResponse.getStatusCode() returned 200.
httpResponse.getStatusMessage() returned OK.
Everything appears normal until I attempt to use DirectionsResult to parse the JSON HttpResponse with:
DirectionsResult directionsResult = HttpResponse.parseAs(DirectionsResult.class);
After which I get a NullPointerException when accessing the two fields of DirectionsResult: routes and geocodedWaypoints.
Has anyone had similar issues with this class? I've been thinking I might submit an issue on the proper google-http-client library GitHub page if this isn't resolved here.

So it turns out that there were two things I was not doing right.
First, I included no API key in the URL, which doesn't explain why I was able to print a correctly formatted JSON response with httpRequest.parseAsString(), but regardless obviously an API key would need to be included for proper billing of my Google Developer account. Another change that needed to be made as a result of this, is changing the URL from 'http' to 'https'.
Second, there seems to be an issue with requesting an Android API key rather than a Server API key. I received this response when using the Android API key:
{
"error_message" : "This IP, site or mobile application is not authorized to use this API key. Request received from IP address 128.210.106.49, with empty referer",
"routes" : [],
"status" : "REQUEST_DENIED"
}
As a solution, when creating an API key, choose the Server option instead of Android.

Related

How does Keycloak with Android work using SAML protocol?

I've successfully created a demo in Android using keycloak openid-connect protocol configuration for SSO. Now I want to do with SAML protocol.
Details I used in openid-connect:
client_id
username
password
grant_type
client_secret
Now, when I changed from openid-connect to SAML inside keycloak dashboard, so client-secreted option got invisible.
So, in android I removed that variable, and also changed in URL from openid-connect to SAML. But getting error that Page not found
I seen lot of example, searched and imported github project as well, but wither I'll get demo with openid-connect or I'll get demo without using keyclaok.
I don't understand what else is required.
BTW, I followed this example for openid-connect and it is working as well: https://github.com/thomasdarimont/android-openid-connect/tree/feature/keycloak-oidc-demo
I'll share a bit code:
protected Boolean doInBackground(String... args) {
String authToken = args[0];
IdTokenResponse response;
showLog("Requesting ID token.");
try {
response = OIDCUtils.requestTokens(Config.tokenServerUrl,
Config.redirectUrl,
Config.clientId,
authToken);
} catch (IOException e) {
Log.e(TAG, "Could not get response.");
e.printStackTrace();
return false;
}
if (isNewAccount) {
createAccount(response);
} else {
setTokens(response);
}
return true;
}
Have a look, and there are really less examples on this things. Don't know why!
SAML is primarily for Browser Based Authentication (including Auth-Requests, Redirects, ...). So that's not really suitable for Android apps.
Do you have a good reason to use SAML and not stick to your (already working) OIDC solution?

What's the best way to do reverse geocoding in Android

I want to do reverse geocoding in Android, and sometimes find the Geocoder is not quite reliable. So I researched to use the google Geocoding API.
I found there are two kinds such API: the client-side geocoding (JavaScript calls to google.maps.Geocoder) and server-side geocoding (HTTP requests to /maps/api/geocode).
Seems client-side geocoding is usually the most appropriate approach as it executes in the browser, so I think it's not suitable for Android. Am I right?
If using the server-side geocoding approach, Android would send the http requests to maps/api/geocode. Then I need to store the api key to the remote server and request it each time when app starts. Is is the best way to do so? Has any one did it this way?
===================================
Another question: should I use the geocoding result combined with google map? Can I just display the result to the end user without showing the map? What rules should I follow?
Google has provided the Geocoder class for handling geocoding and reverse geocoding for android device. You can take a look in this Geocoder class in this article https://developer.android.com/reference/android/location/Geocoder.html
The JavaScript geocoding libraries are not entirely "client-side", they still need to make an RPC to Google to get the geocode results.
You can make HTTP calls to https://maps.googleapis.com/maps/api/geocode from within your Android app easily enough using Volley and then parse the JSON response.
Something like (incomplete example):
Listener<JSONObject> listener = new Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
JSONArray jsonArray = response.getJSONArray("results");
if (jsonArray.length() > 0) {
JSONObject jsonObject = jsonArray.getJSONObject(0);
// Do something...
}
} catch (JSONException e) {
e.printStackTrace();
}
}
};
String url = "http://maps.googleapis.com/maps/api/geocode/json?sensor=true&latlng="
+ lat + "," + lng + "&key=" + API_KEY;
JsonObjectRequest request = new JsonObjectRequest(url, null, listener, errorListener);
mRequestQueue.add(request);

Azure Easy Apis InvokeApi Method is calling GET instead of POST

I am currently working on creating a custom authentication for a Xamarin.Android app using Azure. I have successfully created my API and it is properly returning values when submitting a raw payload using Advanced REST Client.
I am now trying to implement this on Xamarin.Android using Azure's MobileServiceClient SDK and when using the invokeApi method as demonstrated below in my code, I am getting an exception indicating that it is calling GET instead of POST. Is anyone aware of what I might be doing wrong?
ex.Message returns
"Cannot GET /api/register?username=azureAccountTest&password=testingpassword"
public async Task RegisterAsync()
{
Dictionary<string, string> user = new Dictionary<string, string>
{
{ "username", username },
{ "password", password }
};
try
{
CancellationToken ct;
var result = await client.InvokeApiAsync("register", HttpMethod.Post, user, ct);
}
catch(Exception ex)
{
var message = ex.Message;
}
}
According to your description, I tested this issue on my local side and I could retrieve the authenticationToken as follows:
You used the following method for InvokeApiAsync:
public Task<JToken> InvokeApiAsync(string apiName, HttpMethod method, IDictionary<string, string> parameters, CancellationToken cancellationToken = default(CancellationToken));
Note: It summarizes that the Additional data will sent to through the query string.
Per my understanding, you could refer to the following method for sending additional data though the HTTP content as follows:
JObject user = new JObject();
user.Add("username", "bruce");
user.Add("password", "123456");
var result = await App.MobileService.InvokeApiAsync("/.auth/login/custom", HttpMethod.Post, user, ct);
Additionally, you need to specific the mobileAppUri with https endpoint when deploy to azure side. Here is a similar issue, you could refer to here. Moreover, I would recommend you refer to adrian hall's book about Custom Authentication.
UPDATE:
Based on your comment, I checked the custom authentication and found the following note from adrian hall's book about Custom Authentication:
You must turn on Authentication / Authorization in your App Service. Set the Action to take when request is not authenticated to Allow Request (no action) and do not configure any of the supported authentication providers.

How do I get Robospice to treat anything other than a 200 response from Retrofit & OKHttp as an error

I am using Robospice on android with Retrofit and OKHttp. All works great with responses passed back to the activity using the Robospice RequestListener. The problem is that it only returns a failure if the connection times out or another network issue. If a 401 is returned then it is classed as a success but with a null response as it couldn't parse the JSON into our MobileAppSetup POJO.
At the moment I'm having to do null checking on the response but I have no idea what the reason was if it was a server error or a valid 401.
public final class HTTPRequestListener implements RequestListener<MobileAppSetup> {
#Override
public void onRequestFailure(SpiceException spiceException) {
Log.d("", "failure:"+ spiceException);
loginProgress.hide();
}
#Override
public void onRequestSuccess(final MobileAppSetup response) {
Log.d("","success. Data: "+response);
if(response==null)
showDialog("Error logging in", "Please check your username and password and try again.", "");
loginProgress.hide();
postLoginProcess(response);
}
}
I need to pass these errors to the onRequestFailure callback so I can properly handle it. Is there a way to specify error codes that Robospice should treat as an error. I think it involves adding some kind of custom error handler but really can't find a solution at the moment.
This due to the bug in OKHTTP client possible bug!
Problem is When the server answers with a 401 Unauthorized responses,
the Callback object calls its failure() method..
When the server returns with the 401 status, the RetrofitError
response object is null, and the networkError flag is set to true,
making it impossible for the app to check
error.getResponse().getStatus() I believe the error lies on the http
client. When using OkClient I get this error: java.io.IOException:
No authentication challenges found
I suggest you to download new okhttp jar file from square/okhttp run the project again! or try with any other client instead of okhttp.

Mock HttpResponse with Robolectric

Using Robolectric 2.3-SNAPSHOT, I want to test an object that'll execute a request in the background. In order to isolate it, I'm trying to mock the HttpResponse returned, without success after some hours invested.
I've created a project that anyone can clone. Simly run ./gradlew check https://github.com/Maragues/RobolectricDummyProject (git clone https://github.com/Maragues/RobolectricDummyProject.git)
I've tried
Robolectric.setDefaultHttpResponse(200, "my_mocked_word");
MockWebServer (https://code.google.com/p/mockwebserver/)
But the tests fail because they query the real URL
private static final String MOCKED_WORD = "MOCKED";
#Test
public void mockedRequestUsingMockServer() throws Exception {
mMockWebServer.enqueue(new MockResponse().setBody(MOCKED_WORD));
mMockWebServer.play();
Robolectric.getFakeHttpLayer().interceptHttpRequests(false);
Robolectric.getFakeHttpLayer().interceptResponseContent(false);
String result = request.loadDataFromNetwork();
assertEquals(MOCKED_WORD, result);
}
#Test
public void mockedRequestUsingRobolectric() throws Exception {
Robolectric.setDefaultHttpResponse(200, MOCKED_WORD);
String result = request.loadDataFromNetwork();
assertEquals(MOCKED_WORD, result);
}
The code executing the request
public String loadDataFromNetwork() throws Exception {
// With Uri.Builder class we can build our url is a safe manner
Uri.Builder uriBuilder = Uri.parse("http://robospice-sample.appspot.com/reverse").buildUpon();
uriBuilder.appendQueryParameter("word", word);
String url = uriBuilder.build().toString();
HttpURLConnection urlConnection = (HttpURLConnection) new URL(url)
.openConnection();
String result = IOUtils.toString(urlConnection.getInputStream());
urlConnection.disconnect();
return result;
}
Possibly related questions
Can't capture HTTP request with robolectric (I've tried that without success. Perhaps I'm missing something)
Anyone had success mocking HttpRequests with Robolectric? (I'm not using eclipse)
You're disabling Roboelectric's HTTP layer, so you're using the real HTTP layer. This means that there's no clever magic happening under the hood of your test: when you send an HTTP request, it's really going out onto the internet (as you are seeing).
MockWebServer doesn't stop this. It just sets up a web server locally, that your test can connect to.
So to resolve this problem, you need to stop attempting to connect to a real server, and instead, connect to the mock server. To do this, yo need to inject/set the URL in the request.
#Test
public void mockedRequestUsingMockServer() throws Exception {
mMockWebServer = new MockWebServer();
mMockWebServer.play();
mMockWebServer.enqueue(new MockResponse().setResponseCode(200).setBody(MOCKED_WORD));
request.myUrl = mMockWebServer.getUrl("/");
String result = request.loadDataFromNetwork();
assertEquals(MOCKED_WORD, result);
mMockWebServer.shutdown();
}
It turns out that Robolectric's FakeHttpLayer only works with Apache's HttpClient, which is highly discouraged on versions greater than Froyo. Extracted from Robolectric's Google Group
That being said, the usage of HttpUrlConnection will cause you trouble. I'd try to use Android's implementation of HttpClient where possible, since Robolectric intercepts all calls to that library and lets you set up canned responses to your HTTP calls. We're looking at doing the same for HttpUrlConnection, though it's not clear when that'll happen.
Apart from that, a unit test should not need to mock the HTTP layer. My approach was wrong from the beginning.
You can try this(ref:https://github.com/square/okhttp/tree/master/mockwebserver).
// Create a MockWebServer. These are lean enough that you can create a new
// instance for every unit test.
MockWebServer server = new MockWebServer();
// Schedule some responses.
server.enqueue(new MockResponse().setBody("it's all cool"));
// Start the server.
server.play();
// Ask the server for its URL. You'll need this to make HTTP requests.
//Http is my own http executor.
Http.Response response = http.get(server.getUrl("/"));
then, you can compare the response to server.enqueue(new MockResponse().setBody("it's all cool"));
MockWebServer is a part of okhttp https://github.com/square/okhttp/tree/master/mockwebserver. the URLConnectionImpl in android 4.4 have been changed from defaultHttpClient to Okhttp.

Categories

Resources