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:

Place Picker UI widget – A great new UI control, which gives the flexibility of selecting a place from nearby places. Current Place – An API method though which nearby places can be retrieved. Place Autocomplete – An API method, designed to give suggestions in the AutocompleteTextView. Place Add – An API method for adding places in the Google Places database. Place Report – An API method for reviewing places by creating a place report. 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:

Create a project in Google Developers console or use an existing one. Navigate to “APIs & Auth” section, select APIs. Search and select “Places API for Android”. Enable it. Then go to the credentials section. Create a key for Android application. Enter your SHA1 fingerprint with package name in the desired format. Use this SHA1 fingerprint tutorial to get your fingerprint. 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.

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.