Spotted a bug? Have a great idea? Help us make google.dev great!

Learn how to use the Google Maps Platform Maps and Places SDKs for Android to present the user with a list of possible Places to identify their current location.

What you'll learn

  • How to add a map to an Android app
  • How to use location permissions to geolocate the user
  • How to fetch Places near the user's current location
  • How to present likely Places to the user for identifying their current place

What you'll need

  • Basic understanding of Java
  • You'll build your Android app from scratch, but you can download the sample code for comparison when debugging

Download sample code or if you already have git set up for command line use on your machine, use

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

Before you begin coding, there are a few prerequisites that you'll need to set up.

Android Studio

Android Studio may be downloaded from https://developer.android.com/studio.

If you already have Android Studio, make sure you have the latest version by clicking in the Android Studio menu and selecting "Check for Updates..."

This lab was written using Android Studio 3.4.

Android SDK

In Android Studio, you can configure your desired SDKs using the SDK Manager. This lab uses the Android Q SDK.

From the Android Studio Welcome Screen, click the Configure drop-down at the bottom and select "SDK Manager".

Select your desired SDK, and click "Apply". If you don't have the SDK yet, this will initiate downloading of the SDK to your machine.

Google Play Services

From the SDK manager, you'll also need to install Google Play services. Click to the ‘SDK Tools' tab and make sure "Google Play services" is checkmarked and update if the status says "Update available".

To run the app, you can connect your own device or use the Android Emulator. If using your own device, skip to the "Real device instructions: Update Google Play Services" section at the bottom of this page.

Add an emulator

  1. From the Android Studio welcome screen, go to the Configure drop-down menu, then select ‘AVD Manager'.
  2. This brings you to the Android Virtual Device Manager. At the bottom of this dialog, there is a ‘Create Virtual Device..' button. Select it.
  3. You'll then be given a set of devices you can pick. Select one with the Play icon under the "Play Store" column and click ‘Next.
  4. You'll see a set of System Images that you can install. If ‘Q' targeting Android 9.+ (with Google Play) has the word Download next to it, click the word to download it.
  5. Press Next to give your Virtual Device a name, and then click Finish.
  6. You'll be returned to the list of Your Virtual Devices. On this, click the ‘Start' button beside your new device:

After a few moments, the emulator will open.

Emulator instructions: Update Google Play services

Once the emulator launches, on the right hand side of the emulator, there is an action bar of emulator controls.

  1. At the bottom of this bar, you'll see a ‘...' button. Select it.
  2. This will open the extended controls dialog, and one of the options in the menu will be Google Play. Click that, and if the Google Play services version has an "Update" button under it, click "Update".
  3. You will need to sign in to the emulator with any Google account. You can use your own or create a new account for free to keep your testing separate from your personal information.
  4. When you are through signing in to the emulator, you will see a Google Play screen with the Google Play services screen. Click the UPDATE button to get the latest version of Google Play services.
  5. If asked to complete your account setup and add a payment option, choose SKIP at the bottom.

Set location in the emulator

Follow the steps below to set the device location to a latitude and longitude of your choosing:

  1. Once the emulator launches, tap in the search bar on the home screen and type "maps" to pull up the Google Maps app icon. Tap it to launch it.
  2. You'll see a default map. At the bottom right of the map, you'll see the "My Location" button. Press this, and you'll be asked to give the phone permissions to use location.
  3. To the right of the emulator, use the "..." button again to open the Extended Controls menu. Click the "Location" tab on the left side menu.
  4. On the right hand side of this, you can enter a Latitude and Longitude. Enter anything you like here, but make sure it's in an area with plenty of places. For example, use Latitude 20.7818 and Longitude -156.4624 for the town of Kihei on Maui in Hawaii to replicate the results from this lab.
  5. Once you're done, press ‘Send', and the map will update with this location.

You're now ready to run your app and test it with location. Skip to the next step.

Real device instructions: Update Google Play Services

If you're using a real Android device, use the search bar on your home screen to search for "Google Play services" and tap on the icon for Google Play services, then click "More Details". If there is an UPDATE button on the app details screen, click it.

  1. Back at the Welcome to Android Studio screen, choose "Start a new Android Studio project" and choose "Google Maps Activity" for the Phone and Tablet tab.
  2. You'll see the ‘Configure your project" dialog. Here is where you name your app and create the package based on your domain. Here are the settings for an app called Current Place, which corresponds to the package com.google.codelab.currentplace.
  3. Choose Java as the language, checkmark "Use androidx.* artifacts", and keep the defaults for the rest of the settings, and press ‘Finish'.

To access location permissions in Android, you'll need Google Location and Activity Recognition API from Google Play Services. You can see the latest guidance for adding this and other Play Services APIs on the Set Up Google Play Services page.

Android Studio projects typically have 2 build.gradle files. One is for the overall project, and one is for the app. If you have the Android Studio Project explorer in ‘Android' view, you'll see both of them in the ‘Gradle Scripts' folder. You'll need to edit the Gradle Scripts > build.gradle (Module: app) file to add Google services.

Open it, and edit it:

  1. Add two compileOptions to the android section since our code will use Java 8 language features (sample code in context)
  2. Add two lines to the dependencies section to add Google services for location and the Places API (sample code in context)

build.gradle (Module: app)

apply plugin: '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'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

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'
}

This section explains how to authenticate your app to the Maps JavaScript API and Places API using your own API key.

Go to the Google Cloud Platform Console.

Create a new project.

Enable Billing

When you create a new project, you're prompted to choose which of your billing accounts you want to link to the project. If you have a single billing account, that account is automatically linked to your project. If you don't have a billing account, you must create one and enable billing for your project before you can use many Google Cloud Platform features.

To create a new billing account:

  1. Open the Google Cloud Platform Console navigation menu and select Billing.
  2. Click the Add billing account button. (If this is not your first billing account, click the Create account button)
  3. Enter the name of the billing account and enter your billing information. The options you see depend on the country of your billing address. Note that for United States accounts, you cannot change tax status after the account is created.
  4. Click Submit and enable billing.
  5. By default, the person who creates the billing account is a billing administrator for the account.
  6. For information about verifying bank accounts and adding backup methods of payment, see Add, remove, or update a payment method.

Get an API key

Follow these steps to enable the APIs used in this lab and get an API key:

  1. From the Navigation menu, select APIs & Services > Library.
  2. Click the Maps SDK for Android tile and click the Enable button.
  3. Repeat steps 3 and 4 to enable the Places API.
  4. From the Navigation menu, select APIs & Services > Credentials.
  5. Click Create Credentials and choose API key.
  6. You will see an API key that has been generated. Copy that key.
  7. Back in Android Studio, find the file google_maps_api.xml under Android > app > res > values and paste the API key to replace the text "YOUR_KEY_HERE".

Your app is now configured. In the next step you'll edit the layout file containing your UI.

In your project explorer, open the activity_maps.xml file in the Android > app > res > layout folder:

You'll see the basic UI open on the right of the screen, and there'll be tabs at the bottom allowing you to select the Design or Text editor for your layout. Select ‘Text', and then replace the entire contents of the layout file with this:

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">
    </androidx.appcompat.widget.Toolbar>

    <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"></ListView>
    </LinearLayout>

</LinearLayout>

This will give you a user interface that looks like this:

To give the user a button to click when they want to pick their current place, add an app bar with an icon that finds the user's current place and displays nearby likely places. It will look like this (on a phone, only the icon is shown. On a tablet with more space, the text is also included):

Create the icon

In the project explorer, right-click on the Android > app > res folder and select New > Image Asset. The Asset Studio will open.

  1. Next to Icon Type, choose "Action Bar and Tab Icons".
  2. Name your asset ic_geolocate.
  3. Make sure the Asset Type is "Clip Art" and click on the graphic next to the Clip Art: label. This will open the "Select Icon" window and provide you with a variety of choices for your icon. You can use the search bar to find icons related to your intent.
  4. In this case, we search for "location" and pick a location-related icon. The "my location" icon is the same as the one used in the Google Maps app for when a user wants to snap the camera to their current location.
  5. Click OK, Next, and Finish and confirm there is a new folder res > drawable that contains your new icon files.

Add string resources

In the project explorer, expand the Android > app > res > values folder and open the file strings.xml inside.

Add three new lines; the first will be used in your app bar when there is space to include a text label next to the icon. The others will be used for markers that you add to the map.

strings.xml

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

Add the app bar

In the project explorer, right-click on the Android > app > res folder and select New > Directory to create a new subdirectory under app/src/main/res. Name the directory menu.

Right-click on your new res > menu folder and select New > File. Name the file menu.xml.

Paste in this code:

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>

Update the app bar style

In the project explorer, expand the Android > app > res > values folder and open the file styles.xml inside.

In the <style> tag edit the parent property to be "Theme.AppCompat.NoActionBar". Note the "name" property as well; you will use this in the next step.

styles.xml

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

Update the app theme in AndroidManifest.xml

Expand the Android > app > manifests folder and open the file AndroidManifest.xml inside.

Find the android:theme line and edit or confirm the value to be @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">

You're now ready to begin coding!

In your project explorer find the MapsActivity.java file. It will be in the folder corresponding to the package that you created for your app in step 1.

Open it, and you'll be in the Java Code editor.

Import the Places SDK and other dependencies

Add these lines at the top of MapsActivity.java, replacing the existing import statements. They include the existing imports and add many more that will be used in the code in this lab.

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.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;

Update the class signature

The Places API uses AndroidX components for backwards-compatible support, so you need to define it to extend the AppCompatActivity. It will replace the FragmentActivity extension that is defined by default for a Maps Activity.

public class MapsActivity extends AppCompatActivity implements OnMapReadyCallback {

Add class variables

Next, declare the various class variables that will be used in different class methods. These include the UI elements, and status codes. These should be just below the variable declaration for GoogleMap gMap.

    // 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;

Update the onCreate method

You'll need to update the onCreate method to handle setting up the UI elements, creating the Places API client and handling runtime user permissions for location services.

Add to the lines of code regarding the action toolbar, views setup, and Places client to the end of the existing onCreate() method.

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);
    }

Add code for your app bar menu

These two methods add the app bar menu (with a single item, the Pick Place icon) and handle the user click on the icon.

Copy these two methods into your file, after the onCreate method.

MapsActivity.java onCreateOptionsMenu() and 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);

        }
    }

Test it out

From Android Studio, press the ‘Run' button or Run menu > Run ‘app' to start the app running.

You'll be asked to select your deployment target -- the running emulator should appear on this list. Select it, and Android Studio will deploy the app to the emulator for you.

After a few moments, the app will launch, and you'll see the map centered on Sydney, Australia with the single button and unpopulated places list.

The focus of the map will not move to the user's location unless we request permission to access the device's location. The next step teaches how to request and handle location permissions.

Request location permissions after the map is ready

  1. Define a method called getLocationPermission that will request user permissions. Paste this code below the onOptionsSelected method you just created.

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. Add two lines to the end of the existing onMapReady method to enable zoom controls and request location permissions from the user.

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();

    }

Handle the result from requested permissions.

When the user responds to the request permission dialog, this callback will be called by Android.

Paste this code below the getLocationPermission() method:

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;
                }
            }
        }
    }

When the user taps on the "Pick Place" icon in the app bar, the app will call the method pickCurrentPlace() which calls the getDeviceLocation() method you defined earlier. The getDeviceLocation method calls a method getCurrentPlaceLikelihoods after retrieving the latest device location.

Call the findCurrentPlace API and handle the response

getCurrentPlaceLikelihoods constructs a findCurrentPlaceRequest and calls the Places API's findCurrentPlace task. If the task successfully returns a findCurrentPlaceResponse which contains a list of placeLikelihood objects. Each of these have a number of properties, including the name and address of the place, and the likelihood probability that you are in that place (a double value from 0 to 1). This method handles the response by constructing lists of place details from the placeLikelihoods.

This code will iterate through the five most likely places, and add ones with a likelihood > 0 to a list which it will then render. If you would like to display more or fewer than five, edit the M_MAX_ENTRIES constant.

Paste this code below the onMapReady method.

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 : String.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());
                            }
                        }
                    }
                });
    }

Move the map camera to the device's current location

If the user grants permission, the app fetches the user's latest location and moves the camera to center around that location.

If the user denies permission, the app simply moves the camera to the default location defined among the constants at the beginning of this page (in the sample code, it is Sydney, Australia).

Paste this code below the getPlaceLikelikhoods() method:

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());
        }
    }

Check for location permissions when the user clicks the Pick Place button

When the user taps the Pick Place button you created, this method checks for location permissions and re-prompts for permission if the user has not yet granted permission.

If the user has granted permission, then the method calls getDeviceLocation to initiate the process of getting the current likely places.

  1. Add this method below 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. Now that pickCurrentPlace is defined, find the line in onOptionsItemSelected() that calls pickCurrentPlace and un-comment it.

MapsActivity.java onOptionItemSelected()

           case R.id.action_geolocate:

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

Test it out

If you run the app now and tap the Pick Place button that you created, it should prompt for location permissions.

  • If you allow permission, that preference will be saved and you will not get re-prompted. If you deny permission, you will get re-prompted the next time you press the button.
  • Although getPlaceLikelihoods has fetched the likely current places, the ListView does not display them yet. In Android Studio, you can press ⌘-6 to check the logs in Logcat for statements tagged "MapsActivity" to verify that your new methods are working properly.
  • If you granted permission, the logs will include a statement for "Latitude:" and a statement for "Longitude:" showing the detected location of the device. If you used Google Maps and the emulator's extended menu earlier to specify a location for the emulator, these statements should show that location.
  • If the call to findCurrentPlace was successful, the logs will include five statements printing the names and locations of the five most likely places.

Set up a handler for picked places

Let's think about what we want to happen when the user clicks an item in the ListView. To confirm the use's choice of which place they are currently at, we can add a marker to the map at that place. If the user clicks that marker, an InfoWindow will pop up displaying the place name and address.

Paste this click handler below the pickCurrentPlace method.

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));
        }
    };

Populate the ListView

  1. Now that we have our list of most likely places that the user is currently visiting, we can present those options to the user in the ListView. We can also set the ListView's click listener to use the click handler we just defined above.

    Paste this method below the click handler:

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);
    }
  1. Now that fillPlacesList is defined, find the line toward the end of findPlaceLikelihoods that calls fillPlacesList and un-comment it.

MapsActivity.java fillPlaceLikelihoods()

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

That is all the code needed for the place picker!

Test picking a place

Run the app again. This time when you press the ‘Pick Place' button that you created, the app will now populate the list with named places close to the location. Close to this location on Maui are places like Ululani's Hawaiian Shave Ice and Sugar Beach Bake Shop. Because the several places are very close to the location coordinates, this is a list of likely places you may be in.

When you click on a place name in the ListView, you should see a marker added to the map. If you tap the marker, you can see place details.

Test a different location

If you want to change your location and are using the emulator, the device location will not automatically update when you update the location coordinates in the emulator's extended menu. To get around this, follow the steps below to use the native Google Maps app to force updates to the emulator's location:

  1. Open the Google Maps application
  2. Use the extended menu (...) > Location screen to change the Latitude and Longitude to new coordinates and press Send. For example, you can use Latitude: 49.2768 and Longitude: -123.1142 to set the location to downtown Vancouver, Canada.
  3. Verify that the Google Maps application has recentered on your new coordinates. You may need to press the "My Location" button in the Google Maps app to request the recentering.
  4. Return to your Current Place app and click the "Pick Place" icon to get the map on the new coordinates and see a new list of likely current places.

And that's it! You've now built a simple app that checks for the places at the current location, and gives you a likelihood of which ones you're at. Enjoy!

You've now built a simple app that checks for the most likely places at the current location and adds a marker to the map for the place the user selects.

What we've covered

Next steps

What other codelabs would you like to see?

The Kotlin version of this Current Place Picker codelab The iOS version of this Current Place Picker codelab A codelab demonstrating Place Autocomplete in a mobile app

Is the codelab you want not listed above? Request it with a new issue here.

To prevent theft of your API key, secure it so only your Android app can use the key. If left unrestricted, anyone with your key could use it to call Google Maps Platform APIs and cause you to get billed.

Get your SHA-1 Certificate

You'll need this later when you restrict your API keys. Below are instructions for getting your debug certificates.

For Linux or macOS, open a terminal window and enter the following:

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

For Windows Vista and Windows 7, run:

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

You should see output similar to this:

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

The line that begins SHA1 contains the certificate's SHA-1 fingerprint. The fingerprint is the sequence of 20 two-digit hexadecimal numbers separated by colons.

When you are ready to release an app, use the instructions in our documentation to retrieve your release certificate.

Add restrictions to your API key

  1. In Google Cloud Console Navigation Menu, navigate to APIs & Services > Credentials.
  2. The key you used for this app should be listed under "API Keys". Click the pencil icon to edit the key settings.
  3. On the API key page, under Key restrictions, set the Application restrictions.
  • Select Android apps and follow the instructions.
  • Click ADD AN ITEM.
  • Enter your package name and SHA-1 certificate fingerprint (retrieved in the previous section). For example:
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. For further protection, set the API restrictions.
  • Under API restrictions, choose "Restrict key"
  • Select the Maps SDK for Android and Places API.
  1. Click Done and Save.