Active los servicios de ubicación sin navegar a la página de configuración

Contra el enfoque tradicional de pedir al usuario que vaya a la página de configuración y habilitar los servicios de localización y regresar, he notado una forma más simple de hacer lo mismo en algunas de las últimas aplicaciones.

En referencia a la captura de pantalla siguiente, se solicita un diálogo al usuario para habilitar los servicios de ubicación con un solo clic y funciona en esas aplicaciones.

¿Cómo puedo lograr lo mismo?

enter image description here

Este cuadro de diálogo es creado por LocationSettingsRequest.Builder disponible en los servicios de Google Play.

build.gradle agregar una dependencia a su aplicación build.gradle :

 compile 'com.google.android.gms:play-services-location:10.0.1' 

Entonces puedes usar este ejemplo mínimo:

 private void displayLocationSettingsRequest(Context context) { GoogleApiClient googleApiClient = new GoogleApiClient.Builder(context) .addApi(LocationServices.API).build(); googleApiClient.connect(); LocationRequest locationRequest = LocationRequest.create(); locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); locationRequest.setInterval(10000); locationRequest.setFastestInterval(10000 / 2); LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder().addLocationRequest(locationRequest); builder.setAlwaysShow(true); PendingResult result = LocationServices.SettingsApi.checkLocationSettings(googleApiClient, builder.build()); result.setResultCallback(new ResultCallback() { @Override public void onResult(LocationSettingsResult result) { final Status status = result.getStatus(); switch (status.getStatusCode()) { case LocationSettingsStatusCodes.SUCCESS: Log.i(TAG, "All location settings are satisfied."); break; case LocationSettingsStatusCodes.RESOLUTION_REQUIRED: Log.i(TAG, "Location settings are not satisfied. Show the user a dialog to upgrade location settings "); try { // Show the dialog by calling startResolutionForResult(), and check the result // in onActivityResult(). status.startResolutionForResult(MainActivity.this, REQUEST_CHECK_SETTINGS); } catch (IntentSender.SendIntentException e) { Log.i(TAG, "PendingIntent unable to execute request."); } break; case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE: Log.i(TAG, "Location settings are inadequate, and cannot be fixed here. Dialog not created."); break; } } }); } 

Puedes encontrar el ejemplo completo aquí .

Siga los pasos que se mencionan a continuación

1) Crea una LocationRequest según tu deseo

 LocationRequest mLocationRequest = LocationRequest.create() .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY) .setInterval(10 * 1000) .setFastestInterval(1 * 1000); 

2) Crear un LocationSettingsRequest.Builder

 LocationSettingsRequest.Builder settingsBuilder = new LocationSettingsRequest.Builder() .addLocationRequest(mLocationRequest); settingsBuilder.setAlwaysShow(true); 

3) Obtiene la Task LocationSettingsResponse usando el siguiente código

 Task result = LocationServices.getSettingsClient(this) .checkLocationSettings(settingsBuilder.build()); 

Nota: LocationServices.SettingsApi está en desuso por lo tanto, use SettingsClient lugar.

4) Agregue un OnCompleteListener para obtener el resultado de la Task Cuando la Task complete, el cliente puede verificar la configuración de ubicación mirando el código de estado del objeto LocationSettingsResponse .

 result.addOnCompleteListener(new OnCompleteListener() { @Override public void onComplete(@NonNull Task task) { try { LocationSettingsResponse response = task.getResult(ApiException.class); } catch (ApiException ex) { switch (ex.getStatusCode()) { case LocationSettingsStatusCodes.RESOLUTION_REQUIRED: try { ResolvableApiException resolvableApiException = (ResolvableApiException) ex; resolvableApiException .startResolutionForResult(MapsActivity.this, LOCATION_SETTINGS_REQUEST); } catch (IntentSender.SendIntentException e) { } break; case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE: break; } } } }); 

CASO 1: LocationSettingsStatusCodes.RESOLUTION_REQUIRED : la ubicación no está habilitada, pero podemos pedirle al usuario que habilite la ubicación pidiéndole que active la ubicación con el cuadro de diálogo (llamando a startResolutionForResult ).

Solicitud de configuración de ubicación de Google Map

CASO 2: LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE : la configuración de ubicación no está satisfecha. Sin embargo, no tenemos forma de corregir la configuración, por lo que no mostraremos el diálogo.

5) OnActivityResult podemos obtener la acción del usuario en el cuadro de diálogo de configuración de ubicación. RESULT_OK => El usuario activó la ubicación. RESULT_CANCELLED : el usuario rechazó la solicitud de configuración de ubicación.

Android Marshmallow 6 admite permisos de tiempo de ejecución. Los permisos de tiempo de ejecución solo funcionan en Marshmallow y en pre-Marshmallow todavía funciona de la manera antigua.

Puede obtener más información al respecto en este video oficial para desarrolladores de Android:

https://www.youtube.com/watch?v=C8lUdPVSzDk

Y solicitando permiso: http://developer.android.com/training/permissions/requesting.html

Su funcionamiento es similar al de los mapas de google

Agregar dependencia en el archivo build.gradle

 compile 'com.google.android.gms:play-services:8.3.0' 

esta o aquella

 compile 'com.google.android.gms:play-services-location:10.0.1' 

enter image description here

 import android.content.Context; import android.content.IntentSender; import android.location.LocationManager; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.widget.Button; import android.widget.TextView; import android.widget.Toast; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.api.GoogleApiClient; import com.google.android.gms.common.api.PendingResult; import com.google.android.gms.common.api.ResultCallback; import com.google.android.gms.common.api.Status; import com.google.android.gms.location.LocationRequest; import com.google.android.gms.location.LocationServices; import com.google.android.gms.location.LocationSettingsRequest; import com.google.android.gms.location.LocationSettingsResult; import com.google.android.gms.location.LocationSettingsStatusCodes; import java.util.List; public class LocationOnOff_Similar_To_Google_Maps extends AppCompatActivity { protected static final String TAG = "LocationOnOff"; private GoogleApiClient googleApiClient; final static int REQUEST_LOCATION = 199; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.setFinishOnTouchOutside(true); // Todo Location Already on ... start final LocationManager manager = (LocationManager) LocationOnOff_Similar_To_Google_Maps.this.getSystemService(Context.LOCATION_SERVICE); if (manager.isProviderEnabled(LocationManager.GPS_PROVIDER) && hasGPSDevice(LocationOnOff_Similar_To_Google_Maps.this)) { Toast.makeText(LocationOnOff_Similar_To_Google_Maps.this,"Gps already enabled",Toast.LENGTH_SHORT).show(); finish(); } // Todo Location Already on ... end if(!hasGPSDevice(LocationOnOff_Similar_To_Google_Maps.this)){ Toast.makeText(LocationOnOff_Similar_To_Google_Maps.this,"Gps not Supported",Toast.LENGTH_SHORT).show(); } if (!manager.isProviderEnabled(LocationManager.GPS_PROVIDER) && hasGPSDevice(LocationOnOff_Similar_To_Google_Maps.this)) { Log.e("keshav","Gps already enabled"); Toast.makeText(LocationOnOff_Similar_To_Google_Maps.this,"Gps not enabled",Toast.LENGTH_SHORT).show(); enableLoc(); }else{ Log.e("keshav","Gps already enabled"); Toast.makeText(LocationOnOff_Similar_To_Google_Maps.this,"Gps already enabled",Toast.LENGTH_SHORT).show(); } } private boolean hasGPSDevice(Context context) { final LocationManager mgr = (LocationManager) context .getSystemService(Context.LOCATION_SERVICE); if (mgr == null) return false; final List providers = mgr.getAllProviders(); if (providers == null) return false; return providers.contains(LocationManager.GPS_PROVIDER); } private void enableLoc() { if (googleApiClient == null) { googleApiClient = new GoogleApiClient.Builder(LocationOnOff_Similar_To_Google_Maps.this) .addApi(LocationServices.API) .addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() { @Override public void onConnected(Bundle bundle) { } @Override public void onConnectionSuspended(int i) { googleApiClient.connect(); } }) .addOnConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener() { @Override public void onConnectionFailed(ConnectionResult connectionResult) { Log.d("Location error","Location error " + connectionResult.getErrorCode()); } }).build(); googleApiClient.connect(); LocationRequest locationRequest = LocationRequest.create(); locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); locationRequest.setInterval(30 * 1000); locationRequest.setFastestInterval(5 * 1000); LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder() .addLocationRequest(locationRequest); builder.setAlwaysShow(true); PendingResult result = LocationServices.SettingsApi.checkLocationSettings(googleApiClient, builder.build()); result.setResultCallback(new ResultCallback() { @Override public void onResult(LocationSettingsResult result) { final Status status = result.getStatus(); switch (status.getStatusCode()) { case LocationSettingsStatusCodes.RESOLUTION_REQUIRED: try { // Show the dialog by calling startResolutionForResult(), // and check the result in onActivityResult(). status.startResolutionForResult(LocationOnOff_Similar_To_Google_Maps.this, REQUEST_LOCATION); finish(); } catch (IntentSender.SendIntentException e) { // Ignore the error. } break; } } }); } } } 

Gracias Mattia Maestrini por la Respuesta, me gustaría agregar que usar

compile 'com.google.android.gms:play-services-location:8.1.0'

bastaría. Esto evita que su aplicación incluya bibliotecas innecesarias y ayuda a mantener baja su cuenta de métodos.

Gracias a Mattia Maestrini +1

Solución de Xamarin:

 using Android.Gms.Common.Apis; using Android.Gms.Location; public const int REQUEST_CHECK_SETTINGS = 0x1; private void DisplayLocationSettingsRequest() { var googleApiClient = new GoogleApiClient.Builder(this).AddApi(LocationServices.API).Build(); googleApiClient.Connect(); var locationRequest = LocationRequest.Create(); locationRequest.SetPriority(LocationRequest.PriorityHighAccuracy); locationRequest.SetInterval(10000); locationRequest.SetFastestInterval(10000 / 2); var builder = new LocationSettingsRequest.Builder().AddLocationRequest(locationRequest); builder.SetAlwaysShow(true); var result = LocationServices.SettingsApi.CheckLocationSettings(googleApiClient, builder.Build()); result.SetResultCallback((LocationSettingsResult callback) => { switch (callback.Status.StatusCode) { case LocationSettingsStatusCodes.Success: { DoStuffWithLocation(); break; } case LocationSettingsStatusCodes.ResolutionRequired: { try { // Show the dialog by calling startResolutionForResult(), and check the result // in onActivityResult(). callback.Status.StartResolutionForResult(this, REQUEST_CHECK_SETTINGS); } catch (IntentSender.SendIntentException e) { } break; } default: { // If all else fails, take the user to the android location settings StartActivity(new Intent(Android.Provider.Settings.ActionLocationSourceSettings)); break; } } }); } protected override void OnActivityResult(int requestCode, Android.App.Result resultCode, Intent data) { switch (requestCode) { case REQUEST_CHECK_SETTINGS: { switch (resultCode) { case Android.App.Result.Ok: { DoStuffWithLocation(); break; } case Android.App.Result.Canceled: { //No location break; } } break; } } } 

Con la actualización reciente de Marshmallow, incluso cuando la configuración de Ubicación esté activada, su aplicación requerirá pedir explícitamente permiso. La forma recomendada de hacerlo es mostrar la sección Permisos de su aplicación, donde el usuario puede alternar el permiso según sea necesario. El fragmento de código para hacer esto es el siguiente:

 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (this.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { final AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("Location Permission"); builder.setMessage("The app needs location permissions. Please grant this permission to continue using the features of the app."); builder.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSION_REQUEST_COARSE_LOCATION); } }); builder.setNegativeButton(android.R.string.no, null); builder.show(); } } else { // do progtwigtically as show in the other answer } 

Y anule el método onRequestPermissionsResult siguiente manera:

 @Override public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { switch (requestCode) { case PERMISSION_REQUEST_COARSE_LOCATION: { if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { Log.d(TAG, "coarse location permission granted"); } else { Intent intent = new Intent(); intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); Uri uri = Uri.fromParts("package", getPackageName(), null); intent.setData(uri); startActivity(intent); } } } } 

Otro enfoque es que también puede usar SettingsApi para averiguar qué proveedor (es) de ubicación están habilitados. Si ninguno está habilitado, puede solicitar un diálogo para cambiar la configuración desde dentro de la aplicación.