Saturday, November 2, 2013

Google Map

In this tutorial, you will learn to create a Google Map app. The Google Map app will display the Google map and spot the current location of the device on the map by a red-filled circle. In case that the current location can not be retrieved at the time, you will not see the red-filled circle at the correct location. When the user touches any location on the map, the address of that location will be shown. The address to display will include latitude, longitude, street, city, and country. Without internet connection, the app is able to show only the latitude and longitude of the location. To get the full address as mentioned, you need to make sure the internet connection work properly.



To begin the GoogleMap app, you will create a new Android Project in Eclipse. The name of the project will be GMap.

Getting Google Map to work in your app requires many steps as shown below.

1. Download and install Google Play Service API. You can use the Android SDK Manager to install this API. You would get the google-play-service.jar file stored in the directory where you store the Android SDK. In my machine, this is the path of the jar file: D:\androidbundle\sdk\extras\google\google_play_services\libproject\google-play-services_lib\libs. To use the API in the GMap project, you need to add this jar file into the project build path (Project->Properties->Java Build Path->Libraries->Add External Jars...) of the Eclipse.

2. Get the SHA-1 fingerprint for your certificate. For Window 7 or Vista users, you can get the SHA-1 key by issuing the following command from the command prompt window. You will need to change the path of the keystore file. In my case, the keystore file is in the path C:\Users\Acer\.android.

keytool -list -v -alias androiddebugkey -keystore C:\Users\Acer\.android\debug.keystore -alias name: androiddebugkey -storepass android -keypass android

3. You would see the output similar to this:
Creation date: Sep 8, 2013
Entry type: PrivateKeyEntry
Certificate chain length: 1
Certificate[1]:
Owner: CN=Android Debug, O=Android, C=US
Issuer: CN=Android Debug, O=Android, C=US
Serial number: 5883f7cc
Valid from: Sun Sep 08 14:28:53 ICT 2013 until: Tue Sep 01 14:28:53 ICT 2043
Certificate fingerprints:
MD5: 2A:9E:7C:7B:87:6C:5D:1F:B4:84:C0:84:BB:45:10:69
SHA1: D0:91:62:F8:32:45:B1:89:94:B3:79:B4:FD:DD:64:22:C9:72:B9:E3
SHA256: FF:4C:BF:52:EA:C1:0E:0D:FF:C0:8E:C3:2A:0D:41:ED:07:DA:3A:3D:40:
81:7F:2C:9A:13:17:AD:F5:C6:78:5A
Signature algorithm name: SHA256withRSA
Version: 3
Extensions:
#1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 2F 69 DC 79 F8 A5 07 1A 10 61 EC BD 1D E0 58 AC /i.y.....a....X.
0010: 94 CB 18 C5 ....
]
]

4. Obtain API key from Google. To get the API key from Google, you can follow the steps below:
- Open Google Console then create a new project by clicking the Create... from the drop-down list.
- Select API Access from the active project you created. In the resulting page, click Create New Android Key....In the resulting page, you are required to enter the SHA-1 key, semi-colon, and the package name of the your project. See the picture below.



- You will get the API key similar to this AIzaSyB6aqPG9XhbPMGVzkoohdlgK2HzRHe85nA.
- Turn on Goole Map Android API v2 service. You will select Services and turn on Goole Map Android API v2.
- Register the API key to your GMap app. You will open the AndroidManifest.xml file of the app and just above </application> paste the following code.

<meta-data
android:name="com.google.android.maps.v2.API_KEY"
android:value="AIzaSyB6aqPG9XhbPMGVzkoohdlgK2HzRHe85nA"/>
- You will need to set some permissons and the use of OpenGL ES version 2 feature in the AndroidManifest file of your app.
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES"/>
<!-- The following two permissions are not required to use
Google Maps Android API v2, but are recommended. -->
<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" />

This is the complete AndroidManifest.xml file.

AndroidManifest.xml file

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

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />
 
    <uses-feature
        android:glEsVersion="0x00020000"
        android:required="true" />

  <uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission     android:name="com.google.android.providers.gsf.permission.READ_GSERVICES"/>
<!-- The following two permissions are not required to use
     Google Maps Android API v2, but are recommended. -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

    <application
        android:allowBackup="true"
        android:icon="@drawable/gmaptr"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.gmap.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="AIzaSyB6aqPG9XhbPMGVzkoohdlgK2HzRHe85nA"/>
    </application>

</manifest>


Now you are ready to add a map to the GMap app. You will copy and paste (override) the following code to the activity_main.xml file.

<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:map="http://schemas.android.com/apk/res-auto"
android:id="@+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.google.android.gms.maps.SupportMapFragment"
/>

In the MainActivity class, you will need more code to show the map, apply the settings to map, identify the current location, and display the address of the location when the user touches that location. Here is the content of the MainActivity class.

MainActivity. java file

package com.example.gmap;
import java.util.List;
import java.util.Locale;
import android.content.Context;
import android.graphics.Color;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import android.view.Menu;
import android.widget.Toast;

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.GoogleMap.OnMapClickListener;
import com.google.android.gms.maps.UiSettings;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.Circle;
import com.google.android.gms.maps.model.CircleOptions;
import com.google.android.gms.maps.model.LatLng;

public class MainActivity extends FragmentActivity{
  private GoogleMap map;
  private LocationManager locationManager;
  private Location mylocation;
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    determineLocation();
  }

  protected void onStart() {
       super.onStart();
       setupMap();
       appMapSettings();
       spotCurrentLocation(mylocation);
  }

  public void setupMap(){
 if(map==null){
  SupportMapFragment mf=(SupportMapFragment)getSupportFragmentManager().findFragmentById(R.id.map);  
   map=mf.getMap();
     
 }

  }
 

  public void appMapSettings(){
 if(map!=null){
 //enable map click
 map.setOnMapClickListener(new MapClick());
 //specify the type of map
 map.setMapType(GoogleMap.MAP_TYPE_HYBRID);
 //enable my location on the map
 map.setMyLocationEnabled(true);
 //enable button for my location
 UiSettings uis=map.getUiSettings();
 uis.setMyLocationButtonEnabled(true);



 }
  }

  public void spotCurrentLocation(Location location){
     double lat,lng;
   
// Instantiates a new CircleOptions object and defines the center and radius
 CircleOptions circleOptions = new CircleOptions();
 circleOptions.strokeColor(Color.RED);
 circleOptions.fillColor(Color.RED);
 if(location==null) {//default center
 lat=12.7333;
   lng=105.6666;
 }

 else{
 lat=location.getLatitude();
 lng=location.getLongitude();
 }
 //center based on the current location
     circleOptions.center(new LatLng(lat,lng));
 circleOptions.radius(1000); // In meters
 Circle circle = map.addCircle(circleOptions);
 circle.setVisible(true);
 //set target location
 CameraUpdate center=CameraUpdateFactory.newLatLng(new LatLng(lat,lng));
         CameraUpdate zoom=CameraUpdateFactory.zoomTo(15);
         //set zoom level
     map.moveCamera(center);
     map.animateCamera(zoom);
  }
  class MapClick implements OnMapClickListener{

 public void onMapClick(LatLng coor){

 doInBackground(coor);

}

  }

  public void doInBackground(LatLng coordinate){
 final LatLng coor=coordinate;
 Handler handler=new Handler();
 handler.post(new Runnable(){
 public void run(){
 showAddress(coor.latitude,coor.longitude);
 }
 });
  }

  public void showAddress(double lat,double lng){

 Geocoder geocoder =new Geocoder(getBaseContext(), Locale.getDefault());
 List<Address> addresses = null;
 String addressText="";
 int count=0;
 try {    
 addresses = geocoder.getFromLocation(lat, lng, 1);
 while(count<10){
 addresses = geocoder.getFromLocation(lat, lng, 1);
 count++;
 }
 } catch (Exception e1) {Log.e(this.toString(),"Error...");}

 if (addresses != null && addresses.size() > 0) {
// Get the first address
Address address = addresses.get(0);
//get street, city, and country
addressText =address.getMaxAddressLineIndex()>0?address.getAddressLine(0)+", ":"null, ";
addressText+=address.getLocality()+", "+address.getCountryName();

 }

 Toast.makeText(getBaseContext(), "Address:("+lat+","+lng+") "+addressText, Toast.LENGTH_SHORT).show();
  }



  public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
  }

  public void determineLocation() {
String location_context = Context.LOCATION_SERVICE;
//Create locationManager object from the Android system location service
locationManager = (LocationManager)getSystemService(location_context);
//retrieve the available location providers
  List<String> providers = locationManager.getProviders(true);
  for (String provider : providers) {
 
  locationManager.requestLocationUpdates(provider, 1000, 0, new LocationListener() {
  public void onLocationChanged(Location location) {
  //spot the current update location
  spotCurrentLocation(location);
  }
  public void onProviderDisabled(String provider){}
  public void onProviderEnabled(String provider){}
  public void onStatusChanged(String provider, int status, Bundle extras){}
  });
  //get the current device' location from the provider
  mylocation= locationManager.getLastKnownLocation(provider);
 
  }
 
  }

}

In the onCreate method, the determineLocation method is called to detect the current location of the device. The getSystemService method returns the LocationManager object. This object will be used to get the information about location providers. Each provider represents a different technology used to determine the current locaiton. A location on the device changes when the device moves. So to get the current updated location from Android, you will need to invoke the requestLocationUpdates method of the LocationManager class. The getLastKnownLocation method will be used to get the current locaiton of the device.

In the onStart method, the setupMap, appMapSettings, and spotCurrentLocation methods are invoked. The setupMap method will show the map. The appMapSettings method specifies settings for the map. You will read he comments in code to get the idea about each setting. The spotCurrentLocation will spot the current location by a red-filled circle. The circle will cover 1000 meters around the current location.

The showAddress method will be called each time the user touched the map. The getFromLocation method of the Geocoder class is used to get the address of the current location. This method return a string that contain street, city, and country of the current location.

Download the apk file of the GMap app.

No comments:

Post a Comment