My app is currently using Maps by Google Play Services
speficying:
mMap.setMyLocationEnabled(true);
I realize each time I am displaying the map in my app:
However, I can see there are apps that use Maps and still show the location blue dot, but the location icon doesn't appear in top bar and their battery usage is low.
My app currently grants both permissions:
android.permission.ACCESS_COARSE_LOCATION
android.permission.ACCESS_FINE_LOCATION
My question is:
how can I show the location blue dot with low battery usage?
is it possible to specify the accuracy/battery usage by code?
UPDATE
Actually I realized that the way to do it is to use the GoogleApiClient
's FusedLocationApi
mGoogleApiClient = new GoogleApiClient.Builder(context)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
I have configured the GoogleApiClient inside my Activity, calling:
GoogleApiClient.connect()
on the Activity's startGoogleApiClient.disconnect()
on the Activity's stopon the onConnected
callback I set the criteria for the location updates: fastest interval of 1 minute with low power priority:
private static final LocationRequest REQUEST = LocationRequest.create()
.setFastestInterval(60000) // in milliseconds
.setInterval(180000) // in milliseconds
.setPriority(LocationRequest.PRIORITY_LOW_POWER);
@Override
public void onConnected(Bundle bundle) {
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient,
REQUEST,
this); // LocationListener
}
I have tested that the GoogleApiClient connects correctly at start, but for some reasons whenever I visit the fragment with the embedded MapView, I still get the high battery use for my app on the Settings/Location screen!
It seems the MapView is ignoring these low power criterias!
FINALLY FOUND THE SOLUTION!!! thanks to Tristan for his answer!
By default, GoogleMap uses its on location provider, which is not the Fused Location Provider. In order to use the Fused Location Provider (which allows you to control the location accuracy and power consumption) you need to explicitely set the map location source with GoogleMap.setLocationSource()
(documentation)
I am reporting here a sample activity to do that:
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks;
import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.GoogleMap.OnMyLocationButtonClickListener;
import com.google.android.gms.maps.LocationSource;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import android.location.Location;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends FragmentActivity
implements
ConnectionCallbacks,
OnConnectionFailedListener,
LocationSource,
LocationListener,
OnMyLocationButtonClickListener,
OnMapReadyCallback {
private GoogleApiClient mGoogleApiClient;
private TextView mMessageView;
private OnLocationChangedListener mMapLocationListener = null;
// location accuracy settings
private static final LocationRequest REQUEST = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mMessageView = (TextView) findViewById(R.id.message_text);
SupportMapFragment mapFragment =
(SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
}
@Override
protected void onResume() {
super.onResume();
mGoogleApiClient.connect();
}
@Override
public void onPause() {
super.onPause();
mGoogleApiClient.disconnect();
}
@Override
public void onMapReady(GoogleMap map) {
map.setLocationSource(this);
map.setMyLocationEnabled(true);
map.setOnMyLocationButtonClickListener(this);
}
public void showMyLocation(View view) {
if (mGoogleApiClient.isConnected()) {
String msg = "Location = "
+ LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show();
}
}
/**
* Implementation of {@link LocationListener}.
*/
@Override
public void onLocationChanged(Location location) {
mMessageView.setText("Location = " + location);
if (mMapLocationListener != null) {
mMapLocationListener.onLocationChanged(location);
}
}
@Override
public void onConnected(Bundle connectionHint) {
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient,
REQUEST,
this); // LocationListener
}
@Override
public void onConnectionSuspended(int cause) {
// Do nothing
}
@Override
public void onConnectionFailed(ConnectionResult result) {
// Do nothing
}
@Override
public boolean onMyLocationButtonClick() {
Toast.makeText(this, "MyLocation button clicked", Toast.LENGTH_SHORT).show();
// Return false so that we don't consume the event and the default behavior still occurs
// (the camera animates to the user's current position).
return false;
}
@Override
public void activate(OnLocationChangedListener onLocationChangedListener) {
mMapLocationListener = onLocationChangedListener;
}
@Override
public void deactivate() {
mMapLocationListener = null;
}
}