Selecting Google Place from AutoCompleteTextView and marking in Google Map Android API V2

March 6, 2013
By

In this article, we will develop an Android application which facilitates users to select a place from AutoCompleteTextView and that place will be marked in Google Map Android API V2.

This application is developed in Eclipse (4.2.1) with ADT plugin (21.0.0) and Android SDK (21.0.0) and tested in a real device with Android 2.3.6  ( GingerBread ).


1. Create a new Android application project namely “LocationAutoGoogleMapV2″

Create a new Android application project

Figure 1 : Create a new Android application project


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 Eclips

Google Map for Android is now integrated with Google Play Services. So we need to set up Google Play Service Library for developing Google Map application in Android.

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

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

Note : Please ensure that, the latest version of Google Play Service Library is installed


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">LocationAutoGoogleMapV2</string>
    <string name="action_settings">Settings</string>
    <string name="hello_world">Hello world!</string>
    <string name="str_atv_places">Enter Place Here</string>

</resources>


12. Create a class namely “CustomAutoCompleteTextView” in the file src/in/wptrafficanalyzer/locationautogooglemapv2/CustomAutoCompleteTextView.java


package in.wptrafficanalyzer.locationautogooglemapv2;

import java.util.HashMap;

import android.content.Context;
import android.util.AttributeSet;
import android.widget.AutoCompleteTextView;

/** Customizing AutoCompleteTextView to return Place Description
*  corresponding to the selected item
*/
public class CustomAutoCompleteTextView extends AutoCompleteTextView {

    public CustomAutoCompleteTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    /** Returns the Place Description corresponding to the selected item */
    @Override
    protected CharSequence convertSelectionToString(Object selectedItem) {
        /** Each item in the autocompetetextview suggestion list is a hashmap object */
        HashMap<String, String> hm = (HashMap<String, String>) selectedItem;
        return hm.get("description");
    }
}


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

    <in.wptrafficanalyzer.locationautogooglemapv2.CustomAutoCompleteTextView
        android:id="@+id/atv_places"
        android: layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:hint="@string/str_atv_places"
        android:singleLine="true" />

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

</RelativeLayout>


14. Create a new class namely “PlaceJSONParser” in the file src/in/wptrafficanalyzer/locationautogooglemapv2/PlaceJSONParser.java


package in.wptrafficanalyzer.locationautogooglemapv2;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

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

public class PlaceJSONParser {

    /** Receives a JSONObject and returns a list */
    public List<HashMap<String,String>> parse(JSONObject jObject){

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

    private List<HashMap<String, String>> getPlaces(JSONArray jPlaces){
        int placesCount = jPlaces.length();
        List<HashMap<String, String>> placesList = new ArrayList<HashMap<String,String>>();
        HashMap<String, String> place = null;

        /** 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 */
                place = getPlace((JSONObject)jPlaces.get(i));
                placesList.add(place);

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

    /** Parsing the Place JSON object */
    private HashMap<String, String> getPlace(JSONObject jPlace){

        HashMap<String, String> place = new HashMap<String, String>();

        String id="";
        String reference="";
        String description="";

        try {
            description = jPlace.getString("description");
            id = jPlace.getString("id");
            reference = jPlace.getString("reference");

            place.put("description", description);
            place.put("_id",id);
            place.put("reference",reference);

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


15. Create a new class namely “PlaceDetailsJSONParser” in the file src/in/wptrafficanalyzer/locationautogooglemapv2/PlaceDetailsJSONParser.java


package in.wptrafficanalyzer.locationautogooglemapv2;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

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

public class PlaceDetailsJSONParser {

    /** Receives a JSONObject and returns a list */
    public List<HashMap<String,String>> parse(JSONObject jObject){

        Double lat = Double.valueOf(0);
        Double lng = Double.valueOf(0);

        HashMap<String, String> hm = new HashMap<String, String>();
        List<HashMap<String, String>> list = new ArrayList<HashMap<String,String>>();

        try {

            lat = (Double)jObject.getJSONObject("result").getJSONObject("geometry").getJSONObject("location").get("lat");
            lng = (Double)jObject.getJSONObject("result").getJSONObject("geometry").getJSONObject("location").get("lng");

        } catch (JSONException e) {
            e.printStackTrace();
        }catch(Exception e){
            e.printStackTrace();
        }

        hm.put("lat", Double.toString(lat));
        hm.put("lng", Double.toString(lng));

        list.add(hm);
        return list;
    }
}


16. Update the class “MainActivity” in the file src/in/wptrafficanalyzer/locationautogooglemapv2/MainActivity.java


package in.wptrafficanalyzer.locationautogooglemapv2;

import java.io.BufferedReader;
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 java.util.List;

import org.json.JSONObject;

import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AutoCompleteTextView;
import android.widget.ListView;
import android.widget.SimpleAdapter;

import com.google.android.gms.maps.CameraUpdate;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;

public class MainActivity extends FragmentActivity {

    AutoCompleteTextView atvPlaces;

    DownloadTask placesDownloadTask;
    DownloadTask placeDetailsDownloadTask;
    ParserTask placesParserTask;
    ParserTask placeDetailsParserTask;

    GoogleMap googleMap;

    final int PLACES=0;
    final int PLACES_DETAILS=1;

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

        // Getting a reference to the AutoCompleteTextView
        atvPlaces = (AutoCompleteTextView) findViewById(R.id.atv_places);
        atvPlaces.setThreshold(1);

        // Adding textchange listener
        atvPlaces.addTextChangedListener(new TextWatcher() {

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                // Creating a DownloadTask to download Google Places matching "s"
                placesDownloadTask = new DownloadTask(PLACES);

                // Getting url to the Google Places Autocomplete api
                String url = getAutoCompleteUrl(s.toString());

               // Start downloading Google Places
                // This causes to execute doInBackground() of DownloadTask class
                placesDownloadTask.execute(url);
            }

            @Override
            public void beforeTextChanged(CharSequence s, int start, int count,
            int after) {
                // TODO Auto-generated method stub
            }

            @Override
            public void afterTextChanged(Editable s) {
                // TODO Auto-generated method stub
            }
        });

        // Setting an item click listener for the AutoCompleteTextView dropdown list
        atvPlaces.setOnItemClickListener(new OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> arg0, View arg1, int index,
            long id) {

                ListView lv = (ListView) arg0;
                SimpleAdapter adapter = (SimpleAdapter) arg0.getAdapter();

                HashMap<String, String> hm = (HashMap<String, String>) adapter.getItem(index);

                // Creating a DownloadTask to download Places details of the selected place
                placeDetailsDownloadTask = new DownloadTask(PLACES_DETAILS);

                // Getting url to the Google Places details api
                String url = getPlaceDetailsUrl(hm.get("reference"));

                // Start downloading Google Place Details
                // This causes to execute doInBackground() of DownloadTask class
                placeDetailsDownloadTask.execute(url);

            }
        });
    }

    private String getAutoCompleteUrl(String place){

        // Obtain browser key from https://code.google.com/apis/console
        String key = "key=YOUR_API_KEY";

        // place to be be searched
        String input = "input="+place;

        // place type to be searched
        String types = "types=geocode";

        // Sensor enabled
        String sensor = "sensor=false";

        // Building the parameters to the web service
        String parameters = input+"&"+types+"&"+sensor+"&"+key;

        // Output format
        String output = "json";

        // Building the url to the web service
        String url = "https://maps.googleapis.com/maps/api/place/autocomplete/"+output+"?"+parameters;

        return url;
    }

    private String getPlaceDetailsUrl(String ref){

        // Obtain browser key from https://code.google.com/apis/console
        String key = "key=YOUR_API_KEY";

        // reference of place
        String reference = "reference="+ref;

        // Sensor enabled
        String sensor = "sensor=false";

        // Building the parameters to the web service
        String parameters = reference+"&"+sensor+"&"+key;

        // Output format
        String output = "json";

        // Building the url to the web service
        String url = "https://maps.googleapis.com/maps/api/place/details/"+output+"?"+parameters;

        return url;
    }

    /** A method to download json data from 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;
    }

    // Fetches data from url passed
    private class DownloadTask extends AsyncTask<String, Void, String>{

        private int downloadType=0;

        // Constructor
        public DownloadTask(int type){
            this.downloadType = type;
        }

        @Override
        protected String doInBackground(String... url) {

            // For storing data from web service
            String data = "";

            try{
                // Fetching the data from web service
                data = downloadUrl(url[0]);
            }catch(Exception e){
                Log.d("Background Task",e.toString());
            }
            return data;
        }

        @Override
        protected void onPostExecute(String result) {
            super.onPostExecute(result);

            switch(downloadType){
            case PLACES:
                // Creating ParserTask for parsing Google Places
                placesParserTask = new ParserTask(PLACES);

                // Start parsing google places json data
                // This causes to execute doInBackground() of ParserTask class
                placesParserTask.execute(result);

                break;

            case PLACES_DETAILS :
                // Creating ParserTask for parsing Google Places
                placeDetailsParserTask = new ParserTask(PLACES_DETAILS);

                // Starting Parsing the JSON string
                // This causes to execute doInBackground() of ParserTask class
                placeDetailsParserTask.execute(result);
            }
        }
    }

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

        int parserType = 0;

        public ParserTask(int type){
            this.parserType = type;
        }

        @Override
        protected List<HashMap<String, String>> doInBackground(String... jsonData) {

            JSONObject jObject;
            List<HashMap<String, String>> list = null;

            try{
                jObject = new JSONObject(jsonData[0]);

                switch(parserType){
                case PLACES :
                    PlaceJSONParser placeJsonParser = new PlaceJSONParser();
                    // Getting the parsed data as a List construct
                    list = placeJsonParser.parse(jObject);
                    break;
                case PLACES_DETAILS :
                    PlaceDetailsJSONParser placeDetailsJsonParser = new PlaceDetailsJSONParser();
                    // Getting the parsed data as a List construct
                    list = placeDetailsJsonParser.parse(jObject);
                }

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

        @Override
        protected void onPostExecute(List<HashMap<String, String>> result) {

            switch(parserType){
            case PLACES :
                String[] from = new String[] { "description"};
                int[] to = new int[] { android.R.id.text1 };

                // Creating a SimpleAdapter for the AutoCompleteTextView
                SimpleAdapter adapter = new SimpleAdapter(getBaseContext(), result, android.R.layout.simple_list_item_1, from, to);

                // Setting the adapter
                atvPlaces.setAdapter(adapter);
                break;
            case PLACES_DETAILS :
                HashMap<String, String> hm = result.get(0);

                // Getting latitude from the parsed data
                double latitude = Double.parseDouble(hm.get("lat"));

                // Getting longitude from the parsed data
                double longitude = Double.parseDouble(hm.get("lng"));

                // Getting reference to the SupportMapFragment of the activity_main.xml
                SupportMapFragment fm = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);

                // Getting GoogleMap from SupportMapFragment
                googleMap = fm.getMap();

                LatLng point = new LatLng(latitude, longitude);

                CameraUpdate cameraPosition = CameraUpdateFactory.newLatLng(point);
                CameraUpdate cameraZoom = CameraUpdateFactory.zoomBy(5);

                // Showing the user input location in the Google Map
                googleMap.moveCamera(cameraPosition);
                googleMap.animateCamera(cameraZoom);

                MarkerOptions options = new MarkerOptions();
                options.position(point);
                options.title("Position");
                options.snippet("Latitude:"+latitude+",Longitude:"+longitude);

                // Adding the marker in the Google Map
                googleMap.addMarker(options);

                break;
            }
        }
    }

    @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 :  Replace “YOUR_API_KEY” at the lines 114 and 140 with the API key obtained in Step 9


17. 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.locationautogooglemapv2"
    android:versionCode="1"
    android:versionName="1.0" >

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

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

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

     <uses-permission android:name="in.wptrafficanalyzer.locationautogooglemapv2.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.locationautogooglemapv2.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_API_KEY"/>
    </application>
</manifest>

Note :  Replace “YOUR_API_KEY” at the 45 with the API key obtained in Step 8



18. Screenshots of the application

Lists Google Places as the user inputs place

Figure 7 : Lists Google Places as the user inputs place

Showing the selected place in Google Map Android API V2

Figure 8 : Showing the selected place in Google Map Android API V2


19. 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: , , , , , , ,

22 Responses to Selecting Google Place from AutoCompleteTextView and marking in Google Map Android API V2

  1. sue on May 24, 2013 at 7:52 am

    your article is very very helpful. i really appreciate for your article!! anyway, i have a question. didnt it need this -> class=”com.google.android.gms.maps.SupportMapFragment”<- under <fragment
    android:id="@+id/map"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"

    android:layout_below="@id/atv_places" <- here ?
    plz, recomment~

    • george on May 24, 2013 at 8:10 am

      Yes, that is needed.

      Thank you for reporting this and corrected it in the article.

      • sue on May 24, 2013 at 12:54 pm

        no thx! all your tutorial is always helful!

  2. Jack on June 4, 2013 at 3:20 pm

    Thanks for the wonderful tutorial.
    I have one question:why it always mark the same wrong place no matter what place I input

    • Jack on June 4, 2013 at 3:26 pm

      So sorry for disturbing you. I just found I forgot one of the brower KEY

  3. krishna on July 25, 2013 at 2:42 pm

    Thanks for Your Tutorial

    am not getting any kind of places in autocompletetextview am confused at generating browser key. There is no google maps in our website this is the problem or not.

  4. Buddhika on January 2, 2014 at 11:52 am

    When using Google Places API, Users with an API key are allowed 1 000 requests per 24 hour period. after exceeding this limit, we got “OVER_QUERY_LIMIT” error.

    How could i handle this in your code ?

  5. Prushni on February 13, 2014 at 5:32 pm

    Hello sir,
    I am using this project in my app. but i am getting only map. I am not getting any auto suggestions when i type any place. please guide

    • bakabt on April 19, 2014 at 4:01 pm

      I’m getting the same problem

    • Virat Singh on May 29, 2014 at 8:11 am

      Same here, any solution?

      • denz on August 30, 2014 at 10:17 am

        check your browser key. Make sure you create new browser key, then for the reference leave it blank so that it will referred any.

  6. Andrei Harasemiuc on March 27, 2014 at 12:47 am

    Hello,

    Thanks very much for this example.

    I succesfully implemented it in my app.
    There is one problem however.
    The SimpleAdapter has a filter which breaks words apart. So for instance if you press space after a word, no more results are showing. Did you find a workaround this?

  7. Hiren on September 13, 2014 at 1:08 pm

    Sir I have not my own website then how i generate the browser key
    i went to use browser key in android application

  8. gaurav kumar gupta on October 18, 2014 at 6:07 pm

    this is really very helpful example .
    but is this possible to use autocomplete edittext for two marker and and find the driving route between that markers??
    please recomment for this……

  9. vaisakh on December 18, 2014 at 1:56 pm

    12-18 00:24:53.863: E/AndroidRuntime(738): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.googlemap/com.example.googlemap.MainActivity}: android.view.InflateException: Binary XML file line #15: Error inflating class fragment

  10. Mounika on February 16, 2015 at 2:48 pm

    Hello sir,
    I am using this project in my app. but i am getting only map. I am not getting any auto suggestions when i type any place. please guide me

  11. zoney on March 8, 2015 at 1:04 pm

    i want to add 2 autocomplete text view in which user enters source and destinations and when user preses find directions button then the directions/route/path from source to destination should be displayed on map , how to do that, kindly help , its really urgent

  12. Vũ Đình Dũng (FGR HN) on July 13, 2015 at 10:04 am

    hi sir. The tutorial is very useful!
    I run the project. It’s work well. But autocomplete text just correct first time it suggestion. When i try the second time it make wrong position,and I dont know why?

  13. Rainer on September 30, 2015 at 3:43 pm

    Great tutorial. Thanks for this.
    Can you please confirm, that you are fine with the code of this tutorial being used in one’s own apps free of charge. I am asking since there is no Licence file in the code download. This would be a great help.
    Thanks,
    Rainer

  14. meghna shinde on April 2, 2016 at 11:39 am

    Hello Sir,

    The tutorial is very useful!, but my autocomplete text view not working, i am adding brwser key(goolgle place Map android(enable) -> api key -> Credentials -> browser key with empty)
    But, autocomplete text view not running .
    please. tell me what happen.

  15. zlatan on May 15, 2016 at 8:01 am

    Sir please what is the difference between the Browser key and the Api key
    are they the same

  16. Arpit on July 13, 2016 at 2:56 pm

    Hello sir,

    can you please tell me how to show the search result list in a listview.
    you show it in a default simple_list_item_1 but i want to show it in an own created list view.

    please help me sir

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