Introduction and Background
So, I have got admission for my MCS classes in a (far off) university, and my parents always force me to send them a text or call them to notify them of my current location, where I am, what are the current stats, whether I got the bus or not and so on. That was not trouble, the trouble was that I usually keep listening to Eminem and so I forget to inform them where am I and so on.
To solve the riddle, I thought I should make my Android a bit useful for myself and notify my parents by a text message, where currently I am! This article does not only focus on creating that one simple application, but also focused on the LocationManager, LocationListener, PendingIntent and a few other concepts in Android programming that you may want to understand to build other similar applications that require GPS or Network-based location services and to notify the clients.
The application also uses SmsManager, the service that provides you with functions to send SMS messages using the client's network, rates apply. I hope the article will interest you and it may be catchy for you.
Construction and Concept
- LocationManager for managing everything that a location-aware application needs.
- A listener that may work for our application to execute code when we are being notified about any changes in the location. Now, this point is divided into two more components and I will talk about them in detail later.
- An object that gets triggered and notifies our clients. The object can be anything, in my case, I am going to use SmsManager to send the SMS messages to the people that I want to receive those notifications.
This way, I will be able to broadcast the location updates to the ones that I want to be notified.
Since this is a general and unit overview, you can easily change the implementation to suit your own needs. For example, you can change how you notify the clients. You can remove the SmsManager and implement your own API, send the details to an online cloud, transmit over to a web service, store the location on your own device or whatever! That is all a good side of this article because I will not hard code everything in one activity but instead, I will try to provide you with multiple services classes and functions that can be ported for other usages, other functions, other services, and other implementations.
Read the rest of the article to see how easy it is to implement the location awareness in your Android applications and how easy it is to actually share that data with clients or do whatever you want to do.

Figure 1- Demonstration of our requirement and workaround. Explains what happens and what objects are being used in this demonstration.
Understanding the Android Location APIs
LocationManager description
- <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
- Approximate location, (with accuracy of almost 200ft), ACCESS_COARSE_LOCATION.
- Accurate location (with accuracy of 20ft), ACCESS_FINE_LOCATION.
Mostly, you should consider using ACCESS_FINE_LOCATION, if your application however wants to access location with less precision you can consider ACCESS_COARSE_LOCATION type. Along with the accuracy, there is a difference between the battery juice required by both of them.
To create a new instance of this object, you do not call the new operator on it, instead you call the getSystemService and then cast it to a LocationManager. For example,
Code
- LocationManager manager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
Requesting location updates
Code
- manager.requestLocationUpdate(PROVIDER, minMinutes, minMeters, handler);
The code for handling the updates is the same in both the cases, now you should understand what each of these variables is.
- Provider
As a Java developer, you might have got the idea that a "String" constant comes here. Built-in values for these providers are,
- LocationManager.GPS_PROVIDER provides access to the location services using GPS satellites.
- LocationManager.NETWORK_PROVIDER provides location services using the network. Less accurate location is provided as compared to GPS satellites.
- minMinutes
You can control how often does LocationManager update your handlers with an update of location. Set it to a value greater than 0, to get notified after a while. The value is in minutes.
- minMetersAnother flag to get notified only if the user has moved a few meters away from his previous location. Helps if you want to notify them after 100m or 1000m (1km) and so on.
- handlerNow, this is a conceptual point and you want to understand this. The handler is just the code that gets triggered when an update is ready for your application to work on.The handler comes in two shapes and sizes,
- LocationListener
- PendingIntent
The handler details will be discussed in the next sections. Up to this point, LocationManager must be cleared as to what it is and what it provides us with.
LocationListener description
- package com.afzaalahmadzeeshan.mylocation; // Package name
- // Some required imports
- import android.location.Location;
- import android.location.LocationListener;
- import android.os.Bundle;
- // Entire class structure with empty functions.
- public class SampleListener implements LocationListener
- {@
- Override
- public void onLocationChanged(Location location)
- {
- // Gets executed once location change has been notified to application.
- }@
- Override
- public void onStatusChanged(String provider, int status, Bundle extras)
- {
- // Status of location provider has been changed
- }@
- Override
- public void onProviderEnabled(String provider)
- {
- // Provider enabled by user
- }@
- Override
- public void onProviderDisabled(String provider)
- {
- // Opposite of onProviderEnabled(String)
- }
- }
- onLocationChanged(Location)This is the first function in the above list of available functions that we can use to get notified about changes in location API. The function provides us with the new location that the user is currently holding, the new location is passed as a parameter for our function.This function gets executed each time an update is available for our application. You can use it as the base for your application's business logic and execute the tasks here, like re-drawing the UI, updating the databases and so on.
- onStatusChanged(String, int, Bundle)This function is executed when the status for a provider is changed from available to not-available and so on and so forth. The function is passed with information about the provider, status code and other details that might help in processing the change.
- ProviderThe provider is, as already discussed, the service provider for location APIs. It can be GPS_PROVIDER or other ones that may provide you with location services. It helps you find out which provider has changed the status and so that you can work appropriately for that change.
- Status
This parameter determines what status it has now. Collectively with the provider, it will let you find out which provider is active and which is down at the moment. It has the following values, using which you can determine how your application should continue receiving the updates and if none of them is available then it must notify the user about the scenario,
- OUT_OF_SERVICE
- TEMPORARILY_UNAVAILABLE
- AVAILABLE
- Extras
As already said, any other detail that may help in this function is added to an Android Bundle as is passed to the function.
- Provider
- onProviderEnabled(String)This (and the later function) are triggered by user interaction. Like, when the user has enabled the provider manually. You can use this function to reactivate the service and continue processing the location updates.
- onProviderDisabled(String)Just like the former one, this one also gets triggered when user interaction takes place and a provider is disabled. Use it to disable the services in your application for location.
This way you can manage how you get the updates and what happens when anything changes.LocationListener is a very easy and effective way of handling the location updates. But wait, there is also a downside for this. To handle location updates using LocationListener your application needs to be visible and active, as soon as your application is removed, listeners are also removed so you cannot capture the location activity from the background, like a service.
In other words, your application no longer acts as a location capturing service but a "current location viewer" kind of app. If that is the case, then great, this listener is enough for you! But, if you want to get updates when your application is not running or is in the background, and the main worker thread may not be available, then read the next section for PendingIntent. For background services, PendingIntent works perfectly and provides you with updates even if your application is closed since PendingIntent executes on its own thread.
PendingIntent description
Create a service
- package com.afzaalahmadzeeshan.mylocation;
- import android.app.IntentService;
- import android.content.Intent;
- import android.content.Context;
- import android.location.Location;
- public class BroadcastLocationService extends IntentService
- {
- public BroadcastLocationService()
- {
- super("BroadcastLocationService");
- }@
- Override
- protected void onHandleIntent(Intent intent)
- {
- sendMessage(getApplicationContext(), new LocationService(getApplicationContext()).getLocation());
- }
- private void sendMessage(Context mContext, Location location)
- {
- // Code here to broadcast the location
- }
- }
In the above class for our application, we are having two functions. One is inherited and other one is custom one, that we are creating our self. Now, consider this, when a new request is sent to this service to execute, it would execute the code under onHandleIntent(Intent) function. The Intent that needs to be handled is passed as a parameter.
Creating an intent to run the service
- Intent intent = new Intent(getApplicationContext(), BroadcastLocationService.class);
- PendingIntent pIntent = PendingIntent.getService(
- getApplicationContext(), // Get the context
- 0, // Request code
- intent, // The intent we created
- FLAG_CANCEL_CURRENT // A flag
- );
Receiving the updates
- manager.requestLocationUpdates(GPS_PROVIDER, 10, 1000, pIntent);
- SmsManager manager = SmsManager.getDefault();
Code
- <uses-permission android:name="android.permission.SEND_SMS" />
It would allow your application to send the messages.
Writing the application

Figure 2 Main page input fields for time interval and the minimum meters moved

Figure 3- Disabled service interface on the main activity

Figure 4- Android application displaying the details about our service
- <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"
- android:paddingLeft="@dimen/activity_horizontal_margin"
- android:paddingRight="@dimen/activity_horizontal_margin"
- android:paddingTop="@dimen/activity_vertical_margin"
- android:paddingBottom="@dimen/activity_vertical_margin"
- tools:context=".HomeActivity">
- <CheckBox
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/enable_service"
- android:id="@+id/enable_service"
- android:layout_alignParentTop="true"
- android:layout_alignParentLeft="true"
- android:layout_alignParentStart="true"
- android:checked="false" />
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text=""
- android:id="@+id/welcome_text"
- android:layout_below="@+id/enable_service"
- android:layout_alignParentLeft="true"
- android:layout_alignParentStart="true"
- android:layout_marginTop="10dp"
- android:textColor="#000000" />
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:id="@+id/welcome_information_home"
- android:layout_alignTop="@+id/welcome_text"
- android:layout_alignParentLeft="true"
- android:layout_alignParentStart="true"
- android:textColor="#000" />
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:text="Configuration"
- android:id="@+id/textView4"
- android:layout_below="@+id/welcome_text"
- android:layout_alignParentLeft="true"
- android:layout_alignParentStart="true"
- android:layout_marginTop="50dp"
- android:textColor="#000" />
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:text="Time interval"
- android:id="@+id/textView5"
- android:layout_below="@+id/textView4"
- android:layout_alignParentLeft="true"
- android:layout_alignParentStart="true"
- android:layout_marginTop="28dp"
- android:textColor="#000" />
- <EditText
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:inputType="number"
- android:ems="10"
- android:id="@+id/time_interval"
- android:layout_below="@+id/textView5"
- android:layout_alignParentLeft="true"
- android:layout_alignParentStart="true"
- android:layout_alignParentRight="true"
- android:layout_alignParentEnd="true"
- android:hint="In minutes; 5-18000" />
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:text="Minimum distance covered"
- android:id="@+id/textView6"
- android:layout_centerVertical="true"
- android:layout_alignParentLeft="true"
- android:layout_alignParentStart="true"
- android:textColor="#000" />
- <EditText
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:inputType="number"
- android:ems="10"
- android:id="@+id/meters_distance"
- android:layout_below="@+id/textView6"
- android:layout_alignParentLeft="true"
- android:layout_alignParentStart="true"
- android:layout_alignParentRight="true"
- android:layout_alignParentEnd="true"
- android:hint="In meters." />
- <Button
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="Update"
- android:id="@+id/update_button"
- android:layout_below="@+id/meters_distance"
- android:layout_centerHorizontal="true" />
- </RelativeLayout>
Managing the data sources
- SQLiteOpenHelper class
- BaseColumns interface
1. SQLiteOpenHelper class
- private final static String COMMAND = "CREATE TABLE " + TABLE_NAME + "(" + _ID + " INTEGER PRIMARY KEY, " + COLUMN_ONE + " TEXT," + COLUMN_TWO + " TEXT" + ")";@
- Override
- public void onCreate(SQLiteDatabase db)
- {
- // Execute the codes here...
- db.execSQL(COMMAND);
- }
2. BaseColumns interface
Code
- public class MyClass extends SQLiteOpenHelper implements BaseColumns {
- /*
- * The code comes here to manage the SQL databases.
- * The functions as discussed also need to be implemented to trigger our own logic each time a database needs to be created.
- */
- }
I also have used same methods to create the databases and store the values for each of the item. It is included in the sample!
Capturing the location
Code
- package com.afzaalahmadzeeshan.mylocation;
- import android.app.AlertDialog;
- import android.app.PendingIntent;
- import android.content.Context;
- import android.content.DialogInterface;
- import android.content.Intent;
- import android.location.*;
- import android.provider.Settings;
- public class LocationService
- {
- private Context mContext;
- private Location mLocation;
- private LocationManager locationManager;
- private PendingIntent intent;
- private static long distance;
- private static long minutes;
- public LocationService(Context context)
- {
- mContext = context;
- // Set up to capture the location updates
- Intent smsIntent = new Intent(mContext, BroadcastLocationService.class);
- intent = PendingIntent.getService(mContext, 0, smsIntent, 0);
- }
- public static long getDistance()
- {
- return distance;
- }
- public static long getMinutes()
- {
- return minutes;
- }
- public void cancelUpdates()
- {
- if (locationManager != null)
- {
- locationManager.removeUpdates(intent);
- }
- }
- public Location getLocation()
- {
- locationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
- // Check if the tracking is enabled.
- boolean isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
- boolean isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
- if (!isGPSEnabled && !isNetworkEnabled)
- {
- // Prompt to get the settings enabled by the user.
- showSettingsDialog();
- }
- else
- {
- // Either one is enabled
- // 10 * 60 * 1000 = 10 minutes
- // 1000 = 1 km
- // this = listener
- if (isGPSEnabled)
- {
- // Get the location from GPS
- try
- {
- locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, getMinutes() * 1000 * 60, getDistance(), intent);
- if (mLocation == null)
- {
- mLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
- }
- }
- catch (SecurityException e)
- {
- showSettingsDialog();
- }
- }
- else
- {
- // Get the location from GPS
- try
- {
- // Set up to capture the location updates
- Intent smsIntent = new Intent(mContext, BroadcastLocationService.class);
- PendingIntent intent = PendingIntent.getService(mContext, 0, smsIntent, 0);
- locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, getMinutes() * 1000 * 60, getDistance(), intent);
- if (mLocation == null)
- {
- mLocation = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
- }
- }
- catch (SecurityException e)
- {
- showSettingsDialog();
- }
- }
- }
- return mLocation;
- }
- public void showSettingsDialog()
- {
- new AlertDialog.Builder(mContext).setTitle("Enable GPS").setMessage("Enable GPS in your settings for receiving active location details.").setNegativeButton("Cancel", null).setPositiveButton("Settings", new DialogInterface.OnClickListener()
- {@
- Override
- public void onClick(DialogInterface dialog, int which)
- {
- Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
- mContext.startActivity(intent);
- }
- }).create().show();
- }
- }
This code runs in the background, and our home activity uses the functions available here to perform actions and to get details about the location manager and location APIs.
Broadcasting the location
- package com.afzaalahmadzeeshan.mylocation;
- import android.content.Context;
- import android.telephony.SmsManager;
- import java.util.ArrayList;
- public class SmsService
- {
- public static boolean sendMessage(Context context, String location)
- {
- boolean result = false;
- try
- {
- SmsManager manager = SmsManager.getDefault();
- String message;
- // Get the string
- message = "[AUTOMATIC MESSAGE]\n" + "I am currently at " + location + " (approximately; accuracy within 100 meters).";
- ArrayList < Number > numbers = new ContentManager(context).getNumbers();
- if (numbers != null && numbers.size() > 0)
- {
- for (Number number: numbers)
- {
- String telNumber = number.getNumber();
- manager.sendTextMessage(telNumber, null, message, null, null);
- }
- result = true;
- }
- }
- catch (Exception ignored)
- {}
- return result;
- }
- }
- Table not foundThe first error that may raise in your application is, "table not found". Well, that is legit error in your application and is a cause that a table you may wanted to create initially when database was created, (table) was not created and now it cannot be created until you remove the previous database and re-execute the onCreate function.To solve it, on the development environment, you can delete the data and then re-execute the application. But remember to always create the tables, and define the schema in the database's onCreate function.
- Providers not availableSince our application depends on the location providers, we need to make sure that they are available before we start cap*turing the location from our application and to get notified about other changes in the location of the user. You can use manager and get the location services and providers.The following code for example, determines whether the provider for GPS is enabled or not:You can get other providers in a similar manner. Since that is a boolean object, you can use it in a condition and work appropriately. You can also create a logic to show a dialog and open the settings if user needs to trigger the providers.Code
- boolean isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
Code- if(!isGPSEnabled && !isNetworkEnabled) {
- showSettingsDialog();
- }
This would trigger another function that prompts the user to activate the provider in settings. The function has the following structure:Code- public void showSettingsDialog()
- {
- new AlertDialog.Builder(mContext).setTitle("Enable GPS").setMessage("Enable GPS in your settings for receiving active location details.").setNegativeButton("Cancel", null).setPositiveButton("Settings", new DialogInterface.OnClickListener()
- {@
- Override
- public void onClick(DialogInterface dialog, int which)
- {
- Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
- mContext.startActivity(intent);
- }
- }).create().show();
- }
This would prompt the user to activate the location services. Just for the sake of this article, I can mimic the scenario and show you how it works. For example, we have an application that activates the location providers and gets the location from them.
Figure 5- Android device showing the settings and location is enabled by defaultWe can disable the location to see how our application would behave.
Figure 6- Location is now turned offNow, we can trigger the capturing function in our application to see what happens. Firstly, consider we are having a condition that checks if the providers are enabled. If they are not, then the function displays an alert box, otherwise if that was not the case, then an exception may have been raised because providers are not available.When we click to enable the service, our location manager would tell us that providers are not enabled and thus our application prompts user to enable the services. Otherwise, cancel the operation.
Figure 7- The android alert dialog, to prompt him to enable the locationUser can then enable the location in their settings, since they were disabled.CodeThe above intent would take the user to location settings by default, so that is the same thing other applications do which take you directly to the settings.- Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
Figure 8- Location turned off. User can turn it on to enable the providersGPS can then be seen to notify that the location providers are working and location can be captured by your application for users.
Figure 9- GPS sign is shown in the system traySo, this explains how you should consider checking the paths that your application goes from and make sure you write the efficient application that takes care of most of the things for user. - boolean isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
Managing the resources
The application shown above uses SMS resources, location resources, and battery. For this sake, since we just want to notify the users, you must consider keeping the time span large to save battery. Each time GPS engine is turned on, it would start consuming battery juice so you may want to make sure your application doesn't waste the juice.- Minimum timeSet it to like, 10 minutes at minimum. You do not want constant updates unless you are showing the GPS on screen.
- Minimum distance
100 meters doesn't matter at all, so, this may be set as a minimum distance traveled.
- Minimum time
This would allow our application to sleep for a while and then access the location after a while. Since our application is able to work in the background, we don't need to worry whether user triggers the request himself or the application is going to manage that itself.
SMS manager would consume resources and would charge the user, so make sure you write the text very briefly, yet a small one.
In the application that I wrote, has the following code,
Code
- if(m > 99 && min > 4 && min < 18001) {
- /* m is the variable for meters
- * min is the variable for minutes
- *
- * The above condition checks if minimum minutes are less than 18000, that is enough!
- * also checks whether meters providers are greater than 100 or not.
- * This ensures that user receives updates for location changes and battery isn't
- * drained without need.
- */
- new ContentManager(getBaseContext()).setupSettings(getBaseContext(), m, min);
- }
- LocationManager
- LocationListener
- PendingIntent
- SmsManager
- SQLiteOpenHelper
- BaseColumns
- And much more.
Summary
The article doesn't force you to stick to one framework or method, you are free to write it in your own way and implement it. The article is just a resource that you can use to build your own application from scratch! Download the source code and get started.

Santhakumar MunuswamyPosted Oct 25, 2015, 10:42 AM
Great Article
Madhuram SrivastavaPosted Oct 24, 2015, 2:17 PM
nyc one sir
Afzaal Ahmad ZeeshanPosted Oct 24, 2015, 1:05 PM
Thank you very much for your nice words, Nilesh Jadav! :-)
Nilesh JadavPosted Oct 24, 2015, 12:42 PM
This is huge sir !! Nice share, Good work on android !!
Mukesh KumarPosted Oct 24, 2015, 12:03 PM
Good Job
Ankit BansalPosted Oct 24, 2015, 12:02 PM
Really nice
Isham KhanPosted Oct 24, 2015, 8:25 AM
Gr8 one.. informative
Harshad PansuriyaPosted Oct 24, 2015, 7:01 AM
Nice one