Using the New Google Places API for Android - Truiton
Skip to content

Using the New Google Places API for Android

Android Places API for Android

One of the most recent developments in the world of Android has been the release of Google Places API for Android. This new API gives us the full access to Google’s database for 100 million places. What’s great about this API is that, to receive data from Google, no XML, or Json parsing needs to be done on the client. All the request and response parsing is done by the Android Places API client itself. It gives us, many new convenience methods through which we can access places API data directly. All we need to do is, use an API key in the project.

The release of Android places API not only simplifies the data access but also spares the developers from keeping track of latitudes and longitudes. Earlier, to access place data in Android, one had to retrieve all the information from a web service by passing various parameters like latitudes and longitudes to it. The API used at that time was Google Maps API. But now thankfully, nothing of this sort needs to be done. As the new Android places API is powerful enough to detect your current location and retrieve all the place data automatically. Google Places API for Android includes six new features:

  1. Place Picker UI widget – A great new UI control, which gives the flexibility of selecting a place from nearby places.
  2. Current Place – An API method though which nearby places can be retrieved.
  3. Place Autocomplete – An API method, designed to give suggestions in the AutocompleteTextView.
  4. Place Add – An API method for adding places in the Google Places database.
  5. Place Report – An API method for reviewing places by creating a place report.
  6. Place Details – One of the most basic methods, used to retrieve place details by its ID.

Although discussing all of them in a single article would not be possible. Therefore we will be discussing only some of the important features of Android Places API here. But before starting, lets add Google play services and generate an API key first:

Add this in dependencies section:

compile 'com.google.android.gms:play-services:8.4.0'

Add this in application tag of your manifest :

<meta-data
            android:name="com.google.android.gms.version"
            android:value="@integer/google_play_services_version"/>

Add these permissions in the manifest:

<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

For more details please refer to this setting up play services page. Next lets have a look at the steps to generate Places API for Android key:

  1. Create a project in Google Developers console or use an existing one.
  2. Navigate to “APIs & Auth” section, select APIs.
  3. Search and select “Places API for Android”.
  4. Enable it.
  5. Then go to the credentials section.
  6. Create a key for Android application.
  7. Enter your SHA1 fingerprint with package name in the desired format. Use this SHA1 fingerprint tutorial to get your fingerprint.
  8. Paste the API key in a meta tag under the application tag of your Android Manifest as shown below.
<meta-data
    android:name="com.google.android.geo.API_KEY"
    android:value="{YOUR_API_KEY}"/>

Google Places API for Android : Place Picker

PlacePicker is a new UI widget introduced with Places API. This widget can greatly reduce the development efforts in a scenario where requirement is to select a nearby place. Android PlacePicker widget, displays a map and a list of nearby places. By this widget user can pick a place, whose details would be returned to the calling activity. Another great feature about PlacePicker is that, it allows the customization of its headers as well. For example if you have set the colorPrimary and colorPrimaryDark properties in the styles.xml. They would be inherited in the PlacePicker UI as-well, just to maintain consistency in the application flow.

To start, lets design a simple layout to launch PlacePicker and display the results:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:tools="http://schemas.android.com/tools"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:paddingLeft="@dimen/activity_horizontal_margin"
                android:paddingRight="@dimen/activity_horizontal_margin"
                android:paddingTop="@dimen/activity_vertical_margin"
                android:paddingBottom="@dimen/activity_vertical_margin"
                tools:context=".PlacePickerActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/textView"
        android:layout_alignParentTop="true"
        android:layout_marginTop="20dp"
        android:layout_centerHorizontal="true"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/textView2"
        android:layout_below="@+id/textView"
        android:layout_centerHorizontal="true"/>

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Launch Places API Picker"
        android:id="@+id/pickerButton"
        android:layout_below="@+id/textView2"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="50dp"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/textView3"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true"/>

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@+id/textView3"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true"
        android:id="@+id/poweredBy"
        android:src="@drawable/powered_by_google_light"/>

    <ImageView
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_marginBottom="-20dp"
        android:layout_above="@+id/poweredBy"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true"
        android:id="@+id/truiton_image"
        android:src="@mipmap/truiton_short_no_back"/>
</RelativeLayout>

Please note:

  • According to Google, when using PlacePicker UI to to pick a place, a powered by Google attribution image needs to be shown on the screen. Also if any third party attributions are present, they are also required to be shown as per these policies.
  • To use place picker UI widget, an API key is also required.

Next lets have a look at the main activity:

package com.truiton.placepicker;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.text.Html;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import com.google.android.gms.common.GooglePlayServicesNotAvailableException;
import com.google.android.gms.common.GooglePlayServicesRepairableException;
import com.google.android.gms.location.places.Place;
import com.google.android.gms.location.places.ui.PlacePicker;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.LatLngBounds;


public class PlacePickerActivity extends AppCompatActivity {
    private static final int PLACE_PICKER_REQUEST = 1;
    private TextView mName;
    private TextView mAddress;
    private TextView mAttributions;
    private static final LatLngBounds BOUNDS_MOUNTAIN_VIEW = new LatLngBounds(
            new LatLng(37.398160, -122.180831), new LatLng(37.430610, -121.972090));

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_place_picker);
        mName = (TextView) findViewById(R.id.textView);
        mAddress = (TextView) findViewById(R.id.textView2);
        mAttributions = (TextView) findViewById(R.id.textView3);
        Button pickerButton = (Button) findViewById(R.id.pickerButton);
        pickerButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    PlacePicker.IntentBuilder intentBuilder =
                            new PlacePicker.IntentBuilder();
                    intentBuilder.setLatLngBounds(BOUNDS_MOUNTAIN_VIEW);
                    Intent intent = intentBuilder.build(PlacePickerActivity.this);
                    startActivityForResult(intent, PLACE_PICKER_REQUEST);

                } catch (GooglePlayServicesRepairableException
                        | GooglePlayServicesNotAvailableException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    @Override
    protected void onActivityResult(int requestCode,
                                    int resultCode, Intent data) {

        if (requestCode == PLACE_PICKER_REQUEST
                && resultCode == Activity.RESULT_OK) {

            final Place place = PlacePicker.getPlace(this, data);
            final CharSequence name = place.getName();
            final CharSequence address = place.getAddress();
            String attributions = (String) place.getAttributions();
            if (attributions == null) {
                attributions = "";
            }

            mName.setText(name);
            mAddress.setText(address);
            mAttributions.setText(Html.fromHtml(attributions));

        } else {
            super.onActivityResult(requestCode, resultCode, data);
        }
    }

}

The above code fires an intent to launch PlacePicker widget, which returns the data for the selected place. A point to note here is that, bounds for place picker can be set through the setLatLngBounds method. As shown this method allows us to launch place picker for a specific area as well. Next, have a look at the Google Places API for Android, PlacePicker screenshots:

Source code for Android place picker widget example using Google Places API:

Source Code

Google Places API for Android : Current Place

PlaceDetectionApi.getCurrentPlace() is another useful API method introduced with this new Android places API. This API returns nearby places of the device. Android current place API, does not require you to explicitly define the location in the request. Place detection API, has the ability to detect your location automatically from your device and return the places nearby. This makes this API very fast and easy to implement. As with earlier Google Maps API’s, we had to detect our latitude, longitude and pass them as a parameter in the request.

The current place detection API is likely to return multiple current places in a PlaceLikelihoodBuffer list, of PlaceLikelihood objects. As its not possible at times to detect the exact location. A PlaceLikelihood object basically contains a probability of correctness, on a scale of 0 to 1.0 and the place data. Where 1 is being the most likely to be the current place. The Current place API for Android also requires a Google API hit. Therefore before making a request you may need to configure a Google API project for it. To generate an API key please refer to the steps above in the first section.

<meta-data
    android:name="com.google.android.geo.API_KEY"
    android:value="{YOUR_API_KEY}"/>

We already have the permissions defined in the manifest, hence lets move on to the main class:

package com.truiton.placesapi;

import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.PendingResult;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.location.places.PlaceLikelihood;
import com.google.android.gms.location.places.PlaceLikelihoodBuffer;
import com.google.android.gms.location.places.Places;


public class PlacesAPIActivity extends AppCompatActivity implements
        GoogleApiClient.OnConnectionFailedListener {
    private static final String LOG_TAG = "PlacesAPIActivity";
    private static final int GOOGLE_API_CLIENT_ID = 0;
    private GoogleApiClient mGoogleApiClient;
    private static final int PERMISSION_REQUEST_CODE = 100;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_places_api);
        Button currentButton = (Button) findViewById(R.id.currentButton);
        mGoogleApiClient = new GoogleApiClient.Builder(PlacesAPIActivity.this)
                .addApi(Places.PLACE_DETECTION_API)
                .enableAutoManage(this, GOOGLE_API_CLIENT_ID, this)
                .build();
        currentButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mGoogleApiClient.isConnected()) {
                    if (ContextCompat.checkSelfPermission(PlacesAPIActivity.this,
                            Manifest.permission.ACCESS_FINE_LOCATION)
                            != PackageManager.PERMISSION_GRANTED) {
                        ActivityCompat.requestPermissions(PlacesAPIActivity.this,
                                new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                                PERMISSION_REQUEST_CODE);
                    } else {
                        callPlaceDetectionApi();
                    }

                }
            }
        });
    }

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {
        Log.e(LOG_TAG, "Google Places API connection failed with error code: "
                + connectionResult.getErrorCode());

        Toast.makeText(this,
                "Google Places API connection failed with error code:" +
                        connectionResult.getErrorCode(),
                Toast.LENGTH_LONG).show();
    }

    @Override
    public void onRequestPermissionsResult(int requestCode,
                                           String permissions[], int[] grantResults) {
        switch (requestCode) {
            case PERMISSION_REQUEST_CODE:
                if (grantResults.length > 0
                        && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    callPlaceDetectionApi();
                }
                break;
        }
    }

    private void callPlaceDetectionApi() throws SecurityException {
        PendingResult<PlaceLikelihoodBuffer> result = Places.PlaceDetectionApi
                .getCurrentPlace(mGoogleApiClient, null);
        result.setResultCallback(new ResultCallback<PlaceLikelihoodBuffer>() {
            @Override
            public void onResult(PlaceLikelihoodBuffer likelyPlaces) {
                for (PlaceLikelihood placeLikelihood : likelyPlaces) {
                    Log.i(LOG_TAG, String.format("Place '%s' with " +
                                    "likelihood: %g",
                            placeLikelihood.getPlace().getName(),
                            placeLikelihood.getLikelihood()));
                }
                likelyPlaces.release();
            }
        });
    }
}

Also in the above piece of code you may observe, that its not that direct to request the current place. Now first you need to request the Manifest.permission.ACCESS_FINE_LOCATION permission from the user. If the permission is granted then we can go ahead and request the current place. Layout for Current place detection API:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:tools="http://schemas.android.com/tools"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:paddingLeft="@dimen/activity_horizontal_margin"
                android:paddingRight="@dimen/activity_horizontal_margin"
                android:paddingTop="@dimen/activity_vertical_margin"
                android:paddingBottom="@dimen/activity_vertical_margin"
                tools:context=".PlacesAPIActivity"
                android:id="@+id/main_layout">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Get Current Place"
        android:id="@+id/currentButton"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="50dp"/>

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true"
        android:id="@+id/poweredBy"
        android:src="@drawable/powered_by_google_light"/>

    <ImageView
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_marginBottom="-20dp"
        android:layout_above="@+id/poweredBy"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true"
        android:id="@+id/truiton_image"
        android:src="@mipmap/truiton_short_no_back"/>
</RelativeLayout>

It has a comparatively simple layout file as, this example prints all locations in the log. Also please don’t forget to add attributions according to these policies.

Android Places API Current Place

In the current place detection API above, you may have noticed that no HttpRequest code is present. This is the beauty of this new Android places API. All you need to do is create an object of GoogleApiClient and add Places.PLACE_DETECTION_API with enableAutoManage, and by using this you can make successful API calls. To fully understand the working have a look at the code sample repository:

Source Code

Conclusion

To conclude, I would like to say that Google Places API for Android is a new and improved version of previous maps API. As this new API provides direct integration with Android, which makes the development process very simple. Also a great feature which comes along with this API, is the themes integration for PlacePicker. This is some thing completely new in Android. This feature supports the usage of consistent user interfaces, giving a better user experience in the app. Hope this helped. Connect with us on Facebook, Google+ and Twitter for more updates.

37 thoughts on “Using the New Google Places API for Android”

  1. I got some error in XML Layout (android:src=”@mipmap/truiton_short_no_back”). Did you miss something to add here?
    Thanks 🙂

  2. Hi, I tried without API_KEY for Place Picker widget but it fails. Then tried with obtained API_KEY from Google account now it is working as expected. Any thoughts on this. I saw many more tutorials about Google Places starts with obtaining API_KEY. Kindly share your thoughts here. Thanks.

  3. Thanks for the article and insight! I’ve been trying to run this code but when I click the “Launch Places API Picker” button to open places, places will not open. Did you experience any issues like this?

  4. Hi, That was really helpful.
    But the particular Place picker UI flashes only for a few seconds & returns to the home.I’m unable to figure out the reason.Please could you help me out on this.

    Thanks in advance.

  5. It’s great tutorial but only one problem that is you should change meta tag in this format ” ” after this screen will not be disappear. Happy Coding.. 🙂

  6. Sir If can Sort out my problem ill be very happy, i have a data of lattitude and longitude i want to show it on map, as a small part in my layout , i want to use this new android place lib.. can you plz help me out how do i do that?

  7. Hey i am trying to use Places API for eclipse, i got your entire tutorial but about the build.gradle what do i do with that, as i am using eclipse with adt plugin it dose’nt have build.gradle, can you help me as to what should i do?

  8. Hey Great tutorial it works just fine!!!
    but can u plz suggest me is there a way to modify the search result…
    for example im just trying to make a app which should list nearby hospitals
    so is there a way to display only nearby hospitals in “Nearby Places” tab in place Picker
    and also in search bar it should list hospitals names
    plz reply asap thankyou

    1. hey i also have to implement same functionality i have read many blogs but till now i didn’t get any solution if you have any idea please suggest me thank you.

  9. I’m try to do this in a Fragment.
    Where it is asking for @NotNull Activity in the intentBuilder.build(), what do I put? And other places that need context?
    This is for the Place Picker.

      1. I have latitude and longitude, I want place details of that particular location. I want only one result for that location. How can I get the detail like Place name (eg xzy’s Pizza).

  10. hii, i want to say thankss ….and i want to ask thing..what i have to do if i need only particular kind of place like any restaurent any cafe etc…can u plz help…i love your blog.it really helpful..plzz ans me either on my mail or here.

  11. Great tutorial? I have only question.

    How can we show only coffe shop, or bank, but not show all of them in maps.

    Sorry for my bad english

    Thanks you

  12. Hey Mohit, thanks for the awesome tutorial!

    One problem ive got is the CurrentPlace apk. I copied and pasted 3 times the code from here and the code from gitHub into my Android Studio. When i start this APK, i see the “Get Current Place” Button and when i click on the button, NOTHING happens.. There is not even a error message in Android Studio or something.

    Tried it also on my mobile phone and same there.. when i click on the button, nothing happens, the app doesnt crash or the view doesnt change.

    Any ideas how to solve it?

  13. Very useful tutorial.

    I got everything as i needed, but i dont want to set the country and state name to autocompletetextview, how can i do that?

  14. The Place Picker doesn’t display the place the user selected. The map always displays the t longitude and latitude set but not the place the user has selected. How can we fix this?

  15. Just wanted to leave a comment: this is the only tutorial that was simple and actually worked for me. Everything else I’ve found is years old. Thank you so much!

  16. Thank you. it is very simple and helpful, moving ahead..can we customize the layouts for place picker screen or the search screen.

Leave a Reply

Your email address will not be published. Required fields are marked *