Sunday, September 23, 2012

GPS tracker for Android

1. Introduction

      Being in mountains I often ask myself -  what's the current altitude above sea level and how many meters we got from the starting. This summer I decided to create Android application  to always know this valuable information. In addition to the altitude it would be helpful to know longitude, latitude, current accuracy of GPS signal and have an ability to track the received data for the further analyze.

2. What's GPS

Before we go, let's check what's we know about GPS.

- It is absolutely free and available for everyone.
- The whole system consists of 24 satellites on Earth orbit at an altitude of about 24,000 meters.
- Each satellite transmits frames with the current time and satellite position.
- Four or more satellites must be visible to obtain an accurate result.
- The accuracy of the GPS signal is the same for the civilian GPS service (SPS) and the military GPS service (PPS).
- My Smart GSmart 1310 has chipset Qualcomm MSM7225-1 with embedded gpsOne Gen 7 GPS module.

Those who need the details can refer to the GPS official site at http://www.gps.gov.


3. Requirements

   Even though Android gives us a wide range of possibilities (GPS, Cell-ID and WiFi) to acquire our location we are interested in GPS method.
 I consider to make an application for outdoor activities where we can rely to GPS signal only.

First at all, we are expecting the program shows as at least: latitude, longitude, altitude and detected accuracy. Secondly, it must be able to save shown data in a file on SD card for further analyze.
  
4. Implementation

   We will use Eclipse as an IDE for the program development. It seems to be the best framework to  create and build Android applications.
It is important that the program has  necessary permissions to access the resources. We need GPS and  SD card, therefore the below lines must be in AndroidManifest.xml
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE">
<uses-permission android:name="android.permission.MODE_WORLD_WRITABLE"> 
There are two major parts of the program:
- GPS asyncronous listener
- functions and handlers to receive data from GPS listener to show the information on the screen or send to a file.

Perhaps the first question that comes to a programmer who want to write GPS application is - Where can I get GPS data? Android has a special class LocationManager to provide access to a wide range of location services. First at all we need to activate it and check whether GPS provider is  available in the current configuration:
mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
gpsEnabled = mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
If GPS receiver is  active then register our listener GPSlistener to  receive location updates as soon as new GPS information is available.
if(gpsEnabled == true){
mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, minTime, minDistance , GPSlistener);
};
minTime - minimum time interval between location updates, in milliseconds,
minDistance - minimum distance between location updates, in meters
GPSlistener - an object which method onLocationChanged(Location) will be called for each location update.

Consider this listener in details.
private final LocationListener GPSlistener = new LocationListener() {
    public void onLocationChanged(Location location) {
           ...
    }
};
It is instantiated from class LocationListener and  overwrites the method which is called when GPS has new data. The information is passed with object Location that has a set of methods and properties to operate with GPS location data.
    // define variables
    double alt, latitude, longitude;
    float bear, speed, acc;

    // get current accuracy
    acc = location.getAccuracy();

    // Altitude
    alt = location.getAltitude();

    // Latitude
    latitude = location.getLatitude();

    // Longitude
    longitude = location.getLongitude();

   Well, now we have the information we are interested in. But how to show it on the screen and save to a file? Obviously, we cannot do it from the method onLocationChanged. It is a listener and doesn't have an access to a screen and file. Fortunately, there is a way to communicate between GPS listener and the main parts of the program. On start we need to define Handler object and manage its method handleMessages to receive messages outside. Each message has unique identifier Message.what that helps us to distinguish them from each other. The below snap explains how to register Handler and receive messages
public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        // find references to the main fields
        mAlt = (TextView) findViewById(R.id.alt);

        // define receiver of the main commands from GPS block
        mHandler = new Handler() {
           public void handleMessage(Message msg) {
                switch (msg.what) {
                case UPDATE_ALT:
                    mAlt.setText((String) msg.obj);
                    break;
                }
            }
        }; // end of mHandler
};

Now we need to add message sending to Location listener to deliver GPS information to Handler we registered above.
double alt = location.getAltitude();
Message.obtain(mHandler, UPDATE_ALT,String.format("%.2f", alt) + " meters").sendToTarget();
Notice that Message.obtain and handleMessage use the same constant UPDATE_ALT to exchange altitude values.

Once the application is finishing the GPS listener must be disabled.
mLocationManager.removeUpdates(GPSlistener);

Well, now the program delivers GPS information to the screen. Next step is to take care of the tracking the data over time. It can be done through saving each GPS point to a file.
   Let's add new code to GPS listener. To keep things simple we will pass a completed string with all available GPS information of the current point: time, latitude, longitude,accuracy, bearing and speed. For example:
1344522949506;38.85288574;69.00157641;2363.10009765625;7.0;93.1;0.5;

String toMark = getTime + ";" + latitude + ";" + longitude + ";" + alt + ";" + acc + ";" + bear + ";" + speed + ";";
Message.obtain(mHandler, UPDATE_MARK, toMark).sendToTarget();
To receive the above message the handler part must be modified too.
mHandler = new Handler() {
   public void handleMessage(Message msg) {
    switch (msg.what) {
    ...
    case UPDATE_MARK:
     WriteToFile((String) msg.obj);
     break;
    }
   }
  }; // end of mHandler
The final step is to save the received data to a file. It is done by method WriteToFile that writes data to SD card.
private boolean WriteToFile(String data) {
  try {
   // Write data to a file to keep tracking
   File extStore = Environment.getExternalStorageDirectory();
   String SD_PATH = extStore.getAbsolutePath();

   File gps_data = new File(SD_PATH + "/" + file_name);

   FileWriter writer = new FileWriter(gps_data, true);
   writer.append(data + "\n");
   writer.flush();
   writer.close();
   Log.d(TAG, "Data saved OK");

  } catch (FileNotFoundException e) {
   Log.d(TAG, "File not found: " + e.getMessage());
   return false;
  } catch (IOException e) {
   Log.d(TAG, "Error accessing file: " + e.getMessage());
   return false;
  }
  return true;
 }
file_name is a global String that is defined at start with help of function CurrentDateFormatted.
file_name = CurrentDateFormatted() + ".txt";
The function returns a current date time formatted in the way to use as filename. For example: 16_29_26_2012_08_09.txt
public static String CurrentDateFormatted() {
  String ret;
  SimpleDateFormat dateFormat = new SimpleDateFormat(
    "HH_mm_ss_yyyy_MM_dd");
  Date date = new Date();
  ret = dateFormat.format(date);

  return ret;
 };

 The above explains the main design of the program. The full source code of the application is available here:
https://github.com/serjio28/gps_tracker.git


No comments:

Post a Comment