Android Get current and Nearby Places Using Places SDK

The Google Play Services version of the Places SDK for Android (i.e. com.google.android.gms:play-services-places) is turned off on July 29, 2019. Now a new version of the Places SDK for Android is available which depends on AndroidX.

In this article, we will talk about how to get current and nearby places of user’s device using a new Google Places library and also how to implement it in google map.

The new version of the Places SDK for Android introduces new methods :

fetchPlace() : Fetches the details about a particular place.

fetchPhoto() : Fetches a photo. The photos service may cache the image data. If the requested photo does not exist in the cache then a network lookup will be performed.

findCurrentPlace() : Fetches the approximate current location of the user’s device. It returns a list of PlaceLikelihoods indicating places where the user’s device is most likely to be located.

findAutocompletePredictions() : It return place predictions in response to user search queries.

Adding the client library

In the dependencies section of your app-level build.gradle file, add a dependency for the new SDK client library, as shown below:

dependencies {
  implementation 'com.google.android.libraries.places:places:2.0.0'
}

Make sure that the minSdkVersion for your application project is 16 or higher

Initialize the new Places SDK client

Initialize the new Places SDK client as shown below:

// Add an import statement for the client library.
import com.google.android.libraries.places.api.Places;

...

// Initialize Places.
Places.initialize(getApplicationContext(), apiKey);

// Create a new Places client instance.
PlacesClient placesClient = Places.createClient(this);

Now let’s see how to implement this in an example project.

Creating New Project

1 .Create a new project in Android Studio from File ⇒ New Project and fill the project details.

Getting the API key

  • Go to Google API Console.
  • Create a new project and generate a new API key corresponding to your SHA1 and application package name.
  • To integrate google map and to access nearby places in your application enable Maps SDK for Android and Places API.
  • Open AndroidManifest.xml and add the generated API key to your project above the application tag as shown below :

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.getnearbyplaces">

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>

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

    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

    <meta-data
        android:name="com.google.android.geo.API_KEY"
        android:value="@string/API_KEY" />

</application>

</manifest>

2. Open build.gradle and add dependency for the new Places SDK client library to get current and nearby places and also add a dependency for google map as shown below:

build.gradle

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'

    //library for google map
    implementation 'com.google.android.gms:play-services-maps:16.1.0'

    //Places SDK client library
    implementation 'com.google.android.libraries.places:places:2.0.0'

    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test:runner:1.2.0'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}

.Open AndroidManifest file and add all the permissions which you want to request above the application tag.

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.getnearbyplaces">

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>

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

    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

    <meta-data
        android:name="com.google.android.geo.API_KEY"
        android:value="@string/API_KEY" />

</application>

</manifest>

4. Open the layout file of your main activity (activity_main.xml ). Now add map fragment to show map and one button to get nearby places.

activity_main.xml 

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/btn_nearby_places"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_margin="16dp"
        android:background="@color/colorPrimary"
        android:text="Find NearBy Places"
        android:textColor="#FFFFFF"
        android:textStyle="bold" />

    <fragment
        android:id="@+id/map"
        android:name="com.google.android.gms.maps.SupportMapFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</RelativeLayout>

Initialize the new Places SDK client

.Open MainActivity.java and inside onCreate() initialize the new Places SDK client as shown below:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // Initialize Places.
    Places.initialize(getApplicationContext(), "AIzaSyCMznC3Jp0dQQTqLkq15qnz-U-kDA2_pHo");

    // Create a new Places client instance.
    placesClient = Places.createClient(this);
}

Finding Current Location

Places SDK library provide a method called  findCurrentPlace() to find the current location of the user’s device.It returns a list of PlaceLikelihoods indicating places where the user’s device is most likely to be located.

.Create a FindCurrentPlaceRequest, including a list of place data types to return.

// Use fields to define the data types to return.
  List<Place.Field> placeFields = Arrays.asList(Place.Field.ID,
Place.Field.NAME,Place.Field.ADDRESS);

  // Use the builder to create a FindCurrentPlaceRequest.
  FindCurrentPlaceRequest request =
          FindCurrentPlaceRequest.builder(placeFields).build();

.Call findCurrentPlace and handle the response, checking first to verify that the user has granted permission to use their device location.

if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {

    placesClient.findCurrentPlace(request).addOnCompleteListener(new OnCompleteListener() {
        @Override
        public void onComplete(@NonNull Task task) {

            if (task.isSuccessful()) {

                FindCurrentPlaceResponse response = task.getResult();
                placeLikelihoods = new ArrayList<>();
                placeLikelihoods.addAll(response.getPlaceLikelihoods());

                //response.getPlaceLikelihoods() will return list of PlaceLikelihood
                //we need to create a custom comparator to sort list by likelihoods
                Collections.sort(placeLikelihoods, new Comparator() {
                    @Override
                    public int compare(PlaceLikelihood placeLikelihood, PlaceLikelihood t1) {
                        return new Double(placeLikelihood.getLikelihood()).compareTo(t1.getLikelihood());
                    }
                });

                //After sort ,it will order by ascending , we just reverse it to get first item as nearest place
                Collections.reverse(placeLikelihoods);

                placeId = placeLikelihoods.get(0).getPlace().getId();
                latLng = placeLikelihoods.get(0).getPlace().getLatLng();
                address = placeLikelihoods.get(0).getPlace().getAddress();

                //Removing item of the list at 0 index
                placeLikelihoods.remove(0);

                SupportMapFragment supportMapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
                supportMapFragment.getMapAsync(MainActivity.this);

            }

        }
    }).addOnFailureListener(new OnFailureListener() {
        @Override
        public void onFailure(@NonNull Exception e) {

            Toast.makeText(MainActivity.this, "Place not found: " + e.getMessage(), Toast.LENGTH_LONG).show();
        }
    });
} else {

    //Requesting permission if it is not already granted
    ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_CODE);
    return;
}

Complete Code

.Open MainActivity.java and write the below code.

MainActivity.java

package com.example.getnearbyplaces;

import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

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.BitmapDescriptorFactory;
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.OnFailureListener;
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.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

public class MainActivity extends AppCompatActivity implements OnMapReadyCallback {

    private static final int REQUEST_CODE = 200;
    PlacesClient placesClient;
    List placeFields = Arrays.asList(Place.Field.ID, Place.Field.NAME, Place.Field.ADDRESS);
    Button btn_nearby_places;
    LatLng latLng;
    String address;
    private String placeId;
    private List placeLikelihoods;
    GoogleMap map;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Initialize Places.
        Places.initialize(getApplicationContext(), "AIzaSyCMznC3Jp0dQQTqLkq15qnz-U-kDA2_pHo");

        // Create a new Places client instance.
        placesClient = Places.createClient(this);

        btn_nearby_places = findViewById(R.id.btn_nearby_places);

        //Get the current place and nearby places of your device
        getCurrentPlace();

        btn_nearby_places.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                //setting Marker at nearby places
                setMarkerAtNearbyPlaces();
            }
        });
    }

    private void getCurrentPlace() {

        FindCurrentPlaceRequest request =
                FindCurrentPlaceRequest.builder(placeFields).build();

        // Call findCurrentPlace and handle the response (first check that the user has granted permission).
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {

            placesClient.findCurrentPlace(request).addOnCompleteListener(new OnCompleteListener() {
                @Override
                public void onComplete(@NonNull Task task) {

                    if (task.isSuccessful()) {

                        FindCurrentPlaceResponse response = task.getResult();
                        placeLikelihoods = new ArrayList<>();
                        placeLikelihoods.addAll(response.getPlaceLikelihoods());

                        //response.getPlaceLikelihoods() will return list of PlaceLikelihood
                        //we need to create a custom comparator to sort list by likelihoods
                        Collections.sort(placeLikelihoods, new Comparator() {
                            @Override
                            public int compare(PlaceLikelihood placeLikelihood, PlaceLikelihood t1) {
                                return new Double(placeLikelihood.getLikelihood()).compareTo(t1.getLikelihood());
                            }
                        });

                        //After sort ,it will order by ascending , we just reverse it to get first item as nearest place
                        Collections.reverse(placeLikelihoods);

                        placeId = placeLikelihoods.get(0).getPlace().getId();
                        latLng = placeLikelihoods.get(0).getPlace().getLatLng();
                        address = placeLikelihoods.get(0).getPlace().getAddress();

                        //Removing item of the list at 0 index
                        placeLikelihoods.remove(0);

                        SupportMapFragment supportMapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
                        supportMapFragment.getMapAsync(MainActivity.this);
                    }


               }
            }).addOnFailureListener(new OnFailureListener() {
                @Override
                public void onFailure(@NonNull Exception e) {

                    Toast.makeText(MainActivity.this, "Place not found: " + e.getMessage(), Toast.LENGTH_LONG).show();
              }
            });
        } else {

            //Requesting permission if it is not already granted
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_CODE);
            return;
        }

    }

    private void setMarkerAtNearbyPlaces() {

        for (PlaceLikelihood place : placeLikelihoods) {

            MarkerOptions markerOptions = new MarkerOptions().position(place.getPlace().getLatLng()).title(place.getPlace().getAddress());

            map.addMarker(markerOptions);
        }

    }

    @Override
    public void onMapReady(GoogleMap googleMap) {
        map = googleMap;

        //Adding marker in map at current location
        MarkerOptions markerOptions = new MarkerOptions().position(latLng).title(address).icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_AZURE));
        googleMap.animateCamera(CameraUpdateFactory.newLatLng(latLng));
        googleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, 15));
        googleMap.addMarker(markerOptions);
    }

    //handling request permission response
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {

        switch (requestCode) {
            case REQUEST_CODE:

                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    Toast.makeText(this, "Permission granted", Toast.LENGTH_LONG).show();
                    getCurrentPlace();
                } else
                    Toast.makeText(this, "Permission denied", Toast.LENGTH_LONG).show();
                break;
        }
    }

}

Leave a Reply