Showing nearby places with photos at any location in Google Maps Android API V2

May 22, 2013
By

In this article, we will develop an Android application which displays nearby places as a set of markers in Google Maps Android API V2 corresponding to the user touched location in the Google Maps and place type selected in the Spinner view.

On clicking a marker, the place details like place name, vicinity and photo ( if available )  will be shown in dialog fragment window.

Screenshots of the application is available towards the end of this article.



Some of the user defined classes that are used in this application are explained below :

MainActivity : This is the activity class which is opened when the application launches.

PlaceDialogFragment :  A dialog window which is opened on clicking a marker. It shows place name, vicinity and photo corresponding to the marked place.

PlacesTask : This is an inner class of the MainActivity class and is extending the class AsycTask. PlacesTask is used to fetch JSON data from Google Places Web Service in non-ui thread.

ParserTask : This is an inner class of the MainActivity class and is extending the class AsyncTask. ParserTask is used to parse the JSON data fetched from Google Places Web Service in a non-ui thread.

ImageDownloadTask : This is an inner class of PlaceDialogFragment and is extending the class AsyncTask. This is used to download image from Google Places Web Service.

Place : This class represents a nearby location with the information like latitude, longitude, place name, vicinity and photos. We are making this as a Parcelable class in order to retain the instances of this class during screen rotation.

Photo : This class represents a photo returned from Google Places Web Service  with the information like width, height, photo reference and attributions. This is also a parcelable class.

Attribution : This class is used to represent photo attributions. This is also a parcelable class.

PlaceJSONParser : A utility class to parse JSON data.

This application is developed in Eclipse (4.2.1) with ADT plugin (21.1.0) and Android SDK (21.1.0) and tested in Android devices with versions 2.3.6 ( Gingerbread ) and 4.0.4 ( Ice Cream Sandwich ).



1. Create a new Android application project namely “LocationNearbyPlacesPhotos”

Create new Android application project namely "LocationNearbyPlacesPhotos"

Figure 1 : Create new Android application project namely "LocationNearbyPlacesPhotos"


2. Configure the project

Configure the project

Figure 2 : Configure the project


3. Design application launcher icon

Design Application launcher icon

Figure 3 : Design Application launcher icon


4. Create a blank activity

Create a blank activity

Figure 4 : Create a blank activity


5. Enter MainActivity details

Enter MainActivity details

Figure 5 : Enter MainActivity details


6. Download and configure Google Play Services Library in Eclipse

Please follow the given below link to setup Google Play Service library in Eclipse.

http://developer.android.com/google/play-services/setup.html


7. Add Google Play Services Library to this project

Add Google Play Services Library to this project

Figure 6 : Add Google Play Services Library to this project


8. Get the API key for Google Maps Android API V2

We need to get an API key from Google to use Google Maps in Android application.

Please follow the given below link to get the API key for Google Maps Android API v2.

https://developers.google.com/maps/documentation/android/start


9. Get the API key for Google Places API

We can create API key for Google Place API by clicking “Create new Browser key”  available at the “API Access” pane of the Google console URL : http://code.google.com/apis/console.

Also ensure that, “Places API” is enabled in the “Services” pane of the Google console.


10. Add Android Support library to this project

By default, Android support library (android-support-v4.jar ) is added to this project by Eclipse IDE to the directory libs. If it is not added, we can do it manually by doing the following steps :

  • Open Project Explorer by Clicking “Window -> Show View -> Project Explorer”
  • Right click this project
  • Then from popup menu, Click “Android Tools -> Add Support Library “

11. Update the file res/values/strings.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">LocationNearby</string>
    <string name="hello_world">Hello world!</string>
    <string name="menu_settings">Settings</string>
    <string name="str_btn_find">Find</string>

    <string-array name="place_type">
        <item>airport</item>
        <item>atm</item>
        <item>bank</item>
        <item>bus_station</item>
        <item>church</item>
        <item>doctor</item>
        <item>hospital</item>
        <item>mosque</item>
        <item>movie_theater</item>
        <item>hindu_temple</item>
        <item>restaurant</item>
    </string-array>

    <string-array name="place_type_name">
        <item>Airport</item>
        <item>ATM</item>
        <item>Bank</item>
        <item>Bus Station</item>
        <item>Church</item>
        <item>Doctor</item>
        <item>Hospital</item>
        <item>Mosque</item>
        <item>Movie Theater</item>
        <item>Hindu Temple</item>
        <item>Restaurant</item>
    </string-array>
</resources>

Note : Defining string arrays to populate Spinner Widget with Place types.


12. Update the layout file res/layout/activity_main.xml


<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"
    tools:context=".MainActivity" >

    <Spinner
        android:id="@+id/spr_place_type"
        android:layout_width="wrap_content"
        android:layout_height="60dp"
        android:layout_alignParentTop="true" />

    <Button
        android:id="@+id/btn_find"
        android:layout_width="wrap_content"
        android:layout_height="60dp"
        android:layout_alignParentTop="true"
        android:layout_toRightOf="@id/spr_place_type"
        android:text="@string/str_btn_find" />

    <fragment
        android:id="@+id/map"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/spr_place_type"
        class="com.google.android.gms.maps.SupportMapFragment" />

</RelativeLayout>


13. Create the layout file res/layout/dialog_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    andoid:layout_height="wrap_content"
    android:orientation="vertical"
    android:gravity="center_horizontal" >

    <TextView
        android:id="@+id/tv_vicinity"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:maxLines="2" />

    <ViewFlipper
        android:id="@+id/flipper"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" >
    </ViewFlipper>

    <TextView
        android:id="@+id/tv_photos_count"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

14. Create the class “Attribution” in the file src/in/wptrafficanalyzer/locationnearbyplacesphotos/Attribution.java


package in.wptrafficanalyzer.locationnearbyplacesphotos;

import android.os.Parcel;
import android.os.Parcelable;

public class Attribution implements Parcelable{

    // Attribution of the photo
    String mHtmlAttribution="";

    @Override
    public int describeContents() {
        return 0;
    }

    /** Writing Attribution object data to Parcel */
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(mHtmlAttribution);
    }

    public Attribution(){
    }

    /** Initializing Attribution object from Parcel object */
    private Attribution(Parcel in){
        this.mHtmlAttribution = in.readString();
    }

    /** Generates an instance of Attribution class from Parcel */
    public static final Parcelable.Creator<Attribution> CREATOR = new Parcelable.Creator<Attribution>() {

        @Override
        public Attribution createFromParcel(Parcel source) {
            return new Attribution(source);
        }

        @Override
        public Attribution[] newArray(int size) {
            // TODO Auto-generated method stub
            return null;
        }
    };
}


15. Create the class “Photo” in the file src/in/wptrafficanalyzer/locationnearbyplacesphotos/Photo.java


package in.wptrafficanalyzer.locationnearbyplacesphotos;

import android.os.Parcel;
import android.os.Parcelable;

public class Photo implements Parcelable{

    // Width of the Photo
    int mWidth=0;

    // Height of the Photo
    int mHeight=0;

    // Reference of the photo to be used in Google Web Services
    String mPhotoReference="";

    // Attributions of the photo
    // Attribution is a Parcelable class
    Attribution[] mAttributions={};

    @Override
    public int describeContents() {
        // TODO Auto-generated method stub
        return 0;
    }

    /** Writing Photo object data to Parcel */
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(mWidth);
        dest.writeInt(mHeight);
        dest.writeString(mPhotoReference);
        dest.writeParcelableArray(mAttributions, 0);
    }

    public Photo(){
    }

    /** Initializing Photo object from Parcel object */
    private Photo(Parcel in){
        this.mWidth = in.readInt();
        this.mHeight = in.readInt();
        this.mPhotoReference = in.readString();
        this.mAttributions = (Attribution[])in.readParcelableArray(Attribution.class.getClassLoader());
    }

    /** Generates an instance of Place class from Parcel */
    public static final Parcelable.Creator<Photo> CREATOR = new Parcelable.Creator<Photo>() {
        @Override
        public Photo createFromParcel(Parcel source) {
            return new Photo(source);
        }

        @Override
        public Photo[] newArray(int size) {
            // TODO Auto-generated method stub
            return null;
        }
    };
}


16. Create the class “Place” in the file src/in/wptrafficanalyzer/locationnearbyplacesphotos/Place.java


package in.wptrafficanalyzer.locationnearbyplacesphotos;

import android.os.Parcel;
import android.os.Parcelable;

public class Place implements Parcelable{
    // Latitude of the place
    String mLat="";

    // Longitude of the place
    String mLng="";

    // Place Name
    String mPlaceName="";

    // Vicinity of the place
    String mVicinity="";

    // Photos of the place
    // Photo is a Parcelable class
    Photo[] mPhotos={};

    @Override
    public int describeContents() {
        // TODO Auto-generated method stub
        return 0;
    }

    /** Writing Place object data to Parcel */
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(mLat);
        dest.writeString(mLng);
        dest.writeString(mPlaceName);
        dest.writeString(mVicinity);
        dest.writeParcelableArray(mPhotos, 0);
    }

    public Place(){
    }

    /** Initializing Place object from Parcel object */
    private Place(Parcel in){
        this.mLat = in.readString();
        this.mLng = in.readString();
        this.mPlaceName = in.readString();
        this.mVicinity = in.readString();
        this.mPhotos = (Photo[])in.readParcelableArray(Photo.class.getClassLoader());
    }

    /** Generates an instance of Place class from Parcel */
    public static final Parcelable.Creator<Place> CREATOR = new Parcelable.Creator<Place>(){
        @Override
        public Place createFromParcel(Parcel source) {
            return new Place(source);
        }

        @Override
        public Place[] newArray(int size) {
            // TODO Auto-generated method stub
            return null;
        }
    };
}


17. Create the class “PlaceJSONParser” in the file src/in/wptrafficanalyzer/locationnearbyplacesphotos/PlaceJSONParser.java


package in.wptrafficanalyzer.locationnearbyplacesphotos;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.util.Log;

public class PlaceJSONParser {

    /** Receives a JSONObject and returns a list */
    public Place[] parse(JSONObject jObject){

        JSONArray jPlaces = null;
        try {
            /** Retrieves all the elements in the 'places' array */
            jPlaces = jObject.getJSONArray("results");
        } catch (JSONException e) {
            e.printStackTrace();
        }
        /** Invoking getPlaces with the array of json object
        * where each json object represent a place
        */
        return getPlaces(jPlaces);
    }

    private Place[] getPlaces(JSONArray jPlaces){
        int placesCount = jPlaces.length();
        Place[] places = new Place[placesCount];

        /** Taking each place, parses and adds to list object */
        for(int i=0; i<placesCount;i++){
            try {
                /** Call getPlace with place JSON object to parse the place */
                places[i] = getPlace((JSONObject)jPlaces.get(i));

            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
        return places;
    }

    /** Parsing the Place JSON object */
    private Place getPlace(JSONObject jPlace){

        Place place = new Place();

        try {
            // Extracting Place name, if available
            if(!jPlace.isNull("name")){
                place.mPlaceName = jPlace.getString("name");
            }

            // Extracting Place Vicinity, if available
            if(!jPlace.isNull("vicinity")){
                place.mVicinity = jPlace.getString("vicinity");
            }

            if(!jPlace.isNull("photos")){
                JSONArray photos = jPlace.getJSONArray("photos");
                place.mPhotos = new Photo[photos.length()];
                for(int i=0;i<photos.length();i++){
                    place.mPhotos[i] = new Photo();
                    place.mPhotos[i].mWidth = ((JSONObject)photos.get(i)).getInt("width");
                    place.mPhotos[i].mHeight = ((JSONObject)photos.get(i)).getInt("height");
                    place.mPhotos[i].mPhotoReference = ((JSONObject)photos.get(i)).getString("photo_reference");
                    JSONArray attributions = ((JSONObject)photos.get(i)).getJSONArray("html_attributions");
                    place.mPhotos[i].mAttributions = new Attribution[attributions.length()];
                    for(int j=0;j<attributions.length();j++){
                        place.mPhotos[i].mAttributions[j] = new Attribution();
                        place.mPhotos[i].mAttributions[j].mHtmlAttribution = attributions.getString(j);
                    }
                }
            }

            place.mLat = jPlace.getJSONObject("geometry").getJSONObject("location").getString("lat");
            place.mLng = jPlace.getJSONObject("geometry").getJSONObject("location").getString("lng");

        } catch (JSONException e) {
            e.printStackTrace();
            Log.d("EXCEPTION", e.toString());
        }
        return place;
    }
}


18. Create the class “PlaceDialogFragment” in the file src/in/wptrafficanalyzer/locationnearbyplacesphotos/PlaceDialogFragment.java


package in.wptrafficanalyzer.locationnearbyplacesphotos;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ViewFlipper;

// Defining DialogFragment class to show the place details with photo
public class PlaceDialogFragment extends DialogFragment{

    TextView mTVPhotosCount = null;
    TextView mTVVicinity = null;
    ViewFlipper mFlipper = null;
    Place mPlace = null;
    DisplayMetrics mMetrics = null;

    public PlaceDialogFragment(){
        super();
    }

    public PlaceDialogFragment(Place place, DisplayMetrics dm){
        super();
        this.mPlace = place;
        this.mMetrics = dm;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {

        // For retaining the fragment on screen rotation
        setRetainInstance(true);
        super.onCreate(savedInstanceState);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                            Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.dialog_layout, null);

        // Getting reference to ViewFlipper
        mFlipper = (ViewFlipper) v.findViewById(R.id.flipper);

        // Getting reference to TextView to display photo count
        mTVPhotosCount = (TextView) v.findViewById(R.id.tv_photos_count);

        // Getting reference to TextView to display place vicinity
        mTVVicinity = (TextView) v.findViewById(R.id.tv_vicinity);

        if(mPlace!=null){

            // Setting the title for the Dialog Fragment
            getDialog().setTitle(mPlace.mPlaceName);

            // Array of references of the photos
            Photo[] photos = mPlace.mPhotos;

            // Setting Photos count
            mTVPhotosCount.setText("Photos available : " + photos.length);

            // Setting the vicinity of the place
            mTVVicinity.setText(mPlace.mVicinity);

            // Creating an array of ImageDownloadTask to download photos
            ImageDownloadTask[] imageDownloadTask = new ImageDownloadTask[photos.length];

            int width = (int)(mMetrics.widthPixels*3)/4;
            int height = (int)(mMetrics.heightPixels*1)/2;

            String url = "https://maps.googleapis.com/maps/api/place/photo?";
            String key = "key=YOUR_BROWSER_KEY";
            String sensor = "sensor=true";
            String maxWidth="maxwidth=" + width;
            String maxHeight = "maxheight=" + height;
            url = url + "&" + key + "&" + sensor + "&" + maxWidth + "&" + maxHeight;

            // Traversing through all the photoreferences
            for(int i=0;i<photos.length;i++){
                // Creating a task to download i-th photo
                imageDownloadTask[i] = new ImageDownloadTask();

                String photoReference = "photoreference="+photos[i].mPhotoReference;

                // URL for downloading the photo from Google Services
                url = url + "&" + photoReference;

                // Downloading i-th photo from the above url
                imageDownloadTask[i].execute(url);
            }
        }
        return v;
    }

    @Override
    public void onDestroyView() {
        if (getDialog() != null && getRetainInstance())
            getDialog().setDismissMessage(null);
            super.onDestroyView();
    }

    private Bitmap downloadImage(String strUrl) throws IOException{
        Bitmap bitmap=null;
        InputStream iStream = null;
        try{
            URL url = new URL(strUrl);

            /** Creating an http connection to communcate with url */
            HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();

            /** Connecting to url */
            urlConnection.connect();

            /** Reading data from url */
            iStream = urlConnection.getInputStream();

            /** Creating a bitmap from the stream returned from the url */
            bitmap = BitmapFactory.decodeStream(iStream);

        }catch(Exception e){
            Log.d("Exception while downloading url", e.toString());
        }finally{
            iStream.close();
        }
        return bitmap;
    }

    private class ImageDownloadTask extends AsyncTask<String, Integer, Bitmap>{
        Bitmap bitmap = null;
        @Override
        protected Bitmap doInBackground(String... url) {
            try{
                // Starting image download
                bitmap = downloadImage(url[0]);
            }catch(Exception e){
                Log.d("Background Task",e.toString());
            }
            return bitmap;
        }

        @Override
        protected void onPostExecute(Bitmap result) {
            // Creating an instance of ImageView to display the downloaded image
            ImageView iView = new ImageView(getActivity().getBaseContext());

            // Setting the downloaded image in ImageView
            iView.setImageBitmap(result);

            // Adding the ImageView to ViewFlipper
            mFlipper.addView(iView);

            // Showing download completion message
            Toast.makeText(getActivity().getBaseContext(), "Image downloaded successfully", Toast.LENGTH_SHORT).show();
        }
    }
}

Note : Ensure that “YOUR_BROWSER_KEY” at the line 84 is replaced with the api key obtained in Step 9 


19. Update the class “MainActivity” in the file src/in/wptrafficanalyzer/locationnearbyplacesphotos/MainActivity.java

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;

import org.json.JSONObject;

import android.app.Dialog;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.Spinner;
import android.widget.Toast;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.GoogleMap.OnMapClickListener;
import com.google.android.gms.maps.GoogleMap.OnMarkerClickListener;
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.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
public class MainActivity extends FragmentActivity{

    // GoogleMap
    GoogleMap mGoogleMap;

    // Spinner in which the location types are stored
    Spinner mSprPlaceType;

    // A button to find the near by places
    Button mBtnFind=null;

    // Stores near by places
    Place[] mPlaces = null;

    // A String array containing place types sent to Google Place service
    String[] mPlaceType=null;

    // A String array containing place types displayed to user
    String[] mPlaceTypeName=null;

    // The location at which user touches the Google Map
    LatLng mLocation=null;

    // Links marker id and place object
    HashMap<String, Place> mHMReference = new HashMap<String, Place>();

    // Specifies the drawMarker() to draw the marker with default color
    private static final float UNDEFINED_COLOR = -1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Array of place types
        mPlaceType = getResources().getStringArray(R.array.place_type);

        // Array of place type names
        mPlaceTypeName = getResources().getStringArray(R.array.place_type_name);

        // Creating an array adapter with an array of Place types
        // to populate the spinner
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
                                                                android.R.layout.simple_spinner_dropdown_item,
                                                                 mPlaceTypeName);

        // Getting reference to the Spinner
        mSprPlaceType = (Spinner) findViewById(R.id.spr_place_type);

        // Setting adapter on Spinner to set place types
        mSprPlaceType.setAdapter(adapter);

        // Getting reference to Find Button
        mBtnFind = ( Button ) findViewById(R.id.btn_find);

        // Getting Google Play availability status
        int status = GooglePlayServicesUtil.isGooglePlayServicesAvailable(getBaseContext());

        if(status!=ConnectionResult.SUCCESS){ // Google Play Services are not available

            int requestCode = 10;
            Dialog dialog = GooglePlayServicesUtil.getErrorDialog(status, this, requestCode);
            dialog.show();

        }else { // Google Play Services are available

            // Getting reference to the SupportMapFragment
            SupportMapFragment fragment = ( SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);

            // Getting Google Map
            mGoogleMap = fragment.getMap();

            // Enabling MyLocation in Google Map
            mGoogleMap.setMyLocationEnabled(true);

            // Handling screen rotation
            if(savedInstanceState !=null) {

                // Removes all the existing links from marker id to place object
                mHMReference.clear();

                //If near by places are already saved
                if(savedInstanceState.containsKey("places")){

                    // Retrieving the array of place objects
                    mPlaces = (Place[]) savedInstanceState.getParcelableArray("places");

                    // Traversing through each near by place object
                    for(int i=0;i<mPlaces.length;i++){

                        // Getting latitude and longitude of the i-th place
                        LatLng point = new LatLng(Double.parseDouble(mPlaces[i].mLat),
                        Double.parseDouble(mPlaces[i].mLng));

                        // Drawing the marker corresponding to the i-th place
                        Marker m = drawMarker(point,UNDEFINED_COLOR);

                        // Linkng i-th place and its marker id
                        mHMReference.put(m.getId(), mPlaces[i]);
                    }
                }

                // If a touched location is already saved
                if(savedInstanceState.containsKey("location")){

                    // Retrieving the touched location and setting in member variable
                    mLocation = (LatLng) savedInstanceState.getParcelable("location");

                   // Drawing a marker at the touched location
                   drawMarker(mLocation, BitmapDescriptorFactory.HUE_GREEN);
               }
           }

            // Setting click event lister for the find button
            mBtnFind.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {

                    int selectedPosition = mSprPlaceType.getSelectedItemPosition();
                    String type = mPlaceType[selectedPosition];

                    mGoogleMap.clear();

                    if(mLocation==null){
                        Toast.makeText(getBaseContext(), "Please mark a location", Toast.LENGTH_SHORT).show();
                        return;
                    }

                    drawMarker(mLocation, BitmapDescriptorFactory.HUE_GREEN);

                    StringBuilder sb = new StringBuilder("https://maps.googleapis.com/maps/api/place/nearbysearch/json?");
                    sb.append("location="+mLocation.latitude+","+mLocation.longitude);
                    sb.append("&radius=5000");
                    sb.append("&types="+type);
                    sb.append("&sensor=true");
                    sb.append("&key=YOUR_BROWSER_KEY");

                    // Creating a new non-ui thread task to download Google place json data
                    PlacesTask placesTask = new PlacesTask();

                    // Invokes the "doInBackground()" method of the class PlaceTask
                    placesTask.execute(sb.toString());
                }
            });

            // Map Click listener
            mGoogleMap.setOnMapClickListener(new OnMapClickListener() {

                @Override
                public void onMapClick(LatLng point) {

                    // Clears all the existing markers
                    mGoogleMap.clear();

                    // Setting the touched location in member variable
                    mLocation = point;

                    // Drawing a marker at the touched location
                    drawMarker(mLocation,BitmapDescriptorFactory.HUE_GREEN);
                }
            });

            // Marker click listener
            mGoogleMap.setOnMarkerClickListener(new OnMarkerClickListener() {

                @Override
                public boolean onMarkerClick(Marker marker) {

                    // If touched at User input location
                    if(!mHMReference.containsKey(marker.getId()))
                        return false;

                    // Getting place object corresponding to the currently clicked Marker
                    Place place = mHMReference.get(marker.getId());

                    // Creating an instance of DisplayMetrics
                    DisplayMetrics dm = new DisplayMetrics();

                    // Getting the screen display metrics
                    getWindowManager().getDefaultDisplay().getMetrics(dm);

                    // Creating a dialog fragment to display the photo
                    PlaceDialogFragment dialogFragment = new PlaceDialogFragment(place,dm);

                    // Getting a reference to Fragment Manager
                    FragmentManager fm = getSupportFragmentManager();

                    // Starting Fragment Transaction
                    FragmentTransaction ft = fm.beginTransaction();

                    // Adding the dialog fragment to the transaction
                    ft.add(dialogFragment, "TAG");

                    // Committing the fragment transaction
                    ft.commit();

                    return false;
                }
            });
        }
    }

    /**
    * A callback function, executed on screen rotation
    */
    @Override
    protected void onSaveInstanceState(Bundle outState) {

        // Saving all the near by places objects
        if(mPlaces!=null)
            outState.putParcelableArray("places", mPlaces);

        // Saving the touched location
        if(mLocation!=null)
            outState.putParcelable("location", mLocation);

        super.onSaveInstanceState(outState);
    }

    /** A method to download json data from argument url */
    private String downloadUrl(String strUrl) throws IOException{
        String data = "";
        InputStream iStream = null;
        HttpURLConnection urlConnection = null;
        try{
            URL url = new URL(strUrl);

            // Creating an http connection to communicate with url
            urlConnection = (HttpURLConnection) url.openConnection();

            // Connecting to url
            urlConnection.connect();

            // Reading data from url
            iStream = urlConnection.getInputStream();

            BufferedReader br = new BufferedReader(new InputStreamReader(iStream));

            StringBuffer sb = new StringBuffer();

            String line = "";
            while( ( line = br.readLine()) != null){
                sb.append(line);
            }

            data = sb.toString();

            br.close();

        }catch(Exception e){
            Log.d("Exception while downloading url", e.toString());
        }finally{
            iStream.close();
            urlConnection.disconnect();
        }
        return data;
    }
    /** A class, to download Google Places */
    private class PlacesTask extends AsyncTask<String, Integer, String>{

        String data = null;

        // Invoked by execute() method of this object
        @Override
        protected String doInBackground(String... url) {
            try{
                data = downloadUrl(url[0]);
            }catch(Exception e){
                Log.d("Background Task",e.toString());
            }
            return data;
        }

        // Executed after the complete execution of doInBackground() method
        @Override
        protected void onPostExecute(String result){
            ParserTask parserTask = new ParserTask();

            // Start parsing the Google places in JSON format
            // Invokes the "doInBackground()" method of ParserTask
            parserTask.execute(result);
        }
    }

    /** A class to parse the Google Places in JSON format */
    private class ParserTask extends AsyncTask<String, Integer, Place[]>{

        JSONObject jObject;

        // Invoked by execute() method of this object
        @Override
        protected Place[] doInBackground(String... jsonData) {

            Place[] places = null;
            PlaceJSONParser placeJsonParser = new PlaceJSONParser();

            try{
                jObject = new JSONObject(jsonData[0]);
                /** Getting the parsed data as a List construct */
                places = placeJsonParser.parse(jObject);

            }catch(Exception e){
                Log.d("Exception",e.toString());
            }
            return places;
        }

        // Executed after the complete execution of doInBackground() method
        @Override
        protected void onPostExecute(Place[] places){

            mPlaces = places;

            for(int i=0;i< places.length ;i++){
                Place place = places[i];

                // Getting latitude of the place
                double lat = Double.parseDouble(place.mLat);

                // Getting longitude of the place
                double lng = Double.parseDouble(place.mLng);

                LatLng latLng = new LatLng(lat, lng);

                Marker m = drawMarker(latLng,UNDEFINED_COLOR);

                // Adding place reference to HashMap with marker id as HashMap key
                // to get its reference in infowindow click event listener
                mHMReference.put(m.getId(), place);
            }
        }
    }

    /**
    * Drawing marker at latLng with color
    */
    private Marker drawMarker(LatLng latLng,float color){
        // Creating a marker
        MarkerOptions markerOptions = new MarkerOptions();

        // Setting the position for the marker
        markerOptions.position(latLng);

        if(color != UNDEFINED_COLOR)
            markerOptions.icon(BitmapDescriptorFactory.defaultMarker(color));

        // Placing a marker on the touched position
        Marker m = mGoogleMap.addMarker(markerOptions);

        return m;
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
}

Note : Ensure that “YOUR_BROWSER_KEY” at the line 173 is replaced with the api key obtained in Step 9


20. Update the file AndroidManifest.xml


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="in.wptrafficanalyzer.locationnearbyplacesphotos"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />

    <permission
        android:name="in.wptrafficanalyzer.locationnearbyplacesphotos.permission.MAPS_RECEIVE"
        android:protectionLevel="signature"/>

    <uses-permission android:name="in.wptrafficanalyzer.locationnearbyplacesphotos.permission.MAPS_RECEIVE"/>

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

    <uses-feature
        android:glEsVersion="0x00020000"
        android:required="true"/>

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="in.wptrafficanalyzer.locationnearbyplacesphotos.MainActivity"
            android:label="@string/app_name" >
            <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.maps.v2.API_KEY"
            android:value="YOUR_ANDROID_API_KEY"/>
    </application>
</manifest>

Note : Ensure that “YOUR_BROWSER_KEY” at the line 44 is replaced with the api key obtained in Step 8 


21. Screenshots of the application in Android 4.0.4 ( Ice Cream Sandwich )

Showing nearby places

Figure 7 : Showing nearby restaurants

Displaying photo attached with a Restaurant

Figure 8 : Displaying photo attached with a Restaurant


22. Screenshots of the application in Android 2.3.6 ( Ginger Bread )

Showing nearby restaurants

Figure 9 : Showing nearby restaurants

Displaying a photo on clicking the marker

Figure 10 : Displaying a photo on clicking the marker


23. Download Source code


How to hire me?

I am George Mathew, working as software architect and Android app developer at wptrafficanalyzer.in

You can hire me on hourly basis or on project basis for Android applications development.

For hiring me, please mail your requirements to info@wptrafficanalyzer.in.

My other blogs
store4js.blogspot.com


Android Knowledge Quiz

Ready to test your knowledge in Android? Take this quiz :



Tags: , , , , , , , , ,

40 Responses to Showing nearby places with photos at any location in Google Maps Android API V2

  1. mithran on May 24, 2013 at 9:42 am

    you are the best!! and i mean it

  2. Adeel on May 24, 2013 at 7:33 pm

    Hi George

    I Run the above code and install the Apk on the real device(Sumsang Glaxy S3) but it does not show any response.. App run and nothing Display even Google Map

    • george on May 24, 2013 at 9:10 pm

      Hi Adeel,
      Please check that you have specified the correct api keys in the code.

      • Adeel on May 25, 2013 at 1:13 am

        Thanks..
        But Sir Image Downloaded Successfully message appears but it does not display

  3. Elena on May 25, 2013 at 2:20 am

    hey george ;
    i run your app, but map doesnt come. apı key is true , what can i do

  4. nani on May 27, 2013 at 5:41 pm

    hai sir ,
    I Run the above code and install the Apk on the real device App run but not finding hospital, restaurants…?only map displaying. how can i find hospitals, restaurants?

  5. Wyllyam on June 1, 2013 at 12:19 am

    very good article! Keep it up.

    Did you know if you can provide some article about the x server client communication using android as client and server with java. Standards JSON, Restful and Gson.

    thank you

  6. rendi on June 6, 2013 at 2:50 am

    request. direction shortst routue to destination

  7. Divyang on July 3, 2013 at 11:49 am

    Very Good Article…but there is some error in PlaceDialogFragment class in the parameterized constructor. It says avoid non default constructor in fragments and instead use setArgument(Bundle)…I m not sure how to deal with it…plzz help

    • eminence on July 10, 2013 at 6:51 pm

      @DivYangle

      what you can do is to create a Bundle object and pass in this case your Place object in the bundle like :

      public static PlaceDialogFragment newIntance(Place place){
      PlaceDialogFragment fragment = new PlaceDialogFragment():
      // Create your bundle object here
      Bundle args = new Bundle();
      args.putParcelable(“key”,place);
      fragment.setArguments(args);
      return fragment;
      }
      // then to access this value , go to onCreate method
      you do something like:
      mPlace = getArguments().getParcelable(“key”,place);
      that’s all .

  8. Chris on July 29, 2013 at 8:09 am

    Great tutorial. I used some of your code to get the JSON response and populate a listview with the surrounding places. Is there an easy way to pass the locations to a new activity that shows all the locations in the listview on a map?

  9. Rabin on August 7, 2013 at 6:28 pm

    app run successfully and map appear but when i click find nothing occur what should i do to make the them appear.thanx

    • Rabin on August 8, 2013 at 4:19 pm

      how to obtain browser key

  10. manoj on October 4, 2013 at 2:50 pm

    Hi sir, i am Manoj. I am following your tutorial. I am getting all detals well but i also want phone number of that restaurent. Please help.

  11. jatinder singh on October 24, 2013 at 12:37 am

    Hello Sir
    I am jatinder i want find nearby cities under 100 mile radius using google api please help me if you have any api which find the cities according radius form one city with in 100 mile

  12. jay on October 24, 2013 at 10:40 am

    Thnx a lot sir, really time saving post ………..Many Thnx again…

  13. jay on October 25, 2013 at 10:30 am

    Hello sir , app running succesfully on my tablet , when i mark place and it display mi near by place of that mark location…. my question is ,i want to display the location name with marker ….?? Thnx a lot in advance

  14. jignesh on December 31, 2013 at 1:10 pm

    hello sir , i read ur articles ,it seems awesome and very helpful to me.
    There is problem regarding this one ,that i import your project and replace the API key with mine ,but it can’t work ,only front page is displayed with out map ,nothing else .
    if u have time then plz suggest me in this,how can i successfully run your sample project ..thanx in Advance …

  15. abhishek shakwala on February 25, 2014 at 7:43 pm

    When i executed your code, it is not generating R.java file. I hav tried many solutions to resolve it but i m unable to do it… plzz help me out….

  16. Shubhangi Garg on April 30, 2014 at 8:03 pm

    hiii sir can you plz tell how to generate the browser key..and also this code shows error in MainActivity and PlaceDialogFragment.java files in all “R.id” lines wherever we have used that.

  17. hieu on May 29, 2014 at 6:38 am

    I get browser key but I don’t understand put what URL in field? Thank

    • hieu on May 29, 2014 at 6:40 am

      I don’t know how to get browser key

      • Albert on October 3, 2014 at 8:09 am

        go to google api console and on the Places API and create new browser key, leave it blank…

  18. Albert on October 3, 2014 at 7:25 am

    I run your code, I am able to display the map, but when i placed a marker and click on find, nothing was displayed..

    • Albert on October 3, 2014 at 8:07 am

      Sir I already run the map and display the marker when i search but the only problem is that it says Image downloaded successfully but nothing is displayed. Thanks

      • Albert on October 3, 2014 at 8:19 am

        I got it already sir, I forgot to replace my browser key in PlacesDialogFragmentClass.. Thank you so much, very nice tutorial

        • Albert on October 3, 2014 at 8:34 am

          how about if I display all tourist spot, what is the places name sir?

        • altaf on August 14, 2015 at 11:02 am

          Albert sir send me the coding of nearby places which is running mode because i have try it many times but nothing happen when i click on find button.

        • altaf on August 14, 2015 at 11:03 am

          sir send me the coding of nearby places which is running mode because i have try it many times but nothing happen when i click on find button.

  19. Davvy on October 15, 2014 at 10:45 am

    thxx for this tutorial.

    all project runs well but it d’nt show images of serch places…
    plzz give me any solution..

  20. mansour on January 24, 2015 at 11:59 pm

    sir. thanks i run the code but i can not see even the marker any help sir

  21. mansour on January 25, 2015 at 12:01 am

    please any one can help on this

  22. zoniee on February 2, 2015 at 1:20 am

    hello :) this site is extremely good and very very helpful , i would like to thanx to george u r great ,

    i run this app on my device but errors come and after some the app stops , can anyone plzz tell me how to solve this error , below is the logcat

    Calling connect() while still connected, missing disconnect() for com.google.android.location.internal.GoogleLocationManagerService.START

    what to do to solve it ???

    thanx :)

  23. john on February 18, 2015 at 4:57 pm

    Hi. Thanx for great article it is very helpful. I have one problem with this code. I need more than one photo for places can you please tell me how to do that. I found somewhere that i need to do detail search but I don’t know how to do that. Thank you one more time

  24. toan on March 31, 2015 at 8:20 am

    please tutorial step by step create browser key

  25. abhishek on April 4, 2015 at 2:26 pm

    Hi George
    thnks for this code.But Plz help me in this how to get shortest distance more then 3 location using Google Directions in Google Map Android API V2.

  26. tanvir ahmed on June 9, 2015 at 10:36 pm

    In the mainActivity class there is a problem to add fragment.
    ft.add(dialogFragment, “TAG”);
    Still i can’t get a solution and also my map is not showing nearest location like (arport,bank etc)..please give me some solution.

  27. Vishal on January 18, 2016 at 1:39 pm

    How can i solve this error?

  28. Rahul on March 15, 2016 at 11:03 am

    Hello sir,
    Thanx for good article
    Can You guide me how to display the nearby details and images of places in listview please
    It will be greatful if replied
    Thank you once again

  29. Vino on July 6, 2016 at 10:29 pm

    Hi George,

    Great Article. I am working on a similar project to get the nearby places in a list view and so far achieved the place name and address but no luck with images. Could you please post the code to get the url into the Imageview holder within the placeslistadpater?

    Your help is much appreciated

    Vino.

Leave a Reply

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

Be friend at g+

Subscribe for Lastest Updates

FBFPowered by ®Google Feedburner