Crea il tuo selettore Luogo attuale per Android (Java)

1. Prima di iniziare

Scopri come utilizzare Google Maps Platform e l'SDK Places per Android per presentare agli utenti un elenco di luoghi per identificare le loro posizioni attuali.

bd07a9ad2cb27a06.png

Prerequisiti

  • Competenze di base di Java

In questo lab proverai a:

  • Aggiungi una mappa a un'app Android.
  • Utilizza le autorizzazioni di accesso alla posizione per geolocalizzare l'utente.
  • Recupera luoghi vicino alla posizione corrente dell'utente.
  • Presenta i luoghi probabili all'utente per identificare la sua posizione corrente.

Cosa devi creare

Puoi creare la tua app Android da zero, ma puoi scaricare il codice campione per confrontarlo durante il debug. Scarica il codice di esempio da GitHub o, se hai impostato Git per l'uso dalla riga di comando, inserisci quanto segue:

git clone https://github.com/googlecodelabs/current-place-picker-android.git

Se riscontri problemi (bug di codice, errori grammaticali, parole non chiare o altro) mentre lavori al codelab, segnala il problema tramite il link Segnala un errore nell'angolo in basso a sinistra del codelab.

2. Per iniziare

Prima di iniziare questo codelab, devi configurare quanto segue:

Android Studio

Scarica Android Studio da https://developer.android.com/studio.

Se hai già Android Studio, assicurati di avere la versione più recente facendo clic su Android Studio > Verifica disponibilità di aggiornamenti....

1f36bae83b64e33.png

Questo lab è stato scritto con Android Studio 3.4.

SDK Android

In Android Studio puoi configurare gli SDK desiderati utilizzando SDK Manager. Questo lab utilizza l'SDK Android Q.

  1. Dalla schermata di benvenuto di Android Studio, fai clic su Configure (Configura) > SDK Manager.

d3fa03c269ec231c.png

  1. Seleziona la casella di controllo SDK che preferisci, poi fai clic su Applica.

Se non hai ancora l'SDK, viene avviato il download dell'SDK sul tuo computer.

884e0aa1314f70d.png

Google Play Services

Devi anche installare Google Play Services da SDK Manager.

  1. Fai clic sulla scheda Strumenti SDK e seleziona la casella di controllo Google Play Services.

Aggiorna se lo stato è Aggiornamento disponibile.

ad6211fd78f3b629.png

3. Prepara l'emulatore

Per eseguire l'app, puoi connettere il tuo dispositivo o utilizzare l'emulatore Android.

Se utilizzi il tuo dispositivo, vai alla sezione Istruzioni per i dispositivi reali: aggiorna Google Play Services alla fine di questa pagina.

Aggiungi un emulatore

  1. Nella schermata di benvenuto di Android Studio, fai clic su Configure (Configura) > AVD Manager (Gestione AVD).

5gg2d14c9c56d3f9.png

Viene visualizzata la finestra di dialogo Android Virtual Device Manager.

  1. Fai clic su Crea dispositivo virtuale... per aprire un elenco di dispositivi tra cui scegliere.

2d44eada384f8b35.png

  1. Scegli un dispositivo con l'icona Riproduci d5722488d80cd6be.png nella colonna Play Store e fai clic su Avanti.

e0248f1c6e85ab7c.png

Vedrai un insieme di immagini di sistema che puoi installare. Se Q ha come target Android 9.+ (Google Play) e ha la parola Scarica, fai clic su Scarica.

316d0d1efabd9f24.png

  1. Fai clic su Avanti per assegnare un nome al dispositivo virtuale, quindi fai clic su Fine.

Tornerai all'elenco I tuoi dispositivi virtuali.

  1. Fai clic su Avvia ba8adffe56d3b678.png accanto al nuovo dispositivo:

7605864ed27f77ea.png

Dopo qualche istante, si apre l'emulatore.

Istruzioni per l'emulatore: aggiorna Google Play Services

  1. Una volta avviato l'emulatore, fai clic su ... nella barra di navigazione visualizzata**.**

2e1156e02643d018.png

In questo modo si apre la finestra di dialogo Controlli estesi.

  1. Fai clic su Google Play nel menu.

Se è disponibile un aggiornamento, fai clic su Aggiorna.

5afd2686c5cad0e5.png

  1. Accedi all'emulatore con un Account Google.

Puoi utilizzare il tuo o creare un nuovo account senza costi per mantenere i test separati dalle tue informazioni personali.

Google Play si apre quindi in Google Play Services.

  1. Fai clic su Aggiorna per scaricare l'ultima versione di Google Play Services.

f4bc067e80630b9c.png

Se ti viene chiesto di completare la creazione dell'account e di aggiungere un'opzione di pagamento, fai clic su Ignora.

Imposta posizione nell'emulatore

  1. Una volta avviato l'emulatore, digita "mappe". Nella barra di ricerca della schermata Home viene visualizzata l'icona dell'app Google Maps.

2d996aadd53685a6.png

  1. Fai clic sull'icona per avviare l'app.

Viene visualizzata una mappa predefinita.

  1. In basso a destra sulla mappa, fai clic su La tua posizione c5b4e2fda57a7e71.png.

Ti viene chiesto di autorizzare il telefono a usare la posizione.

f2b68044eabca151.png

  1. Fai clic su ... per aprire il menu Controlli estesi.
  2. Fai clic sulla scheda Località.
  3. Inserisci latitudine e longitudine.

Inserisci tutto ciò che ti piace, ma assicurati che si trovi in una zona con molti luoghi.

(Usa Latitude 20.7818 e Longitude -156.4624 per la città di Kihei alle Maui alle Hawaii per replicare i risultati di questo codelab.)

  1. Fai clic su Invia e la mappa verrà aggiornata con questa località.

f9576b35218f4187.png

Ora puoi eseguire la tua app e testarla con la posizione.

Istruzioni per dispositivi reali: aggiorna Google Play Services

Se utilizzi un dispositivo Android reale, procedi nel seguente modo:

  1. Utilizza la barra di ricerca nella schermata Home per cercare e aprire Google Play Services.
  2. Fai clic su More Details (Ulteriori dettagli).

Se disponibile, fai clic su Aggiorna.

ad16cdb975b5c3f7.png baf0379ef8a9c88c.png

4. Creare la shell dell'app con un'attività di Google Maps

  1. Nella schermata di benvenuto di Android Studio, seleziona Avvia un nuovo progetto Android Studio.
  2. Nella scheda Telefono e tablet, seleziona Attività su Google Maps.

c9c80aa8211a8761.png

Viene visualizzata la finestra di dialogo Configura il tuo progetto. Qui puoi assegnare un nome alla tua app e creare il pacchetto in base al tuo dominio.

Di seguito sono riportate le impostazioni di un'app chiamata Luogo attuale, che corrisponde al pacchetto com.google.codelab.currentplace.

37f5b93b94ee118c.png

  1. Scegli Java come lingua e seleziona Utilizza artefatti androidx*.

Mantieni i valori predefiniti per le altre impostazioni.

  1. Fai clic su Fine.

5. Aggiungere dipendenze dei servizi Google al file di build Gradle

Per accedere alle autorizzazioni di accesso alla posizione in Android, devi disporre dell'API Google Location and Recognition API di Google Play Services. Per ulteriori informazioni sull'aggiunta di questa e di altre API Google Play Services, vedi Configurare Google Play Services.

In genere, i progetti Android Studio hanno due file build.gradle. Uno è per il progetto generale e uno per l'app. Se hai l'Explorer di progetto Android Studio nella visualizzazione Android, li vedi entrambi nella cartella Gradle Scripts. Per aggiungere servizi Google devi modificare il file build.gradle (Module: app).

f3043429cf719c47.png

  1. Aggiungi due righe alla sezione dependencies per aggiungere i servizi Google per la località e l'API Places (codice di esempio nel contesto).

build.gradle (modulo: app)

plugins {
  id 'com.android.application'
}

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "com.google.codelab.currentplace"
        minSdkVersion 19
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'androidx.appcompat:appcompat:1.0.2'
    implementation 'com.google.android.gms:play-services-maps:16.1.0'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test:runner:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'

    implementation 'com.google.android.gms:play-services-location:16.0.0'
    implementation 'com.google.android.libraries.places:places:1.1.0'
}

6. Abilita le API Google Maps Platform e ottieni una chiave API

Per il seguente passaggio di attivazione , devi attivare l'SDK Maps per Android e l'API Places.

Configurare Google Maps Platform

Se non hai ancora un account Google Cloud Platform e un progetto con la fatturazione abilitata, consulta la guida Utilizzo di Google Maps Platform per creare un account di fatturazione e un progetto.

  1. In Cloud Console, fai clic sul menu a discesa del progetto e seleziona il progetto che vuoi utilizzare per questo codelab.

  1. Abilita le API e gli SDK di Google Maps Platform richiesti per questo codelab in Google Cloud Marketplace. Per farlo, segui la procedura descritta in questo video o in questa documentazione.
  2. Genera una chiave API nella pagina Credentials di Cloud Console. Puoi seguire la procedura descritta in questo video o in questa documentazione. Tutte le richieste a Google Maps Platform richiedono una chiave API.

Copia la chiave API appena creata. Torna ad Android Studio e cerca il file google_maps_api.xml in Android > app > res > value.

Sostituisci YOUR_KEY_HERE con la chiave API che hai copiato.

aa576e551a7a1009.png

La tua app è configurata.

7. Modificare il file di layout

  1. In Esplora progetto, apri il file activity_maps.xml in Android > app > res > layout.

4e0d986480c57efa.png

  1. Vedrai l'interfaccia utente di base aperta sulla destra dello schermo, con le schede nella parte inferiore che ti permettono di selezionare l'Editor di progettazione o Testo per il tuo layout. Seleziona Testo e sostituisci l'intero contenuto del file di layout con questo:

activity_maps.xml

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    android:orientation="vertical">

    <androidx.appcompat.widget.Toolbar
        android:id="@+id/toolbar"
        android:minHeight="?attr/actionBarSize"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:titleTextColor="@android:color/white"
        android:background="@color/colorPrimary" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <fragment
            android:id="@+id/map"
            android:name="com.google.android.gms.maps.SupportMapFragment"
            android:layout_width="match_parent"
            android:layout_height="349dp"
            tools:context=".MapsActivity" />

        <ListView
            android:id="@+id/listPlaces"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </LinearLayout>

</LinearLayout>

In questo modo avrai un'interfaccia utente simile alla seguente:

1bf786808a4697ce.png

8. Configurare la barra dell'app

Per fare in modo che l'utente facciano clic su un pulsante per scegliere il luogo in cui si trova attualmente, aggiungi una barra delle app con un'icona che indica la posizione corrente dell'utente e la posizione in cui si trovano nelle vicinanze. L'aspetto sarà simile al seguente:

3a17c92b613a26c5.png

Su un telefono viene mostrata solo l'icona. Su un tablet con più spazio, è incluso anche il testo.

Creare l'icona

  1. In Esplora progetto, fai clic su Android > app, quindi fai clic con il pulsante destro del mouse sulla cartella res e seleziona Nuovo > asset immagine.

Si apre Asset Studio.

  1. Nel menu Tipo di icona, fai clic su Barra delle azioni e Icone.
  2. Assegna un nome all'asset ic_geolocate.
  3. Seleziona Clip art come tipo di risorsa**.
  4. Fai clic sull'immagine accanto a Clip art.

Viene visualizzata la finestra Seleziona icona.

  1. Scegli un'icona.

Puoi utilizzare la barra di ricerca per trovare le icone correlate all'intenzione.

  1. Cerca location e scegli un'icona relativa alla località.

L'icona La mia posizione corrisponde a quella utilizzata nell'app Google Maps quando un utente vuole agganciare la fotocamera alla propria posizione corrente.

  1. Fai clic su OK > Next > Finish (Fine) e conferma che è presente una nuova cartella chiamata drawable contenente i nuovi file dell'icona.

b9e0196137ed18ae.png

Aggiungi risorse stringa

  1. In Esplora progetto, fai clic su Android > app > res > values e apri il file strings.xml.
  2. Aggiungi le seguenti righe dopo <string name="title_activity_maps">Map</string>:

stringhe.xml

    <string name="action_geolocate">Pick Place</string>
    <string name="default_info_title">Default Location</string>
    <string name="default_info_snippet">No places found, because location permission is disabled.</string>

La prima riga viene utilizzata nella barra dell'app quando c'è spazio per includere un'etichetta di testo accanto all'icona. Gli altri vengono utilizzati per gli indicatori che aggiungi alla mappa.

A questo punto il codice nel file ha il seguente aspetto:

<resources>
    <string name="app_name">Current Place</string>
    <string name="title_activity_maps">Map</string>
    <string name="action_geolocate">Pick Place</string>
    <string name="default_info_title">Default Location</string>
    <string name="default_info_snippet">No places found, because location permission is disabled.</string>
</resources>

Aggiungere la barra dell'app

  1. In Esplora progetto, fai clic su Android > app, quindi fai clic con il pulsante destro del mouse sulla cartella res e seleziona Nuovo > directory per creare una nuova sottodirectory in app/src/main/res.
  2. Assegna alla directory il nome menu.
  3. Fai clic con il pulsante destro del mouse sulla cartella menu e seleziona Nuovo > File.
  4. Assegna al file il nome menu.xml.
  5. Incolla questo codice:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <!-- "Locate me", should appear as action button if possible -->
    <item
        android:id="@+id/action_geolocate"
        android:icon="@drawable/ic_geolocate"
        android:title="@string/action_geolocate"
        app:showAsAction="always|withText" />

</menu>

Aggiorna lo stile della barra delle app

  1. In Esplorazione progetto, espandi il file Android > app > res > values e apri il file styles.xml.
  2. Nel tag <style>, modifica la proprietà principale in modo che sia "Theme.AppCompat.NoActionBar".
  3. Osserva la proprietà name, che utilizzerai nel passaggio successivo.

styles.xml

<style name="AppTheme" parent="Theme.AppCompat.NoActionBar">

Aggiorna il tema dell'app in AndroidManifest.xml

  1. Fai clic su Android > app > manifests e apri il file AndroidManifest.xml.
  2. Trova la riga android:theme e modifica o conferma il valore in @style/AppTheme.

AndroidManifest.xml

   <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

Ora puoi iniziare la programmazione.

9. Inizializza l'app

  1. In Esplora progetto, trova il file MapsActivity.java.

Si trova nella cartella corrispondente al pacchetto che hai creato per la tua app nel passaggio 1.

8b0fa27d417f5f55.png

  1. Apri il file e apri l'editor di codice Java.

Importare l'SDK Places e altre dipendenze

Aggiungi queste righe nella parte superiore di MapsActivity.java, sostituendo le istruzioni di importazione esistenti.

Includono le importazioni esistenti e ne aggiungono molte altre utilizzate nel codice in questo codelab.

MapsActivity.java

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;

import com.google.android.gms.common.api.ApiException;
import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;

import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.android.gms.tasks.Task;
import com.google.android.libraries.places.api.Places;
import com.google.android.libraries.places.api.model.Place;
import com.google.android.libraries.places.api.model.PlaceLikelihood;
import com.google.android.libraries.places.api.net.FindCurrentPlaceRequest;
import com.google.android.libraries.places.api.net.FindCurrentPlaceResponse;
import com.google.android.libraries.places.api.net.PlacesClient;

import java.util.Arrays;
import java.util.List;

Aggiornare la firma del corso

L'API Places utilizza i componenti AndroidX per il supporto compatibile con le versioni precedenti, quindi devi definirla per estendere il AppCompatActivity. Sostituisce l'estensione FragmentActivity definita per impostazione predefinita per un'attività su Maps.

public class MapsActivity extends AppCompatActivity implements OnMapReadyCallback {

Aggiungere variabili di classe

In seguito, dichiara le varie variabili del corso utilizzate in diversi metodi. Questi includono gli elementi dell'interfaccia utente e i codici di stato. Questi valori dovrebbero essere appena sotto la dichiarazione della variabile per GoogleMap mMap.

    // New variables for Current Place picker
    private static final String TAG = "MapsActivity";
    ListView lstPlaces;
    private PlacesClient mPlacesClient;
    private FusedLocationProviderClient mFusedLocationProviderClient;

    // The geographical location where the device is currently located. That is, the last-known
    // location retrieved by the Fused Location Provider.
    private Location mLastKnownLocation;

    // A default location (Sydney, Australia) and default zoom to use when location permission is
    // not granted.
    private final LatLng mDefaultLocation = new LatLng(-33.8523341, 151.2106085);
    private static final int DEFAULT_ZOOM = 15;
    private static final int PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION = 1;
    private boolean mLocationPermissionGranted;

    // Used for selecting the Current Place.
    private static final int M_MAX_ENTRIES = 5;
    private String[] mLikelyPlaceNames;
    private String[] mLikelyPlaceAddresses;
    private String[] mLikelyPlaceAttributions;
    private LatLng[] mLikelyPlaceLatLngs;

Aggiornare il metodo onCreate

Dovrai aggiornare il metodo onCreate per gestire le autorizzazioni dell'utente runtime per i servizi di geolocalizzazione, configurare gli elementi dell'interfaccia utente e creare il client API Places.

Aggiungi le seguenti righe di codice sulla barra degli strumenti delle azioni, la configurazione delle viste e il client Places alla fine del metodo onCreate() esistente.

MapsActivity.java onCreate()

   @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_maps);
        // 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);

        //
        // PASTE THE LINES BELOW THIS COMMENT
        //
        
        // Set up the action toolbar
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        // Set up the views
        lstPlaces = (ListView) findViewById(R.id.listPlaces);

        // Initialize the Places client
        String apiKey = getString(R.string.google_maps_key);
        Places.initialize(getApplicationContext(), apiKey);
        mPlacesClient = Places.createClient(this);
        mFusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);
    }

Aggiungere il codice per il menu della barra dell'app

Questi due metodi consentono di aggiungere il menu della barra delle applicazioni (con un singolo elemento, l'icona Scegli luogo) e di gestire i clic dell'utente.

Copia questi due metodi nel file dopo il metodo onCreate.

MapsActivity.java onCreateOptionsMenu() e onOptionsItemSelected()

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu, menu);

        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
           case R.id.action_geolocate:
                
                // COMMENTED OUT UNTIL WE DEFINE THE METHOD
                // Present the current place picker
                // pickCurrentPlace();
                return true;

            default:
                // If we got here, the user's action was not recognized.
                // Invoke the superclass to handle it.
                return super.onOptionsItemSelected(item);

        }
    }

Prova

  1. Da Android Studio, fai clic su Esegui o Esegui menu > esegui "app'.

28bea91c68c36fb2.png

  1. Ti verrà chiesto di selezionare il target di deployment. L'emulatore in esecuzione dovrebbe essere presente in questo elenco. Selezionala e Android Studio esegue il deployment dell'app nell'emulatore.

f44658ca91f6f41a.png

Dopo qualche istante, l'app viene avviata. Vedrai la mappa centrata su Sydney, in Australia, con un singolo pulsante e un elenco di luoghi disabitati.

68eb8c70f4748350.png

Lo stato attivo della mappa non si sposta nella posizione dell'utente, a meno che non richiedi l'autorizzazione ad accedere alla posizione del dispositivo.

10. Richiedere e gestire le autorizzazioni di accesso alla posizione

Richiedere le autorizzazioni di accesso alla posizione quando la mappa è pronta

  1. Definisci un metodo chiamato getLocationPermission che richiede le autorizzazioni utente.

Incolla questo codice sotto il metodo onOptionsSelected che hai appena creato.

MapsActivity.java getLocationPermission()

    private void getLocationPermission() {
        /*
         * Request location permission, so that we can get the location of the
         * device. The result of the permission request is handled by a callback,
         * onRequestPermissionsResult.
         */
        mLocationPermissionGranted = false;
        if (ContextCompat.checkSelfPermission(this.getApplicationContext(),
                android.Manifest.permission.ACCESS_FINE_LOCATION)
                == PackageManager.PERMISSION_GRANTED) {
            mLocationPermissionGranted = true;
        } else {
            ActivityCompat.requestPermissions(this,
                    new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION},
                    PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION);
        }
    }
  1. Aggiungi due righe alla fine del metodo onMapReady esistente per attivare i controlli zoom e richiedere all'utente le autorizzazioni di accesso alla posizione.

MapsActivity.java onMapReady()

   @Override
    public void onMapReady(GoogleMap googleMap) {
        mMap = googleMap;

        // Add a marker in Sydney and move the camera
        LatLng sydney = new LatLng(-34, 151);
        mMap.addMarker(new MarkerOptions().position(sydney).title("Marker in Sydney"));
        mMap.moveCamera(CameraUpdateFactory.newLatLng(sydney));

        //
        // PASTE THE LINES BELOW THIS COMMENT
        //

        // Enable the zoom controls for the map
        mMap.getUiSettings().setZoomControlsEnabled(true);

        // Prompt the user for permission.
        getLocationPermission();

    }

Gestire il risultato dalle autorizzazioni richieste

Quando l'utente risponde alla finestra di dialogo per la richiesta di autorizzazione, il callback viene chiamato da Android.

Incolla questo codice dopo il metodo getLocationPermission():

MapsActivity.java onRequestPermissionsResult()

   /**
     * Handles the result of the request for location permissions
     */
    @Override
    public void onRequestPermissionsResult(int requestCode,
                                           @NonNull String permissions[],
                                           @NonNull int[] grantResults) {
        mLocationPermissionGranted = false;
        switch (requestCode) {
            case PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION: {
                // If request is cancelled, the result arrays are empty.
                if (grantResults.length > 0
                        && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    mLocationPermissionGranted = true;
                }
            }
        }
    }

11. Individuare la posizione attuale e recuperare i luoghi probabili

Quando l'utente fa clic su Scegli luogo nella barra dell'app, l'app chiama il metodo pickCurrentPlace(), che chiama il metodo getDeviceLocation() definito in precedenza. Il metodo getDeviceLocation chiama un altro metodo, getCurrentPlaceLikelihoods, dopo aver recuperato la posizione più recente del dispositivo.

Chiama l'API FindCurrentPlace e gestisci la risposta

getCurrentPlaceLikelihoods crea un elemento findCurrentPlaceRequest e chiama l'attività Places findCurrentPlace. Se l'attività ha esito positivo, restituisce un findCurrentPlaceResponse, che contiene un elenco di oggetti placeLikelihood. Ognuno di questi elementi ha una serie di proprietà, tra cui il nome e l'indirizzo del luogo, e la probabilità che tu ti trovi in quel luogo (un valore doppio compreso tra 0 e 1). Questo metodo gestisce la risposta creando elenchi di dettagli dei luoghi da placeLikelihoods.

Questo codice esegue l'iterazione tra le cinque posizioni con maggiori probabilità e aggiunge quelle con una probabilità maggiore di 0 a un elenco che viene poi visualizzato. Se vuoi che vengano visualizzati più o meno di cinque, modifica la costante M_MAX_ENTRIES.

Incolla questo codice dopo il metodo onMapReady.

MapsActivity.java getCurrentPlaceLikelihoods()

   private void getCurrentPlaceLikelihoods() {
        // Use fields to define the data types to return.
        List<Place.Field> placeFields = Arrays.asList(Place.Field.NAME, Place.Field.ADDRESS,
                Place.Field.LAT_LNG);

        // Get the likely places - that is, the businesses and other points of interest that
        // are the best match for the device's current location.
        @SuppressWarnings("MissingPermission") final FindCurrentPlaceRequest request =
                FindCurrentPlaceRequest.builder(placeFields).build();
        Task<FindCurrentPlaceResponse> placeResponse = mPlacesClient.findCurrentPlace(request);
        placeResponse.addOnCompleteListener(this,
                new OnCompleteListener<FindCurrentPlaceResponse>() {
                    @Override
                    public void onComplete(@NonNull Task<FindCurrentPlaceResponse> task) {
                        if (task.isSuccessful()) {
                            FindCurrentPlaceResponse response = task.getResult();
                            // Set the count, handling cases where less than 5 entries are returned.
                            int count;
                            if (response.getPlaceLikelihoods().size() < M_MAX_ENTRIES) {
                                count = response.getPlaceLikelihoods().size();
                            } else {
                                count = M_MAX_ENTRIES;
                            }

                            int i = 0;
                            mLikelyPlaceNames = new String[count];
                            mLikelyPlaceAddresses = new String[count];
                            mLikelyPlaceAttributions = new String[count];
                            mLikelyPlaceLatLngs = new LatLng[count];

                            for (PlaceLikelihood placeLikelihood : response.getPlaceLikelihoods()) {
                                Place currPlace = placeLikelihood.getPlace();
                                mLikelyPlaceNames[i] = currPlace.getName();
                                mLikelyPlaceAddresses[i] = currPlace.getAddress();
                                mLikelyPlaceAttributions[i] = (currPlace.getAttributions() == null) ?
                                        null : TextUtils.join(" ", currPlace.getAttributions());
                                mLikelyPlaceLatLngs[i] = currPlace.getLatLng();

                                String currLatLng = (mLikelyPlaceLatLngs[i] == null) ?
                                        "" : mLikelyPlaceLatLngs[i].toString();

                                Log.i(TAG, String.format("Place " + currPlace.getName()
                                        + " has likelihood: " + placeLikelihood.getLikelihood()
                                        + " at " + currLatLng));

                                i++;
                                if (i > (count - 1)) {
                                    break;
                                }
                            }


                            // COMMENTED OUT UNTIL WE DEFINE THE METHOD
                            // Populate the ListView
                            // fillPlacesList();
                        } else {
                            Exception exception = task.getException();
                            if (exception instanceof ApiException) {
                                ApiException apiException = (ApiException) exception;
                                Log.e(TAG, "Place not found: " + apiException.getStatusCode());
                            }
                        }
                    }
                });
    }

Sposta la fotocamera della mappa nella posizione corrente del dispositivo

Se l'utente concede l'autorizzazione, l'app recupera l'ultima posizione dell'utente e sposta la fotocamera al centro dell'utente.

Se l'utente nega l'autorizzazione, l'app si limita a spostare la fotocamera nella posizione predefinita definita tra le costanti all'inizio di questa pagina (nel codice di esempio, si tratta di Sydney, Australia).

Incolla questo codice dopo il metodo getPlaceLikelihoods():

MapsActivity.java getDeviceLocation()

    private void getDeviceLocation() {
        /*
         * Get the best and most recent location of the device, which may be null in rare
         * cases when a location is not available.
         */
        try {
            if (mLocationPermissionGranted) {
                Task<Location> locationResult = mFusedLocationProviderClient.getLastLocation();
                locationResult.addOnCompleteListener(this, new OnCompleteListener<Location>() {
                    @Override
                    public void onComplete(@NonNull Task<Location> task) {
                        if (task.isSuccessful()) {
                            // Set the map's camera position to the current location of the device.
                            mLastKnownLocation = task.getResult();
                            Log.d(TAG, "Latitude: " + mLastKnownLocation.getLatitude());
                            Log.d(TAG, "Longitude: " + mLastKnownLocation.getLongitude());
                            mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(
                                    new LatLng(mLastKnownLocation.getLatitude(),
                                            mLastKnownLocation.getLongitude()), DEFAULT_ZOOM));
                        } else {
                            Log.d(TAG, "Current location is null. Using defaults.");
                            Log.e(TAG, "Exception: %s", task.getException());
                            mMap.moveCamera(CameraUpdateFactory
                                    .newLatLngZoom(mDefaultLocation, DEFAULT_ZOOM));
                        }

                       getCurrentPlaceLikelihoods();
                    }
                });
            }
        } catch (SecurityException e)  {
            Log.e("Exception: %s", e.getMessage());
        }
    }

Verifica le autorizzazioni di accesso alla posizione quando l'utente fa clic su Scegli luogo

Quando l'utente tocca Scegli luogo, questo metodo controlla le autorizzazioni di accesso alla posizione e chiede l'autorizzazione se non è stato concesso.

Se l'utente ha concesso l'autorizzazione, il metodo chiama getDeviceLocation per avviare il processo di recupero delle posizioni correnti.

  1. Aggiungi questo metodo dopo il giorno getDeviceLocation():

MapsActivity.java pickCurrentPlace()

   private void pickCurrentPlace() {
        if (mMap == null) {
            return;
        }

        if (mLocationPermissionGranted) {
            getDeviceLocation();
        } else {
            // The user has not granted permission.
            Log.i(TAG, "The user did not grant location permission.");

            // Add a default marker, because the user hasn't selected a place.
            mMap.addMarker(new MarkerOptions()
                    .title(getString(R.string.default_info_title))
                    .position(mDefaultLocation)
                    .snippet(getString(R.string.default_info_snippet)));

            // Prompt the user for permission.
            getLocationPermission();
        }
    }
  1. Ora che hai definito pickCurrentPlace, trova la riga in onOptionsItemSelected() che chiama pickCurrentPlace e annulla il commento.

MapsActivity.java onOptionItemSelected()

           case R.id.action_geolocate:

                // COMMENTED OUT UNTIL WE DEFINE THE METHOD
                // Present the Current Place picker
                pickCurrentPlace();
                return true;

Prova

Se esegui l'app adesso e tocchi Scegli luogo, dovrebbero essere richieste le autorizzazioni di accesso alla posizione.

  • Se autorizzi l'autorizzazione, questa preferenza verrà salvata e non ti verrà chiesto. Se neghi l'autorizzazione, ricevi un nuovo avviso quando tocchi il pulsante.
  • Anche se getPlaceLikelihoods ha recuperato i probabili luoghi correnti, ListView non li mostra ancora. In Android Studio, puoi fare clic su ⌘6 per controllare nei log di Logcat le istruzioni con l'etichetta MapsActivity da verificare che i nuovi metodi funzionino correttamente.
  • Se hai concesso l'autorizzazione, i log includono un'istruzione per Latitude: e un'istruzione per Longitude: che mostra la posizione rilevata del dispositivo. Se hai utilizzato Google Maps e il menu esteso dell'emulatore in precedenza per specificare una posizione per l'emulatore, queste dichiarazioni mostrano la posizione.
  • Se la chiamata al numero findCurrentPlace ha avuto esito positivo, i log includono cinque istruzioni che stampano i nomi e le posizioni dei cinque luoghi che con maggiori probabilità vengono visualizzati.

d9896a245b81bf3.png

12. Completa il selettore dei luoghi attuali

Configurazione di un gestore per i luoghi selezionati

Vediamo cosa succede quando l'utente fa clic su un elemento nel ListView. Per confermare la scelta dell'utente del luogo in cui si trova attualmente, puoi aggiungere un indicatore alla mappa. Se l'utente fa clic sull'indicatore, viene visualizzata una finestra informativa che mostra il nome e l'indirizzo del luogo.

Incolla questo gestore dei clic dopo il metodo pickCurrentPlace.

MapsActivity.java listClickedHandler

    private AdapterView.OnItemClickListener listClickedHandler = new AdapterView.OnItemClickListener() {
        public void onItemClick(AdapterView parent, View v, int position, long id) {
            // position will give us the index of which place was selected in the array
            LatLng markerLatLng = mLikelyPlaceLatLngs[position];
            String markerSnippet = mLikelyPlaceAddresses[position];
            if (mLikelyPlaceAttributions[position] != null) {
                markerSnippet = markerSnippet + "\n" + mLikelyPlaceAttributions[position];
            }

            // Add a marker for the selected place, with an info window
            // showing information about that place.
            mMap.addMarker(new MarkerOptions()
                    .title(mLikelyPlaceNames[position])
                    .position(markerLatLng)
                    .snippet(markerSnippet));

           // Position the map's camera at the location of the marker.
            mMap.moveCamera(CameraUpdateFactory.newLatLng(markerLatLng));
        }
    };

Compilare la ListView

Ora che hai creato un elenco dei luoghi che molto probabilmente sta visitando l'utente, puoi presentare queste opzioni all'utente in ListView. puoi anche impostare il listener di clic su ListView in modo che utilizzi il gestore dei clic appena definito.

Incolla questo metodo dopo il gestore dei clic:

MapsActivity.java FillLuoghiList()

    private void fillPlacesList() {
        // Set up an ArrayAdapter to convert likely places into TextViews to populate the ListView
        ArrayAdapter<String> placesAdapter =
                new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mLikelyPlaceNames);
        lstPlaces.setAdapter(placesAdapter);
        lstPlaces.setOnItemClickListener(listClickedHandler);
    }

Ora che è stato definito fillPlacesList, trova la riga verso la fine del findPlaceLikelihoods che chiama fillPlacesList e annulla il commento.

MapsActivity.java FillPlaceLikelihoods()

               // COMMENTED OUT UNTIL WE DEFINE THE METHOD
                // Populate the ListView
                fillPlacesList();

Ecco tutto il codice necessario per il selettore dei luoghi attuali.

13. Esegui l'app

Testare la scelta di un luogo

  1. Esegui di nuovo l'app.

Questa volta, quando tocchi Scegli luogo l'app completa l'elenco con i luoghi denominati vicino al luogo. Vicino a questa località di Maui si trovano luoghi come l'Hawaiian Shave Ice e il Sugar Beach Bake Shop. Dato che i vari luoghi sono molto vicini alle coordinate di posizione, questo è un elenco di posti in cui potresti trovarti.

  1. Fai clic sul nome di un luogo nella ListView.

Dovresti vedere un indicatore aggiunto alla mappa.

  1. Tocca l'indicatore.

Puoi visualizzare i dettagli del luogo.

e52303cc0de6a513.png 864c74342fb52a01.png

Testare una località diversa

Se vuoi cambiare la tua posizione e stai utilizzando l'emulatore, la posizione del dispositivo non viene aggiornata automaticamente quando aggiorni le coordinate della posizione nel menu esteso dell'emulatore.

Per aggirare il problema, segui questi passaggi per utilizzare l'app nativa di Google Maps per forzare gli aggiornamenti alla posizione dell'emulatore:

  1. Apri Google Maps.
  2. Tocca ... > Posizione per modificare la latitudine e la longitudine in base alle nuove coordinate, quindi tocca Invia.
  3. Ad esempio, puoi utilizzare Latitudine: 49.2768 e Longitudine: -123.1142 per impostare la posizione al centro di Vancouver, Canada.
  4. Verifica che Google Maps sia stato rinnovato in base alle nuove coordinate. Per richiedere la ricentrazione, potresti dover toccare il pulsante La mia posizione nell'app Google Maps.
  5. Torna all'app Luogo corrente e tocca Scegli luogo per visualizzare la mappa sulle nuove coordinate e visualizzare un nuovo elenco di luoghi attuali.

9adb99d1ce25c184.png

e il gioco è fatto. Hai creato un'app semplice che controlla i luoghi nella posizione attuale e ti dà la probabilità di vedere quelli in cui ti trovi. Buon divertimento!

Ora continua e passa all'app con le modifiche che hai apportato per completare questo passaggio bonus!

14. Passaggi successivi

Per impedire il furto della chiave API, devi proteggerla in modo che solo la tua app Android possa utilizzarla. Se non vengono applicate limitazioni, chiunque abbia il tuo token potrebbe utilizzarlo per chiamare le API di Google Maps Platform e farti pagare.

Ottieni il certificato SHA-1

Questa operazione è necessaria in un secondo momento per limitare le chiavi API. Di seguito è riportato un insieme di istruzioni per ottenere il certificato di debug.

Per Linux o macOS, apri una finestra del terminale e inserisci quanto segue:

keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android

Per Windows Vista e Windows 7, esegui il comando seguente:

keytool -list -v -keystore "%USERPROFILE%\.android\debug.keystore" -alias androiddebugkey -storepass android -keypass android

Dovresti vedere un output simile al seguente:

Alias name: androiddebugkey
Creation date: Jan 01, 2013
Entry type: PrivateKeyEntry
Certificate chain length: 1
Certificate[1]:
Owner: CN=Android Debug, O=Android, C=US
Issuer: CN=Android Debug, O=Android, C=US
Serial number: 4aa9b300
Valid from: Mon Jan 01 08:04:04 UTC 2013 until: Mon Jan 01 18:04:04 PST 2033
Certificate fingerprints:
     MD5:  AE:9F:95:D0:A6:86:89:BC:A8:70:BA:34:FF:6A:AC:F9
     SHA1: BB:0D:AC:74:D3:21:E1:43:07:71:9B:62:90:AF:A1:66:6E:44:5D:75
     Signature algorithm name: SHA1withRSA
     Version: 3

La riga che inizia in SHA1 contiene l'impronta SHA-1 del certificato. L'impronta è la sequenza di 20 numeri esadecimali a due cifre separati da due punti.

Quando è tutto pronto per rilasciare un'app, segui le istruzioni riportate in questa documentazione per recuperare il certificato di rilascio.

Aggiungere limitazioni alla chiave API

  1. In Cloud Console, vai ad API e servizi > Credenziali.

La chiave utilizzata per questa app deve essere elencata in Chiavi API.

  1. Fai clic su 6454a04865d551e6.png per modificare le impostazioni della chiave.

316b052c621ee91c.png

  1. Nella pagina della chiave API, dopo Limitazioni chiave, imposta le Limitazioni dell'applicazione procedendo nel seguente modo:
  2. Seleziona App Android e segui le istruzioni.
  3. Fai clic su Aggiungi un elemento.
  4. Inserisci il nome del pacchetto e l'impronta digitale del certificato SHA-1 (recuperato nella sezione precedente).

Ad esempio:

com.google.codelab.currentplace
BB:0D:AC:74:D3:21:E1:43:07:71:9B:62:90:AF:A1:66:6E:44:5D:75s
  1. Per una maggiore protezione, imposta le restrizioni dell'API come descritto di seguito.
  2. Dopo le limitazioni dell'API, scegli Limita la chiave.
  3. Seleziona l'SDK Maps per Android e per l'API Places.
  4. Fai clic su Fine e Salva.

15. Complimenti

Hai creato un'app semplice che controlla la posizione più probabile nella posizione corrente e aggiunge un indicatore alla mappa per il luogo selezionato.

Scopri di più