Crea il tuo selettore di Current Place 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 in cui identificare le loro posizioni attuali.

bd07a9ad2cb27a06.png

Prerequisiti

  • Competenze di base di Java

In questo lab proverai a:

  • Aggiungere una mappa a un'app per Android.
  • Utilizza le autorizzazioni di accesso alla posizione per geolocalizzare l'utente.
  • Recupera i luoghi vicini alla posizione attuale dell'utente.
  • Mostra all'utente i luoghi più probabili per identificare la sua posizione attuale.

Cosa creerai

Crei la tua app per Android da zero, ma puoi scaricare il codice di esempio per il confronto durante il debug. Scarica il codice di esempio da GitHub oppure, se hai configurato Git per l'utilizzo della riga di comando, inserisci quanto segue:

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

Se riscontri problemi (bug del codice, errori grammaticali, formulazione poco chiara o altro) mentre segui questo codelab, segnala il problema tramite il link Segnala un errore nell'angolo in basso a sinistra del codelab.

2. Inizia

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 l'ultima versione facendo clic su Android Studio > Controlla aggiornamenti….

1f36bae83b64e33.png

Questo lab è stato scritto utilizzando Android Studio 3.4.

SDK Android

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

  1. Nella schermata di benvenuto di Android Studio, fai clic su Configura > SDK Manager.

d3fa03c269ec231c.png

  1. Seleziona la casella di controllo dell'SDK che preferisci e poi fai clic su Applica.

Se non hai ancora l'SDK, verrà avviato il download sulla tua macchina.

884e0aa1314f70d.png

Google Play Services

Dal gestore SDK, devi installare anche Google Play Services.

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

Aggiorna se lo stato indica Aggiornamento disponibile.

ad6211fd78f3b629.png

3. Preparare l'emulatore

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

Se utilizzi il tuo dispositivo, vai a Istruzioni per il dispositivo reale: aggiorna Google Play Services alla fine di questa pagina.

Aggiungere un emulatore

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

5dd2d14c9c56d3f9.png

Si aprirà 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 Play d5722488d80cd6be.png nella colonna Play Store e fai clic su Avanti.

e0248f1c6e85ab7c.png

Vedrai un insieme di immagini di sistema che puoi installare. Se il targeting Q Android 9+ (Google Play) include la parola Download, fai clic su Download.

316d0d1efabd9f24.png

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

Tornerai all'elenco dei tuoi dispositivi virtuali.

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

7605864ed27f77ea.png

Dopo qualche istante, l'emulatore si apre.

Istruzioni per l'emulatore: aggiorna Google Play Services

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

2e1156e02643d018.png

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 account o crearne uno nuovo senza costi per mantenere i test separati dalle tue informazioni personali.

Si apre Google Play con 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 configurazione dell'account e aggiungere un'opzione di pagamento, fai clic su Salta.

Impostare la posizione nell'emulatore

  1. Una volta avviato l'emulatore, digita "maps" nella barra di ricerca della schermata Home per visualizzare l'icona dell'app Google Maps.

2d996aadd53685a6.png

  1. Fai clic sull'icona per avviare.

Viene visualizzata una mappa predefinita.

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

Ti viene chiesto di concedere allo smartphone le autorizzazioni per utilizzare la posizione.

f2b68044eabca151.png

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

Inserisci quello che vuoi, ma assicurati che sia in una zona con molti luoghi.

(Utilizza la latitudine 20.7818 e la longitudine -156.4624 per la città di Kihei a Maui, nelle Hawaii, per replicare i risultati di questo codelab.)

  1. Fai clic su Invia e la mappa si aggiorna con questa posizione.

f9576b35218f4187.png

Ora puoi eseguire l'app e testarla con la posizione.

Istruzioni per il dispositivo reale: 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 Altri dettagli.

Se disponibile, fai clic su Aggiorna.

ad16cdb975b5c3f7.png baf0379ef8a9c88c.png

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

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

c9c80aa8211a8761.png

Si apre la finestra di dialogo Configura il progetto. Qui puoi dare un nome alla tua app e creare il pacchetto in base al tuo dominio.

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

37f5b93b94ee118c.png

  1. Scegli Java come linguaggio e seleziona Usa artefatti androidx*.

Mantieni i valori predefiniti per le altre impostazioni.

  1. Fai clic su Fine.

5. Aggiungere le 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 Activity Recognition di Google Play Services. Per ulteriori informazioni sull'aggiunta di questa e di altre API di Google Play Services, consulta Configurare Google Play Services.

I progetti Android Studio in genere hanno due file build.gradle. Uno è per il progetto complessivo e l'altro per l'app. Se hai l'esploratore di progetti di Android Studio nella visualizzazione Android, li vedi entrambi nella cartella Gradle Scripts. Devi modificare il file build.gradle (Module: app) per aggiungere i servizi Google.

f3043429cf719c47.png

  1. Aggiungi due righe alla sezione dependencies per aggiungere i servizi Google per la posizione 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. Attivare le API di Google Maps Platform e ottenere una chiave API

Per il seguente passaggio di attivazione , devi abilitare Maps SDK for 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 Guida introduttiva a Google Maps Platform per creare un account di fatturazione e un progetto.

  1. Nella console Cloud, 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 i passaggi descritti in questo video o in questa documentazione.
  2. Genera una chiave API nella pagina Credenziali di Cloud Console. Puoi seguire i passaggi descritti in questo video o in questa documentazione. Tutte le richieste a Google Maps Platform richiedono una chiave API.

Copia la chiave API che hai appena creato. Torna ad Android Studio e trova il file google_maps_api.xml in Android > app > res > values.

Sostituisci YOUR_KEY_HERE con la chiave API che hai copiato.

aa576e551a7a1009.png

La tua app è ora configurata.

7. Modificare il file di layout

  1. Nell'explorer del progetto, apri il file activity_maps.xml in Android > app > res > layout.

4e0d986480c57efa.png

  1. Vedrai l'interfaccia utente di base aprirsi a destra dello schermo, con le schede in basso che ti consentono di selezionare l'editor di progettazione o di testo per il 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, l'interfaccia utente avrà questo aspetto:

1bf786808a4697ce.png

8. Configurare la barra delle app

Per fornire all'utente un pulsante su cui fare clic quando vuole scegliere il luogo in cui si trova, aggiungi una barra delle app con un'icona che trova il luogo in cui si trova l'utente e mostra i luoghi nelle vicinanze più probabili. L'aspetto sarà simile al seguente:

3a17c92b613a26c5.png

Su uno smartphone viene visualizzata solo l'icona. Su un tablet con più spazio, è incluso anche il testo.

Crea l'icona

  1. In Esplora progetti, fai clic su Android > app, poi fai clic con il tasto destro del mouse sulla cartella res e seleziona Nuovo > Risorsa immagine.

Si apre Asset Studio.

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

Si apre la finestra Seleziona icona.

  1. Scegli un'icona.

Puoi utilizzare la barra di ricerca per trovare icone correlate alla tua intenzione.

  1. Cerca location e scegli un'icona correlata alla posizione.

L'icona La mia posizione è la stessa utilizzata nell'app Google Maps quando un utente vuole centrare la videocamera sulla sua posizione attuale.

  1. Fai clic su Ok > Avanti > Fine e verifica che sia presente una nuova cartella denominata drawable che contiene i nuovi file delle icone.

b9e0196137ed18ae.png

Aggiungere risorse stringa

  1. In Esplora progetti, 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>:

strings.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 delle app quando c'è spazio per includere un'etichetta di testo accanto all'icona. Gli altri vengono utilizzati per i marcatori che aggiungi alla mappa.

Ora il codice nel file ha un aspetto simile al seguente:

<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 delle app

  1. In Esplora progetti, fai clic su Android > app, quindi fai clic con il tasto 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 tasto 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>

Aggiornare lo stile della barra delle app

  1. In Esplora progetti, espandi Android > app > res > values e apri il file styles.xml al suo interno.
  2. Nel tag <style>, modifica la proprietà principale in "Theme.AppCompat.NoActionBar".
  3. Prendi nota della 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 @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 a programmare.

9. Inizializzare l'app

  1. In Esplora progetti, 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 si aprirà l'editor di codice Java.

Importa Places SDK 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 di 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 della compatibilità con le versioni precedenti, pertanto devi definirla per estendere AppCompatActivity. Sostituisce l'estensione FragmentActivity definita per impostazione predefinita per un'attività di Maps.

public class MapsActivity extends AppCompatActivity implements OnMapReadyCallback {

Aggiungere variabili della classe

Successivamente, dichiara le varie variabili di classe utilizzate in diversi metodi di classe. Sono inclusi gli elementi dell'interfaccia utente e i codici di stato. Questi devono trovarsi 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 utente di runtime per i servizi di localizzazione, configurare gli elementi dell'interfaccia utente e creare il client dell'API Places.

Aggiungi le seguenti righe di codice relative alla barra degli strumenti delle azioni, alla configurazione delle visualizzazioni e al 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 aggiungono il menu della barra delle app (con un solo elemento, l'icona Scegli luogo) e gestiscono il clic dell'utente sull'icona.

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. In Android Studio, fai clic su Esegui o Menu Esegui > Esegui "app".

28bea91c68c36fb2.png

  1. Ti viene chiesto di selezionare la destinazione di implementazione. L'emulatore in esecuzione dovrebbe essere visualizzato in questo elenco. Selezionalo e Android Studio esegue il deployment dell'app nell'emulatore.

f44658ca91f6f41a.png

Dopo qualche istante, l'app viene avviata. Vedi la mappa centrata su Sydney, in Australia, con il singolo pulsante e l'elenco dei luoghi non popolati.

68eb8c70f4748350.png

La mappa non si sposta sulla posizione dell'utente, a meno che tu non richieda l'autorizzazione per accedere alla posizione del dispositivo.

10. Richiedere e gestire le autorizzazioni di accesso alla posizione

Richiedere le autorizzazioni di accesso alla posizione dopo che la mappa è pronta

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

Incolla questo codice sotto il metodo onOptionsSelected 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 dello zoom e richiedere le autorizzazioni di localizzazione all'utente.

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 delle autorizzazioni richieste

Quando l'utente risponde alla finestra di dialogo di richiesta di autorizzazione, questo 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. Recuperare la posizione attuale e i luoghi più probabili

Quando l'utente fa clic su Scegli luogo nella barra delle 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 l'ultima posizione del dispositivo.

Chiama l'API findCurrentPlace e gestisci la risposta

getCurrentPlaceLikelihoods crea un findCurrentPlaceRequest e chiama l'attività findCurrentPlace dell'API Places. Se l'attività ha esito positivo, restituisce un findCurrentPlaceResponse, che contiene un elenco di oggetti placeLikelihood. Ognuna di queste 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 del luogo da placeLikelihoods.

Questo codice scorre le cinque località più probabili e aggiunge quelle con una probabilità maggiore di 0 a un elenco che poi esegue il rendering. Se vuoi visualizzare 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 videocamera della mappa nella posizione corrente del dispositivo

Se l'utente concede l'autorizzazione, l'app recupera l'ultima posizione dell'utente e sposta la videocamera in modo che sia centrata su quella posizione.

Se l'utente nega l'autorizzazione, l'app sposta semplicemente la videocamera nella posizione predefinita definita tra le costanti all'inizio di questa pagina (nel codice di esempio, è 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());
        }
    }

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

Quando l'utente tocca Scegli luogo, questo metodo verifica le autorizzazioni di accesso alla posizione e chiede all'utente l'autorizzazione se non è stata concessa.

Se l'utente ha concesso l'autorizzazione, il metodo chiama getDeviceLocation per avviare il processo di recupero dei luoghi probabili attuali.

  1. Aggiungi questo metodo dopo 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 pickCurrentPlace è definito, trova la riga in onOptionsItemSelected() che chiama pickCurrentPlace e rimuovi 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 ora e tocchi Scegli luogo, dovrebbe richiedere le autorizzazioni di accesso alla posizione.

  • Se concedi l'autorizzazione, la preferenza viene salvata e non ti verrà più chiesto. Se neghi l'autorizzazione, ti verrà chiesto di nuovo la prossima volta che toccherai il pulsante.
  • Anche se getPlaceLikelihoods ha recuperato i luoghi attuali probabili, ListView non li visualizza ancora. In Android Studio, puoi fare clic su ⌘6 per controllare i log in Logcat per le istruzioni taggate MapsActivity per verificare che i nuovi metodi funzionino correttamente.
  • Se hai concesso l'autorizzazione, i log includono una dichiarazione per Latitude: e una per Longitude: che mostra la posizione rilevata del dispositivo. Se in precedenza hai utilizzato Google Maps e il menu esteso dell'emulatore per specificare una posizione per l'emulatore, queste istruzioni mostrano la posizione.
  • Se la chiamata a findCurrentPlace ha avuto esito positivo, i log includono cinque istruzioni che stampano i nomi e le posizioni dei cinque luoghi più probabili.

d9896a245b81bf3.png

12. Compilare il selettore Luogo attuale

Configurare un gestore per i luoghi selezionati

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

Incolla questo gestore di 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));
        }
    };

Popolare ListView

Ora che hai l'elenco dei luoghi più probabili che l'utente sta visitando, puoi presentare queste opzioni all'utente in ListView. Puoi anche impostare il listener di clic ListView in modo che utilizzi il gestore dei clic appena definito.

Incolla questo metodo dopo il gestore di clic:

MapsActivity.java fillPlacesList()

    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 fillPlacesList è definito, trova la riga verso la fine di findPlaceLikelihoods che chiama fillPlacesList e rimuovi il commento.

MapsActivity.java fillPlaceLikelihoods()

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

Questo è tutto il codice necessario per il selettore di luogo corrente.

13. Esegui l'app

Testare la scelta di un luogo

  1. Esegui di nuovo l'app.

Questa volta, quando tocchi Scegli luogo, l'app compila l'elenco con i luoghi denominati vicini alla posizione. Vicino a questa località di Maui si trovano luoghi come Ululani's Hawaiian Shave Ice e Sugar Beach Bake Shop. Poiché i vari luoghi sono molto vicini alle coordinate della posizione, questo è un elenco di luoghi probabili in cui potresti trovarti.

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

Dovresti vedere un indicatore aggiunto alla mappa.

  1. Tocca il pennarello.

Puoi visualizzare i dettagli del luogo.

e52303cc0de6a513.png 864c74342fb52a01.png

Testare una posizione diversa

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

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

  1. Apri Google Maps.
  2. Tocca > Posizione per modificare la latitudine e la longitudine con nuove coordinate, quindi tocca Invia.
  3. Ad esempio, puoi utilizzare Latitudine: 49.2768 e Longitudine: -123.1142 per impostare la posizione nel centro di Vancouver, in Canada.
  4. Verifica che Google Maps sia stato ricentrato sulle nuove coordinate. Potresti dover toccare il pulsante La mia posizione nell'app Google Maps per richiedere il ricentramento.
  5. Torna all'app Current Place e tocca Scegli luogo per visualizzare la mappa con le nuove coordinate e un nuovo elenco di luoghi attuali probabili.

9adb99d1ce25c184.png

È tutto. Hai creato un'app semplice che controlla i luoghi nella posizione attuale e ti indica la probabilità che tu ti trovi in uno di questi. Buon divertimento!

Ora esegui l'app con le modifiche apportate per completare questo passaggio del bonus.

14. Passaggi successivi

Per evitare il furto della tua chiave API, devi proteggerla in modo che solo la tua app per Android possa utilizzarla. Se non viene limitata, chiunque abbia la tua chiave potrebbe utilizzarla per chiamare le API Google Maps Platform e farti addebitare dei costi.

Ottenere il certificato SHA-1

Ti servirà 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 seguente comando:

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

Dovresti visualizzare un output simile a questo:

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 con SHA1 contiene l'impronta SHA-1 del certificato. L'impronta è la sequenza di 20 numeri esadecimali a due cifre separati da due punti.

Quando l'app è pronta per la release, segui le istruzioni riportate in questa documentazione per recuperare il certificato di rilascio.

Aggiungere limitazioni alla chiave API

  1. Nella console Cloud, vai ad API e servizi > Credenziali.

La chiave che hai utilizzato per questa app dovrebbe 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 della chiave, imposta le Restrizioni delle applicazioni procedendo nel seguente modo:
  2. Seleziona App per Android e segui le istruzioni.
  3. Fai clic su Aggiungi un elemento.
  4. Inserisci il nome del pacchetto e l'impronta del certificato SHA-1 (recuperati 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 delle API procedendo nel seguente modo.
  2. Dopo le restrizioni delle API, scegli Limita chiave.
  3. Seleziona Maps SDK for Android e l'API Places.
  4. Fai clic su Fine e su Salva.

15. Complimenti

Hai creato un'app semplice che controlla i luoghi più probabili nella posizione attuale e aggiunge un indicatore sulla mappa per il luogo selezionato dall'utente.

Scopri di più