12.6: Il LocationManager: localizzare l’utente pt.2, la richiesta dei permessi a runtime

Condividi su:

Con lo scorso articolo abbiamo visto come poter ottenere la posizione dell’utente sfruttando il LocationManager e un apposito listener per reagire ai cambiamenti di posizione. A meno che non abbiate utilizzato come SDK target una vecchia versione di Android, non sarete riusciti a vedere l’app all’opera, questo perché con le nuove versioni di Android determinati permessi vanno richiesti esplicitamente all’utente, tra cui quello di accesso alla posizione.





In questa seconda parte vedremo proprio come richiedere tale permesso. In questa situazione Android Studio vi segnalerà anche un errore sull’istruzione che di fatto va a richiedere la posizione e se cliccate sulla lampadina rossa di fianco a questa vi chiederà di implementare del codice del genere:

if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
        && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
    // TODO: Consider calling
    //    ActivityCompat#requestPermissions
    // here to request the missing permissions, and then overriding
    //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
    //                                          int[] grantResults)
    // to handle the case where the user grants the permission. See the documentation
    // for ActivityCompat#requestPermissions for more details.
    return;
}

Di fatto controlla, attraverso il metodo “checkSelfPermission()“, lo stato di determinati permessi, nel nostro caso localizzazione precisa e localizzazione approssimata (che non avendo usato possiamo anche eliminare dal controllo). A noi interessa controllare che questi non siano stati concessi, infatti l’if è predisposto in questo modo.

All’interno di questo controllo dovremo quindi invocare il metodo necessario alla richiesta di questo permesso, cioè “requestPermission()” della classe “ActivityCompat“. Questo metodo non fa altro che presentare all’utente la finestra di dialogo a cui ormai saremo tutti abituati, cioè quella che richiede la concessione di un determinato permesso (che ovviamente potrà anche essere negato).

Ovviamente non finisce qui, poiché andrà effettuato anche l’override del metodo “onRequestPermissionResult()“, poiché sarà qui che dovremmo gestire il da farsi, nel nostro caso registrare il listener attraverso il metodo “requestLocationUpdates()”. Questo metodo sarà infatti invocato quando l’utente darà una risposta alla richiesta di concessione del permesso. Quindi sarà sempre qui che gestiremo l’eventuale diniego del permesso.

Ancora non abbiamo finito, poiché dovremo fare in modo che l’app funzioni anche su versioni precedenti ad Android 6.0, cioè quelle che non hanno bisogno della richiesta a runtime dei permessi pericolosi.

Vediamo quindi come sarà il codice adattato:

public class MainActivity extends AppCompatActivity {
    //Dichiariamo un LocationManager per poter poi accedere al servizio di localizzazione
    private LocationManager locationManager;
    //Dichiariamo un LocationListener usato per rimanere in ascolto di cambi di posizione
    private LocationListener locationListener;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //Istanziamo il LocationManager recuperando il servizio di localizzazione
        locationManager = (LocationManager) this.getSystemService(LOCATION_SERVICE);
        //Istanziamo il listener che monitorerà cambi nella posizione
        locationListener = new LocationListener() {
            @Override
            public void onLocationChanged(Location location) {
                /*
                 * Metodo invocato quando cambia la posizione
                 */

                //Visualizzazione della posizone nel log
                Log.d("Location: ", location.toString());
            }

            @Override
            public void onStatusChanged(String provider, int status, Bundle extras) {
                /*
                 * Metodo invocato quando cambia lo stato del provider, ad esempio quando questo non
                 * è in grado di recuperare la posizione, oppure quando è ritornato disponibile dopo
                 * un periodo di non disponibilità
                 */
            }

            @Override
            public void onProviderEnabled(String provider) {
                /*
                 * Metodo invocato quando il provider viene abilitato dall'utente
                 */
            }

            @Override
            public void onProviderDisabled(String provider) {
                /*
                 * Metodo invocato quando l'utente disabilita il provider o quando è già disabilitato
                 * al momento della chiamata del metodo "requestLocationUpdates()"
                 */
            }
        };

        /*
         * Se stiamo esegendo l'app su una versione di Android uguale o superiore alla 6.0
         * dobbiamo richiedere necessariamente il permesso di accedere alla localizzazione a
         * runtime prima di poter avere accesso a questa, altrimenti registriamo direttamente il listener
         */
        if (Build.VERSION.SDK_INT >= 23) {
            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                //Richiediamo il permesso all'utente
                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1);
                return;
            } else {
                //Registriamo il listener per ricevere aggiornamenti sulla posizione
                locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
            }
        } else {
            //Registriamo il listener per ricevere aggiornamenti sulla posizione
            locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        /*
         * Metodo invocato alla richiesta del permesso a runtime
         */

        //Se il permesso specifico è stato concesso, ci registriamo per la posizione
        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
                    == PackageManager.PERMISSION_GRANTED){
                //Registriamo il listener per ricevere aggiornamenti sulla posizione
                locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
            }
        }
    }
}

Per prima cosa verifichiamo che la build su cui stiamo operando abbia SDK maggiore o uguale di 23, cioè se il dispositivo ha una versione uguale o superiore a Marshmallow (Android 6.0), se così fosse, controlliamo lo stato del permesso che ci interessa. Se non concesso, richiamiamo il metodo apposito per poterlo richiedere all’utente. Tra i parametri indichiamo l’activity, i permessi da richiedere all’interno di un array di stringhe e un requestCode che banalmente sfruttiamo per indicare il numero di permessi richiesti.
Se è già stato concesso allora possiamo eseguire l’istruzione critica, cioè quella che registra il listener per poter ricevere aggiornamenti sulla posizione.
Se ci troviamo su una vecchia versione di Android, anche in questo caso richiamiamo l’istruzione critica.

All’interno del metodo “onRequestPermissionResult()” facciamo una serie di controlli, prima di richiamare l’istruzione critica (dobbiamo infatti fare in modo che l’app funzioni anche nel momento in cui il permesso è stato appena concesso). Tra i parametri questo metodo offre un array contenente lo stato dei permessi richiesti. Controlliamo che questo array non sia vuoto e che il primo e unico elemento (avendo richiesto un solo permesso) sia un permesso accettato.
Per scrupolo controlliamo anche che il permesso sia stato effettivamente concesso e procediamo.


Conclusioni

Grazie alla necessità di dover operare con la localizzazione e sviluppando app per le nuove versioni di Android abbiamo finalmente visto come poter richiedere permessi a runtime. L’operazione non è complessa, si tratta esclusivamente di una serie di controlli da effettuare e di richiamare i metodi appropriati. Tutto il resto verrà gestito dalla piattaforma.

Abbiamo inoltre visto come poter supportare versioni diverse di Android con caratteristiche diverse. Nel nostro esempio Android Lollipop permette direttamente l’accesso alla posizione, Marshmallow no, ma la nostra app, così strutturata, è in grado di funzionare senza problemi su entrambe le versioni.

Con questo articolo abbiamo terminato, nel prossimo vedremo come unire la possibilità di localizzare l’utente con Google Maps.

Condividi su:

label, , , , ,

About the author