/**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the Qt Mobility Components. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Digia. For licensing terms and ** conditions see http://qt.digia.com/licensing. For further information ** use the contact form at http://qt.digia.com/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Digia gives you certain additional ** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include "symbian_lbsfacade_p.h" #include QTM_BEGIN_NAMESPACE CSelfManagingPsy::CSelfManagingPsy(TPositionModuleInfo* aPsy, CPsyContainer *aContainer, MPsyRequestCallback* aRequestCallback, TPositionInfoBase &aPos) : CActive(EPriorityNormal), iContainer(aContainer), iPositioner(NULL), iPsyModInfo(aPsy), iRequestCallback(aRequestCallback), iPosInfo(aPos), iClientRequestActive(EFalse), iPsyAvailabilityStatus(EFalse) { TBuf<20> psyName; iPsyModInfo->GetModuleName(psyName); QString qPsyName((QChar*)psyName.Ptr(), psyName.Length()); iPsyName = qPsyName; } void CSelfManagingPsy::ConstructL() { qDebug() << "CSelfManagingPsy::ConstructL " << iPsyName ; TPositionModuleInfo modInfo; //If there is any problem with mod ID, then no point in continuing User::LeaveIfError(iContainer->PosServer().GetModuleInfoById(iPsyModInfo->ModuleId(), modInfo)); iPsyAvailabilityStatus = modInfo.IsAvailable(); iContainer->RegisterPsyStatusListenerL(this, iPsyModInfo->ModuleId()); InitPositioner(); CActiveScheduler::Add(this); } CSelfManagingPsy::~CSelfManagingPsy() { qDebug() << "CSelfManagingPsy::~CSelfManagingPsy " << iPsyName; iContainer->DeRegisterPsyStatusListener(this); iPositioner->Close(); delete iPositioner; iPositioner = NULL; } void CSelfManagingPsy::Cancel() { qDebug() << "CSelfManagingPsy::Cancel " << iPsyName; iClientRequestActive = EFalse; CActive::Cancel(); } TPositionModuleInfo* CSelfManagingPsy::GetModInfo() { return iPsyModInfo; } void CSelfManagingPsy::DoCancel() { qDebug() << "CSelfManagingPsy::DoCancel " << iPsyName; if (iPositioner) iPositioner->CancelRequest(EPositionerNotifyPositionUpdate); iClientRequestActive = EFalse; } void CSelfManagingPsy::HandlePositionCallback(TRequestStatus &aStatus) { switch (aStatus.Int()) { case KErrNone: qDebug() << "CSelfManagingPsy::HandlePositionCallback - Good fix " << iPsyName ; iRequestCallback->LocationUpdate(iPosInfo, this); break; default: qDebug() << "CSelfManagingPsy::HandlePositionCallback - ERROR " << iPsyName << " Err=" << iStatus.Int() ; iRequestCallback->RequestTimedOut(this); break; } } void CSelfManagingPsy::NotifyPsyStatusChange(TBool aAvailability) { qDebug() << "CSelfManagingPsy::NotifyPsyStatusChange " << iPsyName << " availability=" << aAvailability << " iClientRequestActive=" << iClientRequestActive << " iPositioner " << iPositioner ; iPsyAvailabilityStatus = aAvailability; if (iPsyAvailabilityStatus && iClientRequestActive) { if (!iPositioner) { if (!InitPositioner()) return; } CSelfManagingPsy::IssueRequest(iUpdInterval, iTimeout); } } TBool CSelfManagingPsy::InitPositioner() { qDebug() << "CSelfManagingPsy::InitPositioner " << iPsyName ; if (iPositioner) { qDebug() << "CSelfManagingPsy::InitPositioner ALREADY INTITIALIZED " << iPsyName ; return ETrue; } TRAPD(ret, iPositioner = new(ELeave) RPositioner()); if (ret != KErrNone) { qDebug() << "CSelfManagingPsy::InitPositioner create positioner failed " << iPsyName ; return EFalse;//Nothing can be done } TInt err = iPositioner->Open(iContainer->PosServer(), iPsyModInfo->ModuleId()); if (err != KErrNone) { delete iPositioner; iPositioner = NULL; return EFalse; //Nothing can be done } iPositioner->SetRequestor(CRequestor::ERequestorService, CRequestor::EFormatApplication, _L("QTmobility_Location")); qDebug() << "CSelfManagingPsy::InitPositioner SUCCESS " << iPsyName ; return ETrue; } void CSelfManagingPsy::IssueRequest(TTimeIntervalMicroSeconds aUpdInterval, TTimeIntervalMicroSeconds aTimeOut) { qDebug() << "CSelfManagingPsy::IssueRequest " << iPsyName ; if (IsActive()) Cancel(); TPositionQuality quality; iPsyModInfo->GetPositionQuality(quality); if (aUpdInterval < quality.TimeToNextFix()) aUpdInterval = quality.TimeToNextFix(); if (aTimeOut < quality.TimeToFirstFix()) aTimeOut = quality.TimeToFirstFix(); iUpdInterval = aUpdInterval; iTimeout = aTimeOut; if (!iPositioner) { qDebug() << "CSelfManagingPsy::IssueRequest " << iPsyName << " POSITIONER NOT AVBL"; return; } if (!iPsyAvailabilityStatus) { //PSY is not avbl so no point calling NotifyPositionUpdate //If the PSY becomes available, then NotifyPositionUpdate //will be called from NotifyPsyStatusChange qDebug() << "CSelfManagingPsy::IssueRequest " << iPsyName << " NOT AVBL"; return; } TPositionUpdateOptions updateOptions(iUpdInterval, iTimeout); iPositioner->SetUpdateOptions(updateOptions); iPositioner->NotifyPositionUpdate(iPosInfo, iStatus); SetActive(); } void CSelfManagingPsy::RequestPositionAgain() { qDebug() << "CSelfManagingPsy::RequestPositionAgain" << iPsyName ; if (iPsyAvailabilityStatus) { iPositioner->NotifyPositionUpdate(iPosInfo, iStatus); SetActive(); } } void CSelfManagingPsy::CancelPositionRequest() { qDebug() << "CSelfManagingPsy::CancelPositionRequest" << iPsyName; iClientRequestActive = EFalse; if (iPositioner) iPositioner->CancelRequest(EPositionerNotifyPositionUpdate); } TInt CSelfManagingPsy::RunError() { qDebug() << "CSelfManagingPsy::RunError" << iPsyName; //IGNORE return KErrNone; } CPsyContainer* CPsyContainer::NewL() { CPsyContainer *container = new(ELeave) CPsyContainer; TRAPD(err, container->ConstructL()); if (err == KErrNone) return container; else { delete container; return NULL; } } CPsyContainer::~CPsyContainer() { for (int i = 0; i < iAllPsys.Count(); i++) delete iAllPsys[i]; iAllPsys.Close(); for (int j = 0; j < iPsyStatusListeners.Count(); j++) delete iPsyStatusListeners[j]; iPsyStatusListeners.Close(); delete iPsyModules; iPosServer.Close(); } CPsyContainer::CPsyContainer() : iNWCallback(NULL), iGPSCallback(NULL), iPsyModules(NULL) {} void CPsyContainer::ConstructL() { User::LeaveIfError(iPosServer.Connect()); //Get all modules and store them InitAllPsysL(); iPsyModules = CPosModules::OpenL(); iPsyModules->SetObserverL(*this); } void CPsyContainer::RegisterPsyStatusListenerL(MPsyStatusChangeCallback *aCallBack, TPositionModuleId aModId) { TPsyStatusListener *ptr = new(ELeave) TPsyStatusListener(); ptr->iCallBack = aCallBack; ptr->iModId = aModId; iPsyStatusListeners.Insert(ptr, iPsyStatusListeners.Count()); } void CPsyContainer::DeRegisterPsyStatusListener(MPsyStatusChangeCallback *aCallBack) { for (int i = 0; i < iPsyStatusListeners.Count(); i++) { if (iPsyStatusListeners[i]->iCallBack == aCallBack) { delete iPsyStatusListeners[i]; iPsyStatusListeners.Remove(i); break; } } } void CPsyContainer::HandleSettingsChangeL(TPosModulesEvent aEvent) { TPositionModuleId modId = aEvent.iModuleId; if (aEvent.iType & EPosModulesEventModuleRemoved) { //1) Update the module info list TPositionModuleInfo *modInfo = NULL; for (int i = 0; i < iAllPsys.Count(); i++) { if (modId == iAllPsys[i]->ModuleId()); { modInfo = iAllPsys[i]; iAllPsys.Remove(i); break; } } //2) Notify listeners if (PsyUtils::IsSatellitePsy(modInfo)) if (iGPSCallback) iGPSCallback->PsyUninstalled(modId); else /*if(IsNWPsy)*/ if (iNWCallback) iNWCallback->PsyUninstalled(modId); delete modInfo; return; } if (aEvent.iType & EPosModulesEventModuleInstalled) { TPositionModuleInfo *modInfo = new TPositionModuleInfo ; if (!modInfo) return;//nothing can be done //If there is any problem with mod ID, then no point in continuing if (KErrNone != iPosServer.GetModuleInfoById(modId, *modInfo)) { delete modInfo; return; } iAllPsys.Insert(modInfo, iAllPsys.Count()); if (PsyUtils::IsSatellitePsy(modInfo)) iGPSCallback->PsyInstalled(modInfo); else /*if(IsNWPsy)*/ iNWCallback->PsyInstalled(modInfo); return; } if (aEvent.iType & EPosModulesEventAvailabilityChanged) { TPositionModuleInfo modInfo; if (KErrNone == iPosServer.GetModuleInfoById(modId, modInfo)) { for (int i = 0; i < iPsyStatusListeners.Count(); i++) { if (iPsyStatusListeners[i]->iModId == modId) iPsyStatusListeners[i]->iCallBack->NotifyPsyStatusChange(modInfo.IsAvailable()); //There can be multiple listeners (tracking, single shot) so do not break here } for (int j = 0; j < iAllPsys.Count(); j++) { if (modId == iAllPsys[j]->ModuleId()); { iAllPsys[j]->SetIsAvailable(modInfo.IsAvailable()); break; } } } } } void CPsyContainer::InitAllPsysL() { TUint totalModules = 0; iPosServer.GetNumModules(totalModules); TInt insertCount = 0 ; for (TInt i = 0 ; i < totalModules ; i++) { TPositionModuleInfo *modInfo = new(ELeave) TPositionModuleInfo; if (KErrNone == iPosServer.GetModuleInfoByIndex(i, *modInfo)) iAllPsys.Insert(modInfo, insertCount++); else delete modInfo; } qDebug() << "CPsyContainer::InitAllPsysL - End Inserted " << insertCount << " psys" ; } void CPsyContainer::GetAvailablePsys(TBool aNWTye, RArray &aPsys) { TUint insertCount = 0; for (int i = 0; i < iAllPsys.Count(); i++) { TPositionModuleInfo::TTechnologyType ttype = iAllPsys[i]->TechnologyType(); TPositionModuleInfo::TCapabilities capabilities = iAllPsys[i]->Capabilities(); if (aNWTye) { if ((ttype & TPositionModuleInfo::ETechnologyNetwork) && (!(capabilities & TPositionModuleInfo::ECapabilitySatellite))) { aPsys.Insert(iAllPsys[i], insertCount++); //break;//TODO: Hack for ignoring SUPL PSY } } else { if (capabilities & TPositionModuleInfo::ECapabilitySatellite) { aPsys.Insert(iAllPsys[i], insertCount++); } } } qDebug() << "CPsyContainer::GetAvailablePsys - End insertCount=" << insertCount << " aNWTye=" << aNWTye ; } void CPsyContainer::SetNonSatellitePsyCountChangeCallback(MPsyCountChangeCallback *aNWCallback) { qDebug() << "CPsyContainer::SetNWPSYChangeCallback" ; iNWCallback = aNWCallback; } void CPsyContainer::SetSatellitePsyCountChangeCallback(MPsyCountChangeCallback *aGPSCallback) { qDebug() << "CPsyContainer::SetGPSPSYChangeCallback" ; iGPSCallback = aGPSCallback; } RPositionServer& CPsyContainer::PosServer() { return iPosServer; } QGeoPositionInfo CPsyContainer::lastKnownPosition(bool aFromSatellitePositioningMethodsOnly) { QGeoPositionInfo posUpdate; TPosition pos; TInt error = KErrNone; RPositioner lastKnownpositioner; TRequestStatus status; error = lastKnownpositioner.Open(PosServer()); //request for lastknown position update and wait for the request to complete if (error == KErrNone) { TPositionInfo posInfo; lastKnownpositioner.SetRequestor(CRequestor::ERequestorService , CRequestor::EFormatApplication, _L("QTmobility_Location")); lastKnownpositioner.GetLastKnownPosition(posInfo, status); //Sub-optimal implementation inherited from the previous implementation //Since this is a 'once in a while' usecase, this should be ok //An optimal implementation will be much more complex and will need changes //in the symbian locaiton stack User::WaitForRequest(status); error = status.Int(); lastKnownpositioner.Close(); if ((error == KErrNone) || (error == KPositionPartialUpdate)) { TPositionModuleInfo modInfo; iPosServer.GetModuleInfoById(posInfo.ModuleId(), modInfo); if (!aFromSatellitePositioningMethodsOnly || (aFromSatellitePositioningMethodsOnly && (modInfo.Capabilities() & TPositionModuleInfo::ECapabilitySatellite))) { PsyUtils::TPositionInfo2QGeoPositionInfo(posInfo, posUpdate); } } } return posUpdate; } void PsyUtils::TPositionInfo2QGeoPositionInfo(TPositionInfoBase &aPosInfoBase, QGeoPositionInfo& aQPosInfo) { if (aPosInfoBase.PositionClassType() & EPositionInfoClass || aPosInfoBase.PositionClassType() & EPositionSatelliteInfoClass) { TPositionInfo *posInfo = static_cast(&aPosInfoBase); TPosition pos; QGeoCoordinate coord; posInfo->GetPosition(pos); coord.setLatitude(pos.Latitude()); coord.setLongitude(pos.Longitude()); coord.setAltitude(pos.Altitude()); //store the QGeoCoordinate values aQPosInfo.setCoordinate(coord); TDateTime datetime = pos.Time().DateTime(); QDateTime dt(QDate(datetime.Year() , datetime.Month() + 1, datetime.Day() + 1), QTime(datetime.Hour() , datetime.Minute(), datetime.Second(), datetime.MicroSecond() / 1000), Qt::UTC); //store the time stamp aQPosInfo.setTimestamp(dt); //store the horizontal accuracy aQPosInfo.setAttribute(QGeoPositionInfo::HorizontalAccuracy, pos.HorizontalAccuracy()); //store the vertical accuracy aQPosInfo.setAttribute(QGeoPositionInfo::VerticalAccuracy, pos.VerticalAccuracy()); if (aPosInfoBase.PositionClassType() & EPositionSatelliteInfoClass) { TCourse course; TPositionSatelliteInfo *satInfo = static_cast(&aPosInfoBase); satInfo->GetCourse(course); aQPosInfo.setAttribute(QGeoPositionInfo::Direction, course.Heading()); aQPosInfo.setAttribute(QGeoPositionInfo::GroundSpeed, course.Speed()); aQPosInfo.setAttribute(QGeoPositionInfo::VerticalSpeed, course.VerticalSpeed()); } } if (aPosInfoBase.PositionClassType() & EPositionGenericInfoClass) { HPositionGenericInfo *genInfo = static_cast(&aPosInfoBase); float val; //check for the horizontal speed if (genInfo->IsFieldAvailable(EPositionFieldHorizontalSpeed)) { genInfo->GetValue(EPositionFieldHorizontalSpeed, val); aQPosInfo.setAttribute(QGeoPositionInfo::GroundSpeed, val); } //check for the vertcal speed if (genInfo->IsFieldAvailable(EPositionFieldVerticalSpeed)) { genInfo->GetValue(EPositionFieldVerticalSpeed, val); aQPosInfo.setAttribute(QGeoPositionInfo::VerticalSpeed, val); } //check for the magnetic variation if (genInfo->IsFieldAvailable(EPositionFieldMagneticCourseError)) { genInfo->GetValue(EPositionFieldMagneticCourseError, val); aQPosInfo.setAttribute(QGeoPositionInfo::MagneticVariation, val); } //check for the heading if (genInfo->IsFieldAvailable(EPositionFieldHeading)) { genInfo->GetValue(EPositionFieldHeading, val); aQPosInfo.setAttribute(QGeoPositionInfo::Direction, val); } } } TBool PsyUtils::IsSatellitePsy(TPositionModuleInfo *aModInfo) { if (!aModInfo) return EFalse; TPositionModuleInfo::TTechnologyType ttype = aModInfo->TechnologyType(); TPositionModuleInfo::TCapabilities capabilities = aModInfo->Capabilities(); if (capabilities & TPositionModuleInfo::ECapabilitySatellite) return ETrue; return EFalse; } QTM_END_NAMESPACE