I am trying to get Google Maps to show the user's current location and update every 15 seconds or so. I've implemented the API using the new FusedLocationProviderClient but the camera does not centre on the user location nor does it respond to changes in latitude and longitude.
I have set up the Android Manifest and Gradle dependencies. I know that FusedLocationProviderClient.getLastLocation() is null because there has been no location provided previously. So I've tried implementing LocationCallback and requestLocationUpdates to try update the location but this is not working either.
I had a thought that this whole problem may be due to the Android Virtual Emulator unable to simulate user location although I'm not sure how to work with this.
I am using Nexus 5x API 26 emulator. The code is below.
Thanks
public class ExploreActivity extends FragmentActivity implements OnMapReadyCallback {
private GoogleMap mMap;
FusedLocationProviderClient fusedLocationClient;
LocationRequest locationRequest;
LocationCallback locationCallback;
static final int LOCATION_PERMISSION_REQUEST = 101;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_explore);
if (Build.VERSION.SDK_INT >= 23) {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
Log.i("onCreate", "requesting permission");
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, LOCATION_PERMISSION_REQUEST);
} else {
initMap();
}
}
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
locationRequest = new LocationRequest();
locationRequest.setInterval(15000); //interval between updates
locationRequest.setFastestInterval(5000); //if there is another app updating more often, then simply take that location
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
//setup location call back
locationCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
super.onLocationResult(locationResult);
Log.i("callback", "working");
for (Location location : locationResult.getLocations()) {
LatLng userLocation = new LatLng(location.getLatitude(), location.getLongitude());
Log.i("lat", Double.toString(userLocation.latitude));
Log.i("long", Double.toString(userLocation.longitude));
}
}
};
}
private void initMap() {
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
}
/**
* Manipulates the map once available.
* This callback is triggered when the map is ready to be used.
* This is where we can add markers or lines, add listeners or move the camera. In this case,
* we just add a marker near Sydney, Australia.
* If Google Play services is not installed on the device, the user will be prompted to install
* it inside the SupportMapFragment. This method will only be triggered once the user has
* installed Google Play services and returned to the app.
*/
@Override
public void onMapReady(GoogleMap googleMap) {
Toast.makeText(this, "Map is ready", Toast.LENGTH_SHORT).show();
mMap = googleMap;
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
Log.i("onMapReady", "permission has been granted");
mMap.setMyLocationEnabled(true);
fusedLocationClient.getLastLocation().addOnSuccessListener(new OnSuccessListener<Location>() {
@Override
public void onSuccess(Location location) {
if (location != null) {
Log.i("onSuccess", "success");
LatLng userLocation = new LatLng(location.getLatitude(), location.getLongitude());
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(userLocation, 13));
} else {
Log.i("onSuccess", "failed");
//location is null possibly due last location not being initialized
}
}
});
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
case LOCATION_PERMISSION_REQUEST:
if (grantResults.length > 0) {
for (int i = 0; i < grantResults.length; i++) {
if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "This app requires location permissions for the map to show!", Toast.LENGTH_SHORT).show();
return;
}
}
initMap();
} else {
Toast.makeText(this, "This app requires location permissions for the map to show!", Toast.LENGTH_SHORT).show();
}
}
}
//run after onCreate method
@Override
protected void onResume() {
super.onResume();
startLocationUpdates();
}
@Override
protected void onPause() {
super.onPause();
stopLocationUpdate();
}
private void stopLocationUpdate() {
fusedLocationClient.removeLocationUpdates(locationCallback);
}
private void startLocationUpdates() {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, null);
Log.i("startLocationUpdates", "started");
//looper at null ensures it calls on this thread
} else{
//request permissions again (for safety)
if (Build.VERSION.SDK_INT >= 23) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1);
}
}
}
}