2 // Open Service Platform
3 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
5 // Licensed under the Apache License, Version 2.0 (the License);
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
9 // http://www.apache.org/licenses/LICENSE-2.0
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
19 * @file FLoc_LocationProviderImpl.cpp
20 * @brief This is the implementation file for the %_LocationProviderImpl class.
22 * This implementation file contains the definitions of the %_LocationProviderImpl class methods.
25 #include <unique_ptr.h>
26 #include <FApp_AppManagerImpl.h>
28 #include <FAppTypes.h>
29 #include <FAppUiApp.h>
30 #include <FBaseColArrayList.h>
31 #include <FBaseDouble.h>
32 #include <FBaseRtEvent.h>
33 #include <FBaseRtTimer.h>
34 #include <FBaseSysLog.h>
35 #include <FLocLocationCriteria.h>
36 #include <FLocCoordinates.h>
37 #include <FLocILocationProviderListener.h>
38 #include <FLocLocation.h>
39 #include <FLocTypes.h>
40 #include <FSysPowerManager.h>
41 #include <FSysSystemTime.h>
42 #include <FSys_AlarmImpl.h>
43 #include <FSys_SettingInfoImpl.h>
44 #include "FLoc_LocationImpl.h"
45 #include "FLoc_LocationManager.h"
46 #include "FLoc_LocationMonitor.h"
47 #include "FLoc_LocationProviderImpl.h"
48 #include "FLoc_MathUtils.h"
49 #include "FLoc_Types.h"
52 using namespace Tizen::App;
53 using namespace Tizen::Base;
54 using namespace Tizen::Base::Collection;
55 using namespace Tizen::Base::Runtime;
56 using namespace Tizen::Base::Utility;
57 using namespace Tizen::System;
59 namespace Tizen { namespace Locations
62 _LocationProviderImpl::_LocationProviderImpl(void)
63 : Tizen::Base::Runtime::_Event()
64 , __lastLocationAccuracy(LOC_ACCURACY_INVALID)
65 , __pLocationListener(null)
66 , __pLocationManager(null)
70 _LocationProviderImpl::~_LocationProviderImpl(void)
72 UiApp* pAppInstance = Tizen::App::UiApp::GetInstance();
75 _AppManagerImpl* pAppManager = _AppManagerImpl::GetInstance();
78 pAppManager->RemoveActiveAppEventListener(*this);
82 StopLocationUpdates();
83 RemoveAllMonitoringRegions();
87 _LocationProviderImpl::Construct(const LocationCriteria& criteria, ILocationProviderListener& listener)
89 _LocationManager* pLocationManager = _LocationManager::GetInstance();
90 SysTryReturn(NID_LOC, pLocationManager != null, GetLastResult(), GetLastResult(), "[%s] Failed to get the location manager instance.", GetErrorMessage(GetLastResult()));
92 std::unique_ptr< Tizen::Base::Collection::ArrayList, AllElementsDeleter > pRegionList(new (std::nothrow) ArrayList());
93 SysTryReturn(NID_LOC, pRegionList != null, E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY));
94 result r = pRegionList->Construct();
95 SysTryReturn(NID_LOC, r == E_SUCCESS, r, r, "[%s] Failed to construct the list. Propagating.", GetErrorMessage(r));
97 std::unique_ptr< Tizen::Base::Runtime::Timer> pTimer (new (std::nothrow) Timer());
98 SysTryReturn(NID_LOC, pTimer != null, E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY));
99 r = pTimer->Construct(*this);
100 SysTryReturn(NID_LOC, r == E_SUCCESS, r, r, "[%s] Failed to construct the timer. Propagating.", GetErrorMessage(r));
102 std::unique_ptr< Tizen::System::Alarm> pAlarm (new (std::nothrow) Alarm());
103 SysTryReturn(NID_LOC, pAlarm != null, E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY));
104 r = pAlarm->Construct(*this);
105 SysTryReturn(NID_LOC, r == E_SUCCESS, r, r, "[%s] Failed to construct the alarm. Propagating.", GetErrorMessage(r));
107 UiApp* pAppInstance = Tizen::App::UiApp::GetInstance();
108 if (pAppInstance != null)
110 _AppManagerImpl* pAppManager = _AppManagerImpl::GetInstance();
111 SysTryReturn(NID_LOC, pAppManager, E_SYSTEM, E_SYSTEM, "[E_SYSTEM] System error occured.");
113 r = pAppManager->AddActiveAppEventListener(*this);
114 SysTryReturn(NID_LOC, r == E_SUCCESS, r, r, "[%s] Error occured during adding the event listener to app manager. Propagating.", GetErrorMessage(r));
117 std::unique_ptr< Tizen::Locations::Location > pLastLocation(_LocationImpl::GetLocationInstanceN());
118 SysTryReturn(NID_LOC, pLastLocation != null, E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY));
119 std::unique_ptr<Tizen::Locations::Location> pLastRegionLocation (_LocationImpl::GetLocationInstanceN());
120 SysTryReturn(NID_LOC, pLastRegionLocation != null, E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY));
122 _Event::Initialize();
123 _Event::AddListener(*this);
125 __regionMonitor.pRegionList = std::move(pRegionList);
126 __regionMonitor.pTimer = std::move(pTimer);
127 __regionMonitor.pAlarm = std::move(pAlarm);
128 __regionMonitor.pLocation = std::move(pLastRegionLocation);
129 __locationUpdater.pLocation = std::move(pLastLocation);
131 __criteria = criteria;
132 __pLocationListener = &listener;
133 __pLocationManager = pLocationManager;
135 SysLog(NID_LOC, "Location provider constructed with the accuracy (%x).", criteria.GetAccuracy());
140 _LocationProviderImpl::StartLocationUpdatesByInterval(int interval)
142 bool userConsent = GetUserPrivilege();
143 SysTryReturn(NID_LOC, userConsent, E_USER_NOT_CONSENTED, E_USER_NOT_CONSENTED, "[E_USER_NOT_CONSENTED] The user has disabled the required settings.");
144 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);
146 if (__locationUpdater.type == _LOCATION_UPDATE_TYPE_INTERVAL && __locationUpdater.updateInterval == interval)
150 const double INVALID_DISTANCE_THRESHOLD = 0.0;
151 return StartLocationUpdates(_LOCATION_UPDATE_TYPE_INTERVAL, interval, INVALID_DISTANCE_THRESHOLD);
155 _LocationProviderImpl::StartLocationUpdatesByDistance(double distance)
157 bool userConsent = GetUserPrivilege();
158 SysTryReturn(NID_LOC, userConsent, E_USER_NOT_CONSENTED, E_USER_NOT_CONSENTED, "[E_USER_NOT_CONSENTED] The user has disabled the required settings.");
159 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);
160 SysTryReturn(NID_LOC, Double::IsNaN(distance) == false, E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] The distance is NaN.");
162 if (__locationUpdater.type == _LOCATION_UPDATE_TYPE_DISTANCE && (Double::Compare(__locationUpdater.distanceThreshold, distance) == 0))
166 const int INVALID_INTERVAL = 0;
167 return StartLocationUpdates(_LOCATION_UPDATE_TYPE_DISTANCE, INVALID_INTERVAL, distance);
171 _LocationProviderImpl::StopLocationUpdates(void)
173 SysLog(NID_LOC, "Stopping the location updates for the request ID (%ld)", __locationUpdater.reqId);
174 SysTryReturn(NID_LOC, __locationUpdater.type != _LOCATION_UPDATE_TYPE_NONE, E_INVALID_OPERATION, E_INVALID_OPERATION, "[E_INVALID_OPERATION] Location update has not been requested.");
176 result r = __pLocationManager->StopLocationUpdates(__locationUpdater.reqId);
177 ResetLocationUpdates();
182 _LocationProviderImpl::KeepLocationUpdateAwake(bool enable)
184 if (__locationUpdater.awakeEnabled == enable)
188 __locationUpdater.awakeEnabled = enable;
190 UiApp* appInstance = Tizen::App::UiApp::GetInstance();
191 if (appInstance == null) // This is service APP. So should be handled now.
193 SysLog(NID_LOC, "Handling the request awake mode(%d) for the service application.", enable);
196 if (__locationUpdater.type != _LOCATION_UPDATE_TYPE_NONE && __locationUpdater.status == LOC_SVC_STATUS_PAUSED)
198 SysLog(NID_LOC, "Requesting to start the location updates as the update type is (%x)", __locationUpdater.type);
199 __locationUpdater.status = LOC_SVC_STATUS_NOT_FIXED;
200 __pLocationManager->StartLocationUpdates(__criteria.GetAccuracy(), __locationUpdater.updateInterval, this, __locationUpdater.reqId);
202 NotifyServiceStatus(_LOC_PRV_EVENT_SEND_LOC_SVC_CB, __locationUpdater.status);
207 if (__locationUpdater.type != _LOCATION_UPDATE_TYPE_NONE && (__locationUpdater.status == LOC_SVC_STATUS_RUNNING || __locationUpdater.status == LOC_SVC_STATUS_NOT_FIXED))
209 SysLog(NID_LOC, "Requesting to stop the location updates as the update type is (%x)", __locationUpdater.type);
210 __locationUpdater.status = LOC_SVC_STATUS_PAUSED;
211 __pLocationManager->StopLocationUpdates(__locationUpdater.reqId);
213 NotifyServiceStatus(_LOC_PRV_EVENT_SEND_LOC_SVC_CB, __locationUpdater.status);
220 _LocationProviderImpl::AddMonitoringRegion(const Coordinates& regionCenter, double radius, RegionId& regionId)
222 bool userConsent = GetUserPrivilege();
223 SysTryReturn(NID_LOC, userConsent, E_USER_NOT_CONSENTED, E_USER_NOT_CONSENTED, "[E_USER_NOT_CONSENTED] The user has disabled the required settings.");
224 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.");
225 SysTryReturn(NID_LOC, (!Double::IsNaN(radius) && !Double::IsNaN(regionCenter.GetLatitude()) && !Double::IsNaN(regionCenter.GetLongitude())),
226 E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] One of the value is NaN.");
227 SysSecureLog(NID_LOC, "Requested to add the monitoring region with center (Latitude: %lf, Longitude %lf) and radius (%lf).", regionCenter.GetLatitude(), regionCenter.GetLongitude(), radius);
229 static int nextRegionId = 0;
231 std::unique_ptr< _RegionInfo > pRegionInfo(new (std::nothrow) _RegionInfo(regionCenter, radius, nextRegionId));
232 SysTryReturn(NID_LOC, pRegionInfo != null, E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY));
233 result r = __regionMonitor.pRegionList->Add(*pRegionInfo.get());
234 SysTryReturn(NID_LOC, r == E_SUCCESS, r, r, "[%s] Failed to add the Region info into the list. Propogated.", GetErrorMessage(r));
236 pRegionInfo.release();
237 regionId = nextRegionId;
240 if (__regionMonitor.status != LOC_SVC_STATUS_IDLE)
245 r = ActivateRegionMonitoring(true);
246 SysTryCatch(NID_LOC, r == E_SUCCESS, , r, "[%s] Failed to start the region monitoring. Propogating.", GetErrorMessage(r));
248 __regionMonitor.status = LOC_SVC_STATUS_NOT_FIXED;
249 NotifyServiceStatus(_LOC_PRV_EVENT_SEND_MONITOR_SVC_CB, __regionMonitor.status);
253 __regionMonitor.pRegionList->RemoveAt(0);
258 _LocationProviderImpl::RemoveMonitoringRegion(RegionId regionId)
260 int count = __regionMonitor.pRegionList->GetCount();
261 bool isIdValid = false;
262 SysLog(NID_LOC, "Total regions currently monitored is (%d).", count);
264 for (int i = 0; i < count; i++)
266 _RegionInfo* pRegionInfo = static_cast< _RegionInfo* >(__regionMonitor.pRegionList->GetAt(i));
267 if (regionId == pRegionInfo->GetRegionId())
269 __regionMonitor.pRegionList->RemoveAt(i, true);
275 SysTryReturn(NID_LOC, isIdValid == true, E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] The region ID is invalid.");
276 if (__regionMonitor.pRegionList->GetCount() == 0)
278 __regionMonitor.status = LOC_SVC_STATUS_IDLE;
279 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.
281 __lastLocationAccuracy = LOC_ACCURACY_INVALID;
283 StopRegionMonitoring();
289 _LocationProviderImpl::RemoveAllMonitoringRegions(void)
291 __regionMonitor.pRegionList->RemoveAll(true);
293 if (__regionMonitor.status != LOC_SVC_STATUS_IDLE)
295 __regionMonitor.status = LOC_SVC_STATUS_IDLE;
296 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.
298 __lastLocationAccuracy = LOC_ACCURACY_INVALID;
300 StopRegionMonitoring();
305 LocationServiceStatus
306 _LocationProviderImpl::GetLocationUpdateStatus(void) const
308 return __locationUpdater.status;
311 LocationServiceStatus
312 _LocationProviderImpl::GetRegionMonitoringStatus(void) const
314 return __regionMonitor.status;
318 _LocationProviderImpl::GetCurrentAccuracy(void) const
320 return __lastLocationAccuracy;
324 _LocationProviderImpl::GetLocation(const LocationCriteria& criteria)
326 Location retLocation(_LocationImpl::GetLocationInstance());
328 bool userConsent = GetUserPrivilege();
329 SysTryReturn(NID_LOC, userConsent, retLocation, E_USER_NOT_CONSENTED, "[E_USER_NOT_CONSENTED] The user has disabled the required settings.");
331 Location* pLocation = null;
332 const int MAX_TIMEOUT = 30;
333 result r = E_SUCCESS;
334 _LocationManager* pLocationManager = null;
336 SysLog(NID_LOC, "Requesting for single location with criteria (%x).", criteria.GetAccuracy());
338 std::unique_ptr< _LocationMonitor > pLocMonitor(new (std::nothrow) _LocationMonitor());
339 SysTryCatch(NID_LOC, pLocMonitor, , E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY));
340 r = pLocMonitor->Construct(MAX_TIMEOUT, criteria.GetAccuracy());
341 SysTryCatch(NID_LOC, r == E_SUCCESS, , r, "[%s] Failed to construct the Location Monitor.", GetErrorMessage(r));
343 pLocationManager = _LocationManager::GetInstance();
344 SysTryCatch(NID_LOC, pLocationManager, , r, "[%s] Failed to get the location manager instance.", GetErrorMessage(r));
345 r = pLocationManager->RegisterLocationMonitor(pLocMonitor.get());
346 SysTryCatch(NID_LOC, r == E_SUCCESS, , r, "[%s] Failed to register the location monitor.", GetErrorMessage(r));
348 r = pLocMonitor->Wait();
351 pLocation = pLocMonitor->GetLocationN();
355 retLocation = *pLocation;
359 SetLastResult(E_LOCATION_UNAVAILABLE);
369 _LocationProviderImpl::GetLastKnownLocation(void)
371 Location retLocation(_LocationImpl::GetLocationInstance());
373 bool userConsent = GetUserPrivilege();
374 SysTryReturn(NID_LOC, userConsent, retLocation, E_USER_NOT_CONSENTED, "[E_USER_NOT_CONSENTED] The user has disabled the required settings.");
376 _LocationManager* pLocationManager = _LocationManager::GetInstance();
377 SysTryReturn(NID_LOC, pLocationManager, retLocation, E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY));
379 retLocation = pLocationManager->GetLastKnownLocation();
380 if (!retLocation.IsValid())
382 SetLastResult(E_LOCATION_UNAVAILABLE);
394 _LocationProviderImpl::OnLocationUpdated(RequestId reqId, const Tizen::Locations::Location& location)
396 SysLog(NID_LOC, "Location is updated from Location Manager for the request ID (%ld).", reqId);
398 std::unique_ptr< Location > pLocation(new (std::nothrow) Location(location));
399 SysTryReturnVoidResult(NID_LOC, pLocation, E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY));
400 std::unique_ptr< _LocProviderEventArg > pLocProviderEventArg(new (std::nothrow) _LocProviderEventArg());
401 SysTryReturnVoidResult(NID_LOC, pLocProviderEventArg, E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY));
403 pLocProviderEventArg->SetEventType(_LOC_PRV_EVENT_SEND_LOC);
404 pLocProviderEventArg->SetLocation(pLocation.get());
405 pLocProviderEventArg->SetRequestId(reqId);
408 result r = _Event::FireAsync(*pLocProviderEventArg);
409 SysTryReturnVoidResult(NID_LOC, r == E_SUCCESS, r, "[%s] Failed to fire the event.", GetErrorMessage(r));
410 pLocProviderEventArg.release();
416 _LocationProviderImpl::OnLocationEventReceivedN(RequestId reqId, Tizen::Locations::Location& location)
418 SysLog(NID_LOC, "Location Event received.");
420 LocationAccuracy currentAccuracy = LOC_ACCURACY_INVALID;
421 LocationAccuracy lastLocAccuracy = __lastLocationAccuracy;
422 long long lastLocationTime = 0;
424 Location* pLocation = &location;
425 _LocationImpl* pLocationImpl = _LocationImpl::GetInstance(*pLocation);
427 if (reqId == __locationUpdater.reqId)
429 SysLog(NID_LOC, "The location is updated for Location request.");
430 lastLocationTime = _LocationImpl::GetInstance(*__locationUpdater.pLocation.get())->GetTimestampInMs();
432 else if (reqId == __regionMonitor.reqId)
434 SysLog(NID_LOC, "The location is updated for Region monitoring.");
435 lastLocationTime = _LocationImpl::GetInstance(*__regionMonitor.pLocation.get())->GetTimestampInMs();
438 long long timeDifference = pLocationImpl->GetTimestampInMs() - lastLocationTime;
439 SysLog(NID_LOC, "Time difference between last location timestamp (%lld) and current location timestamp (%lld) is (%lld).", lastLocationTime, pLocationImpl->GetTimestampInMs(), timeDifference);
440 if (timeDifference > 0)
443 currentAccuracy = __pLocationManager->GetAccuracyLevel(pLocation->GetHorizontalAccuracy());
446 if (currentAccuracy != __lastLocationAccuracy)
448 SysLog(NID_LOC, "Notify the accuracy change.");
449 __lastLocationAccuracy = currentAccuracy;
450 __pLocationListener->OnAccuracyChanged(currentAccuracy);
453 if (reqId == __locationUpdater.reqId)
455 HandleLocationUpdate(location, isNew);
457 else if (reqId == __regionMonitor.reqId)
461 bool gpsEnabled = false;
462 _SettingInfoImpl::GetValue(L"http://tizen.org/setting/location.gps", gpsEnabled);
463 SysLog(NID_LOC, "The GPS settings value is %d", gpsEnabled);
465 __regionMonitor.speed = location.GetSpeed() * 0.2777778;
467 if ( currentAccuracy <= lastLocAccuracy || timeDifference > DEFAULT_THRESHOLD_LOC_VALIDITY_TIME_OUT) // Copy the location only if it is new and accuracy is better than before.
469 *__regionMonitor.pLocation = location;
472 if ((currentAccuracy != LOC_ACCURACY_INVALID && currentAccuracy <= __criteria.GetAccuracy()) || !gpsEnabled)
474 SysLog(NID_LOC, "Location criteria (accuracy: %ld) is met for handling region monitoring.", currentAccuracy);
475 result r = __regionMonitor.pTimer->Cancel();
476 SysTryLog(NID_LOC, r == E_SUCCESS, "Failed to cancel the timer.");
478 HandleRegionMonitoring(location, isNew);
482 SysLog(NID_LOC, "Location criteria (accuracy: %ld) is not met for handling region monitoring.", currentAccuracy);
491 _LocationProviderImpl::OnLocationUpdateStatusChanged(Tizen::Locations::LocationServiceStatus locSvcStatus)
493 __pLocationListener->OnLocationUpdateStatusChanged(locSvcStatus);
497 _LocationProviderImpl::OnRegionMonitoringStatusChanged(Tizen::Locations::LocationServiceStatus locSvcStatus)
499 __pLocationListener->OnRegionMonitoringStatusChanged(locSvcStatus);
503 _LocationProviderImpl::OnActiveAppChanged(const Tizen::App::AppId& appId)
505 Tizen::App::App* pApp = Tizen::App::App::GetInstance();
506 Tizen::App::AppId currentAppId = pApp->GetAppId();
508 SysLog(NID_LOC, "Active App ID is (%ls) and the current app Id is (%ls)", appId.GetPointer(), currentAppId.GetPointer());
510 if (currentAppId == appId)
512 SysLog(NID_LOC, "Application is active.");
514 if (__locationUpdater.status == LOC_SVC_STATUS_PAUSED)
516 SysLog(NID_LOC, "Start the location updates as the location update status is PAUSED.");
517 __pLocationManager->StartLocationUpdates(__criteria.GetAccuracy(), __locationUpdater.updateInterval, this, __locationUpdater.reqId);
518 __locationUpdater.status = LOC_SVC_STATUS_NOT_FIXED;
519 __pLocationListener->OnLocationUpdateStatusChanged(__locationUpdater.status);
524 SysLog(NID_LOC, "Application is not active.");
526 if (__locationUpdater.awakeEnabled == false && (__locationUpdater.status == LOC_SVC_STATUS_RUNNING || __locationUpdater.status == LOC_SVC_STATUS_NOT_FIXED))
528 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);
529 __pLocationManager->StopLocationUpdates(__locationUpdater.reqId);
530 __locationUpdater.status = LOC_SVC_STATUS_PAUSED;
531 __pLocationListener->OnLocationUpdateStatusChanged(__locationUpdater.status);
537 _LocationProviderImpl::OnAlarmExpired(Alarm& alarm)
539 SysLog(NID_LOC, "Region Monitor Alarm expired.");
540 result r = ActivateRegionMonitoring(true);
541 SysTryReturnVoidResult(NID_LOC, r == E_SUCCESS, r, "[%s] Failed to start the region monitoring. Propogating.", GetErrorMessage(r));
545 _LocationProviderImpl::OnTimerExpired(Timer& timer)
547 SysLog(NID_LOC, "Region Monitor timer expired due to unavailability of location information.");
548 __pLocationManager->StopLocationUpdates(__regionMonitor.reqId);
549 HandleRegionMonitoring(*__regionMonitor.pLocation, __regionMonitor.pLocation->IsValid());
553 _LocationProviderImpl::StartLocationUpdates(LocationUpdateType updateType, int interval, double distance)
555 result r = E_SUCCESS;
556 bool startUpdate = true;
558 if (updateType == _LOCATION_UPDATE_TYPE_INTERVAL)
560 __locationUpdater.updateInterval = interval;
562 else if (updateType == _LOCATION_UPDATE_TYPE_DISTANCE)
564 __locationUpdater.updateInterval = DEFAULT_DISTANCE_CHECKING_INTERVAL;
565 __locationUpdater.distanceThreshold = distance;
568 if (!__locationUpdater.awakeEnabled)
570 UiApp* pAppInstance = Tizen::App::UiApp::GetInstance();
571 if (pAppInstance == null)
577 AppUiState appUiState = pAppInstance->GetAppUiState();
579 if (appUiState == APP_UI_STATE_BACKGROUND)
581 SysLog(NID_LOC, "App is background.");
589 if (__locationUpdater.type != _LOCATION_UPDATE_TYPE_NONE)
591 SysLog(NID_LOC, "Update session already running. Updating the interval to %d seconds", __locationUpdater.updateInterval);
592 r = __pLocationManager->ChangeUpdateInterval(__locationUpdater.reqId, __locationUpdater.updateInterval);
593 SysTryCatch(NID_LOC, r == E_SUCCESS, , r, "[%s] Failed to update the request interval. Propagating.", GetErrorMessage(r));
594 __locationUpdater.type = updateType;
599 r = __pLocationManager->StartLocationUpdates(__criteria.GetAccuracy(), __locationUpdater.updateInterval, this, __locationUpdater.reqId);
600 SysTryCatch(NID_LOC, r == E_SUCCESS, , r, "[%s] Failed to start the Native location updates. Propagating.", GetErrorMessage(r));
601 __locationUpdater.status = LOC_SVC_STATUS_NOT_FIXED;
606 __locationUpdater.status = LOC_SVC_STATUS_PAUSED;
609 __locationUpdater.type = updateType;
611 SysLog(NID_LOC, "Update type is (%x). The request Id is (%ld) and the update status is (%x).", __locationUpdater.type, __locationUpdater.reqId, __locationUpdater.status);
612 NotifyServiceStatus(_LOC_PRV_EVENT_SEND_LOC_SVC_CB, __locationUpdater.status);
617 __locationUpdater.type = _LOCATION_UPDATE_TYPE_NONE;
622 _LocationProviderImpl::CheckDistanceThreshold(const Location& oldPosition, const Location& newPosition)
624 double displacement = 0.0;
625 const Coordinates coordOld = oldPosition.GetCoordinates();
626 const Coordinates coordNew = newPosition.GetCoordinates();
628 if (__locationUpdater.firstLocationUpdate)
630 SysLog(NID_LOC, "First location update. So send true.");
631 __locationUpdater.firstLocationUpdate = false;
634 displacement = coordOld.GetDistanceTo(coordNew);
635 SysLog(NID_LOC, "Displacement is (%lf)", displacement);
636 return ((displacement > __locationUpdater.distanceThreshold) ? true : false);
640 _LocationProviderImpl::ResetLocationUpdates(void)
642 __locationUpdater.firstLocationUpdate = true;
643 __locationUpdater.reqId = -1;
644 __lastLocationAccuracy = LOC_ACCURACY_INVALID;
645 __locationUpdater.type = _LOCATION_UPDATE_TYPE_NONE;
646 __locationUpdater.status = LOC_SVC_STATUS_IDLE;
647 __locationUpdater.updateInterval = 0;
648 __locationUpdater.distanceThreshold = 0.0;
652 _LocationProviderImpl::FireImpl(Tizen::Base::Runtime::IEventListener& listener, const Tizen::Base::Runtime::IEventArg& arg)
654 _ILocProviderEventListener* pLocProviderEventListener = dynamic_cast< _ILocProviderEventListener* >(&listener);
655 SysTryReturnVoidResult(NID_LOC, pLocProviderEventListener, E_SYSTEM, "[E_INVALID_ARG] The listener is null.");
657 IEventArg* pArg = const_cast< IEventArg* >(&arg);
658 _LocProviderEventArg* pEventArg = dynamic_cast< _LocProviderEventArg* >(pArg);
659 SysTryReturnVoidResult(NID_LOC, pEventArg, E_SYSTEM, "[E_INVALID_ARG] Event argument is null.");
661 _LocProviderEventType eventType = pEventArg->GetEventType();
664 case _LOC_PRV_EVENT_SEND_LOC:
665 pLocProviderEventListener->OnLocationEventReceivedN(pEventArg->GetRequestId(), *pEventArg->GetLocationN());
668 case _LOC_PRV_EVENT_SEND_LOC_SVC_CB:
669 pLocProviderEventListener->OnLocationUpdateStatusChanged(pEventArg->GetLocServiceStatus());
672 case _LOC_PRV_EVENT_SEND_MONITOR_SVC_CB:
673 pLocProviderEventListener->OnRegionMonitoringStatusChanged(pEventArg->GetLocServiceStatus());
679 _LocationProviderImpl::HandleLocationUpdate(Tizen::Locations::Location& location, bool isNew)
681 LocationServiceStatus newLocationUpdateStatus = __locationUpdater.status;
685 if (__locationUpdater.type != _LOCATION_UPDATE_TYPE_NONE && __locationUpdater.status != LOC_SVC_STATUS_PAUSED)
687 newLocationUpdateStatus = LOC_SVC_STATUS_RUNNING;
690 else if (!GetUserPrivilege())
692 SysLog(NID_LOC, "User consent not available.");
693 if (__locationUpdater.type != _LOCATION_UPDATE_TYPE_NONE && __locationUpdater.status != LOC_SVC_STATUS_PAUSED)
695 newLocationUpdateStatus = LOC_SVC_STATUS_DENIED;
700 SysLog(NID_LOC, "Invalid Location Update.");
701 if (__locationUpdater.type != _LOCATION_UPDATE_TYPE_NONE && __locationUpdater.status != LOC_SVC_STATUS_PAUSED)
703 newLocationUpdateStatus = LOC_SVC_STATUS_NOT_FIXED;
707 if (newLocationUpdateStatus != __locationUpdater.status)
709 SysLog(NID_LOC, "Location Update Satus changed to (%x). Notify the status.", newLocationUpdateStatus);
710 __locationUpdater.status = newLocationUpdateStatus;
711 __pLocationListener->OnLocationUpdateStatusChanged(__locationUpdater.status);
714 if (newLocationUpdateStatus == LOC_SVC_STATUS_RUNNING)
716 if (__locationUpdater.type == _LOCATION_UPDATE_TYPE_DISTANCE)
718 if (CheckDistanceThreshold(*__locationUpdater.pLocation.get(), location) == true)
720 SysLog(NID_LOC, "Location displacement exceeds the distance threshold (%lf). Notify the location.", __locationUpdater.distanceThreshold);
721 __pLocationListener->OnLocationUpdated(location);
722 *__locationUpdater.pLocation.get() = location;
725 else if (__locationUpdater.type == _LOCATION_UPDATE_TYPE_INTERVAL)
727 SysLog(NID_LOC, "Location time interval expired. Notify the location.");
728 __pLocationListener->OnLocationUpdated(location);
729 *__locationUpdater.pLocation.get() = location;
735 _LocationProviderImpl::HandleRegionMonitoring(Tizen::Locations::Location& location, bool isNew)
737 LocationServiceStatus newRegionMonitorStatus = __regionMonitor.status;
741 newRegionMonitorStatus = LOC_SVC_STATUS_RUNNING;
743 else if (!GetUserPrivilege())
745 newRegionMonitorStatus = LOC_SVC_STATUS_DENIED;
749 newRegionMonitorStatus = LOC_SVC_STATUS_NOT_FIXED;
752 if (newRegionMonitorStatus != __regionMonitor.status)
754 SysLog(NID_LOC, "Region Monitoring Satus changed to (%x). Notify the status.", newRegionMonitorStatus);
755 __regionMonitor.status = newRegionMonitorStatus;
756 __pLocationListener->OnRegionMonitoringStatusChanged(__regionMonitor.status);
759 if (newRegionMonitorStatus == LOC_SVC_STATUS_RUNNING)
761 NotifyRegionCrossedStatus(location);
764 SetNextRegionMonitoringTime();
768 _LocationProviderImpl::NotifyRegionCrossedStatus(const Tizen::Locations::Location& location)
770 int count = __regionMonitor.pRegionList->GetCount();
772 SysLog(NID_LOC, "Number of regions currently monitored is (%d)", count);
774 for (int i = 0; i < count; i++)
776 _RegionInfo* pRegionInfo = static_cast< _RegionInfo* >(__regionMonitor.pRegionList->GetAt(i));
780 Coordinates regionCoordinate = pRegionInfo->GetCoordinate();
781 _RegionState currentState = REGION_STATE_UNKNOWN;
782 _RegionState previousState = pRegionInfo->GetPreviousValidState();
783 bool notifyStateChange = false;
785 currentState = GetRegionCurrentState(*pRegionInfo, location);
786 SysLog(NID_LOC, "Current Region state is (%d) and Previous Region state is (%d)", currentState, previousState);
788 if (currentState != REGION_STATE_UNKNOWN && previousState != currentState)
790 notifyStateChange = true;
791 pRegionInfo->SetValidPreviousState(currentState);
794 if ((pRegionInfo->GetRegionState() == REGION_STATE_INSIDE || pRegionInfo->GetRegionState() == REGION_STATE_UNKNOWN) && currentState == REGION_STATE_OUTSIDE)
796 if (notifyStateChange)
798 SysLog(NID_LOC, "Notify the boundary crossed event as previous valid region state is INSIDE and current state is OUTSIDE.");
799 __pLocationListener->OnRegionLeft(pRegionInfo->GetRegionId());
802 else if ((pRegionInfo->GetRegionState() == REGION_STATE_OUTSIDE || pRegionInfo->GetRegionState() == REGION_STATE_UNKNOWN) && currentState == REGION_STATE_INSIDE)
804 if (notifyStateChange)
806 SysLog(NID_LOC, "Notify the boundary crossed event as previous valid region state is OUTSIDE and current state is INSIDE.");
807 __pLocationListener->OnRegionEntered(pRegionInfo->GetRegionId());
810 pRegionInfo->SetRegionState(currentState);
816 _LocationProviderImpl::GetRegionCurrentState(const _RegionInfo& region, const Location& location)
818 TryReturn(location.GetHorizontalAccuracy() >= 0.0, REGION_STATE_UNKNOWN, "Location received with invalid accuracy");
820 SysSecureLog(NID_LOC, "[RegionID %d] Region Information is (Center latitude: %lf, Center longitude: %lf, Region radius:%lf", region.GetRegionId(), region.GetCoordinate().GetLatitude(),
821 region.GetCoordinate().GetLongitude(), region.GetRadius());
822 SysSecureLog(NID_LOC, "[RegionID %d] Location Information is (Latitude: %lf, Longitude: %lf, Horizontal accuracy:%lf", region.GetRegionId(), location.GetCoordinates().GetLatitude(),
823 location.GetCoordinates().GetLongitude(), location.GetHorizontalAccuracy());
825 _RegionState regionState = REGION_STATE_UNKNOWN;
826 double distanceBtwCenters = region.GetCoordinate().GetDistanceTo(location.GetCoordinates());
827 double regionRadius = region.GetRadius();
828 double locationRadius = location.GetHorizontalAccuracy();
830 SysLog(NID_LOC, "[RegionID %d] The distance between centers is (%lf)", region.GetRegionId(), distanceBtwCenters);
832 if (distanceBtwCenters >= (regionRadius + locationRadius))
834 regionState = REGION_STATE_OUTSIDE;
836 else if (distanceBtwCenters < regionRadius && Double::Compare(locationRadius, 0.0) == 0)
838 SysLog(NID_LOC, "[RegionID %d] Location Radius is 0 and distance < regionRadius", region.GetRegionId());
839 regionState = REGION_STATE_INSIDE;
843 double radiusThreshold = (1 / Math::Sqrt(2)) * locationRadius;
845 if (regionRadius < radiusThreshold)
847 SysLog(NID_LOC, "[RegionID %d] Region circle is less than 50 percent area of the location circle.", region.GetRegionId());
848 regionState = (distanceBtwCenters >= locationRadius) ? REGION_STATE_OUTSIDE : REGION_STATE_UNKNOWN;
854 double overlapRegion = _MathUtils::CalculateOverlapRegion(region, location);
855 double upperThreshold = 0;
856 double lowerThreshold = 0;
857 double occupancy = 0;
859 SysLog(NID_LOC, "[RegionID %d] OverlapRegion is (%lf)", region.GetRegionId(), overlapRegion);
861 if (regionRadius >= locationRadius)
863 // Calculate occupancy % with the location circle
864 SysLog(NID_LOC, "[RegionID %d] Region radius is bigger.", region.GetRegionId());
865 occupancy = (overlapRegion / (Math::GetPi() * locationRadius * locationRadius)) * 100;
870 else if (regionRadius >= radiusThreshold)
872 SysLog(NID_LOC, "[RegionID %d] The ratio of Region radius to location radius is between 0.707 and 1.", region.GetRegionId());
873 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)
875 SysLog(NID_LOC, "[RegionID %d] Threshold value is %lf.", region.GetRegionId(), thresholdValue);
877 occupancy = (overlapRegion / (Math::GetPi() * locationRadius * locationRadius)) * 100;
879 upperThreshold = 50 + thresholdValue;
880 lowerThreshold = 50 - thresholdValue;
883 // Decide the state with as per the inner and outer thresholds
884 SysLog(NID_LOC, "[RegionID %d] Occupancy is (%lf), Upper threshold is (%lf) and lower threshold is (%lf).", region.GetRegionId(), occupancy, upperThreshold, lowerThreshold);
885 regionState = (occupancy >= upperThreshold) ? REGION_STATE_INSIDE : ((occupancy <= lowerThreshold) ? REGION_STATE_OUTSIDE : REGION_STATE_UNKNOWN);
889 SysLog(NID_LOC, "[RegionID %d] Returning region state as (%d).", region.GetRegionId(), regionState);
894 _LocationProviderImpl::NotifyServiceStatus(_LocProviderEventType eventType, LocationServiceStatus svcStatus)
896 std::unique_ptr< _LocProviderEventArg > pLocProviderEventArg(new (std::nothrow) _LocProviderEventArg());
897 if (pLocProviderEventArg)
899 pLocProviderEventArg->SetEventType(eventType);
900 pLocProviderEventArg->SetLocServiceStatus(svcStatus);
902 result r = _Event::FireAsync(*pLocProviderEventArg.get());
903 SysTryReturnVoidResult(NID_LOC, r == E_SUCCESS, r, "[%s] Failed to fire the event.", GetErrorMessage(r));
905 pLocProviderEventArg.release();
912 _LocationProviderImpl::GetUserPrivilege(void)
914 bool hasPrivilege = false;
915 bool gpsEnabled = true;
916 bool wpsEnabled = true;
918 result gps = _SettingInfoImpl::GetValue(L"http://tizen.org/setting/location.gps", gpsEnabled);
919 result wps = _SettingInfoImpl::GetValue(L"http://tizen.org/setting/location.wps", wpsEnabled);
921 hasPrivilege = gpsEnabled | wpsEnabled;
922 if (gps != E_SUCCESS || wps != E_SUCCESS || hasPrivilege == false)
930 _LocationProviderImpl::ActivateRegionMonitoring(bool startUpdate)
932 long long currentTime;
933 SystemTime::GetTicks(currentTime);
934 int DEFAULT_WAITING_TIME = DEFAULT_WAITING_TIME_FOR_FIXING_GPS_LOCATION;
936 SysLog(NID_LOC, "Current system time is %lld and location update request is %d", currentTime, startUpdate);
938 bool gpsEnabled = false;
939 result gps = _SettingInfoImpl::GetValue(L"http://tizen.org/setting/location.gps", gpsEnabled);
940 if (gps == E_SUCCESS && !gpsEnabled)
942 SysLog(NID_LOC, "The GPS setting is OFF. So wait for only 10 seconds.");
943 DEFAULT_WAITING_TIME = DEFAULT_WAITING_TIME_FOR_FIXING_WPS_LOCATION;
946 result r = __regionMonitor.pTimer->Start(DEFAULT_WAITING_TIME * 1000);
947 SysTryReturn(NID_LOC, r == E_SUCCESS, r, r, "[%s] Failed to start the timer. Propogating.", GetErrorMessage(r));
951 _LocationImpl::GetInstance(*__regionMonitor.pLocation)->SetValidity(false);
952 _LocationImpl::GetInstance(*__regionMonitor.pLocation)->SetTimestamp(currentTime);
954 r = __pLocationManager->StartLocationUpdates(__criteria.GetAccuracy(), MIN_LOCATION_UPDATE_INTERVAL, this, __regionMonitor.reqId);
955 SysTryReturn(NID_LOC, r == E_SUCCESS, r, r, "[%s] Failed to start the location updates. Propogating.", GetErrorMessage(r));
956 SysLog(NID_LOC, "Location updates started.");
963 _LocationProviderImpl::StopRegionMonitoring(void)
965 result r = _AlarmImpl::GetInstance(__regionMonitor.pAlarm.get())->Cancel();
966 SysTryLog(NID_LOC, r == E_SUCCESS, "[%s] Failed to stop the alarm. Ignored.", GetErrorMessage(r));
968 r = __regionMonitor.pTimer->Cancel();
969 SysTryLog(NID_LOC, r == E_SUCCESS, "[%s] Failed to stop the timer. Ignored.", GetErrorMessage(r));
971 r = __pLocationManager->StopLocationUpdates(__regionMonitor.reqId);
972 SysTryReturnVoidResult(NID_LOC, r == E_SUCCESS, r, "[%s] All regions are removed but failed to stop the location updates. Ignored.", GetErrorMessage(r));
976 _LocationProviderImpl::SetNextRegionMonitoringTime(void)
978 DateTime alarmDateTime;
979 long long alarmTime = DEFAULT_REGION_MONITORING_CYCLE_INTERVAL;
980 SystemTime::GetCurrentTime(TIME_MODE_WALL, alarmDateTime);
982 SysLog(NID_LOC, "Current System Time is %ls", alarmDateTime.ToString().GetPointer());
984 double speed = DEFAULT_AVG_SPEED;
985 if (__regionMonitor.speed > DEFAULT_AVG_SPEED)
987 SysLog(NID_LOC, "The speed of the user is greater than the default speed. So updating the value.");
988 speed = __regionMonitor.speed;
990 if (__regionMonitor.pLocation->IsValid())
992 const int bufferTime = 5; //Buffer of 5 seconds for determining the alarmTime;
993 double minDistance = _MathUtils::GetShortestDistance(*__regionMonitor.pLocation, *__regionMonitor.pRegionList);
995 long long newAlarmTime = ((int) minDistance / speed) - bufferTime; //Calculate the alarm time based on the shortest distance between current location and nearest region boundary.
997 if (newAlarmTime < DEFAULT_REGION_MONITORING_CYCLE_INTERVAL)
999 SysLog(NID_LOC, "The alarm time is less than 5 seconds. So do not stop the location updates.");
1000 ActivateRegionMonitoring(false);
1005 alarmTime = newAlarmTime;
1009 result r = __pLocationManager->StopLocationUpdates(__regionMonitor.reqId);
1010 SysTryLog(NID_LOC, r == E_SUCCESS, "Failed to stop the location updates.");
1012 alarmDateTime.AddSeconds(alarmTime);
1013 r = _AlarmImpl::GetInstance(__regionMonitor.pAlarm.get())->Set(alarmDateTime, 0, null);
1014 SysTryLog(NID_LOC, r == E_SUCCESS, "Failed to set the alarm for next cycle.");
1016 SysLog(NID_LOC, "Next alarm expires after %ld seconds.", alarmTime);