The following steps are to be followed when using Location Acquisition API for a simple positioning operation. This is to provide the application developer with general idea of how to use Location Acquisition API. It is not intended as programming example.
RPositionServer
.
RPositioner
.
RPositioner
.
RPositioner
.
As a standard, NotifyPositionUpdate()
takes the parameters TPositionInfo
and
a TRequestStatus
.
TPositionInfo
, and TRequestStatus
contains
the result of the request.
TPositionInfo
.
RPositioner
.
RPositioner
and RPositionServer
.
RPositioner
.
RPositionServer
.
As Location Acquisition API is a client-server interface, a client has
to set up a connection to Location Server by calling RPositionServer
to
get location estimates. According to the common Symbian client/server API
scheme, the RPositioner
class represents a sub-session
to Location Server. The class provides a set of OpenL()
methods
to define additional parameters of the newly opened sub-session: whether to
use the default module, a particular module or a module that conforms to the
client’s criteria. Using a particular positioning module by specifying the
criteria is not supported.
Most location activity is done through RPositioner
.
The actions on getting general Location Server information are covered by RPositionServer
.
See the following paragraphs on how to use these classes.
To close a sub-session, the RPositioner
method
is provided. After the use of Location Server, RPositionServer
must
be called to close the client/server connection. All the used resources are
freed at that moment.
In the same way as with several other Symbian OS interfaces, only one request
can be outstanding on each asynchronous method. For example, it is not allowed
for an application to call NotifyPositionUpdate()
before
all the previous requests on that method have been completed. If the application
wishes to call the same method before all the outstanding requests complete
normally, it must first attempt to cancel those requests. The application
must wait until the cancellation has been confirmed and then re-issue the
desired request.
When a client application wishes to close one of its connections to RPositionServer
,
there can be no outstanding requests on that particular connection. If a client
application attempts to close a connection before outstanding requests have
been cancelled or completed, it is panicked. If the application wishes to
close a RPositioner
sub-session, it must ensure that it
has successfully cancelled requests to GetLastKnownPosition()
and NotifyPositionUpdate()
.
If the application wishes to close the main RPositionServer
session,
it must have successfully cancelled the NotifyModuleStatusEvent()
request.
Determining of someone’s location is a question of the person’s privacy and security. The Symbian OS and Positioning Framework provide a number of safeguards to help prevent the misuse of location information. Location information is not given to a requestor unless the user of the device for which location is requested accepts it. For example, if user A requests the location of user B, acceptance of user B is required to send the location information to user A. User B can accept or deny the particular request, based on the requestor’s information, which is provided by Positioning Framework. Positioning Framework requires the information about the client using Location Acquisition API.
There are two requestor types: service requestors and contact requestors.
A service requestor represents any terminal or network application or service,
and a contact requestor represents an individual person requesting the location. CRequestor
defines
the type of the requestor.
The requestor information must be sent to Location Server before requesting location estimates (otherwise, all such requests fail). This may be done in two different ways:
RPositioner
,
its three-argument variant. In this case, the requestor is defined directly
by the values supplied to the function’s parameters. This case is used by
applications or services if they are the only request source
RPositioner
,
which gets an argument of the type RRequestorStack
. This
approach is used more often when a request is made by an application or service
on behalf of some other entity, such as a contact or some other application.
RRequestorStack
is a container for a list of the requestors
on behalf of which the request is made. Each particular requestor in the stack
is represented by a CRequestor
class.
From S60 release 3.0 onwards platform security rules are enforced. The client application must have the Location capability to use some of methods from the API, related to client-server communication. These methods are:
RPositionServer
class:
GetDefaultModuleId()
GetNumModules()
GetModuleInfoByIndex()
GetModuleStatus()
NotifyModuleStatusEvent()
RPositioner
class:
SetRequestor()
(all overloads)
SetUpdateOptions()
GetUpdateOptions()
GetLastKnownPosition()
NotifyPositionUpdate()
All the other methods from the API do not require any capabilities.
In some cases, a client may need to specify more criteria for how location
updates should be generated, what data should be considered as valid or not
and so on. The RPositioner
function
allows to specify such criteria via the TPositionUpdateOptions
class.
Location update options affect only RPositioner
.
The TPositionUpdateOptions
class provides the following
options:
In addition to the general position classes introduced in Security and capabilities, there are two other position
classes: TPositionCourseInfo
and TPositionSatelliteInfo
.
TPositionCourseInfo
contains a TCourse
object,
which may be used to get information such as the current speed at which the
device is moving, the device’s direction in terms of bearing, and also the
accuracy of these parameters.
TPositionSatelliteInfo
contains information about the
satellites used in locating: how many satellites are available, which of those
were used to produce the current estimate, and a list of the satellites with
their data. A satellite is represented by the TSatelliteData
class.
A client gets the information by sending the appropriate object to Location
Server via NotifyPositionUpdate()
. If the currently used
positioning module supports the data (see Module
Information), it fills the objects with the data and returns it to
the client. TPositionSatellites
inherits TPositionCourseInfo
,
which is derived from the TPositionInfo
class, and thus
the client gets the extended information simultaneously with the general data
in one request. However, if the module does not support the requested data
class, the whole request fails. Therefore, the client should ensure if the
particular position information class is supported by the current module before
it issues a request.
RPositionServer
also provides the methods GetModuleInfoByIndex()
and GetModuleInfoById()
to
get information about the currently available modules. Modules are identified
by the TPositionModuleId
class and its data is provided
in the format of the TPositionModuleInfo
class. To know
the state of a particular module at a given moment, GetModuleStatus()
may
be called. To receive all module status events, the NotifyModuleStatusEvent()
member
function is used.
The module information is delivered in the form of the TPositionModuleInfo
class.
The most important fields are the following:
HPositionGenericInfo
.
The TPositionModuleEvent
class is used to hold information
about the module when a client is informed about events in the module. This
is also used by clients to specify of which types of events happening in the
module they wish to be notified. Clients use this class to determine what
particular events have just occurred and the new status of the module.
Location Acquisition API defines a number of standard classes for holding position information. Unless otherwise stated, these classes use the following measurement system:
A number of the classes described in this document use real numbers to hold position, accuracy and other information. Sometimes some values can be unset. Altitude is a typical example.
Where a real number has not been assigned, Location Framework indicates
this by a special (reserved) bit pattern. This bit pattern is defined by Symbian
OS and is usually referred to as “Not a Number” (NaN). Applications should
check if a value is NaN by using the standard method from the Math library
(Math::IsNaN
).
Although NaN can be tested, the value cannot be used in calculations. Attempting to use a NaN value in an arithmetic expression results in an application panic.
In order to perform a simple location request, a client establishes a connection
with the RPositionServer
and opens a sub-session with positioner.
Then, it sets information about the requestor and calls the asynchronous RPositioner
function
to get location information. After getting location information, the client
closes the sub-session and connection with RPositionServer
.
The following diagram illustrates the steps involved in simple obtaining of location information.
Figure 7: Obtaining current location information:
The following simple example shows the code that a client should execute to get a position update.
#include <lbs.h> // Connect to server and create a session RPositionServer server; RPositioner positioner; User::LeaveIfError(server.Connect()); CleanupClosePushL(server); // use default positioning module User::LeaveIfError(positioner.Open(server)); CleanupClosePushL(positioner); // Set the Requestor information _LIT(KCntPhone, "+358501234567"); _LIT(KSrvName, "MyService"); RRequestorStack stack; CRequestor* contact = CRequestor::NewLC( CRequestor::ERequestorContact, CRequestor::EFormatTel ephone, KCntPhone); stack.Append(contact); CRequestor* service = CRequestor::NewLC(CRequestor::ERequestorService, CRequestor::EFormatAppl ication, KSrvName); stack.Append(service); User::LeaveIfError(positioner.SetRequestor(stack)); //Issue a Location Request TRequestStatus status; TPositionInfo posInfo; positioner.NotifyPositionUpdate(posInfo, status); // asynchronous request User::WaitForRequest(status); // for exemplification only, AOs should be used User::LeaveIfError(status.Int()); //Use the location information present in the posInfo object //Cleanup stack.Reset(); CleanupStack::PopAndDestroy(service); CleanupStack::PopAndDestroy(contact); CleanupStack::PopAndDestroy(&positioner); // this will call Close() method CleanupStack::PopAndDestroy(&server); // this will call Close() method
In order to obtain extended location information, the client needs to specify
what kind of information it expects from Location Server before issuing the
request. This is specified by the setting identifiers of the requested fields
in the HPositionGenericInfo
object: The TPositionFieldId
specifies
the various fields that can be requested.
The following diagram illustrates the steps involved in obtaining extended location information.
Figure 8: Obtaining extended location information:
The following example depicts the code that a client should execute to get extended location information
//Connect to the server and open a session RPositionServer server; RPositioner positioner; User::LeaveIfError(server.Connect()); CleanupClosePushL(server); TPositionModuleId moduleId; moduleId.iUid = KModuleIdThatSupportsAddressCapabilites; // select valid module User::LeaveIfError(positioner.Open(server, moduleId)); // use specific module CleanupClosePushL(positioner); //Init Generic Info buffer HPositionGenericInfo* genInfo = HPositionGenericInfo::NewLC(); // default sizes genInfo->SetRequestedField(EPositionFieldCountry); genInfo->SetRequestedField(EPositionFieldCity); // Specify Requestors _LIT(KSrvName, "MyService"); RRequestorStack stack; CRequestor* service = CRequestor::NewLC( CRequestor::ERequestorService, CRequestor::EFormatApplication, KSrvName); stack.Append(service); User::LeaveIfError(positioner.SetRequestor(stack)); // Make a request TRequestStatus status; positioner.NotifyPositionUpdate(*genInfo, status); User::WaitForRequest(status); User::LeaveIfError(status.Int()); // Get Results TPtrC16 city, country; if (genInfo->IsFieldAvailable(EPositionFieldCountry)) { genInfo->GetValue(EPositionFieldCountry, country); } if (genInfo->IsFieldAvailable(EPositionFieldCity)) { genInfo->GetValue(EPositionFieldCity, city); } // Cleanup stack.Reset(); CleanupStack::PopAndDestroy(service); CleanupStack::PopAndDestroy(contact); CleanupStack::PopAndDestroy(genInfo); CleanupStack::PopAndDestroy(&positioner); // this will call Close() method CleanupStack::PopAndDestroy(&server); // this will call Close() method
To obtain the last known location information, the client application establishes
connection with RPositionServer
and opens a sub-session
using RPositioner
. Then, it sets information about the
requestor and calls the asynchronous RPositioner
function
to get cached location information (if any). After getting location information,
the client closes the sub-session and connection with RPositionServer
.
Following diagram illustrates the steps involved in simple obtaining the last known position information.
Figure 9: Obtaining last known position information:
#include <lbs.h> //Init Connection RPositionServer server; RPositioner positioner; User::LeaveIfError(server.Connect()); CleanupClosePushL(server); User::LeaveIfError(positioner.Open(server)); // use default positioning module CleanupClosePushL(positioner); //Specify Requestors _LIT(KSrvName, "MyService"); RRequestorStack stack; CRequestor* service = CRequestor::NewLC( CRequestor::ERequestorService, CRequestor::EFormatApplication, KSrvName); stack.Append(service); User::LeaveIfError(positioner.SetRequestor(stack)); //Issue a Location Request TRequestStatus status; TPositionInfo posInfo; positioner.GetLastKnownPosition(posInfo, status); // asynchronous request User::WaitForRequest(status); // This is just for demonstration. AOs should be used User::LeaveIfError(status.Int()); // Analyze Results TPosition position; posInfo.GetPosition(position); stack.Reset(); CleanupStack::PopAndDestroy(service); CleanupStack::PopAndDestroy(contact); CleanupStack::PopAndDestroy( &positioner ); // this will call Close() method CleanupStack::PopAndDestroy( &server ); // this will call Close() method
The client application can cancel an outstanding asynchronous location
request from within the RPositioner
class. Canceling requests
is typically attempted when an application is closing down.
The following diagram illustrates the steps involved in cancelling the location request.
Figure 10: Cancelling the request for location information
#include <lbs.h> // CLocationOp is an Active Object and derives from CActive class // In the construction of the object connect to the server // and create the iPositioner session void CLocationOp::RequestLocation() { // Make an asynchronous request for current location iPositioner.NotifyPositionUpdate( iPosInfo, iStatus ); SetActive(); } void CLocationOp::DoCancel() { iPositioner.CancelRequest( EPositionerNotifyPositionUpdate ); } void CLocationOp::RunL() { // Handle the response for the NotifyPositionUpdate. }
The client application can modify the behavior of location requests. For
example after establishing connection with RPositionServer
and
opening a sub-session using RPositioner
, client can specify
periodic update interval through location update option and then requests
for the location information. After getting the information client re-issues
a request for location information and it gets back the information after
the specified time-interval.
The following diagram illustrates the steps involved in getting the periodic position updates.
Figure 11: Getting periodic position updates
//Connect to the server and create a session TInt updateIntervalTime = KUpdateInterval; // Client should define the KUpdateInterval TPositionUpdateOptions updateOptions; updateOptions.SetUpdateInterval(TTimeIntervalMicroSeconds(aIntervalTime)); User::LeaveIfError( iPositioner.SetUpdateOptions(updateOptions) ); // Further calls to NotifyPositionUpdate will use this UpdateInterval option TPositionInfo posInfo; TRequestStatus status; iPositioner.NotifyPositionUpdate(posInfo, iStatus); User::WaitForRequest(status); User::LeaveIfError(status.Int()); // Use the information in posInfo // make another request for current Location iPositioner.NotifyPositionUpdate(posInfo, iStatus); // The client will receive a response for the above request // upon the elapse of the specified interval User::WaitForRequest(status); User::LeaveIfError(status.Int()); // Use the information in posInfo // Close the session and connection to the server finally
Client application can specify the time period for how long it is prepared
to wait to obtain a fix. The timeout period starts when the client application
issues a location request. If an update is not obtained within this time period, NotifyPositionUpdate()
completes
with KErrTimedOut
.
When the client changes the update timeout it does not affect the current location request. The updated timeout interval is applied on further current location requests from the client.
Invoking SetUpdateOptions()
with an update timeout value
of zero sets it to the default behavior, which is to have no time limit.
The following diagram illustrates the steps involved in getting the position updates with time-out specified.
Figure 12: Position update with time-out
//Connect to the server and create a session TInt updateTimeout = KUpdateTimeout; // Client should define the KUpdateTimeout TPositionUpdateOptions updateOptions; updateOptions.SetUpdateTimeOut( TTimeIntervalMicroSeconds(updateTimeout) ); User::LeaveIfError( iPositioner.SetUpdateOptions(updateOptions) ); // Further calls to NotifyPositionUpdate will use this Update Timeout value TPositionInfo posInfo; TRequestStatus status; iPositioner.NotifyPositionUpdate(posInfo, iStatus); User::WaitForRequest(status); // Now if the Location Server is unable to return a position information within the // specified update time then it returns KErrTimedOut User::LeaveIfError(status.Int()); // Use the information in posInfo // Close the session and connection to the server finally
Information about the currently available modules can be obtained using RPositionServer
and RPositionServer
methods. For more details
about the kind of module information topic Module
Information section can be referred.
The following diagram illustrates the steps involved in getting the module information.
Figure 13: Getting the module information
#include <lbs.h> //Init Connection RPositionServer server; User::LeaveIfError(server.Connect()); CleanupClosePushL(server); TPositionModuleInfo moduleInfo; //KModuleIndex should be within the //range of 0 to server.GetNumModules() - 1 TInt moduleIndex = KModuleIndex; User::LeaveIfError( server.GetModuleInfoByIndex( moduleIndex, moduleInfo ) ); // Use the module information here. CleanupStack::PopAndDestroy( &server ); // this will call Close() method
Location requests can be obtained using a specific positioning module.
This is achieved by specifying the module ID as a parameter while opening
the subsession using RPositioner
.
The following diagram illustrates the steps involved in using a specific positioning module for getting the position information.
Figure 14: Using specific positioning module for position information
#include <lbs.h> ... //Init Connection RPositionServer server; RPositioner positioner; User::LeaveIfError(server.Connect()); CleanupClosePushL(server); TPositionModuleId moduleId; //Use the module Id of the positioning module from which //position information is to be requested. moduleId.iUid = KInterestedPositioningModuleId; //request Location server to use a specific positioning module User::LeaveIfError(positioner.Open(server, module)); CleanupClosePushL(positioner); //Specify Requestors _LIT(KSrvName, "MyService"); RRequestorStack stack; CRequestor* service = CRequestor::NewLC( CRequestor::ERequestorService, CRequestor::EFormatApplication, KSrvName); stack.Append(service); User::LeaveIfError(positioner.SetRequestor(stack)); //Issue a Location Request TRequestStatus status; TPositionInfo posInfo; positioner.GetLastKnownPosition(posInfo, status); // asynchronous request User::WaitForRequest(status); // This is just for demonstration. AOs should be used User::LeaveIfError(status.Int()); // Analyze Results TPosition position; posInfo.GetPosition(position); stack.Reset(); CleanupStack::PopAndDestroy(service); CleanupStack::PopAndDestroy(contact); CleanupStack::PopAndDestroy(&positioner); // this will call Close() method CleanupStack::PopAndDestroy(&server); // this will call Close() method
Status changes of either a single module or all positioning modules can
be reported using the asynchronous method RPositionServer
.
After a notification has been received, the client application must re-issue
the status change request if it wishes to obtain further updates.
The following diagram illustrates the steps involved in requesting notifications on positioning module events.
Figure 15: Specifying the positioning module to get the position information
RPositionServer server; User::LeaveIfError( server.Connect() ); CleanupClosePushL( server ); TPositionModuleId moduleId; //Using KPositionNullModuleId will notify when the status //of any module changes. If notification is required for a specific //positioning module then use that module's ID. moduleId.iUid = KPositionNullModuleId; TPositionModuleStatusEvent moduleEvent; TRequestStatus status; //request server to notify when the module's status changes. server.NotifyModuleStatusEvent( moduleEvent, status, moduleId ); //Wait till the server sends a notification. User::WaitForRequest( status ); User::LeaveIfError(status.Int()); //If there is no error then use the moduleEvent to identify //the status of the module //Close the server connection server.Close();
Location Acquisition API uses the standard Symbian error reporting mechanism. In case of an irrecoverable error, panics are used. Otherwise, leaves are used or functions return error codes as their return values.
Location Acquisition API uses standard system error codes plus certain errors defined in Location Acquisition API. They can be found in the LbsErrors.h file.
During the client-server communication process the following errors may occur:
KErrBadHandle
: returned if the connection to Location
Server is not present or is no longer valid.
KErrServerBusy
: this value is returned if Location Server
has taken too long to accept a request.
When using Location Acquisition API, the memory overhead is dependent on the amount of instantiated classes but there are also some cases when extra memory usage can be involved. Nevertheless, the memory usage is always controlled by the client application and there are never any uncontrolled allocations of large amounts of memory that the client cannot prevent or avoid.
When communicating with Location Server, additional buffers are used to
for transferring data (mostly related to the requestor information). Also
the HPositionGenericInfo
class uses a heap to store location
data. However, in all cases, the amount of memory is defined by the client
and thus can be exactly predicted. After use, the needed additional buffers
(if any) are unallocated automatically.
The number of simultaneous sessions and subsessions also has an impact on the overall memory usage. For this reason, unnecessary sessions and sub-sessions should be avoided.
Location Acquisition API can be extended by defining new data classes.
It is possible to provide new location estimate data structures by deriving
new classes from TPositionInfoBase
or any of its descendants.
A positioning module supporting such a class provides the client with new
information.
Applications should use Location Acquisition API appropriately to achieve best user experience and lowest power consumption. The following items are main concerns when requesting location information from the system.
TPositionInfo
, TPositionCourseInfo
, TPositionSatelliteInfo
or HPositionGenericInfo
)
There can be different positioning modules available in the terminal. They are mainly based on two types of positioning technologies.
TPositionInfo
, TPositionCourseInfo
, TPositionSatelliteInfo
and HPositionGenericInfo
data classes.
Unless a client is interested in a specific positioning module, it should
always use the default module when requesting location information from the
system. When default module is used, the system tries to retrieve location
information from all enabled positioning modules based on requested location
data and location update options. Requested location data determines what
positioning modules are used. For example, if client requests TPositionCourseInfo
or TPositionSatelliteInfo
,
positioning modules that based on network technology are not used.
Using location service has quite dramatic impact on battery life of the mobile phone, especially when integrated GPS positioning module is used. Developers must take power consumption into consideration when using this API. The general rule is to make as less location request as possible. When tracking is needed, always select the largest update interval value that is acceptable. If location fix is not required for a long time (i.e. more than 10 minutes), application should close sub-session to Location Server. Network based positioning module consumes much less energy than GPS based positioning module. So, application can consider of using network based positioning modules whenever possible.
In this section we give examples of using Location Acquisition API of the following types of applications.
TPositionSatelliteInfo
.
It shall get information update even location fix can not be made by the system
(i.e. partial update is accepted by the application).
Requested location data (3) | Used positioning technology | Update interval | Update timeout | Update maximum age | Partial update | |
Navigation application (navigation mode) | TPositionCourseInfo
|
GPS based | 1 second | 0 (No timeout set) | 0 (Does not allow old position information) | Not allowed |
Tourist guide application | TPositionInfo |
GPS based or network based | 0 | At least 90 seconds (1) | 60 seconds | Not allowed |
GPS satellite information viewer | TPositionSatelliteInfo
|
GPS based | 1 second | 0 (No timeout set) | 0 (Does not allow old position information) | Allowed |
Fleet-tracking application | TPositionInfo |
GPS based or network based | Depends on actual use case (2) | At least 90 seconds (1) | 60 seconds or depends on actual use case | Not allowed |
(1) Update timeout value shall be long enough for positioning modules (especially modules based on GPS technology) to give a fix. To improve user experience, cancel functionality might be needed for end user to cancel the location request.
(2) Update interval for fleet-tracking application depends on the actual use case. If the update interval is very long (for example over 10 minutes), it's recommended that the application does not set update interval at all. Instead, it should issue location request based on its own timer. And between location requests, the application should close sub-session to Location Server to improve memory usage and save battery life.
(3) Some applications accept only accurate location estimation. Therefore,
to prevent network based positioning modules being used, application may request TPositionCourseInfo
or TPositionSatelliteInfo
.