networkprotocolmodules/suplprotocolmodule/SuplProtocol/src/suplmolrstatehandler.cpp
changeset 0 9cfd9a3ee49c
equal deleted inserted replaced
-1:000000000000 0:9cfd9a3ee49c
       
     1 // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // This file provides the implementation of the class for
       
    15 // the SUPL MO-LR procedure state handler
       
    16 // 
       
    17 //
       
    18 
       
    19 /**
       
    20  @file
       
    21  @internalTechnology
       
    22  @deprecated
       
    23 */
       
    24 
       
    25 #include "suplmolrfsmsession.h"
       
    26 #include "suplmolrstatehandler.h"
       
    27 #include "suplgatewayinterface.h"
       
    28 #include "suplmessagebase.h"
       
    29 #include "suplstart.h"
       
    30 #include "suplpos.h"
       
    31 #include "suplposinit.h"
       
    32 #include "suplresponse.h"
       
    33 #include "suplend.h"
       
    34 #include <etelmm.h>
       
    35 #include "supldevloggermacros.h"
       
    36 
       
    37 
       
    38 /** Static constructor.
       
    39 @param aMachine A reference to the parent state machine.
       
    40 @return A new instance of the CSuplMoLrStateHandler class
       
    41 */
       
    42 CSuplMoLrStateHandler* CSuplMoLrStateHandler::NewL(CSuplFsmSessionBase& aMachine)
       
    43 	{
       
    44 	SUPLLOG(ELogP1, "CSuplMoLrStateHandler::NewL()\n");
       
    45 	CSuplMoLrStateHandler* self = new (ELeave) CSuplMoLrStateHandler(aMachine);
       
    46 	return self;
       
    47 	}
       
    48 
       
    49 /** Standard constructor.
       
    50 @param aMachine A reference to the parent state machine.
       
    51 */  
       
    52 CSuplMoLrStateHandler::CSuplMoLrStateHandler(CSuplFsmSessionBase& aMachine)
       
    53 : CSuplStateHandlerBase(aMachine)
       
    54 	{
       
    55 	SUPLLOG(ELogP1, "CSuplMoLrStateHandler::CSuplMoLrStateHandler() Begin\n");
       
    56 	SUPLLOG(ELogP1, "CSuplMoLrStateHandler::CSuplMoLrStateHandler() End\n");
       
    57 	}
       
    58 
       
    59 
       
    60 /** Standard destructor.
       
    61 */  
       
    62 CSuplMoLrStateHandler::~CSuplMoLrStateHandler()
       
    63 	{
       
    64 	SUPLLOG(ELogP1, "CSuplMoLrStateHandler::~CSuplMoLrStateHandler() Begin\n");
       
    65 	SUPLLOG(ELogP1, "CSuplMoLrStateHandler::~CSuplMoLrStateHandler() End\n");
       
    66 	}
       
    67 	
       
    68 /** Perform entry actions.
       
    69 This is called from the state machine to perform any actions
       
    70 associated with entering the current state following an external
       
    71 event or an autonomous state transition.
       
    72 
       
    73 For some states, there is only one possible course of action.
       
    74 For other states, the event store has to be checked to see what
       
    75 events have occurred and what actions have to be taken to handle
       
    76 such events.
       
    77 
       
    78 If an event conductive to cancelling the state machine had occurred
       
    79 (e.g, an explicit client cancel, an error, or a timeout), then the
       
    80 state machine would have been set in an state that terminates the 
       
    81 session before this method is called (either EStateSuplSessionEnded
       
    82 or EStatePosSessionEnded).
       
    83 
       
    84 @return TBool ETrue if any actions have been taken
       
    85 */  
       
    86 TBool CSuplMoLrStateHandler::EntryActionsL()
       
    87 	{
       
    88 	SUPLLOG(ELogP1, "CSuplMoLrStateHandler::EntryActionsL() Begin\n");
       
    89 	TBool actionsTaken = ETrue;
       
    90 	// Retrieve current state and act accordingly
       
    91 	switch(iMachine.CurrentState())
       
    92 		{
       
    93 		case CSuplFsmSessionBase::EStateProcedureNull:
       
    94 			// No action
       
    95 			break;
       
    96 		
       
    97 		case CSuplFsmSessionBase::EStateNetConnectionStarted:
       
    98 			actionsTaken = EntryActionsFromNetConnectionStarted();
       
    99 			break;
       
   100 
       
   101 		case CSuplFsmSessionBase::EStateStartSent:
       
   102 			// Build and send a SUPL START message
       
   103 			actionsTaken = EntryActionsFromStartSentStateL();
       
   104 			break;
       
   105 			
       
   106 		case CSuplFsmSessionBase::EStateResponseReceived:
       
   107 			// Handle a received SUPL RESPONSE message
       
   108 			actionsTaken = EntryActionsFromResponseReceivedStateL();
       
   109 			break;
       
   110 			
       
   111 		case CSuplFsmSessionBase::EStatePosInitSent:
       
   112 			// Build and send a SUPL POS INIT
       
   113 			actionsTaken = EntryActionsFromPosInitSentStateL();
       
   114 			break;
       
   115 
       
   116 		case CSuplFsmSessionBase::EStatePositioningInProgress:
       
   117 			actionsTaken = EntryActionsFromPositioningInProgressStateL();
       
   118 			break;
       
   119 
       
   120 		case CSuplFsmSessionBase::EStatePositionReceived:
       
   121 			actionsTaken = EntryActionsFromPositionReceivedStateL();
       
   122 			break;
       
   123 			
       
   124 		case CSuplFsmSessionBase::EStateSuplSessionEnded:
       
   125 			// Send SUPL END
       
   126 			actionsTaken = EntryActionsFromSuplSessionEndedStateL();
       
   127 			break;
       
   128 
       
   129 		case CSuplFsmSessionBase::EStatePosSessionEnded:
       
   130 			// Send to Positioning FSM an instruction to terminate silently
       
   131 			//
       
   132 			iMachine.PositioningFsm()->CancelMachine(CSuplPositioningProtocolFsm::ESuplFsmCancel, CSuplFsmSessionBase::EReasonNone);
       
   133 			break;
       
   134 			
       
   135 		case CSuplFsmSessionBase::EStateLbsSessionEnded:
       
   136 			// Send session complete indication to LBS
       
   137 			actionsTaken = EntryActionsFromLbsSessionEndedStateL();
       
   138 			break;
       
   139 			
       
   140 		case CSuplFsmSessionBase::EStateNetConnectionClosed:
       
   141 			// Close the network connection
       
   142 			iMachine.CompleteProcedure();
       
   143 			break;
       
   144 
       
   145 		default:
       
   146 			ASSERT(EFalse);
       
   147 			break;
       
   148 		}
       
   149 	SUPLLOG(ELogP1, "CSuplMoLrStateHandler::EntryActionsL() End\n");	
       
   150 	return actionsTaken;
       
   151 	}
       
   152 //---------------------------------------------------------------------------------------------------------------------
       
   153 // -----------------------     METHODS FOR ACTIONS AFTER ENTERING STATES  ---------------------------------------------
       
   154 //---------------------------------------------------------------------------------------------------------------------
       
   155 
       
   156 /** Actions on entering state EStateNetConnectionStarted
       
   157 
       
   158 This method obtains an SLP Id from the Host Settings store
       
   159 and asks the Connection Manager to provide a connection with it.
       
   160 */
       
   161 TBool CSuplMoLrStateHandler::EntryActionsFromNetConnectionStarted()
       
   162 	{
       
   163 	SUPLLOG(ELogP1, "CSuplMoLrStateHandler::EntryActionsFromNetConnectionStarted() Begin\n");
       
   164 	TLbsHostSettingsId hostId = TUid::Uid(0);
       
   165 	TLbsNetSessionId::TSessionNum sessIdNum = 0;
       
   166 	TInt err = iMachine.GetHostId(hostId); 
       
   167 		
       
   168 	if (KErrNone == err)
       
   169 		{
       
   170 		// Request a connection from the Connection Manager
       
   171 		//
       
   172 		sessIdNum = iMachine.SessionId().SessionNum();
       
   173 		iMachine.Observer().ConnectionManager().Connect(sessIdNum, hostId, CSuplSessionRecord::EServiceMolr, iMachine);
       
   174 		// start the timer that oversees connection creation
       
   175 		iMachine.StartConnectionTimer();		
       
   176 		}
       
   177 	else
       
   178 		{
       
   179 		// Cancel session as a SUPL server could not be determined
       
   180 		iMachine.CancelMachine(CSuplFsmSessionBase::ECancelSuplProt, CSuplFsmSessionBase::EReasonSlpSettingsMissing);
       
   181 		}
       
   182 	SUPLLOG(ELogP1, "CSuplMoLrStateHandler::EntryActionsFromNetConnectionStarted() End\n");
       
   183 	return ETrue;
       
   184 	}
       
   185 	
       
   186 /** Actions on entering state EStateStartSent
       
   187 
       
   188 This method builds a SUPL START and passes it on to
       
   189 the Connection Manager for sending to the SUPL server
       
   190 
       
   191 */
       
   192 TBool CSuplMoLrStateHandler::EntryActionsFromStartSentStateL()
       
   193 	{
       
   194 	SUPLLOG(ELogP1, "CSuplMoLrStateHandler::EntryActionsFromStartSentStateL() Begin\n");
       
   195 	
       
   196 	TLbsNetPosRequestQuality quality;
       
   197 	TLbsNetPosCapabilities capabilities;
       
   198 
       
   199     ASSERT(iMachine.IsSessionConnected()); // should not have transitioned into this state without a connection
       
   200 
       
   201 	// A SUPL START message must contain a Location ID with
       
   202 	// network information (cell ID, etc). If such data has
       
   203 	// not been made available to the state machine then
       
   204 	// cancel ongoing session
       
   205 	CSuplLocationId* locationId ;
       
   206 	if (BuildLocationIdL(locationId))
       
   207 		{
       
   208 		CleanupStack::PushL(locationId);
       
   209 		}
       
   210 	else
       
   211 		{
       
   212 		iMachine.CancelMachine(CSuplFsmSessionBase::ECancelSuplProt, CSuplFsmSessionBase::EReasonNone);
       
   213 		return EFalse;
       
   214 		}
       
   215 
       
   216 	// Create a SUPL message common part.
       
   217 	// Set the SET session ID only in CSuplSessionId.
       
   218 	CSuplSessionId* sessionId = CSuplSessionId::NewL();
       
   219 	CleanupStack::PushL(sessionId);
       
   220 	sessionId->iSetSessionIdPresent = ETrue;
       
   221 	sessionId->iSetSessionId->iSessionId = iMachine.SessionId().SessionNum();
       
   222 	sessionId->iSetSessionId->iSetId->iSetIdType = ESuplSetIdTypeMsisdn; // TSuplSetIdType
       
   223 	
       
   224 	const TUint8 KMaxMsisdnLength = 8;
       
   225 	TDes8& des = sessionId->iSetSessionId->iSetId->iSetId;
       
   226 	if(iMachine.Msisdn())
       
   227 		{
       
   228 		ConvertToBcd(des);
       
   229 		}
       
   230 	else
       
   231 		{
       
   232 		//Fill the descriptor with all bits set to 0, then append a 0xFF to the end to indicate the end of the MSISDN
       
   233 		des.SetLength(KMaxMsisdnLength);
       
   234 		des.Fill(0x00, (KMaxMsisdnLength -1));	//7 0's
       
   235 		des.Append(0xFF);	//Final 1 FF
       
   236 		}
       
   237 	
       
   238 	//The commented code can be used when the set id type selection from the Host Settings API is implemented
       
   239 	//TUint32 ipAddr = iMachine.RetrieveLocalIpAddress().Address();
       
   240 	//sessionId->iSetSessionId->iSetId->iIpAddress->iIpAddressType = ESuplIpAddressTypeV4;
       
   241 	//sessionId->iSetSessionId->iSetId->iIpAddress->iIpAddress.Copy(reinterpret_cast<unsigned char*>(&ipAddr), 4);
       
   242 
       
   243 	// Keep session Id for future reference
       
   244 	iMachine.SetMessageSessionId(sessionId); // ownership transferred
       
   245 	CleanupStack::Pop(sessionId);
       
   246 	
       
   247 	// positioning capabilities and request quality to be set in SUPL START
       
   248 	// are built using the stored Request Options
       
   249 	if (CSuplMolrFsmSession::ESuplMolrCellBased == (reinterpret_cast <CSuplMolrFsmSession&> (iMachine)).MachineType())
       
   250 		{
       
   251 		TLbsNetPosRequestOptions locReqOptions;
       
   252 		iMachine.RetrieveLocationRequestOptions(locReqOptions);
       
   253 		
       
   254 		TLbsNetPosMethod posMethods[1];
       
   255 		posMethods[0].SetPosMethod(KLbsPositioningMeansCell, TPositionModuleInfo::ETechnologyNetwork);
       
   256 		capabilities.SetPosMethods(posMethods, 1);
       
   257 		
       
   258 		locReqOptions.GetRequestQuality(quality);
       
   259 		}
       
   260 	else // Not Cell-Based only
       
   261 		{
       
   262 		// Send all of LBS' capabilities in the SUPL START
       
   263 		BuildCapabilitiesL(capabilities,quality);
       
   264 		}
       
   265 
       
   266 	// Create the SUPL START Message
       
   267 	CSuplStart* suplStart = CSuplStart::NewLC();
       
   268 	TInt err = suplStart->SetCapabilities(capabilities);
       
   269 	err = suplStart->SetLocationId(*locationId);
       
   270 	err= suplStart->SetSessionId(*sessionId);
       
   271 	err = suplStart->SetQoP(quality);
       
   272 	
       
   273 	CleanupStack::Pop(suplStart);
       
   274 	CleanupStack::PopAndDestroy(locationId);
       
   275 	
       
   276  	// Ask the Connection Manager to send the SUPL START message to the server
       
   277 	iMachine.Observer().ConnectionManager().SendMessage(suplStart, iMachine.SessionId().SessionNum());
       
   278 	
       
   279 	iMachine.SetSessionInProgress(ETrue);
       
   280 	  
       
   281 	// start the timer that oversees the arrival of SUPL RESPONSE
       
   282 	(reinterpret_cast <CSuplMolrFsmSession&> (iMachine)).StartSuplResponseTimer();
       
   283 
       
   284 	SUPLLOG(ELogP1, "CSuplMoLrStateHandler::EntryActionsFromStartSentStateL() End\n");
       
   285 	return ETrue;
       
   286 	}
       
   287 
       
   288 /** Actions on entering state EStateResponseReceived
       
   289 
       
   290 This method extracts the positioning method from SUPL RESPONSE and 
       
   291 sends a new location request to LBS.
       
   292 */
       
   293 TBool CSuplMoLrStateHandler::EntryActionsFromResponseReceivedStateL()
       
   294 	{
       
   295 	SUPLLOG(ELogP1, "CSuplMoLrStateHandler::EntryActionsFromResponseReceivedStateL() Begin\n");
       
   296 	TBool actionsTaken = EFalse;
       
   297 	
       
   298 	// A SUPL RESPONSE must be the oldest SUPL message in the 
       
   299 	// event store at this point.
       
   300 
       
   301 	CSuplMessageBase* suplMessage = const_cast <CSuplMessageBase*> (iMachine.RetrieveSuplMessage());
       
   302 	
       
   303 	ASSERT(suplMessage != NULL);
       
   304 	ASSERT(CSuplMessageBase::ESuplResponse == suplMessage->MessageType());
       
   305 	
       
   306 	if ((suplMessage != NULL) && (CSuplMessageBase::ESuplResponse == suplMessage->MessageType()))
       
   307 		{
       
   308 		CSuplResponse* responsePtr = static_cast <CSuplResponse*>(suplMessage);
       
   309 
       
   310 		// Check that the SetId is the same that was sent in the SUPL START
       
   311 		CSuplSessionId *sessId = CSuplSessionId::NewLC();
       
   312 		responsePtr->GetSessionId(*sessId);
       
   313 		if (! ((*(iMachine.MessageSessionId()->iSetSessionId)) == (*(sessId->iSetSessionId))))
       
   314 			{
       
   315 			iMachine.CancelMachine(CSuplFsmSessionBase::ECancelSuplProt,CSuplFsmSessionBase::EReasonInvalidSessId);
       
   316 			// Store received session Id for sending later in SUPL END as per SUPL specification
       
   317 			CleanupStack::Pop(sessId);
       
   318 			iMachine.SetMessageSessionId(sessId); // ownership transferred
       
   319 			delete responsePtr;
       
   320 			SUPLLOG(ELogP1, "CSuplMoLrStateHandler::EntryActionsFromResponseReceivedStateL() End\n");
       
   321 			return actionsTaken;
       
   322 			}
       
   323 		else
       
   324 			{
       
   325 			CleanupStack::Pop(sessId);
       
   326 			// Store received session Id for later use
       
   327 			iMachine.SetMessageSessionId(sessId); // ownership transferred
       
   328 			}
       
   329 
       
   330 		// Extract the Positioning Method that SHALL (as per SUPL specification)
       
   331 		// be used for the SUPL POS session
       
   332 		TLbsNetPosRequestMethod posMethod;
       
   333 		TLbsNetPosMethod selectedMethod; // only one to send to LBS
       
   334 		TInt err = responsePtr->GetPosMethod(posMethod);
       
   335 		TLbsNetPosCapabilities capabilities;
       
   336 		iMachine.Observer().Gateway().GetCapabilities(capabilities);
       
   337 		if ((KErrNone != err) || !iMachine.PosMethodSupported(posMethod, selectedMethod,capabilities))
       
   338 			{
       
   339 			//Cancel with error code posMethodMistmach
       
   340 			iMachine.CancelMachine(CSuplFsmSessionBase::ECancelSuplProt,CSuplFsmSessionBase::EReasonMethodMismatch);
       
   341 			SUPLLOG(ELogP1, "CSuplMoLrStateHandler::EntryActionsFromResponseReceivedStateL() End\n");
       
   342 			delete responsePtr;
       
   343 			return actionsTaken;
       
   344 			}
       
   345 
       
   346 		// send request to LBS
       
   347 		if (CSuplMolrFsmSession::ESuplMolrCellBased != (reinterpret_cast <CSuplMolrFsmSession&> (iMachine)).MachineType())
       
   348 			{
       
   349 			// Methods to be requested from LBS
       
   350 			posMethod.SetPosMethods(&selectedMethod, 1);
       
   351 			
       
   352 			// Quality to be requested from LBS. The SUPL RESPONSE constains no quality requirements.
       
   353 			//  Use the quality originally requested by LBS
       
   354 			TLbsNetPosRequestOptionsAssistance locReqAssistOptions;
       
   355 			TLbsNetPosRequestQuality quality;
       
   356 			iMachine.RetrieveLocationRequestOptions(locReqAssistOptions);
       
   357 			locReqAssistOptions.GetRequestQuality(quality);
       
   358 			
       
   359 			iMachine.Observer().LocationReq(iMachine.LbsSessionId(),	iMachine.LocReqType(),
       
   360 									quality, posMethod);
       
   361 			}
       
   362 
       
   363 		delete responsePtr;
       
   364 		actionsTaken = ETrue;
       
   365 		}
       
   366 	
       
   367 	SUPLLOG(ELogP1, "CSuplMoLrStateHandler::EntryActionsFromResponseReceivedStateL() End\n");
       
   368 	return actionsTaken;
       
   369 	}
       
   370 
       
   371 
       
   372 /** Actions on entering state EStatePosInitSent
       
   373 This method builds a SUPL POS INIT message and hands it over to 
       
   374 the Connection Manager for sending to the SUPL server.
       
   375 */
       
   376 TBool CSuplMoLrStateHandler::EntryActionsFromPosInitSentStateL()
       
   377 	{
       
   378 	SUPLLOG(ELogP1, "CSuplMoLrStateHandler::EntryActionsFromPosInitSentStateL() Begin\n");
       
   379 	TBool err = EFalse;
       
   380 	TLbsNetPosRequestQuality quality;
       
   381 	TLbsNetPosCapabilities capabilities;
       
   382 	TBool actionsTaken = EFalse;
       
   383 	
       
   384 	// There should be an assistance data request from LBS in the event store
       
   385 	//
       
   386 	if (iMachine.IsAssistanceDataRequestStored())
       
   387 		{
       
   388 		ASSERT(iMachine.IsSessionConnected()); // should not have transitioned into this state without a connection
       
   389 
       
   390 		// Create the SUPL POS INIT Message
       
   391 		CSuplPosInit* suplPosInit = CSuplPosInit::NewL();
       
   392 	 	CleanupStack::PushL(suplPosInit);
       
   393 	 	
       
   394 	 	// Set the Location Id in the message
       
   395 		CSuplLocationId* locationId;
       
   396 		if (BuildLocationIdL(locationId))
       
   397 			{
       
   398 			CleanupStack::PushL(locationId);
       
   399 	 	
       
   400 	 		suplPosInit->SetLocationId(*locationId);
       
   401 			CleanupStack::PopAndDestroy(locationId);
       
   402 	 	
       
   403 			// Set Capabilities in the message
       
   404 			BuildCapabilitiesL(capabilities,quality);
       
   405 			User::LeaveIfError(suplPosInit->SetCapabilities(capabilities));
       
   406 			
       
   407 			// Set assistance data request in the message if any data 
       
   408 			// is actually required
       
   409 			TLbsAsistanceDataGroup assitDataReqMask;
       
   410 			TBool assitDataReqPresent = iMachine.RetrieveAssistanceDataRequest(assitDataReqMask);
       
   411 			if (assitDataReqMask != 0)
       
   412 				{
       
   413 				User::LeaveIfError(suplPosInit->SetRequestedAssistanceData(assitDataReqMask));
       
   414 				}
       
   415 			else
       
   416 				{
       
   417 				// No need to set assistance data request parameter
       
   418 				// in SUPL POS INIT when request is empty.
       
   419 				// (intentionally no action taken here)
       
   420 				}
       
   421 
       
   422 			// Set in message header the stored session id
       
   423 			CSuplSessionId* msgId = iMachine.MessageSessionId();
       
   424 			User::LeaveIfError(suplPosInit->SetSessionId(*msgId));
       
   425 	
       
   426 			CleanupStack::Pop(suplPosInit);
       
   427 
       
   428 			// Ask the Connection Manager to send the SUPL POS INIT message
       
   429 			iMachine.Observer().ConnectionManager().SendMessage(suplPosInit, iMachine.SessionId().SessionNum());
       
   430 			
       
   431 			// Start the timer that oversees the arrival of SUPL POS
       
   432 			iMachine.StartSuplPosTimer();
       
   433 			
       
   434 			actionsTaken = ETrue;
       
   435 			}
       
   436 		else
       
   437 			{
       
   438 			// Failed to build Location Id
       
   439 			err = ETrue;
       
   440 			CleanupStack::PopAndDestroy(suplPosInit);
       
   441 			}
       
   442 		}
       
   443 	else
       
   444 		{
       
   445 		// An unexpected event must have happened (e.g. SUPL Message received)
       
   446 		// that triggered the transition to this state.
       
   447 		err = ETrue;
       
   448 		}
       
   449 		
       
   450 	if (err)
       
   451 	{
       
   452 	iMachine.CancelMachine(CSuplFsmSessionBase::ECancelSuplProt, CSuplFsmSessionBase::EReasonNone);			
       
   453 	}
       
   454 	
       
   455 	SUPLLOG(ELogP1, "CSuplMoLrStateHandler::EntryActionsFromPosInitSentStateL() End\n");
       
   456 	return actionsTaken;
       
   457 	}
       
   458 
       
   459 /**
       
   460 Utility method that obtains the capabilities in the stored location request options
       
   461 and adds to them the preferred positioning method also stored in the location request
       
   462 option
       
   463 */
       
   464 TBool CSuplMoLrStateHandler::BuildCapabilitiesL(TLbsNetPosCapabilities& aCapabilities, TLbsNetPosRequestQuality& aQuality)
       
   465 {
       
   466 	SUPLLOG(ELogP1, "CSuplMoLrStateHandler::BuildCapabilitiesL() Begin\n");
       
   467 	TLbsNetPosRequestOptionsAssistance locReqAssistOptions;
       
   468 	TLbsNetPosMethod prefMethod;
       
   469 	TInt numMethods;
       
   470 	TInt index;
       
   471 	TBool ecidSupported = EFalse;
       
   472 	TInt additionalMethods = 0;
       
   473 
       
   474 	// The positioning method preferred by LBS was sent in the call to 
       
   475 	// RequestSelfLocation and was kept in the event store.
       
   476 	iMachine.Observer().Gateway().GetCapabilities(aCapabilities);
       
   477 	numMethods = aCapabilities.NumPosMethods();
       
   478 	iMachine.RetrieveLocationRequestOptions(locReqAssistOptions);
       
   479 	prefMethod.SetPosMethod(KLbsPositioningMeansGps, locReqAssistOptions.PosMode());
       
   480 	additionalMethods ++;
       
   481 	
       
   482 	// Check if E-CID is possible
       
   483 	// (currently this mean Timing Advance only)
       
   484 	if(iMachine.IsNetworkInfoAvailable())
       
   485 		{
       
   486 		RMobilePhone::TMobilePhoneNetworkInfoV1 networkInfo;
       
   487 		RMobilePhone::TMobilePhoneLocationAreaV1 locationArea;
       
   488 		iMachine.RetrieveStoredNetworkInfo(networkInfo, locationArea);	
       
   489 		if (RMobilePhone::ENetworkModeGsm == networkInfo.iMode)
       
   490 			{
       
   491 			RMobilePhone::TMobilePhoneCellInfoV9 cellInfo;
       
   492 			if(iMachine.RetrieveStoredCellInfo(cellInfo))
       
   493 				{
       
   494 				// Timing Advance not supported if negative
       
   495 				ecidSupported = (cellInfo.iTimingAdvance >= 0);
       
   496 				additionalMethods++;			
       
   497 				}
       
   498 			}
       
   499 		}
       
   500 
       
   501 	// The preferred method has to be added at the end of the array of methods in "capabilities"
       
   502 	// because that is where the ASN1 encoder expects it to be.
       
   503 	// If E-CID is supported and there is room for it in the array, it will also be added to the 
       
   504 	// array.
       
   505 	TLbsNetPosMethod* methods;
       
   506 	if  (numMethods + additionalMethods < KLbsMaxNetPosMethods)
       
   507 		{
       
   508 		TLbsNetPosMethod ecidMethod;
       
   509 		ecidMethod.SetPosMethod(KLbsPositioningMeansCell, TPositionModuleInfo::ETechnologyNetwork);
       
   510 		methods = new (ELeave) TLbsNetPosMethod[numMethods + additionalMethods];
       
   511 		
       
   512 		for (index =0; index < numMethods; index++)
       
   513 			{
       
   514 			aCapabilities.GetPosMethod(index, methods[index]);
       
   515 			}
       
   516 			
       
   517 		if (ecidSupported)
       
   518 			{
       
   519 			methods[numMethods] = ecidMethod;	
       
   520 			}
       
   521 			
       
   522 		// Add preferred method at the end
       
   523 		methods[numMethods + additionalMethods - 1] = prefMethod;
       
   524 		aCapabilities.SetPosMethods(methods, numMethods + additionalMethods);
       
   525 		}
       
   526 	else
       
   527 		{
       
   528 		// There is only additional room for 1 or 0 methods.
       
   529 		methods = new (ELeave) TLbsNetPosMethod[KLbsMaxNetPosMethods];
       
   530 
       
   531 		for (index =0; index < KLbsMaxNetPosMethods; index++)
       
   532 			{
       
   533 			aCapabilities.GetPosMethod(index, methods[index]);
       
   534 			}
       
   535 
       
   536 		// Set the preferred method at the end (even if it 
       
   537 		// overwrites current entry)
       
   538 		methods[KLbsMaxNetPosMethods-1] = prefMethod;
       
   539 		aCapabilities.SetPosMethods(methods, KLbsMaxNetPosMethods);	
       
   540 		}
       
   541 
       
   542 	delete[] methods;
       
   543 	locReqAssistOptions.GetRequestQuality(aQuality);
       
   544 	
       
   545 	SUPLLOG(ELogP1, "CSuplMoLrStateHandler::BuildCapabilitiesL() End\n");
       
   546 	return ETrue;
       
   547 }
       
   548