Android Apps

Google Places Api Web Services For Android

androdi google places api
Written by Yasir Ameen

Today i am going to discuss Google Places Api which is very interesting thing along with designing prespective 🙂 . We are going to create a little app consist of Autocomplete location based on Google Places Api. This is the part 2 of GoogleMap Series and you must need to read part 1 before starting this one.

 

Let’s Start Creating Google Places Api

Download Source Code : https://github.com/YasirAmeen/Google-Places-Api-.git

As i said earlier that this tutorial is  the 2nd part of the GoogleMap Series, so i will suggest you see its part 1 before starting this one.

See the final results what we are making

Requirements

You will need CardView dependency for creating Search Bar .
Important : Make sure to visit part 1 in order to get complete dependencies and permission you will required NETWOR Permission also.

compile 'com.android.support:cardview-v7:24.2.1'

Creating Search Layout Design

I used AutocompleteTexView as EditText because we want to populate location according to search term.

Important : Make sure to add call AutoCompleteTextView using findViewById in your MainActivity class.


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/main_layout"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:focusable="true"
    android:focusableInTouchMode="true"
    android:layout_height="match_parent">

    <android.support.v7.widget.CardView
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingBottom="10dp"
        android:layout_marginTop="62dp"
        android:layout_marginRight="16dp"
        android:visibility="visible"
        android:layout_marginLeft="16dp"
        app:cardBackgroundColor="@android:color/white"
        android:id="@+id/cardView">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="55dp"
            android:orientation="horizontal"
            android:gravity="center"
            >

            <ImageView
                android:layout_width="0dp"
                android:layout_weight="0.12"
                android:layout_height="match_parent"
                android:padding="11dp"
                android:src="@drawable/menu"
                android:tint="#363636"
                android:layout_marginLeft="5dp"
                android:id="@+id/imageView" />

            <AutoCompleteTextView
                android:layout_width="0dp"
                android:layout_weight="0.7"
                android:layout_height="wrap_content"
                android:textSize="18sp"
                android:hint="Search Location"
                android:layout_marginTop="10dp"
                android:layout_marginBottom="10dp"
                android:focusableInTouchMode="true"
                android:focusable="true"
                android:textColorHint="#39484F"
                android:drawablePadding="10dp"
                android:layout_marginRight="10dp"
                android:background="@android:color/transparent"
                android:id="@+id/location_text"
                android:nextFocusUp="@id/location_text"
                android:nextFocusLeft="@id/location_text"
                 android:inputType="text"
                android:singleLine="true"
                android:imeOptions="actionDone"
                android:textAppearance="?android:textAppearanceSmall"
                android:textColor="#000000"
                 />

            <ImageView
                android:layout_width="0dp"
                android:layout_weight="0.13"

                android:layout_height="match_parent"
                android:padding="14dp"

                android:src="@drawable/location_pin"
                android:tint="#363636"
                android:id="@+id/image_right" />

        </LinearLayout>


    </android.support.v7.widget.CardView>
    <fragment
        android:name="com.google.android.gms.maps.MapFragment"
        android:id="@+id/map"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</RelativeLayout>

following is the result of above xml

google map location places api

 

Enabling Google Places Api

In order to use Places Api, you will have to enable it from Google Developer Console . Keep in mind that we are using Web Service version so we have to enable it from the developer console. see below images.

Important : we are enabling places api for the GoogleMap key we used in Part 1

enabling google places api

 

After selecting Google Places API Web Service click the enable button and you are done.

enable google places api web service

Writing Google Places Auto Complete Adapter

So this is the very important part, we will write class which will handle and filter our search results See the comments in following snippet.

  
 class GooglePlacesAutocompleteAdapter extends ArrayAdapter implements Filterable {

    private ArrayList resultList;
    private static final String LOG_TAG = "Google Places Autocomplete";
    private static final String PLACES_API_BASE = "https://maps.googleapis.com/maps/api/place";
    private static final String TYPE_AUTOCOMPLETE = "/autocomplete";
    private static final String OUT_JSON = "/json";


    public GooglePlacesAutocompleteAdapter(Context context, int textViewResourceId) {
        super(context, textViewResourceId);
        resultList = new ArrayList();
    }

    @Override
    public int getCount() {
        return resultList.size();
    }

    @Override
    public Object getItem(int index) {
        return resultList.get(index);
    }

    @Override
    public Filter getFilter() {
        Filter filter = new Filter() {
            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
                FilterResults filterResults = new FilterResults();
                if (constraint != null) {
                    // Retrieve the autocomplete results.
                    resultList = autocomplete(constraint.toString());

                    // Assign the data to the FilterResults
                    filterResults.values = resultList;
                    filterResults.count = resultList.size();
                }
                return filterResults;
            }

            @Override
            protected void publishResults(CharSequence constraint, Filter.FilterResults results) {
                if (results != null && results.count > 0) {
                    notifyDataSetChanged();
                } else {
                    notifyDataSetInvalidated();
                }
            }
        };
        return filter;
    }

    @SuppressLint("LongLogTag")
    public static ArrayList autocomplete(String input) {
        ArrayList resultList = null;

        HttpURLConnection conn = null;
        StringBuilder jsonResults = new StringBuilder();
        try {

            //Creating Request URL for Google Places Api
            StringBuilder sb = new StringBuilder(PLACES_API_BASE + TYPE_AUTOCOMPLETE + OUT_JSON);
            sb.append("?key=AIzaSyAztmjFlR3ly2uDMYwR600l4SNA0rMaUac");
            //sb.append("&components=country:pk"); // In case you want to restrict results according to country
            sb.append("&input=" + URLEncoder.encode(input, "utf8"));
            sb.append("&types=geocode");

            URL url = new URL(sb.toString());
            conn = (HttpURLConnection) url.openConnection();
            InputStreamReader in = new InputStreamReader(conn.getInputStream());

            // Load the results into a StringBuilder
            int read;
            char[] buff = new char[1024];
            while ((read = in.read(buff)) != -1) {
                jsonResults.append(buff, 0, read);
            }
        } catch (MalformedURLException e) {
            Log.e(LOG_TAG, "Error processing Places API URL", e);
            return resultList;
        } catch (IOException e) {
            Log.e(LOG_TAG, "Error connecting to Places API", e);
            return resultList;
        } finally {
            if (conn != null) {
                conn.disconnect();
            }
        }

        try {
            // Create a JSON object hierarchy from the results
            JSONObject jsonObj = new JSONObject(jsonResults.toString());
            JSONArray predsJsonArray = jsonObj.getJSONArray("predictions");

            // Extract the Place descriptions from the results
            resultList = new ArrayList(predsJsonArray.length());
            for (int i = 0; i < predsJsonArray.length(); i++) {

                System.out.println(predsJsonArray.getJSONObject(i).getString("description") +"@"+predsJsonArray.getJSONObject(i).getString("place_id"));
                System.out.println();
                System.out.println("============================================================");
                resultList.add(predsJsonArray.getJSONObject(i).getString("description") +"@"+predsJsonArray.getJSONObject(i).getString("place_id"));
            }
        } catch (JSONException e) {
            Log.e("error", "Cannot process JSON results", e);
        }

        return resultList;
    }

}

Modifying setInitialLocation() Method

Now from part 1 open MainActivity.java and modify the setInitialLocation() Method look like below. You will also nneed a textview as a autocomplete_list_item.xml for the suggestion text.

 autocompletelistitem.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_margin="5dp"
    android:padding="10dp"
     android:textSize="15sp"
    android:background="#fff"
    android:textColor="@android:color/black"
    android:layout_height="wrap_content" />

Important : Don,t forget to write getLatLng() Method, see below.

 


private void setInitialLocation() {


    if (ActivityCompat.checkSelfPermission(MainActivity.this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(MainActivity.this, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        // TODO: Consider calling
        //    ActivityCompat#requestPermissions
        // here to request the missing permissions, and then overriding
        //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
        //                                          int[] grantResults)
        // to handle the case where the user grants the permission. See the documentation
        // for ActivityCompat#requestPermissions for more details.
        return;
    }
    LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, request, new LocationListener() {
        @Override
        public void onLocationChanged(Location location) {


            mLastLocation = location;

            try {
                LatLng positionUpdate = new LatLng(location.getLatitude(), location.getLongitude());
                CameraUpdate update = CameraUpdateFactory.newLatLngZoom(positionUpdate, 15);
                mMap.animateCamera(update);

                GooglePlacesAutocompleteAdapter adapter = new  GooglePlacesAutocompleteAdapter(MainActivity.this, R.layout.autocompletelistitem);
                locationTextView.setAdapter(adapter);

                locationTextView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                    @Override
                    public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {


                        InputMethodManager in = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                        in.hideSoftInputFromWindow(view.getApplicationWindowToken(), 0);
                        String str = (String) adapterView.getItemAtPosition(i);
                        String[] places = str.split("@");
                        String place_id = places[1];

                        locationTextView.setText("");
                        locationTextView.setHint(places[0]);
                        //getLatLng Method is not built-in method, find this method below
                        getLatLang(place_id);

                    }
                });

            } catch (Exception ex) {

                ex.printStackTrace();
                Log.e("MapException", ex.getMessage());

            }

        }

    });
}

 

Writing getLatLng() Method

Ok this is very interesting method, why ?? because it will take us to the selected location on map by taking place id. You have already seen in demo video.


public void getLatLang(String placeId) {
    Places.GeoDataApi.getPlaceById(googleApiClient, placeId)
            .setResultCallback(new ResultCallback<PlaceBuffer>() {
                @Override
                public void onResult(PlaceBuffer places) {
                    if (places.getStatus().isSuccess() && places.getCount() > 0) {
                        final Place place = places.get(0);
                        LatLng latLng = place.getLatLng();

                        try {

                            CameraUpdate update = CameraUpdateFactory.newLatLngZoom(latLng, 15);
                            mMap.animateCamera(update);
                        }
                        catch (Exception ex) {

                            ex.printStackTrace();
                            Log.e("MapException",ex.getMessage());

                        }

                        Log.i("place", "Place found: " + place.getName());
                    } else {
                        Log.e("place", "Place not found");
                    }
                    places.release();
                }
            });
}

That’s it 🙂 enjoy

 

About the author

Yasir Ameen

I'm a programmer, teacher, and speaker. I work out of my home in Pakistan, Karachi for the Mobile, especially Android Platform. I discuss about technology, gadgets, codes, the devices we’re going and we’ve been. I’m excited about community, social equity, and media.