How to Get Location Information

This document demonstrates how a client application uses the Location Acquisition API to get a position.

Purpose

This tutorial explains how to get location information using the Location Acquisition API.

Required background

Location Acquisition API Overview describes the main client/server classes of the API.

Position Data and Info Classes describes the classes that hold location information.

Getting location information

This section describes how to get location information using the Location Acquisition API.

Introduction

Client applications use the RPositionServer and RPositioner classes to get position updates. RPositionServer is used by client applications to manage a session with the Location Server and to get Positioning Module information. RPositioner is used by client applications to manage a subsession with the Location Server and to get position updates.

GPS positioning modes

The Global Positioning System (GPS) is a technology that is often included in devices that support LBS.

For each location request from a client, the LBS subsystem can operate in one of several different GPS positioning modes. The Location Acquisition API hides the details of which GPS positioning mode is in use from client applications. A client makes the same sequence of calls to the API to get a position update whichever positioning mode is used. Note that only some of these positioning modes may be available to a client application at runtime.

Each GPS positioning mode is a different way of getting a position fix:

  • Autonomous

    LBS uses a GPS Positioning Module to calculate position fixes without assistance data from the network. This mode typically takes the longest time to obtain a location fix compared to the other modes.

  • Terminal Based Mode

    LBS uses an A-GPS Positioning Module to calculate position fixes using assistance data from the network. Assistance data specifies the GPS satellites that are above the horizon as seen from the mobile device's current location. Assistance data is used by an A-GPS Positioning Module to reduce the time necessary to obtain a position fix.

    The network can also supply a reference position to the LBS subsystem as part of the sequence of events. This position is calculated in the network using cell-based techniques and may be less accurate than that obtained from GPS. If a reference position is available, it may be returned to the client before a GPS position.

    See Location Acquisition API Runtime Behaviour for more information about the position updates that can be returned by LBS.

  • Terminal Assisted Mode

    LBS uses an A-GPS Positioning Module to obtain GPS measurements (using assistance data from the network). GPS measurements are the raw data used to calculate a GPS fix. Measurements are sent to the network and a position fix is calculated by a remote server. The remotely calculated position fix is returned to the mobile device and is known as the final network position. The LBS subsystem returns this position to the client.

  • Simultaneous Terminal Based Mode and Terminal Assisted Mode.

    LBS passes GPS measurements to the network (as in Terminal Assisted Mode), but also attempts to use those measurements to calculate a GPS position fix (as in Terminal Based Mode). The position returned to the client may be either a GPS position (calculated in the mobile device) or a final network position (calculated using the measurements by a remote server in the network). The position that is calculated first (the GPS position or the final network position) is generally returned to the client. The final network position may also be returned to the client after the return of the GPS position.

Some devices also support a Cell-based Mode in which LBS obtains a position fix from the network without using GPS. This position fix is sometimes less accurate than that obtained using GPS.

A client application cannot directly choose the GPS positioning mode that is used for its location request. A handset manufacturer may provide an LBS settings application where the GPS mode can be selected by an end user. However for modes that involve the network (Terminal Based Mode, Terminal Assisted Mode and Cell-based Mode) it is possible for a network operator to override the GPS mode as part of the location request. If a client wants to know precisely how a position fix was calculated, this information is available in the returned position info object (as described in more detail later in this document).

Example sequence

Figure 1 shows a simplified sequence for a client requesting a position update from LBS. The sequence shows simplified behaviour for Terminal Based Mode. The A-GPS Module is a Positioning Module that uses Assisted GPS to calculate a position. The Network Protocol Module is a Positioning Module that obtains GPS assistance data and reference positions (often approximate positions) from the network. Note that Terminal Based Mode may not be available on all mobile devices. This depends on the Positioning Modules that have been installed by the mobile device creator.

Figure: Figure 1. Simplified Terminal Based Mode Sequence

Example code and description

The following code shows a simple example of how a client application can get a single position update. The numbers in the code comments refer to sections that follow the code example.

#include <lbs.h>
#include <lbserrors.h>

...

RPositionServer server;
RPositioner positioner;

// 1. Create a session with the Location Server
User::LeaveIfError(server.Connect());
CleanupClosePushL(server);

// 2. Create a subsession with the Location Server using default positioning module
User::LeaveIfError(positioner.Open(server));
CleanupClosePushL(positioner);

// 3. Set the requester information - in this example define a requester stack... 

_LIT(KCntPhone, "+358501234567");
_LIT(KSrvName, "MyService");
RRequestorStack stack;
CRequestor* contact = CRequestor::NewLC(CRequestor::ERequestorContact, CRequestor::EFormatTelephone, KCntPhone);
stack.Append(contact);
CRequestor* service = CRequestor::NewLC(CRequestor::ERequestorService,    CRequestor::EFormatApplication, KSrvName);
stack.Append(service);
User::LeaveIfError(positioner.SetRequestor(stack));

TPositionInfo posInfo;
TPosition pos;
TRequestStatus status;

/* 4. To set update options, call RPositioner::SetUpdateOptions(). 
      See the description in section 4 below */

/* 5. Request location information
      Could also call positioner.GetLastKnownPosition(posInfo, status) 
      to get cached location information */
positioner.NotifyPositionUpdate(posInfo, status);
User::WaitForRequest(status);

// 6. Receive location information
if (status != KErrNone)
 {
 // Handle possible client/server errors
 ...
 }

// Get the position data object from the wrapper info object
posInfo.GetPosition(pos);

// Use the position data
...

// Reissue the location request if necessary by calling NotifyPositionUpdate() again

/* 7. To cancel or complete a location request a client
 calls RPositioner::CancelRequest() or RPositioner::CompleteRequest() */

// 8. Cleanup
stack.Reset();
CleanupStack::PopAndDestroy(service);
CleanupStack::PopAndDestroy(contact);
CleanupStack::PopAndDestroy(&positioner);
CleanupStack::PopAndDestroy(&server);

The following describes the steps to get location information as shown in the above example:

1. Create a session with the Location Server

To create a session with the Location Server, a client application:

Standard client-server error codes are returned by calls to open the session. A panic occurs if the client application has already created a session with the Location Server. Error and panic codes specific to LBS are defined in LbsErrors.h.

2. Create a subsession with the Location Server

Location information requests are issued on a subsession.

To create a subsession, an application calls one of three overloaded RPositioner::Open() member functions:

  • RPositioner::Open(RPositionServer& aPosServer) uses the Default Positioning Module to get location information. The client application does not specify any position quality criteria (which specify the required position accuracy) and therefore LBS uses default position quality criteria (horizontal accuracy = 50m, vertical accuracy = 1000m, request timeout = 30 seconds).

  • RPositioner::Open(RPositionServer& aPosServer, TPositionModuleId aModuleId) allows a specific Positioning Module to be specified by the client application. LBS uses position quality criteria associated with the specified Positioning Module. No quality criteria are specified and so LBS uses the capabilities of the Positioning Module as the default criteria.

    See Positioning Modules for information about Positioning Module position quality and How to Use Positioning Module Information for more information about how to get a module ID.

The LBS subsystem does not compare the vertical accuracy of a calculated position with the vertical accuracy specified by a client application (specified by position quality criteria, by a quality profile or by a Positioning Module). Only the horizontal accuracy of a calculated position is used to decide if it is accurate enough to be returned to a client application.

3. Set client requester details

A client application can specify the client requesters by calling RPositioner::SetRequestorL() before calling RPositioner::NotifyPositionUpdate().

This is an optional step. Calling SetRequestorL() has no effect in this version of the Symbian platform. Calling SetRequestorL() is required in some devices based on earlier versions of Symbian. To ensure an LBS application runs on devices based on earlier versions of Symbian, it is recommended that it calls SetRequestorL().

See Privacy Requester Classes for more information.

4. Set update options

A client application calls RPositioner::SetUpdateOptions() to set the update options. Calling this method only affects future calls to RPositioner::NotifyPositionUpdate() and RPositioner::GetLastKnownPosition() and does not affect any outstanding requests.

A TPositionUpdateOptions parameter specifies the update options and is passed in RPositioner::SetUpdateOptions(). The properties of TPositionUpdateOptions are set either on its construction or via setter methods. The following properties can be defined:

  • The time interval between position updates

    TPositionUpdateOptions::SetUpdateInterval(TTimeIntervalMicroSeconds aInterval) sets the time interval between position updates.

    Setting a non-zero value indicates that the client requires periodic updates (this is also known as 'tracking'). LBS attempts to send position updates to the client application with this interval between the updates. Note that setting aInterval to 0 (or not setting it) indicates that the client is not tracking.

    Note that when a client application is tracking, LBS does not return reference positions as periodic updates. See the section on Tracking later in this document for more information on tracking behaviour.

  • A position update timeout

    TPositionUpdateOptions::SetUpdateTimeOut(TTimeIntervalMicroSeconds aTimeOut) sets a timeout for the location request. It specifies how long the client application is prepared to wait to obtain a position update. If the timeout expires RPositioner::NotifyPositionUpdate() completes and the client's RunL() method is called.

    After a timeout the value set for the client's TRequestStatus parameter depends on the configuration of the LBS subsystem and may be either KErrTimeOut or KPositionQualityLoss. See Location Acquisition API runtime behaviour for more information.

    Note that calling SetUpdateTimeOut() with a value of 0 (or not setting it) indicates that LBS should not timeout the location request from a client.

  • The maximum age of a position update

    TPositionUpdateOptions::SetMaxUpdateAge(TTimeIntervalMicroSeconds aMaxAge) specifies the maximum age of the position data returned by RPositioner::NotifyPositionUpdate(). Setting this value allows the Location Server to use cached location information in some cases. The default value of 0 indicates that new position data is required.

  • Acceptance of partial updates

    A partial update is a position update that contains only partial position data. Such a position is called an incomplete position. An example of an incomplete position is one that contains data about the satellites used to obtain a GPS fix but no latitude or longitude data. LBS defines an incomplete position to be one where either TPosition::Latitude() or TPosition::Longitude() is NaN (Not a Number).

    TPositionUpdateOptions::SetAcceptPartialUpdates(TBool aPartial) allows an application to choose to accept partial updates. If a partial update is returned an application's TRequestStatus parameter is set to KPositionPartialUpdate when NotifyPositionUpdate() completes.

    If partial updates are not set the default behaviour is for RPositioner::NotifyPositionUpdate() to complete only when the Positioning Module used for the location request has obtained as much information as possible. Note however that this behaviour is configurable by a Symbian device creator (see Location Acquisition API runtime behaviour for more information).

Important note on setting update options

The default constructor of TPositionUpdateOptions sets all update options to zero by default and is the equivalent of calling the following:

  • TPositionUpdateOptions::SetUpdateInterval(0) meaning that tracking is off

  • TPositionUpdateOptions::SetUpdateTimeout(0) meaning that LBS should not timeout the client's request

  • TPositionUpdateOptions::SetMaxUpdateAge(0) meaning that new position data is required

  • TPositionUpdateOptions::SetAcceptPartialUpdates(EFalse) meaning the partial updates are not returned

When setting update options, a client should beware of causing unexpected side effects. For example, if a client wants to accept partial updates, it might do the following:

  • Create a new TPositionUpdateOptions options object

  • Call TPositionUpdateOptions::SetAcceptPartialUpdates(ETrue)

  • Call RPositioner::SetUpdateOptions() passing the options object as a parameter

However, this process has the side-effect of setting all the other update options to their default values as described above. In particular the client request will now not timeout which is unlikely to be the desired behaviour. To avoid this, a client should usually modify the current update options as follows:

  • Get the current update options by calling RPositioner::GetUpdateOptions()

  • Call the appropriate TPositionUpdateOptions::SetXXX() methods for the options to be changed

  • Call RPositioner::SetUpdateOptions() passing the modified options object as a parameter

Examples

The following code shows a simple example of how to set update options. Note that all the options are changed by the client.

...

TPositionUpdateOptions options;

// Frequency of updates in microseconds
const TTimeIntervalMicroSeconds KUpdateInterval(2000000);

// How long the application is willing to wait before timing out the request
const TTimeIntervalMicroSeconds KTimeOut(4000000);

// The maximum acceptable age of the information in an update
const TTimeIntervalMicroSeconds KMaxUpdateAge(1000000);

options.SetUpdateInterval(KUpdateInterval);
options.SetUpdateTimeOut(KTimeOut);
options.SetMaxUpdateAge(KMaxUpdateAge);
options.SetAcceptPartialUpdates(EFalse);

User::LeaveIfError(positioner.SetUpdateOptions(options));

/* Now when the application requests location information
it will be provided with these options */ 

positioner.NotifyPositionUpdate(posInfo, status);

...

The following code example shows an example of how to change one update option (to accept partial updates).

...

TPositionUpdateOptions options;

User::LeaveIfError(positioner.GetUpdateOptions(options));
options.SetAcceptPartialUpdates(ETrue);
User::LeaveIfError(positioner.SetUpdateOptions(options));

// The other update options are unchanged

positioner.NotifyPositionUpdate(posInfo, status);

...

Notes

When a call to RPositioner::NotifyPositionUpdate() or RPositioner::GetLastKnownPosition() completes, it is necessary to re-issue the request by calling one of these methods again to obtain further updates even if RPositioner::SetUpdateOptions() has been called. Setting update options allows a client to specify when the next position update is required, but does not cause periodic requests to the Location Server to be made.

A client application can only have one outstanding request for location information per RPositioner subsession. An attempt to make a second request for location information while one is still outstanding causes a panic to occur. An application must cancel an outstanding request before it makes another request. This process is described in step 7.

5. Request the location information

An application can call one the following methods to obtain position data:

  • RPositioner::NotifyPositionUpdate()

    A client application calls RPositioner::NotifyPositionUpdate() to request a position update. The LBS subsystem can either request that a Positioning Module obtains a new position and returns it to the client or simply returns an existing position calculated at some earlier time. The precise action taken by LBS depends on the quality of position required by the client because it is possible that a position obtained some time ago may meet the client application's position quality requirements.

    RPositioner::NotifyPositionUpdate() is a client-server asynchronous call. The client application can pass any position info class that derives from TPositionInfoBase. The standard position info class is TPositionInfo which is supported by all Positioning Modules. An application can get extended location information (if there is a Positioning Module that can supply it) by passing one of the specialised position info classes such as TCourseInfo or TPositionSatelliteInfo instead of TPositionInfo.

    See Position data and info classes for more information about position data and wrapper info classes.

  • RPositioner::GetLastKnownPosition()

    A client application calls RPositioner::GetLastKnownPosition() to request the device's last known position.

    RPositioner::GetLastKnownPosition() is a client-server asynchronous call. Calling this method does not instigate a new position fix even if the LBS subsystem does not have a last known position. It is therefore possible that this method will fail to return a position if one was not previously calculated. Client applications must check for this possibility by checking the values of TCoordinate::Latitude() and TCoordinate::Longitude() of the TPosition object inside of the TPositionInfo parameter. If latitude and longitude data are not available they are set to NaN (Not a Number). An application may also need to check the timestamp of the information to ensure it still meets its needs as it is possible that the last position update was obtained some time ago.

    If the LBS subsystem has a position from a previous request a call to RPositioner::GetLastKnownPosition() is more efficient in terms of request response time and device power consumption. It may also be cheaper for the mobile device owner who may be charged to obtain a new position.

  • RPositioner::GetLastKnownPositionArea()

    A client application calls RPositioner::GetLastKnownPositionArea() to request the last known position that most closely matches the device's current location. The device's current location is estimated from the network cell ID received from the network.

    RPositioner::GetLastKnownPositionArea() is a client-server asynchronous call. The client application can request the LBS subsystem to provide either basic or the extended area information. The exact signature of the method is as follows:

    RPositioner::GetLastKnownPositionArea(TPositionInfoBase& aPosInfo, TPositionAreaInfoBase& aAreaInfo, TRequestStatus& aStatus) const;

    A client passes in aPosInfo, aAreaInfo and aStatus parameters.

    • On completion, aPosInfo contains the last known position that is the best match with information received from the network.

    • aAreaInfo contains an estimate of the accuracy of the last known position. TPositionAreaInfoBase is the base class for two position area data classes. A client can pass a TPositionAreaInfo object to get basic position accuracy information, or it can pass a TPositionAreaExtendedInfo object to get extra information about how the accuracy estimate was calculated.

    If successful, GetLastKnownPositionArea() returns the best matching last known position in the aPosInfo parameter, an estimate of the position accuracy in the aAreaInfo parameter and a result code of KErrNone.

    See RPositioner::GetLastKnownPositionArea() for more information about using this method and the returned error codes.

    See Position Area Data Classes for information about the classes that used to obtain the position accuracy estimate.

    The following code fragment shows how to use the method and check the accuracy of the returned position:

    // Create an RPositionServer, RPositioner, TRequestStatus as normal and open a session (see above)
    
    ...
    
    // Want to know basic position accuracy, so use TPositionAreaInfo
    
    TRequestStatus status;
    TPositionInfo posInfo;
    TPositionAreaInfo areaInfo;
    
    // Get the last known location and an estimate of its accuracy
    
    positioner.GetLastKnownLocationArea(posInfo, areaInfo, status);
    User::WaitForRequest(status);
    
    // Check the return status 
    
    if ( status == KErrNone )
     {
    
     TPosition pos;
     posInfo.GetPosition(pos);
     TReal64 latitude = pos.Latitude();
     TReal64 longitude = pos.Longitude();
     TTime time = pos.Time();
    
     /*
     Check the posInfo object to see if it contains valid position data before trying to use it.
     Check position latitude, longitude and (if necessary) altitude for Math::IsNaN().
     Also a good idea to check the timestamp against current time, because this position could be old.
     Details omitted...
     */
    
     // Get the accuracy of the position
     TPositionAreaInfo::TArea area = areaInfo.Area();
     
     // Does this position meet your accuracy requirements?
    
     if (area == TPositionAreaInfo::EAreaCity)
      {
      
      /* 
      In this example, want city level position accuracy.
      Is this position accurate enough for your application?
      
      If not you could also check for EAreaDistrict and EAreaStreet.
      TPositionAreaInfo::_TArea defines the values you can check for.
      
      If this position is accurate enough, do something useful with your returned position data...
      
      If it is not accurate enough, you may need to get a new full position fix
      Call positioner.NotifyPositionUpdate() to do this.
      */
      
      }
     
     }
    
    else
    
        {
    
     /*
     Function returned something other than KErrNone.
     It could be KErrNotFound which indicates that no stored position was found.
     Or it could be a system error code if something went wrong - you need to check it.
     */
    
     }
    

Client applications must always check the value of the TRequestStatus parameter as this indicates the success or failure of the location request and may indicate that specified location accuracy criteria could not be satisfied at the time of the request.

The value of TRequestStatus that is set when a position update occurs or times out depends on the configuration of the LBS subsystem. See Location Acquisition API runtime behaviour for more information.

6. Receive and use the location information

When the Location Server obtains a position, the client's TRequestStatus variable is updated. In the example, the TPositionInfo object that was passed to RPositioner::NotifyPositionUpdate() holds the new position data in a TPosition object.

Important notes

An application should test what kind of position is returned by NotifyPositionUpdate(). TPositionInfoBase::PositionMode() returns a bitmask value of type TPositionModuleInfo::TTechnologyType that is composed of values of type TPositionModuleInfo::_TTechnologyType. Valid combinations of this value are as follows:

TPositionInfoBase::PositionMode() Meaning

ETechnologyNetwork

A reference position obtained from the network

ETechnologyTerminal | ETechnologyAssisted

A position calculated using GPS with assistance data from the network

ETechnologyNetwork | ETechnologyAssisted

A position calculated using GPS measurements by a remote server in the network

ETechnologyTerminal

A position calculated using GPS without assistance data (autonomous mode)

A reference position may be returned to a client application by the Location Server before a more accurate position fix is available. Whether a reference position is made available to the Location Server depends on the implementation of the Positioning Modules by the Symbian device creator or handset manufacturer.

If a reference position is returned, the behaviour is as follows:

For the first call to RPositioner::NotifyPositionUpdate()

NotifyPositionUpdate() completes and a reference position is returned to the client. The client application can check for return of a reference position by checking for TPositionInfoBase()::PositionMode() == TPositionModuleInfo::ETechnologyNetwork. If a reference position is returned it may not satisfy the application's position accuracy quality criteria and the application will need to make another NotifyPositionUpdate() request.

For subsequent calls to RPositioner::NotifyPositionUpdate() (made by the same client subsession)

NotifyPositionUpdate() completes and a position is returned to the client. This position may be either:

  • Calculated in the mobile device by GPS with assistance data (for Terminal Based Mode)

    TPositionInfo::PositionMode() == TPositionInfoBase::ETechnologyTerminal | TPositionInfoBase::ETechnologyAssisted

  • Returned from the network, a position known as the final network position (for Terminal Assisted Mode)

    The value of TPositionInfo::PositionMode() for a final network position depends on the configuration of the LBS subsystem:

    Normal behaviour is to return TPositionInfo::PositionMode() == TPositionModuleInfo::ETechnologyNetwork | TPositionModuleInfo::ETechnologyAssisted, but it is possible for LBS to return TPositionModuleInfo::ETechnologyTerminal | TPositionModuleInfo::ETechnologyAssisted if it is configured to do so. See Location Acquisition API runtime behaviour for more information.

Note that NotifyPositionUpdate() may complete early if a GPS positioning module signals to LBS that it will be unable to return a location fix with the required quality criteria. In this case the Location Server returns the best location fix it can obtain to the client. The value of the TRequestStatus parameter of the client is set to either KPositionQualityLoss or KErrNone depending on the configuration of Location Acquisition API runtime behaviour.

Tracking

A position update time line for tracking is shown in figure 2. Note that the exact behaviour of tracking on systems may differ from that shown in Figure 2.

A client application has previously called TPositionUpdateOptions::SetUpdateInterval(T) and RPositioner::SetUpdateOptions() (not shown in figure 2). Partial updates are not set. LBS is also configured to return reference positions and accurate positions only (see Location Acquisition API runtime behaviour for more information about this behaviour). The important points are:

  • A client application makes its first call to RPositioner::NotifyPositionUpdate() (First NPUD in figure 2).

  • After a time t, the client's RunL() method is called and it receives its first position update (the reference position update Ref Pos in figure 2). This first position update is delivered to the client by LBS as soon as possible (t is as short as possible and is not equal to T). The client then makes its next call to NotifyPositionUpdate() (the next NPUD in figure 2). When tracking, a client application should make its next call to RPositioner::NotifyPositionUpdate() as soon as possible in its RunL() method. The time between the client's RunL() and the client's next NPUD is exaggerated for clarity in Figure 2.

  • At a time t + T (where T is the update interval) the client's RunL() method is called and it receives the next position update (GPS Pos in figure 2). The client makes its next call to NotifyPositionUpdate().

  • The next position update is expected at time t + 2T, but in the case shown in figure 2 this is not possible (the mobile device may have moved into an area where the GPS signal is weak). In general if it is not possible to obtain an accurate GPS fix by time t + nT, but the fix is obtained a short time later, the next position update is delivered as soon as possible after time t + nT (after t + 2T in figure 2).

  • The client makes its next call to NotifyPositionUpdate() and at time t + (n+1)T the next position update is delivered (at t + 3T in figure 2).

    The important point to note is that LBS attempts to deliver position updates at regular times t + nT but the time interval between position updates may temporarily be greater than or less than T.

  • Note that if partial updates were enabled, an incomplete position would be delivered at time t + 2T if it were available. Also note that an inaccurate position would be delivered if one was available at that time and LBS was configured to return it.

Figure: Figure 2. Position updates when tracking

Error codes

The value of a client's TRequestStatus can be set to an LBS error code (defined in lbserrors.h) or an error code defined in a licensee's Positioning Module. An error causes NotifyPositionUpdate() to complete. An application should always check the value of TRequestStatus when its RunL() method is called.

7. Cancel or complete a location information request

To cancel a location request a client application calls RPositionerSubSessionBase::CancelRequest(), passing a EPositionerNotifyPositionUpdate parameter. The client's TRequestStatus is set to KErrCancel if the request was successfully cancelled and no position update is returned.

To complete a location request early, a client application calls RPositionerSubSessionBase::CompleteRequest() passing a EPositionerNotifyPositionUpdate parameter. Calling this method does not cancel the position update, but asks the Location Server to return any available position data. The returned position update may be different from that which would have been returned if the request had been allowed to complete normally. If the request is completed early, the client's TRequestStatus is set to KPositionEarlyComplete.

8. Close the subsession and session

RPositioner::Close() closes the subsession. RPositionServer::Close() closes the server session. In the code example the cleanup stack function is used. Any privacy requester objects created by a client must also be cleaned up.