C/C++ Guides

Home

Determining Location

In this tutorial we take a look at how to detect a device's current geographical location and how to use location data in your application. We also describe some basic strategies for updating location data on a regular basis.

Ways of Determining Location

There are two common ways of determining the current location of the user's device:

  • GPS: If the device is equipped with a GPS module that communicates with a satellite network, you can query the GPS module from your MoSync application. 
  • Cell ID: You can also use the mobile phone network to get a good approximation of position by finding out the nearest network cell, and looking up its position in a database.

Most modern smartphones have GPS built in, and many older ones can receive GPS data from a Bluetooth-enabled GPS unit.  GPS will give you a more precise position, but it can be slow and unreliable in built-up areas.  Cell ID works faster, but requires access to a suitable database.

There are also hybrid solutions which work with combinations of network triangulation, cell IDs and GPS, which fall under the collective name of Assisted GPS (A-GPS).

Some platforms are capable of determining location through other means.  In some countries, Android based phones can determine their location by identifying near-by wireless networks.

Accessing GPS Data

The MoSync SDK provides an API for interfacing with GPS modules.  You don't need to do anything special, just start requesting GPS data for your application.  

int res = maLocationStart();      
maLocationStop();

These start and stop methods tell the GPS module to start collecting location data, and deliver it to your application. 

The function maLocationStart() returns an int.  If it returns 1 (MA_LPS_AVAILABLE), then everything is OK.  If it returns a value higher than 1, then it can't start because of network conditions, and you should try later.  If it returns -1, then location data is not available (probably because the handset doesn't have a GPS unit.)

Note: The MoSync IDE's MoRE emulator does not provide GPS data. It will always return -1. 

To receive data, your Moblet needs to respond to system events. You can do this by putting the following code in your Moblet class. This code listens to all events and responds to those that are location messages.

void customEvent(const MAEvent& event)
{
  //Check to see if this is a location event
  if(event.type == EVENT_TYPE_LOCATION)
  {
    MALocation& loc = *(MALocation*)event.data;
    informListeners(loc);
  }
}

In this example, we have a private method for passing the location onto the parts of our application that need it.

The location event returns an MALocation object. This object contains the device's latitude and longitude, as well as data about the accuracy of the reading. GPS locations are not definite. They come with a margin of error You'll have to create a strategy for handling the data depending how confident you are with it.  More on this later.

You can simply display the latitude and longitude data directly on the screen. Or you can pass it to a map with the current location centered on the screen.

Example Application Using GPS

In the following example of a location-handling application, we have a small framework. We have created interfaces for location providers (implemented by Moblet) and for location listeners (our screens which need location data).

Location.h

#ifndef LOCATION_H_
#define LOCATION_H_
 
#include <maapi.h>
#include <MAUtil/Vector.h>
 
using namespace MAUtil;
 
//Provides an interface between Moblet and screens which need location data
 
class ILocationListener
{
  public:
    virtual void locationReceived(MALocation& location);
};
 
class ILocation
{
  public:
    virtual void addLocationListener(ILocationListener* l);
    virtual void removeLocationListener(ILocationListener* l);
 
    virtual void informListeners(MALocation& location);
 
};
 
#endif /* LOCATION_H_ */

Screens can then subscribe to the Moblet class to register for location data. When a location update comes in, the screen is informed.

MapScreen.h

We can use the ILocationListener interface with a map screen to automatically update the map with the user's location.

#ifndef _MAPSCREEN_H_
#define _MAPSCREEN_H_

#include <MAUI/Screen.h>
#include <MAUI/Layout.h>
#include <MAUI/ListBox.h>
#include <MAP/MapWidget.h>
#include <MAP/LonLat.h>
#include <MAP/MapSourceMgr.h>
#include "Location.h"

using namespace MAUI;
using namespace MAP;

class MapScreen : public Screen, public ILocationListener
{
    public:
        MapScreen();
        ~MapScreen();

        void show();
        void locationReceived(MALocation& location);

    private:
        MapWidget* map;
        bool locRec;
};

#endif    //_MAPSCREEN_H_

MapScreen.cpp

#include "MapScreen.h"

MapScreen::MapScreen()
{
  map = NULL;
}

MapScreen::~MapScreen()
{

}

void MapScreen::show()
{
  if(map == NULL)
  {
    MAExtent screenSize = maGetScrSize();
    int scrWidth = EXTENT_X(screenSize);
    int scrHeight = EXTENT_Y(screenSize);

    map = new MapWidget(0, 0, scrWidth, scrHeight, NULL);
    map->setMapSourceKind(MapSourceKind_OpenStreetMap);
    LonLat home;
    home.lat = 51.49663;
    home.lon = 0.00;
    map->setCenterPosition(home);
    map->setMagnification(14);

    this->setMain(map);

  }

  Screen::show();
}

void MapScreen::locationReceived(MALocation& location)
{
  if(map != NULL)
  {
    LonLat myLoc;
    myLoc.lat = location.lat;
    myLoc.lon = location.lon;
    map->setCenterPosition(myLoc);
  }
}

Location Update Strategies

Once you've started to get location data, particularly with GPS, you face a new problem. The GPS system reports to your application everytime it gets a fix - approximately once every second. Each reading is slightly different. If you are trying to plot your position on the map, and you automatically pass the raw location data to the map, the pointer or map center will constantly move around, even if the device is still.

To overcome this, you need an update strategy that works something like this:

  • If the new reading is more accurate (i.e. the accuracy value is lower than the current best reading) use it.
  • If the new reading is outside of a circle created using the reading as the centre point and the accuracy as the radius, assume that the device has moved, and use the new reading.
  • If the new reading is inside the circle of error, and the reading is less accurate, ignore the data and wait for another fix from the satellites.

This keeps the user informed about where they are, without putting a lot of doubt into their minds when it keeps shifting very slightly.

MoSync SDK 3.3
Copyright © 2013 MoSync AB
www.mosync.com