Ilias Tsagklis

About Ilias Tsagklis

Ilias Tsagklis is a senior software engineer working in the telecom domain. He is an applications developer in a wide variety of applications/services. Ilias is co-founder and Executive Editor at Java Code Geeks.

Android Proximity Alerts Tutorial

Smart-phones are taking over the mobile world, this is a fact. Since GPS devices are usually found embedded in those phones, there is already a notable rise in applications that take advantage of the offered geographical positioning functionality. A type of those applications is the one of Location Based Services, where the service exploits knowledge about where the mobile user is globally positioned at. Pretty common are also the applications that use geocoding (finding associated geographic coordinates from geographic data, such as a street address) and reverse geocoding (providing information based on given coordinates). One other aspect of that type of applications is the creation of proximity alerts. As their name suggests, these are alerts that get generated when the user is physically located near a specific Point Of Interest (POI). Proximity alert are going to be a “hot” thing the following years, since a lot of applications are going to make use of them, with the most prominent example being targeted advertising. In this tutorial I am going to show you how to take advantage of Android’s built-in proximity alert capabilities.

Before we begin, it would be helpful to have read introductory articles about location based application and/or geocoding. You might want to take a look at some previous tutorials of mine, such as “Android Location Based Services Application – GPS location” and “Android Reverse Geocoding with Yahoo API – PlaceFinder”. One other thing to note is that this tutorial was inspired by a very cool tutorial named “Developing Proximity Alerts for Mobile Applications using the Android Platform”. This is a four part tutorial, which gets a little complicated at some points and might intimidate a beginner. For that reason, I decided to provided a shorter and more straightforward tutorial.

What we will build is a simple application that stores the user’s coordinates for a point that interests him and then provide a notification when the user is near that point. The coordinates are retrieved on demand when the user is located at that point.

We begin by creating a new Eclipse project, named “AndroidProximityAlertProject” in our case. We also create a main activity for our application under the name “ProxAlertActivity”. Here is what the application’s main page will look like:

Here is the declaration file for the main UI layout, named “main.xml”:

<?xml version="1.0" encoding="utf-8"?>

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

    <EditText 
        android:id="@+id/point_latitude" 
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content"
        android:layout_marginLeft="25dip"
        android:layout_marginRight="25dip"
    />
    
    <EditText 
        android:id="@+id/point_longitude" 
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content"
        android:layout_marginLeft="25dip"
        android:layout_marginRight="25dip"
    />
        
    <Button 
        android:id="@+id/find_coordinates_button" 
        android:text="Find Coordinates"
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
    />
    
    <Button 
        android:id="@+id/save_point_button" 
        android:text="Save Point"
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
    />
    
</LinearLayout>

Let’s now get started with the interesting stuff. First of all, we need a reference to the LocationManager class, which provides access to the system location services. This is done via a call to the getSystemService method of our activity. We can then use the requestLocationUpdates method in order to request notifications when the user’s location changes. This is not strictly required when developing proximity alerts, but I will use it here in order to calculate the distance between the point of interest and the current user location. At any given time, we can call the getLastKnownLocation method and retrieve the last known location of a specific provider, in our case the GPS device. Finally, we will make use of the addProximityAlert method that can be used to set a proximity alert for a location given by specific coordinates (latitude, longitude) and a given radius. We can also optionally define an expiration time for that alert if we wish to monitor the alert for a specific time period. A PendingIntent can also be provided, which will be used to generate an Intent to fire when entry to or exit from the alert region is detected.

All these are translated into code as follows:

package com.javacodegeeks.android.lbs;

import java.text.DecimalFormat;
import java.text.NumberFormat;

import android.app.Activity;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class ProxAlertActivity extends Activity {
    
    private static final long MINIMUM_DISTANCECHANGE_FOR_UPDATE = 1; // in Meters
    private static final long MINIMUM_TIME_BETWEEN_UPDATE = 1000; // in Milliseconds
    
    private static final long POINT_RADIUS = 1000; // in Meters
    private static final long PROX_ALERT_EXPIRATION = -1; 

    private static final String POINT_LATITUDE_KEY = "POINT_LATITUDE_KEY";
    private static final String POINT_LONGITUDE_KEY = "POINT_LONGITUDE_KEY";
    
    private static final String PROX_ALERT_INTENT = 
         "com.javacodegeeks.android.lbs.ProximityAlert";
    
    private static final NumberFormat nf = new DecimalFormat("##.########");
    
    private LocationManager locationManager;
    
    private EditText latitudeEditText;
    private EditText longitudeEditText;
    private Button findCoordinatesButton;
    private Button savePointButton;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);

        locationManager.requestLocationUpdates(
                        LocationManager.GPS_PROVIDER, 
                        MINIMUM_TIME_BETWEEN_UPDATE, 
                        MINIMUM_DISTANCECHANGE_FOR_UPDATE,
                        new MyLocationListener()
        );
        
        latitudeEditText = (EditText) findViewById(R.id.point_latitude);
        longitudeEditText = (EditText) findViewById(R.id.point_longitude);
        findCoordinatesButton = (Button) findViewById(R.id.find_coordinates_button);
        savePointButton = (Button) findViewById(R.id.save_point_button);
        
        findCoordinatesButton.setOnClickListener(new OnClickListener() {            
            @Override
            public void onClick(View v) {
                populateCoordinatesFromLastKnownLocation();
            }
        });
        
        savePointButton.setOnClickListener(new OnClickListener() {            
            @Override
            public void onClick(View v) {
                saveProximityAlertPoint();
            }
        });
       
    }
    
    private void saveProximityAlertPoint() {
        Location location = 
            locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
        if (location==null) {
            Toast.makeText(this, "No last known location. Aborting...", 
                Toast.LENGTH_LONG).show();
            return;
        }
        saveCoordinatesInPreferences((float)location.getLatitude(),
               (float)location.getLongitude());
        addProximityAlert(location.getLatitude(), location.getLongitude());
    }

    private void addProximityAlert(double latitude, double longitude) {
        
        Intent intent = new Intent(PROX_ALERT_INTENT);
        PendingIntent proximityIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
        
        locationManager.addProximityAlert(
            latitude, // the latitude of the central point of the alert region
            longitude, // the longitude of the central point of the alert region
            POINT_RADIUS, // the radius of the central point of the alert region, in meters
            PROX_ALERT_EXPIRATION, // time for this proximity alert, in milliseconds, or -1 to indicate no expiration 
            proximityIntent // will be used to generate an Intent to fire when entry to or exit from the alert region is detected
       );
        
       IntentFilter filter = new IntentFilter(PROX_ALERT_INTENT);  
       registerReceiver(new ProximityIntentReceiver(), filter);
       
    }

    private void populateCoordinatesFromLastKnownLocation() {
        Location location = 
            locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
        if (location!=null) {
            latitudeEditText.setText(nf.format(location.getLatitude()));
            longitudeEditText.setText(nf.format(location.getLongitude()));
        }
    }
    
    private void saveCoordinatesInPreferences(float latitude, float longitude) {
        SharedPreferences prefs = 
           this.getSharedPreferences(getClass().getSimpleName(),
                           Context.MODE_PRIVATE);
        SharedPreferences.Editor prefsEditor = prefs.edit();
        prefsEditor.putFloat(POINT_LATITUDE_KEY, latitude);
        prefsEditor.putFloat(POINT_LONGITUDE_KEY, longitude);
        prefsEditor.commit();
    }
    
    private Location retrievelocationFromPreferences() {
        SharedPreferences prefs = 
           this.getSharedPreferences(getClass().getSimpleName(),
                           Context.MODE_PRIVATE);
        Location location = new Location("POINT_LOCATION");
        location.setLatitude(prefs.getFloat(POINT_LATITUDE_KEY, 0));
        location.setLongitude(prefs.getFloat(POINT_LONGITUDE_KEY, 0));
        return location;
    }
    
    public class MyLocationListener implements LocationListener {
        public void onLocationChanged(Location location) {
            Location pointLocation = retrievelocationFromPreferences();
            float distance = location.distanceTo(pointLocation);
            Toast.makeText(ProxAlertActivity.this, 
                    "Distance from Point:"+distance, Toast.LENGTH_LONG).show();
        }
        public void onStatusChanged(String s, int i, Bundle b) {            
        }
        public void onProviderDisabled(String s) {
        }
        public void onProviderEnabled(String s) {            
        }
    }
    
}

In the onCreate method we hook up the location manager with a custom class that implements the LocationListener interface and allows to get notified on location changes via the onLocationChanged method. We will see how to handle the updates later. We also find the various UI widgets and attach OnClickListeners to the buttons.

When the user wants to find his current coordinates, the “populateCoordinatesFromLastKnownLocation” method is invoked. Inside that, we use the getLastKnownLocation method and retrieve a Location object. The EditTexts are then populated with the retrieved location information.

Similarly, when the user wants to save the point and provide alerts for that (“saveProximityAlertPoint”), the location info is first retrieved. Then, we save the latitude and longitude information as preference data using the SharedPreferences class and more specifically the SharedPreferences.Editor. Finally, we create a PendingIntent by using the getBroadcast static method. For the encapsulated Intent, we create an IntentFilter and use the registerReceiver method to associate a custom BroadcastReceiver with the specific intent filter. Note that this binding could alternatively be achieved in a declarative way using the manifest file.

Now let’s examine how we handle user’s location changes. In the implemented method of the “MyLocationListener” class, we extract the stored location info (“retrievelocationFromPreferences”) from the SharedPreferences class. Then, we use the distanceTo method to calculate the distance between the two locations, the current one and the one corresponding to the point of interest. This is done for debugging purposes, so that we know if we have actually entered the area around the point.

The final step is to handle the events of entering the area of the point of interest. This is done inside the “ProximityIntentReceiver” class that extends the BroadcastReceiver and responds to the custom intent that we attached to the location manager when adding the proximity alert. The handling occurs inside the onReceive method, which gets invoked upon event. Inside that, we retrieve the value of the KEY_PROXIMITY_ENTERING key from the associated intent, which indicates whether a proximity alert is entering (true) or exiting (false). The code is the following:

package com.javacodegeeks.android.lbs;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.location.LocationManager;
import android.util.Log;

public class ProximityIntentReceiver extends BroadcastReceiver {
    
    private static final int NOTIFICATION_ID = 1000;

    @Override
    public void onReceive(Context context, Intent intent) {
        
        String key = LocationManager.KEY_PROXIMITY_ENTERING;

        Boolean entering = intent.getBooleanExtra(key, false);
        
        if (entering) {
            Log.d(getClass().getSimpleName(), "entering");
        }
        else {
            Log.d(getClass().getSimpleName(), "exiting");
        }
        
        NotificationManager notificationManager = 
            (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
        
        PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, null, 0);        
        
        Notification notification = createNotification();
        notification.setLatestEventInfo(context, 
            "Proximity Alert!", "You are near your point of interest.", pendingIntent);
        
        notificationManager.notify(NOTIFICATION_ID, notification);
        
    }
    
    private Notification createNotification() {
        Notification notification = new Notification();
        
        notification.icon = R.drawable.ic_menu_notifications;
        notification.when = System.currentTimeMillis();
        
        notification.flags |= Notification.FLAG_AUTO_CANCEL;
        notification.flags |= Notification.FLAG_SHOW_LIGHTS;
        
        notification.defaults |= Notification.DEFAULT_VIBRATE;
        notification.defaults |= Notification.DEFAULT_LIGHTS;
        
        notification.ledARGB = Color.WHITE;
        notification.ledOnMS = 1500;
        notification.ledOffMS = 1500;
        
        return notification;
    }
    
}

The code is pretty straightforward. After we determine whether we have an entering or exiting proximity alert, we are ready to provide a custom notification. To do so, we first take reference of the appropriate service, i.e. the NotificationManager. Through that service, we may send alerts to the user, wrapped around Notification objects. The notifications can be customized upon will and may include vibration, flashing lights etc. We also added a specific icon that will appear to the status bar. The setLatestEventInfo is preferred when we just want to add a basic title and text message. You can find more about notifications here. Additionally, we can use a PendingIntent in order to define an activity to be invoked when the user acknowledges the notification by clicking on it. However, to keep things simple, I do not use an intent to be launched in my example.

Finally, let’s see what the Android manifest file looks like:

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.javacodegeeks.android.lbs"
      android:versionCode="1"
      android:versionName="1.0">
      
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        
        <activity android:name=".ProxAlertActivity"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>     

    </application>
    
    <uses-sdk android:minSdkVersion="3" />
   
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" /> 
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.VIBRATE" />

</manifest> 

Nothing special here, just remember to add the necessary permissions, i.e.

We are now ready to test our application. Launch the Eclipse configuration. Then, go to the DDMS view of Eclipse and look for the “Emulation Control” tab. There, among other things, you will find the “Location Controls” section, which can send mock location data to the emulator. In the “Manual” tab, just hit the “Send” button, there are already some coordinates set up.

After that, the GPS provider will have a last known location that can provide upon request. So, hit the “Find Coordinates” button and this is what you will get:

Then, hit the “Save Point” in order to declare the current location as a point of interest. The location coordinates will be saved in the preferences and the proximity alert will be added to the location manager.

Next, let’s simulate the fact that the user leaves the location. Change the value of the coordinates, for example change latitude as follows: 37.422006 ? 37.522006. We are now quite far from the point of interest. Let’s suppose now that we are approaching it, thus change the latitude to a closer value, for example: 37.522006 ? 37.423006.

This is inside the radius of the point (this was set to 1000 meters) thus the alert is triggered and our receiver gets notified. There, we create our notification and send it via the notification manager. The notification appears at the status bar as follows:

That’s it, a quick guide on how to implement proximity alerts with the Android platform. You can find here the Eclipse project created for the needs of this tutorial.

Related Articles :

Do you want to know how to develop your skillset to become a Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

JPA Mini Book

Learn how to leverage the power of JPA in order to create robust and flexible Java applications. With this Mini Book, you will get introduced to JPA and smoothly transition to more advanced concepts.

JVM Troubleshooting Guide

The Java virtual machine is really the foundation of any Java EE platform. Learn how to master it with this advanced guide!

Given email address is already subscribed, thank you!
Oops. Something went wrong. Please try again later.
Please provide a valid email address.
Thank you, your sign-up request was successful! Please check your e-mail inbox.
Please complete the CAPTCHA.
Please fill in the required fields.

24 Responses to "Android Proximity Alerts Tutorial"

  1. Karan Chugh says:

    Hi,
    I am new to Android app development.I have followed the above code. But, I am getting an error ‘Error receiving broadcast intent’. The Logcat shows Null pointer exception caused due to the PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, null, 0); Please help. I have been stuck on this for so long. I have read lot of articles about this on net, nothing seems to be working for me.Thanks

  2. leon083 says:

    Hi! Nice post, very useful!

    Everything works fine, but if I’m inside of the radius, the distance is < 1000m, the Intent doesn't fire! Has anybody an idea?

  3. Madhumita Dange says:

    ERROR Messagejava.lang.NullPointerException
    log file – No error in log throws above exception

  4. I’m modifying some code of ProximityIntentReceiver to successful running on 4.0.3 emulator…

    I append a new Intent in the onReceive() while creating pendingIntent , which can be any name you like, and use Notification.Builder to create notification.

    Help it works!

    PendingIntent pendingIntent = PendingIntent.getActivity(context, 0,
    new Intent(PROX_ALERT_INTENT), 0);

    private Notification createNotification(Context context, String title,
    String content, PendingIntent pIntent) {
    Notification notification = new Notification.Builder(context)
    .setContentTitle(title).setContentText(content)
    .setContentIntent(pIntent).getNotification();

    notification.icon = R.drawable.ic_menu_notifications;
    notification.when = System.currentTimeMillis();

    notification.flags |= Notification.FLAG_AUTO_CANCEL;
    notification.flags |= Notification.FLAG_SHOW_LIGHTS;

    notification.defaults |= Notification.DEFAULT_VIBRATE;
    notification.defaults |= Notification.DEFAULT_LIGHTS;

    notification.ledARGB = Color.WHITE;
    notification.ledOnMS = 1500;
    notification.ledOffMS = 1500;

    return notification;
    }

  5. thanks for posting this, however like others, it does not work. trying to run against 4.0.3 HTC one x, when the intent fires for the notification, it crashes with the same error Karan receives,
    Error receiving broadcast intent’. Can you check your code again? I have also not been able to fix this.

    Nevermind fixed it myself: PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);

    change null in the pending intent to say “intent”

  6. Bharath says:

    will it work when app is closed?

  7. First of all, thx a lot for your post. I am also trying to setup a little test system to create and later receive proximity alerts. The difference is simply that I takek the coordinates of a mapView (via getCenter) and then do not register a broadcast receiver programatically but in xml (AndroidManifest). So far, it does not work, and sometimes it leads to an immediate alert which is really strange. My post is here on stackoverflow: http://stackoverflow.com/questions/12686533/android-proximity-alerts-on-galaxy-nexus-with-android-4-1-1-does-it-really-wor

    It would be great if you or others could have a look!

  8. disqus_DqWeJjq6kz says:

    hi..i want to change your code so that the latitude and longitude are saved in database instead of using shared preferences. then i want to request the location update in my application and check if the location is near the location in the database and alert the user. How can i do that. please guide me. i was doing it for weeks but it’s not working. Thank You.

    • Anonmous says:

      Hey could you figure out how to work on this… I know its long you have asked this question. Even I am trying to implement something similiar for my project…Would appreciate if you can guide me..

    • shylendra says:

      Hai disqus_DqWeJjq6kz,

      Have you done what you asked? Me too facing same problem from last 2 weeks Will you please send me your code if you did it to shylendramadda@gmail.com. please help me. Thanks in advance..

  9. adrell says:

    hi…i tried to implement your tutorial. I want to make some changes. i want to fetch the location and save in in database. later i want to check for location update and see if it match the location in the database and alert the user. how can i do this using database instead of using shared preferences?Thank you

  10. myusro says:

    Great tutorials,
    Thank you so much,

  11. Adesh Atole says:

    Totally Great

  12. AndroidTesting says:

    hi i tried your tutorial.but i am not getting the notification.please help me out

  13. tAANi says:

    I have a question ?
    did you notice ..

    LocationManager.addProximityAlert() get paused when the device is asleep…

    if suppose i want to have my service be active when device assleep…

    Can you tell me what will be the reason for this..

  14. Sama says:

    Any body there ?who can help me while doing an android Project

  15. gayatri says:

    pls send this project as a zip format to my mail id…..

  16. Sai Pravesh says:

    Thanks for the tutorial, but app crashes when i press the save button.
    Can anyone please try to find the reason.

    • Sai Pravesh says:

      Does not crash in device, but does not run in background.
      How to modify the code to make it run in background forever.
      Tnx

  17. lucy says:

    Is it possible to add multiple proximity alerts i mean multiple locations to get alerts ?

Leave a Reply


4 + eight =



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy | Contact
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.
Do you want to know how to develop your skillset and become a ...
Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

Get ready to Rock!
You can download the complementary eBooks using the links below:
Close