Acerca de este codelab
1. Antes de comenzar
Aprende a usar Google Maps Platform y el SDK de Places para Android a fin de presentarles a tus usuarios una lista de lugares para identificar sus ubicaciones actuales.
Requisitos previos
- Habilidades básicas de Java
Actividades
- Agregarás un mapa a una app para Android.
- Usarás permisos de ubicación para localizar al usuario según su ubicación geográfica.
- Obtendrás lugares cerca de la ubicación actual del usuario.
- Presentarás lugares probables al usuario para identificar su ubicación actual.
Qué crearás
Crearás tu app para Android desde cero, pero puedes descargar el código de muestra para compararlo durante la depuración. Descarga el código de muestra de GitHub. Si tienes configurado Git para usarlo en la línea de comandos, ingresa lo siguiente:
git clone https://github.com/googlecodelabs/current-place-picker-android.git
Si encuentras algún problema (errores de código, errores gramaticales, palabras poco claras o algún otro inconveniente) mientras trabajas en este codelab, informa el problema a través del vínculo Informar un error, que se encuentra en la esquina inferior izquierda del codelab.
2. Comenzar
Antes de comenzar este codelab, debes configurar lo siguiente:
Android Studio
Descarga Android Studio de https://developer.android.com/studio.
Si ya tienes Android Studio, asegúrate de que sea la última versión. Para ello, haz clic en Android Studio > Check for Updates….
Para este lab, se utilizó Android Studio 3.4.
SDK de Android
En Android Studio, puedes configurar los SDK que desees usando SDK Manager. En este lab, se usa el SDK de Android Q.
- En la pantalla de bienvenida de Android Studio, haz clic en Configure > SDK Manager.
- Selecciona la casilla de verificación del SDK que desees y haz clic en Apply.
Si aún no tienes ese SDK, se iniciará la descarga de este en tu máquina.
Servicios de Google Play
También necesitas instalar los Servicios de Google Play desde SDK Manager.
- Haz clic en la pestaña SDK Tools y selecciona la casilla de verificación Google Play Services.
Si el estado dice Update available, instala la actualización.
3. Prepara el emulador
Para ejecutar la app, puedes conectar tu propio dispositivo o usar Android Emulator.
Si usas tu propio dispositivo, ve directamente a Instrucciones para dispositivos reales: Actualiza los Servicios de Google Play al final de esta página.
Agrega un emulador
- En la pantalla de bienvenida de Android Studio, haz clic en Configure > AVD Manager.
Se abrirá el diálogo Android Virtual Device Manager.
- Haz clic en Create Virtual Device… para abrir la lista de dispositivos que puedes elegir.
- Selecciona un dispositivo que tenga el ícono de Play
en la columna Play Store y haz clic en Next.
Verás un conjunto de imágenes del sistema que puedes instalar. Si la versión de Q orientada a Android 9 o una versión posterior (Google Play), tiene la palabra Download junto a ella, haz clic en esa palabra.
- Haz clic en Next para asignarle un nombre a tu dispositivo virtual y, luego, haz clic en Finish.
Vuelve a mostrarse la lista Your Virtual Devices.
- Haz clic en Start
junto al nuevo dispositivo:
Después de unos segundos, se abrirá el emulador.
Instrucciones del emulador: Actualiza los Servicios de Google Play
- Una vez que se inicie el emulador, haz clic en … en la barra de navegación que aparece**.**
Se abrirá el diálogo Extended controls.
- Haz clic en Google Play en el menú.
Si hay una actualización disponible, haz clic en Update.
- Accede al emulador con una Cuenta de Google.
Puedes usar tu propia cuenta o crear una nueva, de forma gratuita a fin de mantener las pruebas separadas de tu información personal.
A continuación, se abre Google Play en los Servicios de Google Play.
- Haz clic en Actualizar (Update) para obtener la versión más reciente de los Servicios de Google Play.
Si se te solicita completar la configuración de tu cuenta y agregar una opción de pago, haz clic en Omitir.
Configura la ubicación en el emulador
- Una vez que se inicie el emulador, escribe "maps" en la barra de búsqueda de la pantalla principal para acceder al ícono de la app de Google Maps.
- Haz clic en el ícono para abrir la app.
Verás un mapa predeterminado.
- En la parte inferior derecha del mapa, haz clic en Tu ubicación
.
Se te pedirá que le otorgues permiso al teléfono para usar la ubicación.
- Haz clic en … para abrir el menú Extended Controls.
- Haz clic en la pestaña Location.
- Ingresa una latitud y una longitud.
Escribe algo que quieras aquí, pero asegúrate de que se trate de un área con muchos lugares.
(Usa Latitude 20.7818 y Longitude -156.4624 para la ciudad de Kihei en Maui, Hawái, a fin de replicar los resultados de este codelab).
- Haz clic en Send, y el mapa se actualizará con esta ubicación.
Ya está todo listo para que ejecutes tu app y la pruebes con la ubicación.
Instrucciones para dispositivos reales: Actualiza los Servicios de Google Play
Si usas un dispositivo Android real, haz lo siguiente:
- Utiliza la barra de búsqueda de la pantalla principal para buscar y abrir los Servicios de Google Play (Google Play services).
- Haz clic en Más detalles.
Si está disponible, haz clic en Actualizar (Update).
4. Crea el shell de la app con una actividad en Google Maps
- En la pantalla de bienvenida de Android Studio, selecciona Start a new Android Studio project.
- En la pestaña Phone and Tablet, selecciona Google Maps Activity.
Se abre el diálogo Configure your project. Aquí le asignas un nombre a tu app y creas el paquete basado en tu dominio.
Esta es la configuración de una app llamada Current Place, que corresponde al paquete com.google.codelab.currentplace
.
- Elige Java como lenguaje y selecciona Use androidx. artifacts.*
Mantén los valores predeterminados para el resto de la configuración.
- Haz clic en Finish.
5. Agrega las dependencias de los Servicios de Google al archivo de compilación de Gradle
Para acceder a los permisos de ubicación en Android, necesitas las API de Google Location y Activity Recognition de los Servicios de Google Play. Para obtener más información sobre cómo agregar esta y otras API de los Servicios de Google Play, consulta Cómo configurar los Servicios de Google Play.
Los proyectos de Android Studio suelen tener dos archivos build.gradle
. Uno es para el proyecto en general y el otro es para la app. Si tienes el explorador de proyectos de Android Studio en la vista Android, verás ambos en la carpeta Gradle Scripts
. Debes editar el archivo build.gradle (Module: app)
para agregar los servicios de Google.
- Agrega dos líneas a la sección
dependencies
para agregar los servicios de Google correspondientes a la ubicación y la API de Places (código de muestra en contexto).
build.gradle (módulo: 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. Habilita las API de Google Maps Platform y obtén una clave de API
Para el paso siguiente, debes habilitar el SDK de Maps para Android y la API de Places.
Configura Google Maps Platform
Si todavía no tienes una cuenta de Google Cloud Platform y un proyecto con la facturación habilitada, consulta la guía Cómo comenzar a utilizar Google Maps Platform para crear una cuenta de facturación y un proyecto.
- En Cloud Console, haz clic en el menú desplegable del proyecto y selecciona el proyecto que deseas usar para este codelab.
- Habilita las API y los SDK de Google Maps Platform necesarios para este codelab en Google Cloud Marketplace. Para hacerlo, sigue los pasos que se indican en este video o esta documentación.
- Genera una clave de API en la página Credenciales de Cloud Console. Puedes seguir los pasos que se indican en este video o esta documentación. Todas las solicitudes a Google Maps Platform requieren una clave de API.
Copia la clave de API que acabas de crear. Vuelve a Android Studio y busca el archivo google_maps_api.xml
en Android > app > res > values.
Reemplaza YOUR_KEY_HERE
por la clave de API que copiaste.
Tu app ya está configurada.
7. Edita el archivo de diseño
- En el explorador de tu proyecto, abre el archivo
activity_maps.xml
en Android >app
>res
>layout
.
- La IU básica se encuentra a la derecha de la pantalla y tiene pestañas en la parte inferior que te permiten seleccionar el editor de diseño o texto para tu diseño. Selecciona Text y reemplaza todo el contenido del archivo de diseño por lo siguiente:
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>
Verás una interfaz de usuario similar a la siguiente:
8. Configura la barra de la aplicación
Si quieres darle al usuario un botón que pueda hacer clic para seleccionar su lugar actual, agrega una barra de la aplicación con un ícono que busque el lugar actual del usuario y muestre los lugares cercanos probables. Se verá de la siguiente forma:
En un teléfono, solo se muestra el ícono. En una tablet con más espacio, también se incluye el texto.
Crea el ícono
- En el explorador del proyecto, haz clic en Android > app. Luego, haz clic con el botón derecho en la carpeta res y selecciona New > Image Asset.
Se abrirá Asset Studio.
- En el menú Icon Type, haz clic en Action Bar and Tab Icons.
- Asigna un nombre al elemento
ic_geolocate
. - Selecciona Clip Art como el tipo de elemento**.**
- Haz clic en el gráfico junto a Clip Art.
Esta acción abre la ventana Select Icon.
- Selecciona un ícono.
Puedes usar la barra de búsqueda para encontrar íconos relacionados con tu intent.
- Busca
location
y elige un ícono relacionado con la ubicación.
El ícono my location es el mismo que se utiliza en la app de Google Maps cuando un usuario quiere ajustar la cámara a su ubicación actual.
- Haz clic en OK > Next > Finish y confirma que haya una nueva carpeta llamada
drawable
que contenga tus nuevos archivos de íconos.
Agrega recursos de strings
- En el explorador del proyecto, haz clic en Android > app > res > values, y abre el archivo
strings.xml
. - Agrega las siguientes líneas después de
<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 primera línea se usa en la barra de la aplicación cuando hay espacio para incluir una etiqueta de texto junto al ícono. Las demás se usan para los marcadores que agregues al mapa.
Ahora, el código del archivo tiene el siguiente aspecto:
<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>
Agrega la barra de la aplicación
- En el explorador del proyecto, haz clic en Android > app. Luego, haz clic con el botón derecho en la carpeta
res
y selecciona New > Directory para crear un nuevo subdirectorio enapp/src/main/res
. - Asígnale un nombre al directorio
menu
. - Haz clic con el botón derecho en la carpeta
menu
y selecciona New > File. - Asígnale un nombre al archivo
menu.xml
. - Pega el siguiente código:
menu.xml
<?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>
Actualiza el estilo de la barra de la aplicación
- En el explorador del proyecto, expande Android >
app
>res
>values
, y abre el archivostyles.xml
. - En la etiqueta
<style>
, edita la propiedad superior para que sea"Theme.AppCompat.NoActionBar"
. - Observa la propiedad
name
, que usarás en el paso siguiente.
styles.xml
<style name="AppTheme" parent="Theme.AppCompat.NoActionBar">
Actualiza el tema de la app en AndroidManifest.xml.
- Haz clic en Android >
app
>manifests
, y abre el archivoAndroidManifest.xml
. - Busca la línea
android:theme
y confirma que el valor sea@style/AppTheme
o, de lo contrario, edítalo para sea ese.
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">
Ya puedes empezar a programar.
9. Inicializa la app
- En el explorador del proyecto, busca el archivo
MapsActivity.java
.
Se encuentra en la carpeta correspondiente al paquete que creaste para tu app en el paso 1.
- Abre el archivo y estarás dentro del editor de código Java.
Importa el SDK de Places y otras dependencias
Agrega estas líneas en la parte superior de MapsActivity.java
, en reemplazo de las sentencias de importación existentes.
Incluyen las importaciones existentes y agregan muchas más del código que se usa en este 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;
Actualiza la firma de la clase
La API de Places usa componentes de AndroidX para brindar retrocompatibilidad, de modo que debes definir la clase para que extienda AppCompatActivity
. Reemplaza la extensión FragmentActivity
que se define de forma predeterminada para una actividad en Maps.
public class MapsActivity extends AppCompatActivity implements OnMapReadyCallback {
Agrega variables de clases
A continuación, declara las distintas variables de clase que se usan en diferentes métodos de clase. Incluyen los elementos de la IU y códigos de estado. Deben estar justo debajo de la declaración de variables de 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;
Actualiza el método onCreate
Debes actualizar el método onCreate
a fin de controlar los permisos del usuario durante el tiempo de ejecución para los servicios de ubicación, configurar los elementos de la IU y crear el cliente de la API de Places.
Agrega las siguientes líneas de código respecto de la barra de herramientas de acciones, la configuración de vistas y el cliente de Places al final del método onCreate()
existente.
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);
}
Agrega código para el menú de la barra de la aplicación
Estos dos métodos agregan el menú de la barra de la aplicación (con un solo elemento, el ícono de Elegir un lugar) y controlan el clic que haga el usuario en ese ícono.
Copia estos dos métodos en tu archivo después del método onCreate
.
MapsActivity.java onCreateOptionsMenu() y 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);
}
}
Pruébalo
- En Android Studio, haz clic en Run o Run menu > Run ‘app'.
- Se te pedirá que selecciones el objetivo de la implementación. El emulador en ejecución debería aparecer en esta lista. Selecciónalo, y Android Studio implementa la app en el emulador por ti.
Después de unos segundos, se abre la app. Verás el mapa centrado en Sídney, Australia, con un solo botón y la lista de lugares sin completar.
El enfoque del mapa no se mueve a la ubicación del usuario a menos que solicites permiso para acceder a la ubicación del dispositivo.
10. Solicita y controla los permisos de ubicación
Solicita permisos de ubicación una vez que esté listo el mapa
- Define un método llamado
getLocationPermission
que solicite los permisos del usuario.
Pega este código debajo del método onOptionsSelected
que acabas de crear.
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);
}
}
- Agrega dos líneas al final del método
onMapReady
existente para habilitar los controles de zoom y solicitar los permisos de ubicación del usuario.
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();
}
Controla el resultado de los permisos solicitados
Cuando el usuario responde el diálogo que le solicita el permiso, Android llama a esta devolución de llamada.
Pega este código después del método 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. Obtén la ubicación actual y recupera los lugares probables
Cuando el usuario hace clic en Elegir un lugar en la barra de la aplicación, la app llama al método pickCurrentPlace()
, el cual llama al método getDeviceLocation()
que definiste antes. El método getDeviceLocation
llama a otro método, getCurrentPlaceLikelihoods,
después de recuperar la ubicación más reciente del dispositivo.
Llama a la API de findCurrentPlace y controla la respuesta
getCurrentPlaceLikelihoods
construye una solicitud findCurrentPlaceRequest
y llama a la tarea findCurrentPlace
de la API de Places. Si la tarea se realiza correctamente, devuelve una respuesta findCurrentPlaceResponse
, que contiene una lista de objetos placeLikelihood
. Cada uno de ellos tiene una serie de propiedades, incluidos el nombre y la dirección del lugar, y el grado de probabilidad de que estés en ese lugar (un valor doble de 0 a 1). Este método controla la respuesta mediante la construcción de listas con los detalles de los lugares a partir de placeLikelihoods
.
Este código itera a través de los cinco lugares más probables y agrega los que tienen un valor de probabilidad mayor que 0 a una lista que luego renderiza. Si quieres mostrar una cantidad mayor o menor a cinco, edita la constante M_MAX_ENTRIES
.
Pega este código después del método 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());
}
}
}
});
}
Mueve la cámara del mapa a la ubicación actual del dispositivo
Si el usuario otorga el permiso, la app recuperará la ubicación más reciente del usuario y moverá la cámara para centrar el enfoque alrededor de esa ubicación.
Si el usuario rechaza el permiso, la app simplemente mueve la cámara a la ubicación predeterminada definida en las constantes que están al principio de esta página (en el código de muestra, es Sídney, Australia).
Pega este código después del método 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());
}
}
Comprueba los permisos de ubicación cuando el usuario hace clic en Elegir un lugar
Cuando el usuario presiona Elegir un lugar, este método busca los permisos de ubicación y, si el usuario todavía no concedió su permiso, se lo solicita.
Si ya lo hizo, entonces, el método llama a getDeviceLocation
a fin de iniciar el proceso para obtener los lugares actuales probables.
- Agrega este método después de
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();
}
}
- Ahora que
pickCurrentPlace
está definido, busca la línea enonOptionsItemSelected()
que llama apickCurrentPlace
, y quita el comentario.
MapsActivity.java onOptionItemSelected()
case R.id.action_geolocate:
// COMMENTED OUT UNTIL WE DEFINE THE METHOD
// Present the Current Place picker
pickCurrentPlace();
return true;
Pruébalo
Si ejecutas la app ahora y presionas Elegir un lugar, debería solicitarte los permisos de ubicación.
- Si concedes el permiso, se guardará esa preferencia y ya no recibirás ese mensaje. Si rechazas el permiso, aparecerá la próxima vez que presiones el botón.
- Aunque
getPlaceLikelihoods
recuperó los lugares actuales probables, aún no se muestran enListView
. En Android Studio, puedes hacer clic en ⌘6 para revisar los registros de Logcat sobre las sentencias etiquetadas como MapsActivity a fin de verificar que tus nuevos métodos funcionen correctamente. - Si otorgaste el permiso, los registros incluyen una sentencia para
Latitude:
y una paraLongitude:
, las cuales representan la ubicación detectada del dispositivo. Si usaste Google Maps y el menú ampliado del emulador antes para especificar una ubicación para el emulador, estas sentencias mostrarán esa ubicación. - Si la llamada a
findCurrentPlace
se realizó correctamente, los registros incluirán cinco sentencias que imprimen los nombres y las ubicaciones de los cinco lugares más probables.
12. Propaga los datos del selector de Current Place
Configura un controlador para los lugares seleccionados
Pensemos en lo que queremos que suceda cuando el usuario haga clic en un elemento de la ListView
. Para confirmar el lugar que el usuario eligió como aquel en el que se encuentra actualmente, puedes agregar un marcador al mapa en dicha ubicación. Si el usuario hace clic en el marcador, aparecerá una ventana emergente de información con el nombre y la dirección del lugar.
Pega este controlador de clics después del método 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));
}
};
Propaga los datos de la ListView
Ahora que tienes una lista de los lugares más probables para la ubicación actual del usuario, puedes mostrarle esas opciones en la ListView
. También puedes configurar el objeto de escucha de clics de ListView
para usar el controlador de clics que acabas de definir.
Pega este método después del controlador de clics:
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);
}
Ahora que fillPlacesList
está definido, busca la línea hacia el final de findPlaceLikelihoods
que llama a fillPlacesList
y elimina el comentario.
MapsActivity.java fillPlaceLikelihoods()
// COMMENTED OUT UNTIL WE DEFINE THE METHOD
// Populate the ListView
fillPlacesList();
Este es todo el código necesario para el selector de Current Place.
13. Ejecuta la app
Prueba seleccionar un lugar
- Vuelve a ejecutar la app.
Esta vez, cuando presionas Elegir un lugar, la app propaga los lugares detectados cerca de la ubicación para completar la lista. En los alrededores de esta ubicación en Maui, hay lugares como Ululani's Hawaiian Shave Ice y Sugar Beach Bake Shop. Debido a que hay varios lugares muy cerca de las coordenadas de la ubicación, esta es una lista de los posibles lugares en los que podrías encontrarte.
- Haz clic en el nombre de un lugar en
ListView
.
Deberías ver que se agregó un marcador al mapa.
- Presiona el marcador.
Puedes ver los detalles del lugar.
Prueba otra ubicación
Si quieres cambiar la ubicación y estás usando el emulador, la ubicación del dispositivo no se actualizará automáticamente cuando actualices las coordenadas de la ubicación en el menú extendido del emulador.
A fin de solucionar esto, sigue estos pasos para usar la app nativa de Google Maps y forzar las actualizaciones a la ubicación del emulador:
- Abre Google Maps.
- Presiona … > Location para cambiar la latitud y la longitud por coordenadas nuevas y, luego, presiona Send.
- Por ejemplo, puedes usar Latitude: 49.2768 y Longitude: -123.1142 para establecer la ubicación en el centro de Vancouver, Canadá.
- Verifica que Google Maps haya centrado el mapa según tus nuevas coordenadas. Es posible que debas presionar el botón Mi ubicación en la app de Google Maps para solicitar que vuelva a centrar el mapa.
- Regresa a tu app Current Place y presiona Elegir un lugar para obtener el mapa con las nuevas coordenadas y ver una lista nueva de los lugares posibles.
Eso es todo. Compilaste una aplicación simple que verifica los lugares correspondientes a tu ubicación actual y te muestra aquellos en los que es probable que te encuentres. ¡Disfrútala!
Ahora puedes ejecutar la app con las modificaciones que hiciste para completar este paso adicional.
14. Próximos pasos
Para evitar el robo de tu clave de API, debes protegerla de manera que solo tu app para Android pueda usarla. Si no le pones restricciones, cualquier persona que tenga tu clave podrá usarla para llamar a las API de Google Maps Platform y se facturará a tu cuenta.
Obtén tu certificado SHA-1
Lo necesitarás más adelante cuando restrinjas tus claves de API. El siguiente es un conjunto de instrucciones para obtener tu certificado de depuración.
En el caso de macOS o Linux, abre una ventana de la terminal y escribe lo siguiente:
keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android
Para Windows Vista y Windows 7, ejecuta el siguiente comando:
keytool -list -v -keystore "%USERPROFILE%\.android\debug.keystore" -alias androiddebugkey -storepass android -keypass android
Deberías ver un resultado similar a este:
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
En la línea que comienza con SHA1, se incluye la huella digital SHA-1 del certificado. La huella digital es una secuencia de 20 números hexadecimales de dos dígitos separados por dos puntos.
Cuando estés listo para lanzar una app, sigue las instrucciones de esta documentación a fin de recuperar tu certificado de lanzamiento.
Agrega restricciones a tu clave de API
- En Cloud Console, navega hasta API y servicios > Credenciales.
La clave que usaste para esta app debería aparecer en Claves de API.
- Haz clic en
para editar la configuración de la clave.
- En la página de claves de API, después de Restricciones de clave, configura las Restricciones de aplicaciones de la siguiente manera:
- Selecciona Apps de Android y sigue las instrucciones.
- Haz clic en Agregar un elemento.
- Ingresa el nombre de tu paquete y la huella digital del certificado SHA-1 (recuperada en la sección anterior).
Por ejemplo:
com.google.codelab.currentplace
BB:0D:AC:74:D3:21:E1:43:07:71:9B:62:90:AF:A1:66:6E:44:5D:75s
- Para obtener más protección, establece las Restricciones de API de la siguiente manera:
- Después Restricciones de API, selecciona Restringir clave.
- Selecciona el SDK de Maps para Android y la API de Places.
- Haz clic en Listo y, luego, en Guardar.
15. Felicitaciones
Compilaste una app simple que verifica los lugares más probables en la ubicación actual y agrega un marcador al mapa para el sitio que el usuario seleccione.
Más información
- Para acelerar tu desarrollo, aprovecha la Biblioteca de utilidades del SDK de Maps para Android. Estas utilidades hacen el trabajo pesado para algunas de las tareas más populares de las apps que usan Google Maps Platform.
- Si deseas ver más ejemplos de código, en los que se demuestran la mayoría de las funciones de los SDK de Google Maps Platform para Android, clona los repositorios correspondientes para obtener muestras del SDK de Maps para Android y demostraciones del SDK de Places para Android.
- Para obtener información sobre cómo controlar los permisos de ubicación triestado en Android Q, completa el codelab Cómo recibir actualizaciones de ubicación en Android con Kotlin.