I have an location-based application which uses Google Maps API. I've signed up for Google Maps V2 API Keys on Google and although my maps render, my app doesn't seem to be communicating with Google in order to find the current location of the device.
Here is my location detection code:
package ...
import android.content.Context;
import android.location.Location;
import android.os.Bundle;
import android.os.Handler;
import com.cleveroad.wikiguide.components.Settings;
import com.cleveroad.wikiguide.components.WikiGuideApplication;
import com.cleveroad.wikiguide.components.events.LocationRetrievedEvent;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationAvailability;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
public class LocationDetector implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener{
public static final int STATUS_UNKNOWN = -1;
public static final int STATUS_SUCCESS = 0;
public static final int STATUS_RETRIEVING_LOCATION = 1;
public static final int STATUS_CUSTOM_LOCATION = 2;
public static final int STATUS_LOCATION_NOT_AVAILABLE = 10;
public static final int STATUS_TIMEOUT_RESPONSE = 11;
public static final int STATUS_INTERNET_FAILED = 12;
private static LocationDetector object;
private GoogleApiClient googleApiClient;
private Location detectedLocation;
private static int status;
private Thread retrieveThread;
public static LocationDetector getInstance(){
if(object == null)
throw new RuntimeException("You must init location detector first");
return object;
}
public static void init(Context context){
object = new LocationDetector(context);
status = STATUS_UNKNOWN;
}
private LocationDetector(Context context) {
this.googleApiClient = new GoogleApiClient.Builder(context)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
googleApiClient.connect();
}
@Override
public void onConnected(Bundle bundle) {
if (Settings.getInstance().getLocationType() == Settings.LocationType.CUSTOM_LOCATION) {
status = STATUS_CUSTOM_LOCATION;
detectedLocation = Settings.getInstance().getCustomLocation();
WikiGuideApplication.BUS.post(new LocationRetrievedEvent(detectedLocation, status));
} else {
if (retrieveThread != null && retrieveThread.getState() == Thread.State.NEW)
retrieveThread.start();
}
}
public int getStatus(){
return status;
}
public void startThreadRetrievingLocation(){
retrieveThread = new Thread(new RetrieveTask());
retrieveThread.setDaemon(true);
if (googleApiClient.isConnected())
retrieveThread.start();
}
public void stopThreadRetrievingLocation(){
if (retrieveThread != null) {
retrieveThread.interrupt();
}
}
private void retrieveLocation() {
status = STATUS_RETRIEVING_LOCATION;
LocationAvailability availability = LocationServices.FusedLocationApi.getLocationAvailability(googleApiClient);
if (availability == null){
WikiGuideApplication.BUS.post(new LocationRetrievedEvent(LocationServices.FusedLocationApi.getLastLocation(googleApiClient), STATUS_TIMEOUT_RESPONSE));
return;
}
if (!availability.isLocationAvailable()){
WikiGuideApplication.BUS.post(new LocationRetrievedEvent(null, STATUS_LOCATION_NOT_AVAILABLE));
return;
}
LocationRequest mLocationRequest = new LocationRequest();
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
LocationServices.FusedLocationApi.requestLocationUpdates(
googleApiClient, mLocationRequest, new com.google.android.gms.location.LocationListener() {
@Override
public void onLocationChanged(final Location location) {
if (status == STATUS_CUSTOM_LOCATION)
return;
status = STATUS_SUCCESS;
detectedLocation = location;
WikiGuideApplication.BUS.post(new LocationRetrievedEvent(location, STATUS_SUCCESS));
}
});
}
public Location getDetectedLocation(){
return detectedLocation;
}
public void setCustomLocation(double latitude, double longitude){
status = STATUS_CUSTOM_LOCATION;
detectedLocation = new Location("");
detectedLocation.setLatitude(latitude);
detectedLocation.setLongitude(longitude);
WikiGuideApplication.BUS.post(new LocationRetrievedEvent(detectedLocation, STATUS_CUSTOM_LOCATION));
stopThreadRetrievingLocation();
}
@Override
public void onConnectionSuspended(int i) {
}
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
WikiGuideApplication.BUS.post(new LocationRetrievedEvent(null, STATUS_INTERNET_FAILED));
}
private class RetrieveTask implements Runnable{
private final int DELAY = 20000;
private Handler handler;
public RetrieveTask() {
handler = new Handler(WikiGuideApplication.getInstance().getMainLooper());
}
@Override
public void run() {
while (true) {
if (Thread.currentThread().isInterrupted()) {
return;
} else {
handler.post(new Runnable() {
@Override
public void run() {
retrieveLocation();
}
});
}
try {
Thread.sleep(DELAY);
} catch (InterruptedException e) {
e.printStackTrace();
return;
}
}
}
}
}
I have the following permissions set up in my AndroidManifest.xml
...
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
...
I just have my key defined in my string.xml file:
<string name="google_map_api_key">AIzaXXXXXXXXXXXXXXXXXXXXXXXXXXXXXsLc</string>
The symptom that I'm seeing is that my map doesn't update/detect the current location. And I'm receiving a Timeout Response from this code.