FusedLocationProviderApi não funciona sem o provedor de localização de rede: use SettingsApi para verificar e definir a configuração do usuário

TL; DR
FusedLocationProviderApi às vezes não funciona, mesmo quando seu usuário acredita que o GPS está ligado
– Você pode usar SettingsApi para verificar a configuração do usuário e ajudá-lo a definir a preferência de local necessária

O Google introduziu FusedLocationProviderApi na biblioteca do Google Play Service no Google I / O 2013 . Ele fornece um serviço de localização melhor e com eficiência de bateria, utilizando localização baseada em GPS e localização baseada em rede.

No entanto, percebi que FusedLocationProviderApi não fornece nenhum local quando a configuração do usuário é como abaixo:

Cenário

Por quê? Porque o usuário apenas permite o acesso à localização no aplicativo, mas não permite o acesso à localização no Google (!)

Parece que na velhice, o Android tem uma preferência separada intitulada Configurações de localização do Google app. No entanto, não o temos mais no meu Android L. O que vejo é uma configuração de três níveis: “Alta precisão”, “Economia de bateria” e “Somente dispositivo”. E, para minha surpresa, o usuário precisa permitir o acesso à localização do Google app se escolher o modo “Alta precisão” ou “Economia de bateria” .

Cenário

Está confuso? Aqui está uma boa notícia – o Google introduziu recentemente o SettingsApi para verificar se o usuário satisfaz esse requisito complexo e, se não, você pode mostrar uma caixa de diálogo para permitir que o usuário se recupere do status inválido sem sair do aplicativo. Alguns aplicativos primários, como o Google map, também usam a mesma caixa de diálogo.

Cenário

Você pode verificar o seguinte código para verificar a configuração de localização do usuário:

PendingResult<> result = LocationServices.SettingsApi.checkLocationSettings(
mGoogleApiClient
,
new LocationSettingsRequest.Builder().addLocationRequest(createLocationRequest()).build());
result
.setResultCallback(new ResultCallback<LocationSettingsResult>() {
@Override
public void onResult(LocationSettingsResult locationSettingsResult) {
final Status status = locationSettingsResult.getStatus();
switch (status.getStatusCode()) {
case LocationSettingsStatusCodes.SUCCESS:
// Location is available
break;
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
// Location is not available, but we can ask permission from users
break;
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
// Location is not available, and we cannot recover from the situation
break;
}}});
}

Se alcançarmos LocationSettingsStatusCodes.RESOLUTION_REQUIRED , a configuração do usuário não será suficiente para LocationRequest. Você pode usar

status.startResolutionForResult(this /* activity */, REQUEST_LOCATION_SET);

para mostrar uma caixa de diálogo para pedir ao usuário para ligar o provedor de localização GPS ou Wifi e ouvir se o usuário aceita ou não em Activity # onResult

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_LOCATION_SET) {
switch (resultCode) {
case Activity.RESULT_OK:
// TODO
break;
case Activity.RESULT_CANCELED:
// TODO
break;
}
}
}