// // Open Service Platform // Copyright (c) 2012 Samsung Electronics Co., Ltd. // // Licensed under the Apache License, Version 2.0 (the License); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // /** * @file FLoc_LocationProviderImpl.cpp * @brief This is the implementation file for the %_LocationProviderImpl class. * * This implementation file contains the definitions of the %_LocationProviderImpl class methods. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "FLoc_LocationImpl.h" #include "FLoc_LocationManager.h" #include "FLoc_LocationMonitor.h" #include "FLoc_LocationProviderImpl.h" #include "FLoc_MathUtils.h" #include "FLoc_Types.h" using namespace std; using namespace Tizen::App; using namespace Tizen::Base; using namespace Tizen::Base::Collection; using namespace Tizen::Base::Runtime; using namespace Tizen::Base::Utility; using namespace Tizen::System; namespace Tizen { namespace Locations { _LocationProviderImpl::_LocationProviderImpl(void) : Tizen::Base::Runtime::_Event() , __lastLocationAccuracy(LOC_ACCURACY_INVALID) , __pLocationListener(null) , __pLocationManager(null) { } _LocationProviderImpl::~_LocationProviderImpl(void) { UiApp* pAppInstance = Tizen::App::UiApp::GetInstance(); if (pAppInstance) { _AppManagerImpl* pAppManager = _AppManagerImpl::GetInstance(); if (pAppManager) { pAppManager->RemoveActiveAppEventListener(*this); } } StopLocationUpdates(); RemoveAllMonitoringRegions(); } result _LocationProviderImpl::Construct(const LocationCriteria& criteria, ILocationProviderListener& listener) { _LocationManager* pLocationManager = _LocationManager::GetInstance(); SysTryReturn(NID_LOC, pLocationManager != null, GetLastResult(), GetLastResult(), "[%s] Failed to get the location manager instance.", GetErrorMessage(GetLastResult())); std::unique_ptr< Tizen::Base::Collection::ArrayList, AllElementsDeleter > pRegionList(new (std::nothrow) ArrayList(SingleObjectDeleter)); SysTryReturn(NID_LOC, pRegionList != null, E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY)); result r = pRegionList->Construct(); SysTryReturn(NID_LOC, r == E_SUCCESS, r, r, "[%s] Failed to construct the list. Propagating.", GetErrorMessage(r)); std::unique_ptr< Tizen::Base::Runtime::Timer > pTimer(new (std::nothrow) Timer()); SysTryReturn(NID_LOC, pTimer != null, E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY)); r = pTimer->Construct(*this); SysTryReturn(NID_LOC, r == E_SUCCESS, r, r, "[%s] Failed to construct the timer. Propagating.", GetErrorMessage(r)); UiApp* pAppInstance = Tizen::App::UiApp::GetInstance(); if (pAppInstance != null) { _AppManagerImpl* pAppManager = _AppManagerImpl::GetInstance(); SysTryReturn(NID_LOC, pAppManager, E_SYSTEM, E_SYSTEM, "[E_SYSTEM] System error occured."); r = pAppManager->AddActiveAppEventListener(*this); SysTryReturn(NID_LOC, r == E_SUCCESS, r, r, "[%s] Error occured during adding the event listener to app manager. Propagating.", GetErrorMessage(r)); } std::unique_ptr< Tizen::Locations::Location > pLastLocation(_LocationImpl::GetLocationInstanceN()); SysTryReturn(NID_LOC, pLastLocation != null, E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY)); std::unique_ptr< Tizen::Locations::Location > pLastRegionLocation(_LocationImpl::GetLocationInstanceN()); SysTryReturn(NID_LOC, pLastRegionLocation != null, E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY)); _Event::Initialize(); _Event::AddListener(*this); __regionMonitor.pRegionList = std::move(pRegionList); __regionMonitor.pTimer = std::move(pTimer); __regionMonitor.pLocation = std::move(pLastRegionLocation); __locationUpdater.pLocation = std::move(pLastLocation); __criteria = criteria; __pLocationListener = &listener; __pLocationManager = pLocationManager; SysLog(NID_LOC, "Location provider constructed with the accuracy (%x).", criteria.GetAccuracy()); return E_SUCCESS; } result _LocationProviderImpl::StartLocationUpdatesByInterval(int interval) { bool userConsent = GetUserPrivilege(); SysTryReturn(NID_LOC, userConsent, E_USER_NOT_CONSENTED, E_USER_NOT_CONSENTED, "[E_USER_NOT_CONSENTED] The user has disabled the required settings."); SysTryReturn(NID_LOC, interval >= 1, E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] The interval(%d) should be greater than or equal to 1", interval); if (__locationUpdater.type == _LOCATION_UPDATE_TYPE_INTERVAL && __locationUpdater.updateInterval == interval) { return E_SUCCESS; } const double INVALID_DISTANCE_THRESHOLD = 0.0; return StartLocationUpdates(_LOCATION_UPDATE_TYPE_INTERVAL, interval, INVALID_DISTANCE_THRESHOLD); } result _LocationProviderImpl::StartLocationUpdatesByDistance(double distance) { bool userConsent = GetUserPrivilege(); SysTryReturn(NID_LOC, userConsent, E_USER_NOT_CONSENTED, E_USER_NOT_CONSENTED, "[E_USER_NOT_CONSENTED] The user has disabled the required settings."); SysTryReturn(NID_LOC, distance > 0.0, E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] The distance(%lf) should be greater than 0.0", distance); SysTryReturn(NID_LOC, Double::IsNaN(distance) == false, E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] The distance is NaN."); if (__locationUpdater.type == _LOCATION_UPDATE_TYPE_DISTANCE && (Double::Compare(__locationUpdater.distanceThreshold, distance) == 0)) { return E_SUCCESS; } const int INVALID_INTERVAL = 0; return StartLocationUpdates(_LOCATION_UPDATE_TYPE_DISTANCE, INVALID_INTERVAL, distance); } result _LocationProviderImpl::StopLocationUpdates(void) { SysLog(NID_LOC, "Stopping the location updates for the request ID (%ld)", __locationUpdater.reqId); SysTryReturn(NID_LOC, __locationUpdater.type != _LOCATION_UPDATE_TYPE_NONE, E_INVALID_OPERATION, E_INVALID_OPERATION, "[E_INVALID_OPERATION] Location update has not been requested."); result r = __pLocationManager->StopLocationUpdates(__locationUpdater.reqId); ResetLocationUpdates(); return r; } void _LocationProviderImpl::KeepLocationUpdateAwake(bool enable) { if (__locationUpdater.awakeEnabled == enable) { return; } __locationUpdater.awakeEnabled = enable; UiApp* appInstance = Tizen::App::UiApp::GetInstance(); if (appInstance == null) // This is service APP. So should be handled now. { SysLog(NID_LOC, "Handling the request awake mode(%d) for the service application.", enable); if (enable == true) { if (__locationUpdater.type != _LOCATION_UPDATE_TYPE_NONE && __locationUpdater.status == LOC_SVC_STATUS_PAUSED) { SysLog(NID_LOC, "Requesting to start the location updates as the update type is (%x)", __locationUpdater.type); __locationUpdater.status = LOC_SVC_STATUS_NOT_FIXED; __pLocationManager->StartLocationUpdates(__criteria.GetAccuracy(), __locationUpdater.updateInterval, this, __locationUpdater.reqId); NotifyServiceStatus(_LOC_PRV_EVENT_SEND_LOC_SVC_CB, __locationUpdater.status); } } else { if (__locationUpdater.type != _LOCATION_UPDATE_TYPE_NONE && (__locationUpdater.status == LOC_SVC_STATUS_RUNNING || __locationUpdater.status == LOC_SVC_STATUS_NOT_FIXED)) { SysLog(NID_LOC, "Requesting to stop the location updates as the update type is (%x)", __locationUpdater.type); __locationUpdater.status = LOC_SVC_STATUS_PAUSED; __pLocationManager->StopLocationUpdates(__locationUpdater.reqId); NotifyServiceStatus(_LOC_PRV_EVENT_SEND_LOC_SVC_CB, __locationUpdater.status); } } } } result _LocationProviderImpl::AddMonitoringRegion(const Coordinates& regionCenter, double radius, RegionId& regionId) { bool userConsent = GetUserPrivilege(); SysTryReturn(NID_LOC, userConsent, E_USER_NOT_CONSENTED, E_USER_NOT_CONSENTED, "[E_USER_NOT_CONSENTED] The user has disabled the required settings."); SysTryReturn(NID_LOC, radius >= 50.0 && radius <= 100000.00, E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] The radius is not within the specified limits."); SysTryReturn(NID_LOC, (!Double::IsNaN(radius) && !Double::IsNaN(regionCenter.GetLatitude()) && !Double::IsNaN(regionCenter.GetLongitude())), E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] One of the value is NaN."); SysSecureLog(NID_LOC, "Requested to add the monitoring region with center (Latitude: %lf, Longitude %lf) and radius (%lf).", regionCenter.GetLatitude(), regionCenter.GetLongitude(), radius); static int nextRegionId = 0; std::unique_ptr< _RegionInfo > pRegionInfo(new (std::nothrow) _RegionInfo(regionCenter, radius, nextRegionId)); SysTryReturn(NID_LOC, pRegionInfo != null, E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY)); result r = __regionMonitor.pRegionList->Add(*pRegionInfo.get()); SysTryReturn(NID_LOC, r == E_SUCCESS, r, r, "[%s] Failed to add the Region info into the list. Propogated.", GetErrorMessage(r)); pRegionInfo.release(); regionId = nextRegionId; nextRegionId++; if (__regionMonitor.status != LOC_SVC_STATUS_IDLE) { return E_SUCCESS; } r = ActivateRegionMonitoring(true); SysTryCatch(NID_LOC, r == E_SUCCESS, , r, "[%s] Failed to start the region monitoring. Propogating.", GetErrorMessage(r)); __regionMonitor.status = LOC_SVC_STATUS_NOT_FIXED; NotifyServiceStatus(_LOC_PRV_EVENT_SEND_MONITOR_SVC_CB, __regionMonitor.status); return E_SUCCESS; CATCH: __regionMonitor.pRegionList->RemoveAt(0); return r; } result _LocationProviderImpl::RemoveMonitoringRegion(RegionId regionId) { int count = __regionMonitor.pRegionList->GetCount(); bool isIdValid = false; SysLog(NID_LOC, "Total regions currently monitored is (%d).", count); for (int i = 0; i < count; i++) { _RegionInfo* pRegionInfo = static_cast< _RegionInfo* >(__regionMonitor.pRegionList->GetAt(i)); if (regionId == pRegionInfo->GetRegionId()) { __regionMonitor.pRegionList->RemoveAt(i); isIdValid = true; break; } } SysTryReturn(NID_LOC, isIdValid == true, E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] The region ID is invalid."); if (__regionMonitor.pRegionList->GetCount() == 0) { __regionMonitor.status = LOC_SVC_STATUS_IDLE; if (__locationUpdater.status == LOC_SVC_STATUS_IDLE) // As we are using the same variable for both region monitoring and location updates, this set is required here. { __lastLocationAccuracy = LOC_ACCURACY_INVALID; } StopRegionMonitoring(); } return E_SUCCESS; } void _LocationProviderImpl::RemoveAllMonitoringRegions(void) { __regionMonitor.pRegionList->RemoveAll(true); if (__regionMonitor.status != LOC_SVC_STATUS_IDLE) { __regionMonitor.status = LOC_SVC_STATUS_IDLE; if (__locationUpdater.status == LOC_SVC_STATUS_IDLE) // As we are using the same variable for both region monitoring and location updates, this set is required here. { __lastLocationAccuracy = LOC_ACCURACY_INVALID; } StopRegionMonitoring(); } return; } LocationServiceStatus _LocationProviderImpl::GetLocationUpdateStatus(void) const { return __locationUpdater.status; } LocationServiceStatus _LocationProviderImpl::GetRegionMonitoringStatus(void) const { return __regionMonitor.status; } LocationAccuracy _LocationProviderImpl::GetCurrentAccuracy(void) const { return __lastLocationAccuracy; } Location _LocationProviderImpl::GetLocation(const LocationCriteria& criteria) { Location retLocation(_LocationImpl::GetLocationInstance()); bool userConsent = GetUserPrivilege(); SysTryReturn(NID_LOC, userConsent, retLocation, E_USER_NOT_CONSENTED, "[E_USER_NOT_CONSENTED] The user has disabled the required settings."); Location* pLocation = null; const int MAX_TIMEOUT = 30; result r = E_SUCCESS; _LocationManager* pLocationManager = null; SysLog(NID_LOC, "Requesting for single location with criteria (%x).", criteria.GetAccuracy()); std::unique_ptr< _LocationMonitor > pLocMonitor(new (std::nothrow) _LocationMonitor()); SysTryCatch(NID_LOC, pLocMonitor, , E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY)); r = pLocMonitor->Construct(MAX_TIMEOUT, criteria.GetAccuracy()); SysTryCatch(NID_LOC, r == E_SUCCESS, , r, "[%s] Failed to construct the Location Monitor.", GetErrorMessage(r)); pLocationManager = _LocationManager::GetInstance(); SysTryCatch(NID_LOC, pLocationManager, , r, "[%s] Failed to get the location manager instance.", GetErrorMessage(r)); r = pLocationManager->RegisterLocationMonitor(pLocMonitor.get()); SysTryCatch(NID_LOC, r == E_SUCCESS, , r, "[%s] Failed to register the location monitor.", GetErrorMessage(r)); r = pLocMonitor->Wait(); if (!IsFailed(r)) { pLocation = pLocMonitor->GetLocationN(); } if (pLocation) { retLocation = *pLocation; } else { SetLastResult(E_LOCATION_UNAVAILABLE); } delete pLocation; return retLocation; CATCH: return retLocation; } Location _LocationProviderImpl::GetLastKnownLocation(void) { Location retLocation(_LocationImpl::GetLocationInstance()); bool userConsent = GetUserPrivilege(); SysTryReturn(NID_LOC, userConsent, retLocation, E_USER_NOT_CONSENTED, "[E_USER_NOT_CONSENTED] The user has disabled the required settings."); _LocationManager* pLocationManager = _LocationManager::GetInstance(); SysTryReturn(NID_LOC, pLocationManager, retLocation, E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY)); retLocation = pLocationManager->GetLastKnownLocation(); if (!retLocation.IsValid()) { SetLastResult(E_LOCATION_UNAVAILABLE); } else { ClearLastResult(); } return retLocation; } // Private members void _LocationProviderImpl::OnLocationUpdated(RequestId reqId, const Tizen::Locations::Location& location) { SysLog(NID_LOC, "Location is updated from Location Manager for the request ID (%ld).", reqId); std::unique_ptr< Location > pLocation(new (std::nothrow) Location(location)); SysTryReturnVoidResult(NID_LOC, pLocation, E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY)); std::unique_ptr< _LocProviderEventArg > pLocProviderEventArg(new (std::nothrow) _LocProviderEventArg()); SysTryReturnVoidResult(NID_LOC, pLocProviderEventArg, E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY)); pLocProviderEventArg->SetEventType(_LOC_PRV_EVENT_SEND_LOC); pLocProviderEventArg->SetLocation(pLocation.get()); pLocProviderEventArg->SetRequestId(reqId); pLocation.release(); result r = _Event::FireAsync(*pLocProviderEventArg); SysTryReturnVoidResult(NID_LOC, r == E_SUCCESS, r, "[%s] Failed to fire the event.", GetErrorMessage(r)); pLocProviderEventArg.release(); return; } void _LocationProviderImpl::OnAlarmExpired(void) { SysLog(NID_LOC, "The call back of the Alarm expiry is called from location manager."); std::unique_ptr< _LocProviderEventArg > pLocProviderEventArg(new (std::nothrow) _LocProviderEventArg()); SysTryReturnVoidResult(NID_LOC, pLocProviderEventArg, E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY)); pLocProviderEventArg->SetEventType(_LOC_PRV_EVENT_SEND_ALARM_EXPIRY); result r = _Event::FireAsync(*pLocProviderEventArg); SysTryReturnVoidResult(NID_LOC, r == E_SUCCESS, r, "[%s] Failed to fire the event.", GetErrorMessage(r)); pLocProviderEventArg.release(); return; } void _LocationProviderImpl::OnLocationEventReceivedN(RequestId reqId, Tizen::Locations::Location& location) { SysLog(NID_LOC, "Location Event received."); bool isNew = false; LocationAccuracy currentAccuracy = LOC_ACCURACY_INVALID; LocationAccuracy lastLocAccuracy = __lastLocationAccuracy; long long lastLocationTime = 0; Location* pLocation = &location; _LocationImpl* pLocationImpl = _LocationImpl::GetInstance(*pLocation); if (reqId == __locationUpdater.reqId) { SysLog(NID_LOC, "The location is updated for Location request."); lastLocationTime = _LocationImpl::GetInstance(*__locationUpdater.pLocation.get())->GetTimestampInMs(); } else if (reqId == __regionMonitor.reqId) { SysLog(NID_LOC, "The location is updated for Region monitoring."); lastLocationTime = _LocationImpl::GetInstance(*__regionMonitor.pLocation.get())->GetTimestampInMs(); } long long timeDifference = pLocationImpl->GetTimestampInMs() - lastLocationTime; SysLog(NID_LOC, "Time difference between last location timestamp (%lld) and current location timestamp (%lld) is (%lld).", lastLocationTime, pLocationImpl->GetTimestampInMs(), timeDifference); if (timeDifference > 0) { isNew = true; currentAccuracy = __pLocationManager->GetAccuracyLevel(pLocation->GetHorizontalAccuracy()); } if (currentAccuracy != __lastLocationAccuracy) { SysLog(NID_LOC, "Notify the accuracy change."); __lastLocationAccuracy = currentAccuracy; __pLocationListener->OnAccuracyChanged(currentAccuracy); } if (reqId == __locationUpdater.reqId) { HandleLocationUpdate(location, isNew); } else if (reqId == __regionMonitor.reqId) { if (isNew) { bool gpsEnabled = false; _SettingInfoImpl::GetValue(L"http://tizen.org/setting/location.gps", gpsEnabled); SysLog(NID_LOC, "The GPS settings value is %d", gpsEnabled); __regionMonitor.speed = location.GetSpeed() * 0.2777778; if (currentAccuracy <= lastLocAccuracy || timeDifference > DEFAULT_THRESHOLD_LOC_VALIDITY_TIME_OUT) // Copy the location only if it is new and accuracy is better than before. { *__regionMonitor.pLocation = location; } if ((currentAccuracy != LOC_ACCURACY_INVALID && currentAccuracy <= __criteria.GetAccuracy()) || !gpsEnabled) { SysLog(NID_LOC, "Location criteria (accuracy: %ld) is met for handling region monitoring.", currentAccuracy); result r = __regionMonitor.pTimer->Cancel(); SysTryLog(NID_LOC, r == E_SUCCESS, "Failed to cancel the timer."); HandleRegionMonitoring(location, isNew); } else { SysLog(NID_LOC, "Location criteria (accuracy: %ld) is not met for handling region monitoring.", currentAccuracy); } } } delete pLocation; } void _LocationProviderImpl::OnLocationUpdateStatusChanged(Tizen::Locations::LocationServiceStatus locSvcStatus) { __pLocationListener->OnLocationUpdateStatusChanged(locSvcStatus); } void _LocationProviderImpl::OnRegionMonitoringStatusChanged(Tizen::Locations::LocationServiceStatus locSvcStatus) { __pLocationListener->OnRegionMonitoringStatusChanged(locSvcStatus); } void _LocationProviderImpl::OnAlarmExpiredEventReceived(void) { SysLog(NID_LOC, "Region Monitor Alarm expired event received."); result r = ActivateRegionMonitoring(true); SysTryReturnVoidResult(NID_LOC, r == E_SUCCESS, r, "[%s] Failed to start the region monitoring. Propogating.", GetErrorMessage(r)); } void _LocationProviderImpl::OnActiveAppChanged(const Tizen::App::AppId& appId) { Tizen::App::App* pApp = Tizen::App::App::GetInstance(); Tizen::App::AppId currentAppId = pApp->GetAppId(); SysLog(NID_LOC, "Active App ID is (%ls) and the current app Id is (%ls)", appId.GetPointer(), currentAppId.GetPointer()); if (currentAppId == appId) { SysLog(NID_LOC, "Application is active."); if (__locationUpdater.status == LOC_SVC_STATUS_PAUSED) { SysLog(NID_LOC, "Start the location updates as the location update status is PAUSED."); __pLocationManager->StartLocationUpdates(__criteria.GetAccuracy(), __locationUpdater.updateInterval, this, __locationUpdater.reqId); __locationUpdater.status = LOC_SVC_STATUS_NOT_FIXED; __pLocationListener->OnLocationUpdateStatusChanged(__locationUpdater.status); } } else { SysLog(NID_LOC, "Application is not active."); if (__locationUpdater.awakeEnabled == false && (__locationUpdater.status == LOC_SVC_STATUS_RUNNING || __locationUpdater.status == LOC_SVC_STATUS_NOT_FIXED)) { SysLog(NID_LOC, "Stop the location updates as application is not active with awake mode as (%d) and location update state as (%x).", __locationUpdater.awakeEnabled, __locationUpdater.status); __pLocationManager->StopLocationUpdates(__locationUpdater.reqId); __locationUpdater.status = LOC_SVC_STATUS_PAUSED; __pLocationListener->OnLocationUpdateStatusChanged(__locationUpdater.status); } } } void _LocationProviderImpl::OnTimerExpired(Timer& timer) { SysLog(NID_LOC, "Region Monitor timer expired due to unavailability of location information."); __pLocationManager->StopLocationUpdates(__regionMonitor.reqId); HandleRegionMonitoring(*__regionMonitor.pLocation, __regionMonitor.pLocation->IsValid()); } result _LocationProviderImpl::StartLocationUpdates(LocationUpdateType updateType, int interval, double distance) { result r = E_SUCCESS; bool startUpdate = true; if (updateType == _LOCATION_UPDATE_TYPE_INTERVAL) { __locationUpdater.updateInterval = interval; } else if (updateType == _LOCATION_UPDATE_TYPE_DISTANCE) { __locationUpdater.updateInterval = DEFAULT_DISTANCE_CHECKING_INTERVAL; __locationUpdater.distanceThreshold = distance; } if (!__locationUpdater.awakeEnabled) { UiApp* pAppInstance = Tizen::App::UiApp::GetInstance(); if (pAppInstance == null) { startUpdate = false; } else { AppUiState appUiState = pAppInstance->GetAppUiState(); if (appUiState == APP_UI_STATE_BACKGROUND) { SysLog(NID_LOC, "App is background."); startUpdate = false; } } } if (startUpdate) { if (__locationUpdater.type != _LOCATION_UPDATE_TYPE_NONE) { SysLog(NID_LOC, "Update session already running. Updating the interval to %d seconds", __locationUpdater.updateInterval); r = __pLocationManager->ChangeUpdateInterval(__locationUpdater.reqId, __locationUpdater.updateInterval); SysTryCatch(NID_LOC, r == E_SUCCESS, , r, "[%s] Failed to update the request interval. Propagating.", GetErrorMessage(r)); __locationUpdater.type = updateType; return E_SUCCESS; } else { r = __pLocationManager->StartLocationUpdates(__criteria.GetAccuracy(), __locationUpdater.updateInterval, this, __locationUpdater.reqId); SysTryCatch(NID_LOC, r == E_SUCCESS, , r, "[%s] Failed to start the Native location updates. Propagating.", GetErrorMessage(r)); __locationUpdater.status = LOC_SVC_STATUS_NOT_FIXED; } } else { __locationUpdater.status = LOC_SVC_STATUS_PAUSED; } __locationUpdater.type = updateType; SysLog(NID_LOC, "Update type is (%x). The request Id is (%ld) and the update status is (%x).", __locationUpdater.type, __locationUpdater.reqId, __locationUpdater.status); NotifyServiceStatus(_LOC_PRV_EVENT_SEND_LOC_SVC_CB, __locationUpdater.status); return E_SUCCESS; CATCH: __locationUpdater.type = _LOCATION_UPDATE_TYPE_NONE; return r; } bool _LocationProviderImpl::CheckDistanceThreshold(const Location& oldPosition, const Location& newPosition) { double displacement = 0.0; const Coordinates coordOld = oldPosition.GetCoordinates(); const Coordinates coordNew = newPosition.GetCoordinates(); if (__locationUpdater.firstLocationUpdate) { SysLog(NID_LOC, "First location update. So send true."); __locationUpdater.firstLocationUpdate = false; return true; } displacement = coordOld.GetDistanceTo(coordNew); SysLog(NID_LOC, "Displacement is (%lf)", displacement); return ((displacement > __locationUpdater.distanceThreshold) ? true : false); } void _LocationProviderImpl::ResetLocationUpdates(void) { __locationUpdater.firstLocationUpdate = true; __locationUpdater.reqId = -1; __lastLocationAccuracy = LOC_ACCURACY_INVALID; __locationUpdater.type = _LOCATION_UPDATE_TYPE_NONE; __locationUpdater.status = LOC_SVC_STATUS_IDLE; __locationUpdater.updateInterval = 0; __locationUpdater.distanceThreshold = 0.0; } void _LocationProviderImpl::FireImpl(Tizen::Base::Runtime::IEventListener& listener, const Tizen::Base::Runtime::IEventArg& arg) { _ILocProviderEventListener* pLocProviderEventListener = dynamic_cast< _ILocProviderEventListener* >(&listener); SysTryReturnVoidResult(NID_LOC, pLocProviderEventListener, E_SYSTEM, "[E_INVALID_ARG] The listener is null."); IEventArg* pArg = const_cast< IEventArg* >(&arg); _LocProviderEventArg* pEventArg = dynamic_cast< _LocProviderEventArg* >(pArg); SysTryReturnVoidResult(NID_LOC, pEventArg, E_SYSTEM, "[E_INVALID_ARG] Event argument is null."); _LocProviderEventType eventType = pEventArg->GetEventType(); switch (eventType) { case _LOC_PRV_EVENT_SEND_LOC: pLocProviderEventListener->OnLocationEventReceivedN(pEventArg->GetRequestId(), *pEventArg->GetLocationN()); break; case _LOC_PRV_EVENT_SEND_LOC_SVC_CB: pLocProviderEventListener->OnLocationUpdateStatusChanged(pEventArg->GetLocServiceStatus()); break; case _LOC_PRV_EVENT_SEND_MONITOR_SVC_CB: pLocProviderEventListener->OnRegionMonitoringStatusChanged(pEventArg->GetLocServiceStatus()); break; case _LOC_PRV_EVENT_SEND_ALARM_EXPIRY: pLocProviderEventListener->OnAlarmExpiredEventReceived(); break; } } void _LocationProviderImpl::HandleLocationUpdate(Tizen::Locations::Location& location, bool isNew) { LocationServiceStatus newLocationUpdateStatus = __locationUpdater.status; if (isNew) { if (__locationUpdater.type != _LOCATION_UPDATE_TYPE_NONE && __locationUpdater.status != LOC_SVC_STATUS_PAUSED) { newLocationUpdateStatus = LOC_SVC_STATUS_RUNNING; } } else if (!GetUserPrivilege()) { SysLog(NID_LOC, "User consent not available."); if (__locationUpdater.type != _LOCATION_UPDATE_TYPE_NONE && __locationUpdater.status != LOC_SVC_STATUS_PAUSED) { newLocationUpdateStatus = LOC_SVC_STATUS_DENIED; } } else { SysLog(NID_LOC, "Invalid Location Update."); if (__locationUpdater.type != _LOCATION_UPDATE_TYPE_NONE && __locationUpdater.status != LOC_SVC_STATUS_PAUSED) { newLocationUpdateStatus = LOC_SVC_STATUS_NOT_FIXED; } } if (newLocationUpdateStatus != __locationUpdater.status) { SysLog(NID_LOC, "Location Update Satus changed to (%x). Notify the status.", newLocationUpdateStatus); __locationUpdater.status = newLocationUpdateStatus; __pLocationListener->OnLocationUpdateStatusChanged(__locationUpdater.status); } if (newLocationUpdateStatus == LOC_SVC_STATUS_RUNNING) { if (__locationUpdater.type == _LOCATION_UPDATE_TYPE_DISTANCE) { if (CheckDistanceThreshold(*__locationUpdater.pLocation.get(), location) == true) { SysLog(NID_LOC, "Location displacement exceeds the distance threshold (%lf). Notify the location.", __locationUpdater.distanceThreshold); __pLocationListener->OnLocationUpdated(location); *__locationUpdater.pLocation.get() = location; } } else if (__locationUpdater.type == _LOCATION_UPDATE_TYPE_INTERVAL) { SysLog(NID_LOC, "Location time interval expired. Notify the location."); __pLocationListener->OnLocationUpdated(location); *__locationUpdater.pLocation.get() = location; } } } void _LocationProviderImpl::HandleRegionMonitoring(Tizen::Locations::Location& location, bool isNew) { LocationServiceStatus newRegionMonitorStatus = __regionMonitor.status; if (isNew) { newRegionMonitorStatus = LOC_SVC_STATUS_RUNNING; } else if (!GetUserPrivilege()) { newRegionMonitorStatus = LOC_SVC_STATUS_DENIED; } else { newRegionMonitorStatus = LOC_SVC_STATUS_NOT_FIXED; } if (newRegionMonitorStatus != __regionMonitor.status) { SysLog(NID_LOC, "Region Monitoring Satus changed to (%x). Notify the status.", newRegionMonitorStatus); __regionMonitor.status = newRegionMonitorStatus; __pLocationListener->OnRegionMonitoringStatusChanged(__regionMonitor.status); } if (newRegionMonitorStatus == LOC_SVC_STATUS_RUNNING) { NotifyRegionCrossedStatus(location); } SetNextRegionMonitoringTime(); } void _LocationProviderImpl::NotifyRegionCrossedStatus(const Tizen::Locations::Location& location) { int count = __regionMonitor.pRegionList->GetCount(); SysLog(NID_LOC, "Number of regions currently monitored is (%d)", count); for (int i = 0; i < count; i++) { _RegionInfo* pRegionInfo = static_cast< _RegionInfo* >(__regionMonitor.pRegionList->GetAt(i)); if (pRegionInfo) { Coordinates regionCoordinate = pRegionInfo->GetCoordinate(); _RegionState currentState = REGION_STATE_UNKNOWN; _RegionState previousState = pRegionInfo->GetPreviousValidState(); bool notifyStateChange = false; currentState = GetRegionCurrentState(*pRegionInfo, location); SysLog(NID_LOC, "Current Region state is (%d) and Previous Region state is (%d)", currentState, previousState); if (currentState != REGION_STATE_UNKNOWN && previousState != currentState) { notifyStateChange = true; pRegionInfo->SetValidPreviousState(currentState); } if ((pRegionInfo->GetRegionState() == REGION_STATE_INSIDE || pRegionInfo->GetRegionState() == REGION_STATE_UNKNOWN) && currentState == REGION_STATE_OUTSIDE) { if (notifyStateChange) { SysLog(NID_LOC, "Notify the boundary crossed event as previous valid region state is INSIDE and current state is OUTSIDE."); __pLocationListener->OnRegionLeft(pRegionInfo->GetRegionId()); } } else if ((pRegionInfo->GetRegionState() == REGION_STATE_OUTSIDE || pRegionInfo->GetRegionState() == REGION_STATE_UNKNOWN) && currentState == REGION_STATE_INSIDE) { if (notifyStateChange) { SysLog(NID_LOC, "Notify the boundary crossed event as previous valid region state is OUTSIDE and current state is INSIDE."); __pLocationListener->OnRegionEntered(pRegionInfo->GetRegionId()); } } pRegionInfo->SetRegionState(currentState); } } } _RegionState _LocationProviderImpl::GetRegionCurrentState(const _RegionInfo& region, const Location& location) { TryReturn(location.GetHorizontalAccuracy() >= 0.0, REGION_STATE_UNKNOWN, "Location received with invalid accuracy"); SysSecureLog(NID_LOC, "[RegionID %d] Region Information is (Center latitude: %lf, Center longitude: %lf, Region radius:%lf", region.GetRegionId(), region.GetCoordinate().GetLatitude(), region.GetCoordinate().GetLongitude(), region.GetRadius()); SysSecureLog(NID_LOC, "[RegionID %d] Location Information is (Latitude: %lf, Longitude: %lf, Horizontal accuracy:%lf", region.GetRegionId(), location.GetCoordinates().GetLatitude(), location.GetCoordinates().GetLongitude(), location.GetHorizontalAccuracy()); _RegionState regionState = REGION_STATE_UNKNOWN; double distanceBtwCenters = region.GetCoordinate().GetDistanceTo(location.GetCoordinates()); double regionRadius = region.GetRadius(); double locationRadius = location.GetHorizontalAccuracy(); SysLog(NID_LOC, "[RegionID %d] The distance between centers is (%lf)", region.GetRegionId(), distanceBtwCenters); if (distanceBtwCenters >= (regionRadius + locationRadius)) { regionState = REGION_STATE_OUTSIDE; } else if (distanceBtwCenters < regionRadius && Double::Compare(locationRadius, 0.0) == 0) { SysLog(NID_LOC, "[RegionID %d] Location Radius is 0 and distance < regionRadius", region.GetRegionId()); regionState = REGION_STATE_INSIDE; } else { double radiusThreshold = (1 / Math::Sqrt(2)) * locationRadius; if (regionRadius < radiusThreshold) { SysLog(NID_LOC, "[RegionID %d] Region circle is less than 50 percent area of the location circle.", region.GetRegionId()); regionState = (distanceBtwCenters >= locationRadius) ? REGION_STATE_OUTSIDE : REGION_STATE_UNKNOWN; return regionState; } else { double overlapRegion = _MathUtils::CalculateOverlapRegion(region, location); double upperThreshold = 0; double lowerThreshold = 0; double occupancy = 0; SysLog(NID_LOC, "[RegionID %d] OverlapRegion is (%lf)", region.GetRegionId(), overlapRegion); if (regionRadius >= locationRadius) { // Calculate occupancy % with the location circle SysLog(NID_LOC, "[RegionID %d] Region radius is bigger.", region.GetRegionId()); occupancy = (overlapRegion / (Math::GetPi() * locationRadius * locationRadius)) * 100; upperThreshold = 60; lowerThreshold = 40; } else if (regionRadius >= radiusThreshold) { SysLog(NID_LOC, "[RegionID %d] The ratio of Region radius to location radius is between 0.707 and 1.", region.GetRegionId()); double thresholdValue = -136.51 * (regionRadius / locationRadius) + 146.51; // This equation varies the threshold value from 10 (for R/r = 1) to 50 (for R/r = 0.707) SysLog(NID_LOC, "[RegionID %d] Threshold value is %lf.", region.GetRegionId(), thresholdValue); occupancy = (overlapRegion / (Math::GetPi() * locationRadius * locationRadius)) * 100; upperThreshold = 50 + thresholdValue; lowerThreshold = 50 - thresholdValue; } // Decide the state with as per the inner and outer thresholds SysLog(NID_LOC, "[RegionID %d] Occupancy is (%lf), Upper threshold is (%lf) and lower threshold is (%lf).", region.GetRegionId(), occupancy, upperThreshold, lowerThreshold); regionState = (occupancy >= upperThreshold) ? REGION_STATE_INSIDE : ((occupancy <= lowerThreshold) ? REGION_STATE_OUTSIDE : REGION_STATE_UNKNOWN); } } SysLog(NID_LOC, "[RegionID %d] Returning region state as (%d).", region.GetRegionId(), regionState); return regionState; } void _LocationProviderImpl::NotifyServiceStatus(_LocProviderEventType eventType, LocationServiceStatus svcStatus) { std::unique_ptr< _LocProviderEventArg > pLocProviderEventArg(new (std::nothrow) _LocProviderEventArg()); if (pLocProviderEventArg) { pLocProviderEventArg->SetEventType(eventType); pLocProviderEventArg->SetLocServiceStatus(svcStatus); result r = _Event::FireAsync(*pLocProviderEventArg.get()); SysTryReturnVoidResult(NID_LOC, r == E_SUCCESS, r, "[%s] Failed to fire the event.", GetErrorMessage(r)); pLocProviderEventArg.release(); } return; } bool _LocationProviderImpl::GetUserPrivilege(void) { bool hasPrivilege = false; bool gpsEnabled = true; bool wpsEnabled = true; result gps = _SettingInfoImpl::GetValue(L"http://tizen.org/setting/location.gps", gpsEnabled); result wps = _SettingInfoImpl::GetValue(L"http://tizen.org/setting/location.wps", wpsEnabled); hasPrivilege = gpsEnabled | wpsEnabled; if (gps != E_SUCCESS || wps != E_SUCCESS || hasPrivilege == false) { return false; } return true; } result _LocationProviderImpl::ActivateRegionMonitoring(bool startUpdate) { long long currentTime; SystemTime::GetTicks(currentTime); int DEFAULT_WAITING_TIME = DEFAULT_WAITING_TIME_FOR_FIXING_GPS_LOCATION; SysLog(NID_LOC, "Current system time is %lld and location update request is %d", currentTime, startUpdate); bool gpsEnabled = false; result gps = _SettingInfoImpl::GetValue(L"http://tizen.org/setting/location.gps", gpsEnabled); if (gps == E_SUCCESS && !gpsEnabled) { SysLog(NID_LOC, "The GPS setting is OFF. So wait for only 10 seconds."); DEFAULT_WAITING_TIME = DEFAULT_WAITING_TIME_FOR_FIXING_WPS_LOCATION; } result r = __regionMonitor.pTimer->Start(DEFAULT_WAITING_TIME * 1000); SysTryReturn(NID_LOC, r == E_SUCCESS, r, r, "[%s] Failed to start the timer. Propogating.", GetErrorMessage(r)); if (startUpdate) { _LocationImpl::GetInstance(*__regionMonitor.pLocation)->SetValidity(false); _LocationImpl::GetInstance(*__regionMonitor.pLocation)->SetTimestamp(currentTime); r = __pLocationManager->StartLocationUpdates(__criteria.GetAccuracy(), MIN_LOCATION_UPDATE_INTERVAL, this, __regionMonitor.reqId); SysTryReturn(NID_LOC, r == E_SUCCESS, r, r, "[%s] Failed to start the location updates. Propogating.", GetErrorMessage(r)); SysLog(NID_LOC, "Location updates started."); } return E_SUCCESS; } void _LocationProviderImpl::StopRegionMonitoring(void) { result r = __pLocationManager->RequestStopAlarm(__regionMonitor.reqId); SysTryLog(NID_LOC, r == E_SUCCESS, "[%s] Failed to stop the alarm. Ignored.", GetErrorMessage(r)); r = __regionMonitor.pTimer->Cancel(); SysTryLog(NID_LOC, r == E_SUCCESS, "[%s] Failed to stop the timer. Ignored.", GetErrorMessage(r)); r = __pLocationManager->StopLocationUpdates(__regionMonitor.reqId); SysTryReturnVoidResult(NID_LOC, r == E_SUCCESS, r, "[%s] All regions are removed but failed to stop the location updates. Ignored.", GetErrorMessage(r)); } void _LocationProviderImpl::SetNextRegionMonitoringTime(void) { DateTime alarmDateTime; long long alarmTime = DEFAULT_REGION_MONITORING_CYCLE_INTERVAL; SystemTime::GetCurrentTime(TIME_MODE_WALL, alarmDateTime); SysLog(NID_LOC, "Current System Time is %ls", alarmDateTime.ToString().GetPointer()); double speed = DEFAULT_AVG_SPEED; if (__regionMonitor.speed > DEFAULT_AVG_SPEED) { SysLog(NID_LOC, "The speed of the user is greater than the default speed. So updating the value."); speed = __regionMonitor.speed; } if (__regionMonitor.pLocation->IsValid()) { const int bufferTime = 5; //Buffer of 5 seconds for determining the alarmTime; double minDistance = _MathUtils::GetShortestDistance(*__regionMonitor.pLocation, *__regionMonitor.pRegionList); long long newAlarmTime = ((int) minDistance / speed) - bufferTime; //Calculate the alarm time based on the shortest distance between current location and nearest region boundary. if (newAlarmTime < DEFAULT_REGION_MONITORING_CYCLE_INTERVAL) { SysLog(NID_LOC, "The alarm time is less than 5 seconds. So do not stop the location updates."); ActivateRegionMonitoring(false); return; } else { alarmTime = newAlarmTime; } } result r = __pLocationManager->StopLocationUpdates(__regionMonitor.reqId); SysTryLog(NID_LOC, r == E_SUCCESS, "Failed to stop the location updates."); r = __pLocationManager->RequestStartAlarm(alarmTime, this, __regionMonitor.reqId); SysLog(NID_LOC, "Next alarm expires after %ld seconds.", alarmTime); } }}