Download DOC - Your Projects

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts
no text concepts found
Transcript
Google Maps Search Nearby: Displaying
Nearby Places using Google Places API
and Google Maps API V2
In this practical we will learn how to find nearby places in Google Maps. We will
first see how to get current location of user and then will add marker on nearby
places like Restaurants, Hospitals, Schools etc.
Creating new project
Please follow following steps:
1. Open Android Studio and make a new project with name “Google Maps
Search Nearby.
2. Click Next and choose android version Lollipop. Again Click Next and
Choose Google Maps Activity (as shown in following pic).
1. Leave all things remaining same and Click Finish.
Now you will be able to see three files:
1. google_maps_api.xml
2. MapsActivity.java
3. AndroidManifest.xml
1|Page
Configuring Google Play Services
Open google_maps_api.xml. Here you will find a lot of information along with a link.
Copy-Paste this link in your web browser. Also, make a Gmail account through which
you will configure google play services.
Now at the browser choose Create a Project and Click Continue. Following screen will
be displayed:
2|Page
Create your key by clicking Create API key.
Click on RESTRICT KEY.
3|Page
Click on SAVE. Now a key will be created that you shall copy and paste in
google_maps_api.xml. Copy paste it in place where YOUR_KEY_HERE is written:
Code inside google_maps_api.xml is complete.
Code Inside AndroidManifest.xml:
If you go inside AndroidManifest.xml then this key will be displayed in meta tags. Here
you need to add permissions for accessing location of device. The required permission
should be as follows:
ACCESS_NETWORK_STATE – To check network state i.e if we are connected to any
network or not.
INTERNET – If we are connected to Internet or not. ACCESS_COARSE_LOCATION –
To determine user’s location using WiFi and mobile. It will give us approximate location.
ACCESS_FINE_LOCATION – To determine user’s location using GPS. It will give us
precise location.
OpenGL ES V2 – Required for Google Maps V2
Finally, our code inside AndroidManifest.xml will be as follows:
4|Page
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.se245547.googlemapssearchnearby">
// This should match with your username
<!-The ACCESS_COARSE/FINE_LOCATION permissions are not required to use
Google Maps Android API v2, but you must specify either coarse or fine
location permissions for the 'MyLocation' functionality.
-->
<uses-permission android:name="com.example.se245547.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" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<!-The API key for Google Maps-based APIs is defined as a string
resource.
(See the file "res/values/google_maps_api.xml").
Note that the API key is linked to the encryption key used to sign
the APK.
You need a different API key for each encryption key, including the
release key that is used to
sign the APK for publishing.
You can define the keys for the debug and release targets in
src/debug/ and src/release/.
-->
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="@string/google_maps_key" />
<activity
android:name=".MapsActivity"
android:label="@string/title_activity_maps">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Code inside activity_maps.xml:
Here we will add three buttons each for Restaurant, Hospitals and Schools
such that when user clicks on Restaurant then markers will be added on
nearby restaurants. Similarly, in case of other two buttons. For this, we will use
FrameLayout. Refer below code:
5|Page
activity_maps.xml
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android">
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:map="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.se245547.googlemapssearchnearby.MapsActivity" />
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<Button
android:id="@+id/btnRestaurant"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Nearby Restaurants" />
<Button
android:id="@+id/btnHospital"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Nearby Hospitals" />
<Button
android:id="@+id/btnSchool"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Nearby Schools" />
</LinearLayout>
</FrameLayout>
Note: Please see your build.gradle file. It should have following code:
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.4.0'
compile 'com.google.android.gms:play-services:9.2.1'
}
Third line compile 'com.google.android.gms:play-services:9.2.1' is responsible for
inserting Google Play Services. Please make sure this line is present in
build.gradle
MapsActivity.java Code of Google Maps Search Nearby App
This is the main part of our code. We will divide it into parts to get a grasp on
it. Here we won’t discuss code related to getting current user location.
We will divide our project i.e. Google Maps Search Nearby into different
classes so that user can easily debug code. Here we will make three classes
6|Page
apart from MapsActivity.java i.e. GetNearbyPlacesData.java,
DataParser.java and DownloadUrl.java.
First of all, we will check if Google Play Services available or not in onCreate()
function of MapsActivity.java. For that we will use function
CheckGooglePlayServices()
private boolean CheckGooglePlayServices() {
GoogleApiAvailability googleAPI = GoogleApiAvailability.getInstance();
int result = googleAPI.isGooglePlayServicesAvailable(this);
if(result != ConnectionResult.SUCCESS) {
if(googleAPI.isUserResolvableError(result)) {
googleAPI.getErrorDialog(this, result,
0).show();
}
return false;
}
return true;
}
GoogleApiAvailability is the Helper class for verifying that the Google Play
services APK is available and up-to-date on android device. If result is
ConnectionResult.SUCCESS then connection was successful otherwise, we
will return false.
Inserting callbacks:
We need to use following callback in implements portion:
1. GoogleApiClient.ConnectionCallbacks: This callback will have a public function
onConnected() which will be called whenever device is connected and
disconnected.
2. GoogleApiClient.OnConnectionFailedListener: Provides callbacks for scenarios
that result in a failed attempt to connect the client to the service. Whenever
connection is failed onConnectionFailed() will be called.
3. LocationListener: This callback will be called whenever there is change in
location of device. Function onLocationChanged() will be called.
public class MapsActivity extends FragmentActivity implements OnMapReadyCallback,
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener {
Now comes the heart of our Google Maps Search Nearby code i.e.
onMapReady() function. Here we will first build a Google API Client and then
enable current user location using mMap.setMyLocationEnabled(true);
@Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
mMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
//Initialize Google Play Services
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
7|Page
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
buildGoogleApiClient();
mMap.setMyLocationEnabled(true);
}
}
else {
buildGoogleApiClient();
mMap.setMyLocationEnabled(true);
}
}
Define a new function protected synchronized void buildGoogleApiClient() add
following code:
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
mGoogleApiClient.connect();
}
Add following code inside onConnected():
@Override
public void onConnected(@Nullable Bundle bundle) {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(1000);
mLocationRequest.setFastestInterval(1000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient,
mLocationRequest, this);
}
}
Define onLocationChanged() and add following code in it:
@Override
public void onLocationChanged(Location location) {
Log.d("onLocationChanged", "entered");
mLastLocation = location;
if (mCurrLocationMarker != null) {
mCurrLocationMarker.remove();
}
//Place current location marker
latitude = location.getLatitude();
longitude = location.getLongitude();
LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
MarkerOptions markerOptions = new MarkerOptions();
markerOptions.position(latLng);
markerOptions.title("Current Position");
markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MA
GENTA));
mCurrLocationMarker = mMap.addMarker(markerOptions);
8|Page
//move map camera
mMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
mMap.animateCamera(CameraUpdateFactory.zoomTo(11));
Toast.makeText(MapsActivity.this,"Your Current Location",
Toast.LENGTH_LONG).show();
Log.d("onLocationChanged", String.format("latitude:%.3f
longitude:%.3f",latitude,longitude));
//stop location updates
if (mGoogleApiClient != null) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient,
this);
Log.d("onLocationChanged", "Removing Location Updates");
}
Log.d("onLocationChanged", "Exit");
}
Requesting Location Permission
Application will not be granted any permission at installation time. Instead, application
has to ask user for a permission one-by-one at runtime. So now add following code:
public static final int MY_PERMISSIONS_REQUEST_LOCATION = 99;
public boolean checkLocationPermission(){
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
// Asking user if explanation is needed
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.ACCESS_FINE_LOCATION)) {
// Show an explanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.
//Prompt the user once explanation has been shown
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
MY_PERMISSIONS_REQUEST_LOCATION);
} else {
// No explanation needed, we can request the permission.
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
MY_PERMISSIONS_REQUEST_LOCATION);
}
return false;
} else {
return true;
}
}
Handling permission request response
A dialog box is presented whenever any App requests permissions. When the user
responds, the system invokes app’s onRequestPermissionsResult() method, passing
it the user response. Our app has to override this method to find out whether the
permission was granted. Add below code.
9|Page
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_LOCATION: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted. Do the
// contacts-related task you need to do.
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
if (mGoogleApiClient == null) {
buildGoogleApiClient();
}
mMap.setMyLocationEnabled(true);
}
} else {
// Permission denied, Disable the functionality that depends on this
permission.
Toast.makeText(this, "permission denied", Toast.LENGTH_LONG).show();
}
return;
}
// other 'case' lines to check for other permissions this app might request.
// You can add here other case statements according to your requirement.
}
}
These steps we have already discussed in our last week tutorial. So now we
will directly refer to the working of buttons and how to get nearby places using
it. We will explain here functionality of Nearby Restaurants button. Rest of the
two buttons will share same functionality except string passed will be Hospital
or School according to button clicked.
Finding nearby Restaurants on Google Maps
We will start its implementation by setting setOnClickListener() and as soon
as user clicks on it, code inside onClick(View v) executed.
Button btnRestaurant = (Button) findViewById(R.id.btnRestaurant);
btnRestaurant.setOnClickListener(new View.OnClickListener() {
String Restaurant = "restaurant";
@Override
public void onClick(View v) {
Log.d("onClick", "Button is Clicked");
mMap.clear();
String url = getUrl(latitude, longitude, Restaurant);
Object[] DataTransfer = new Object[2];
DataTransfer[0] = mMap;
DataTransfer[1] = url;
Log.d("onClick", url);
GetNearbyPlacesData getNearbyPlacesData = new GetNearbyPlacesData();
getNearbyPlacesData.execute(DataTransfer);
Toast.makeText(MapsActivity.this,"Nearby Restaurants",
Toast.LENGTH_LONG).show();
10 | P a g e
}
});
In the above code first of all Google Map is cleared using mMap.clear(); so that
any pre-deposited markers are deleted. Then we are making a URL using
getUrl() function. It will be used to get information about nearby restaurant on
google maps. This URL is made according to Google Developer Guide for
nearby places (https://developers.google.com/places/web-service/search).
private String getUrl(double latitude, double longitude, String nearbyPlace) {
StringBuilder googlePlacesUrl = new
StringBuilder("https://maps.googleapis.com/maps/api/place/nearbysearch/json?");
googlePlacesUrl.append("location=" + latitude + "," + longitude);
googlePlacesUrl.append("&radius=" + PROXIMITY_RADIUS);
googlePlacesUrl.append("&type=" + nearbyPlace);
googlePlacesUrl.append("&sensor=true");
googlePlacesUrl.append("&key=" + "AIzaSyATuUiZUkEc_UgHuqsBJa1oqaODI-3mLs0");
Log.d("getUrl", googlePlacesUrl.toString());
return (googlePlacesUrl.toString());
}
Finally, markers are added on nearby restaurants using
getNearbyPlacesData.execute(DataTransfer);
Let’s see what is this getNearbyPlacesData is in Google Maps Search Nearby
App.
GetNearbyPlacesData
Make a new class named GetNearbyPlacesData.java. This class should be
extended from AsyncTask.
import
import
import
import
import
android.os.AsyncTask;
android.util.Log;
java.util.HashMap;
java.util.List;
org.json.JSONObject;
import
import
import
import
import
com.google.android.gms.maps.CameraUpdateFactory;
com.google.android.gms.maps.GoogleMap;
com.google.android.gms.maps.model.BitmapDescriptorFactory;
com.google.android.gms.maps.model.LatLng;
com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.maps.GoogleMap;
/**
* Created by se245547 on 26/10/2016.
*/
public class GetNearbyPlacesData extends AsyncTask<Object, String, String> {
String googlePlacesData;
GoogleMap mMap;
String url;
11 | P a g e
@Override
protected String doInBackground(Object... params) {
try {
Log.d("GetNearbyPlacesData", "doInBackground entered");
mMap = (GoogleMap) params[0];
url = (String) params[1];
DownloadUrl downloadUrl = new DownloadUrl();
googlePlacesData = downloadUrl.readUrl(url);
Log.d("GooglePlacesReadTask", "doInBackground Exit");
} catch (Exception e) {
Log.d("GooglePlacesReadTask", e.toString());
}
return googlePlacesData;
}
@Override
protected void onPostExecute(String result) {
Log.d("GooglePlacesReadTask", "onPostExecute Entered");
List<HashMap<String, String>> nearbyPlacesList = null;
DataParser dataParser = new DataParser();
nearbyPlacesList = dataParser.parse(result);
ShowNearbyPlaces(nearbyPlacesList);
Log.d("GooglePlacesReadTask", "onPostExecute Exit");
}
private void ShowNearbyPlaces(List<HashMap<String, String>> nearbyPlacesList) {
for (int i = 0; i < nearbyPlacesList.size(); i++) {
Log.d("onPostExecute","Entered into showing locations");
MarkerOptions markerOptions = new MarkerOptions();
HashMap<String, String> googlePlace = nearbyPlacesList.get(i);
double lat = Double.parseDouble(googlePlace.get("lat"));
double lng = Double.parseDouble(googlePlace.get("lng"));
String placeName = googlePlace.get("place_name");
String vicinity = googlePlace.get("vicinity");
LatLng latLng = new LatLng(lat, lng);
markerOptions.position(latLng);
markerOptions.title(placeName + " : " + vicinity);
mMap.addMarker(markerOptions);
markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RE
D));
//move map camera
mMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
mMap.animateCamera(CameraUpdateFactory.zoomTo(11));
}
}
}
In the above code DownloadUrl is a class which is used to retrieve data from URL
using HttpURLConnection and File handling methods. We will discuss its code
after this class. After retrieving data in the form of googlePlacesData we are
passing it to onPostExecute method. dataParser.parse(result) is used to parse data
and resultant is stored as a list in nearbyPlacesList. Now nearbyPlacesList will
have all information about nearby restaurants which we can easily access and
add markers on corresponding places. Markers are added in Google Maps
using function ShowNearbyPlaces. This is pretty much self-explanatory.
Data from URL will be in the form JSON which needs to be parsed, so we
have made a class named DataParser. DataParser.java file should be added
at the same path as MapsActivity.java.
12 | P a g e
DataParser.java
import android.util.Log;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
/**
* Created by se245547 on 26/10/2016.
*/
public class DataParser {
public List<HashMap<String, String>> parse(String jsonData) {
JSONArray jsonArray = null;
JSONObject jsonObject;
try {
Log.d("Places", "parse");
jsonObject = new JSONObject((String) jsonData);
jsonArray = jsonObject.getJSONArray("results");
} catch (JSONException e) {
Log.d("Places", "parse error");
e.printStackTrace();
}
return getPlaces(jsonArray);
}
private List<HashMap<String, String>> getPlaces(JSONArray jsonArray) {
int placesCount = jsonArray.length();
List<HashMap<String, String>> placesList = new ArrayList<>();
HashMap<String, String> placeMap = null;
Log.d("Places", "getPlaces");
for (int i = 0; i < placesCount; i++) {
try {
placeMap = getPlace((JSONObject) jsonArray.get(i));
placesList.add(placeMap);
Log.d("Places", "Adding places");
} catch (JSONException e) {
Log.d("Places", "Error in Adding places");
e.printStackTrace();
}
}
return placesList;
}
private HashMap<String, String> getPlace(JSONObject googlePlaceJson) {
HashMap<String, String> googlePlaceMap = new HashMap<String, String>();
String placeName = "-NA-";
String vicinity = "-NA-";
String latitude = "";
String longitude = "";
String reference = "";
Log.d("getPlace", "Entered");
try {
if (!googlePlaceJson.isNull("name")) {
placeName = googlePlaceJson.getString("name");
}
if (!googlePlaceJson.isNull("vicinity")) {
vicinity = googlePlaceJson.getString("vicinity");
}
13 | P a g e
latitude =
googlePlaceJson.getJSONObject("geometry").getJSONObject("location").getString("lat");
longitude =
googlePlaceJson.getJSONObject("geometry").getJSONObject("location").getString("lng");
reference = googlePlaceJson.getString("reference");
googlePlaceMap.put("place_name", placeName);
googlePlaceMap.put("vicinity", vicinity);
googlePlaceMap.put("lat", latitude);
googlePlaceMap.put("lng", longitude);
googlePlaceMap.put("reference", reference);
Log.d("getPlace", "Putting Places");
} catch (JSONException e) {
Log.d("getPlace", "Error");
e.printStackTrace();
}
return googlePlaceMap;
}
}
DownloadUrl
This class should be made at the same path as MapsActivity.java with the
name DownloadUrl.java and add following code in it.
import android.util.Log;
import
import
import
import
import
import
java.io.BufferedReader;
java.io.IOException;
java.io.InputStream;
java.io.InputStreamReader;
java.net.HttpURLConnection;
java.net.URL;
/**
* Created by se245547 on 26/10/2016.
*/
public class DownloadUrl {
public String readUrl(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();
Log.d("downloadUrl", data.toString());
br.close();
14 | P a g e
} catch (Exception e) {
Log.d("Exception", e.toString());
} finally {
iStream.close();
urlConnection.disconnect();
}
return data;
}
}
Data returned from web will be in json format which user can get using
HttpURLConnection. You can get more information about how to get data over
web here. So this task will return JSON data returned from web. Our code of
Google Maps Search Nearby App is complete for Adding markers at nearby
restaurants on Google Maps. Now similarly you can do for School and Hospitals.
The only change will be in getUrl() function where string will be passed as
Hospital or School according to the button clicked.
So finally our Google Maps Search Nearby App is complete. We would
suggest you to turn on GPS and Internet Connection. Run this Google Maps
Search Nearby Places App on any android device. It will first display your
location. Now according to button clicked it will display nearby Restaurants,
Schools or Hospitals as shown in following figure:
15 | P a g e