Adding and removing multiple proximity alerts in Google Maps Android API V2

May 3, 2013
By

In this article, we will develop an Android application which demonstrates how to add multiple proximity alerts in Google Maps Android API V2.

We will make use the Android API class “LocationManager” to add and remove the proximity alerts and SharedPreferences to persist the markers on the Google Maps while restarting the application.



In order to define a proximity area, simply tap a location on the Google Maps. Then the area circumventing with a radius of 20 meters will be the proximity area for the tapped location. Once the Android device enters the proximity region, a notification alert will be generated along with system’s default notification ring tone and vibration.

This article is an extension to the article titled “Adding and removing Proximity Alert in Google Map Android API V2 using LocationManager” where we have discussed how to add single proximity alert to Google Maps.

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



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

Create new Android application project

Figure 1 : Create 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 Eclipse

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


7. Link Google Play Services Library to this project

Link Google Play Services library to this project

Figure 6 : Link 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. 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 “

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

    <fragment
        android:id="@+id/map"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</RelativeLayout>


11. Create a layout file res/layout/notification.xml


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/tv_notification"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" />
</LinearLayout>


12. Create the class “NotificationView” in the file src/in/wptrafficanalyzer/multipleproximitymapv2/NotificationView.java


package in.wptrafficanalyzer.proximitymapv2;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class NotificationView extends Activity {
    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView(R.layout.notification);

        TextView tv = (TextView) findViewById(R.id.tv_notification);
        Bundle data = getIntent().getExtras();
        tv.setText(data.getString("content"));
    }
}


13. Create the class “ProximityActivity” in the file src/in/wptrafficanalyzer/multipleproximitymapv2/ProximityActivity.java


package in.wptrafficanalyzer.multipleproximitymapv2;

import android.app.Activity;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.location.LocationManager;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.NotificationCompat;
import android.widget.Toast;

public class ProximityActivity extends Activity {

    String notificationTitle;
    String notificationContent;
    String tickerMessage;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        boolean proximity_entering = getIntent().getBooleanExtra(LocationManager.KEY_PROXIMITY_ENTERING, true);

        double lat = getIntent().getDoubleExtra("lat", 0);

        double lng = getIntent().getDoubleExtra("lng", 0);

        String strLocation = Double.toString(lat)+","+Double.toString(lng);

        if(proximity_entering){
            Toast.makeText(getBaseContext(),"Entering the region"  ,Toast.LENGTH_LONG).show();
            notificationTitle = "Proximity - Entry";
            notificationContent = "Entered the region:" + strLocation;
            tickerMessage = "Entered the region:" + strLocation;
        }else{
            Toast.makeText(getBaseContext(),"Exiting the region"  ,Toast.LENGTH_LONG).show();
            notificationTitle = "Proximity - Exit";
            notificationContent = "Exited the region:" + strLocation;
            tickerMessage = "Exited the region:" + strLocation;
        }

        Intent notificationIntent = new Intent(getApplicationContext(),NotificationView.class);

        /** Adding content to the notificationIntent, which will be displayed on
        * viewing the notification
        */
        notificationIntent.putExtra("content", notificationContent );

        /** This is needed to make this intent different from its previous intents */
        notificationIntent.setData(Uri.parse("tel:/"+ (int)System.currentTimeMillis()));

        /** Creating different tasks for each notification. See the flag Intent.FLAG_ACTIVITY_NEW_TASK */
        PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), 0, notificationIntent, Intent.FLAG_ACTIVITY_NEW_TASK);

        /** Getting the System service NotificationManager */
        NotificationManager nManager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);

        /** Configuring notification builder to create a notification */
        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(getApplicationContext())
                .setWhen(System.currentTimeMillis())
                .setContentText(notificationContent)
                .setContentTitle(notificationTitle)
                .setSmallIcon(R.drawable.ic_launcher)
                .setAutoCancel(true)
                .setTicker(tickerMessage)
                .setContentIntent(pendingIntent)
                .setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION));

        /** Creating a notification from the notification builder */
        Notification notification = notificationBuilder.build();

        /** Sending the notification to system.
        * The first argument ensures that each notification is having a unique id
        * If two notifications share same notification id, then the last notification replaces the first notification
        * */
        nManager.notify((int)System.currentTimeMillis(), notification);

        /** Finishes the execution of this activity */
        finish();
    }
}


14. Update the class “MainActivity” in the file src/in/wptrafficanalyzer/multipleproximitymapv2/MainActivity.java


package in.wptrafficanalyzer.multipleproximitymapv2;

import android.app.Dialog;
import android.app.PendingIntent;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.location.LocationManager;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.view.Menu;
import android.widget.Toast;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
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.GoogleMap.OnMapLongClickListener;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.CircleOptions;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;

public class MainActivity extends FragmentActivity {

    GoogleMap googleMap;
    LocationManager locationManager;
    PendingIntent pendingIntent;
    SharedPreferences sharedPreferences;
    int locationCount = 0;

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

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

        // Showing status
        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 of activity_main.xml
            SupportMapFragment fm = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);

            // Getting GoogleMap object from the fragment
            googleMap = fm.getMap();

            // Enabling MyLocation Layer of Google Map
            googleMap.setMyLocationEnabled(true);

            // Getting LocationManager object from System Service LOCATION_SERVICE
            locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);

            // Opening the sharedPreferences object
            sharedPreferences = getSharedPreferences("location", 0);

            // Getting number of locations already stored
            locationCount = sharedPreferences.getInt("locationCount", 0);

            // Getting stored zoom level if exists else return 0
            String zoom = sharedPreferences.getString("zoom", "0");

             // If locations are already saved
             if(locationCount!=0){

                 String lat = "";
                 String lng = "";

                 // Iterating through all the locations stored
                 for(int i=0;i<locationCount;i++){

                     // Getting the latitude of the i-th location
                     lat = sharedPreferences.getString("lat"+i,"0");

                     // Getting the longitude of the i-th location
                     lng = sharedPreferences.getString("lng"+i,"0");

                     // Drawing marker on the map
                     drawMarker(new LatLng(Double.parseDouble(lat), Double.parseDouble(lng)));

                     // Drawing circle on the map
                     drawCircle(new LatLng(Double.parseDouble(lat), Double.parseDouble(lng)));
                 }

                 // Moving CameraPosition to last clicked position
                 googleMap.moveCamera(CameraUpdateFactory.newLatLng(new LatLng(Double.parseDouble(lat), Double.parseDouble(lng))));

                 // Setting the zoom level in the map on last position  is clicked
                 googleMap.animateCamera(CameraUpdateFactory.zoomTo(Float.parseFloat(zoom)));
            }

            googleMap.setOnMapClickListener(new OnMapClickListener() {

                @Override
                public void onMapClick(LatLng point) {

                    // Incrementing location count
                    locationCount++;

                    // Drawing marker on the map
                    drawMarker(point);

                    // Drawing circle on the map
                    drawCircle(point);

                    // This intent will call the activity ProximityActivity
                    Intent proximityIntent = new Intent("in.wptrafficanalyzer.activity.proximity");

                    // Passing latitude to the PendingActivity
                    proximityIntent.putExtra("lat",point.latitude);

                    // Passing longitude to the PendingActivity
                    proximityIntent.putExtra("lng", point.longitude);

                    // Creating a pending intent which will be invoked by LocationManager when the specified region is
                    // entered or exited
                    pendingIntent = PendingIntent.getActivity(getBaseContext(), 0, proximityIntent,Intent.FLAG_ACTIVITY_NEW_TASK);

                    // Setting proximity alert
                    // The pending intent will be invoked when the device enters or exits the region 20 meters
                    // away from the marked point
                    // The -1 indicates that, the monitor will not be expired
                    locationManager.addProximityAlert(point.latitude, point.longitude, 20, -1, pendingIntent);

                    /** Opening the editor object to write data to sharedPreferences */
                    SharedPreferences.Editor editor = sharedPreferences.edit();

                    // Storing the latitude for the i-th location
                    editor.putString("lat"+ Integer.toString((locationCount-1)), Double.toString(point.latitude));

                    // Storing the longitude for the i-th location
                    editor.putString("lng"+ Integer.toString((locationCount-1)), Double.toString(point.longitude));

                    // Storing the count of locations or marker count
                    editor.putInt("locationCount", locationCount);

                    /** Storing the zoom level to the shared preferences */
                    editor.putString("zoom", Float.toString(googleMap.getCameraPosition().zoom));

                    /** Saving the values stored in the shared preferences */
                    editor.commit();

                    Toast.makeText(getBaseContext(), "Proximity Alert is added", Toast.LENGTH_SHORT).show();
                }
            });

            googleMap.setOnMapLongClickListener(new OnMapLongClickListener() {
                @Override
                public void onMapLongClick(LatLng point) {
                    Intent proximityIntent = new Intent("in.wptrafficanalyzer.activity.proximity");

                    pendingIntent = PendingIntent.getActivity(getBaseContext(), 0, proximityIntent,Intent.FLAG_ACTIVITY_NEW_TASK);

                    // Removing the proximity alert
                    locationManager.removeProximityAlert(pendingIntent);

                    // Removing the marker and circle from the Google Map
                    googleMap.clear();

                    // Opening the editor object to delete data from sharedPreferences
                    SharedPreferences.Editor editor = sharedPreferences.edit();

                    // Clearing the editor
                    editor.clear();

                    // Committing the changes
                    editor.commit();

                    Toast.makeText(getBaseContext(), "Proximity Alert is removed", Toast.LENGTH_LONG).show();
                }
            });
        }
    }

    private void drawCircle(LatLng point){

        // Instantiating CircleOptions to draw a circle around the marker
        CircleOptions circleOptions = new CircleOptions();

        // Specifying the center of the circle
        circleOptions.center(point);

        // Radius of the circle
        circleOptions.radius(20);

        // Border color of the circle
        circleOptions.strokeColor(Color.BLACK);

        // Fill color of the circle
        circleOptions.fillColor(0x30ff0000);

        // Border width of the circle
        circleOptions.strokeWidth(2);

        // Adding the circle to the GoogleMap
        googleMap.addCircle(circleOptions);
    }

    private void drawMarker(LatLng point){
        // Creating an instance of MarkerOptions
        MarkerOptions markerOptions = new MarkerOptions();

        // Setting latitude and longitude for the marker
        markerOptions.position(point);

        // Adding InfoWindow title
        markerOptions.title("Location Coordinates");

        // Adding InfoWindow contents
        markerOptions.snippet(Double.toString(point.latitude) + "," + Double.toString(point.longitude));

        // Adding marker on the Google Map
        googleMap.addMarker(markerOptions);

    }

    @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;
    }
}


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

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

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

    <uses-permission android:name="in.wptrafficanalyzer.multipleproximitymapv2.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.multipleproximitymapv2.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>

        <activity
            android:name=".ProximityActivity"
            android:label="@string/app_name" >
            <intent-filter >
                <action android:name="in.wptrafficanalyzer.activity.proximity"/>
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>

        <activity
            android:name=".NotificationView"
            android:label="@string/app_name" >

            <intent-filter >
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>

        <meta-data
            android:name="com.google.android.maps.v2.API_KEY"
            android:value="YOUR_ANDROID_API_KEY"/>

    </application>

</manifest>

Note : Replace “YOUR_ANDROID_API_KEY” at line 61 with the api key obtained in step 8.


16. Screenshots of the application

Adding proximity alerts to Google Maps

Figure 7 : Adding proximity alerts to Google Maps

List of notifications generated by Proximity Alerts

Figure 8 : List of notifications generated by Proximity Alerts

Viewing a notification content

Figure 9 : Viewing notification content


17. Download the 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: , , , , , , , , , , , , ,

19 Responses to Adding and removing multiple proximity alerts in Google Maps Android API V2

  1. UchihaK on May 5, 2013 at 1:28 pm

    Hi, thanks a lot for your tutorials they are very helpful.
    I was wondering if you can make a tutorial related to indoor map feature for Google Maps Android API V2

    Thank you :)

    • newbie on May 16, 2013 at 9:26 am

      Yeah… Thanks a lot, George!

      Hi there!
      do you have or know any tutorial about indoor map??

  2. mithran on May 18, 2013 at 11:39 am

    Hi,
    This post is very useful,but i have a query .if i am creating multiple alerts and i want remove a particular alert from the alerts..how can i do it??

    Do i have to use diff unique id in pending intent?

  3. Omar on June 14, 2013 at 4:54 pm

    Hi
    Thank you very much for the tutorial it’s very useful i’m having a problem when running the example they telling me that the projet has stopped unexpectedly i follow all the step.
    thank’s for you answer

  4. Iosif on July 4, 2013 at 11:58 pm

    Hey mate …there is one problem with your code ….when i add multiple proximity alerts only the last one works :)

  5. Sumesh on July 23, 2013 at 10:52 am

    Nice tutorial. But when working in 2g/3g network alarm fires only after a long delay(almost 5-10 mins). Works great in wifi.

  6. Hadson on November 13, 2013 at 7:02 pm

    A very good example, but not working. Just the last point touched work. How to fix that? Can you help us? 2 weeks stuck!

  7. El-Che on February 4, 2014 at 1:28 am

    Hello Mathew, really good tutorial. One problem though, i followed your tutorial, but it only add one proximity alert, and when i try adding the second one, it overrides the first one. where could i be wrong ? Thanks

  8. Arun on April 4, 2014 at 5:44 pm

    Hey George Mathew,
    A very good example. I juz wanna ask u something. how u added that markers which changes on move and another marker on stationary. Advance thanks

  9. Prakash on April 8, 2014 at 10:58 am

    thanks for this nice tutorial ..
    Can you tell me how to store and retrive lat and long value in sqlite instead of shared preference in this example..thanks in advance

  10. daniel amaral on April 24, 2014 at 5:38 am

    You saved my life! Tks so much friend!

  11. amir on December 9, 2014 at 12:28 am

    hi, This code is working fine below android api level 17. But not working
    above 17. Please give me the solution for this.

  12. Tausifali Saiyed on January 27, 2015 at 8:57 pm

    This code works fine but I need to add another metadata tag for Google Play Service version and value.

  13. jeeva on August 17, 2015 at 2:34 pm

    Hi Sir,

    Really nice tutorial,But i have one doubt,when i close my application,i am getting proximity alert notification,how to remove this one while close the application.(my mail id jeeva2k10@gmail.com)

    Kindly do the need full.

    Thanks

  14. Sathish on August 27, 2015 at 1:04 am

    when i add multiple proximity alerts only the last one works :) Pls help me… Expecting reply from u..

  15. Sathish on August 27, 2015 at 2:56 pm

    The last added proximity only works… please why? and solution?

  16. Me on August 28, 2015 at 12:07 pm

    Please let me know how to avoid only last added alert work

  17. Berkay Unlu on March 14, 2016 at 8:48 pm

    Sir, how could we run a voice message or a record when we entered the region?

  18. Alvon on July 11, 2016 at 2:14 pm

    Sir, it’s app can’t run on android OS 6.0 ( Marsmellow ) or some code must have to changes? Because i already add marker and my location in the red circle but got nothing notification or like else.

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