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_Config.h"
45 #include "FLoc_LocationImpl.h"
46 #include "FLoc_LocationManager.h"
47 #include "FLoc_LocationMonitor.h"
48 #include "FLoc_LocationProviderImpl.h"
49 #include "FLoc_MathUtils.h"
50 #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;
60 namespace Tizen { namespace Locations
63 _LocationProviderImpl::_LocationProviderImpl(void)
64 : Tizen::Base::Runtime::_Event()
65 , __lastLocationAccuracy(LOC_ACCURACY_INVALID)
66 , __pLocationListener(null)
67 , __pLocationManager(null)
71 _LocationProviderImpl::~_LocationProviderImpl(void)
73 UiApp* pAppInstance = Tizen::App::UiApp::GetInstance();
76 _AppManagerImpl* pAppManager = _AppManagerImpl::GetInstance();
79 pAppManager->RemoveActiveAppEventListener(*this);
83 StopLocationUpdates();
84 RemoveAllMonitoringRegions();
88 _LocationProviderImpl::Construct(const LocationCriteria& criteria, ILocationProviderListener& listener)
90 _LocationManager* pLocationManager = _LocationManager::GetInstance();
91 SysTryReturn(NID_LOC, pLocationManager != null, GetLastResult(), GetLastResult(), "[%s] Failed to get the location manager instance.", GetErrorMessage(GetLastResult()));
93 std::unique_ptr< Tizen::Base::Collection::ArrayList, AllElementsDeleter > pRegionList(new (std::nothrow) ArrayList());
94 SysTryReturn(NID_LOC, pRegionList != null, E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY));
95 result r = pRegionList->Construct();
96 SysTryReturn(NID_LOC, r == E_SUCCESS, r, r, "[%s] Failed to construct the list. Propagating.", GetErrorMessage(r));
98 std::unique_ptr< Tizen::Base::Runtime::Timer> pTimer (new (std::nothrow) Timer());
99 SysTryReturn(NID_LOC, pTimer != null, E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY));
100 r = pTimer->Construct(*this);
101 SysTryReturn(NID_LOC, r == E_SUCCESS, r, r, "[%s] Failed to construct the timer. Propagating.", GetErrorMessage(r));
103 std::unique_ptr< Tizen::System::Alarm> pAlarm (new (std::nothrow) Alarm());
104 SysTryReturn(NID_LOC, pAlarm != null, E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY));
105 r = pAlarm->Construct(*this);
106 SysTryReturn(NID_LOC, r == E_SUCCESS, r, r, "[%s] Failed to construct the alarm. Propagating.", GetErrorMessage(r));
108 UiApp* pAppInstance = Tizen::App::UiApp::GetInstance();
109 if (pAppInstance != null)
111 _AppManagerImpl* pAppManager = _AppManagerImpl::GetInstance();
112 SysTryReturn(NID_LOC, pAppManager, E_SYSTEM, E_SYSTEM, "[E_SYSTEM] System error occured.");
114 r = pAppManager->AddActiveAppEventListener(*this);
115 SysTryReturn(NID_LOC, r == E_SUCCESS, r, r, "[%s] Error occured during adding the event listener to app manager. Propagating.", GetErrorMessage(r));
118 std::unique_ptr< Tizen::Locations::Location > pLastLocation(_LocationImpl::GetLocationInstanceN());
119 SysTryReturn(NID_LOC, pLastLocation != null, E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY));
120 std::unique_ptr<Tizen::Locations::Location> pLastRegionLocation (_LocationImpl::GetLocationInstanceN());
121 SysTryReturn(NID_LOC, pLastRegionLocation != null, E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY));
123 _Event::Initialize();
124 _Event::AddListener(*this);
126 __regionMonitor.pRegionList = std::move(pRegionList);
127 __regionMonitor.pTimer = std::move(pTimer);
128 __regionMonitor.pAlarm = std::move(pAlarm);
129 __regionMonitor.pLocation = std::move(pLastRegionLocation);
130 __locationUpdater.pLocation = std::move(pLastLocation);
132 __criteria = criteria;
133 __pLocationListener = &listener;
134 __pLocationManager = pLocationManager;
136 SysLog(NID_LOC, "Location provider constructed with the accuracy (%x).", criteria.GetAccuracy());
141 _LocationProviderImpl::StartLocationUpdatesByInterval(int interval)
143 bool userConsent = GetUserPrivilege();
144 SysTryReturn(NID_LOC, userConsent, E_USER_NOT_CONSENTED, E_USER_NOT_CONSENTED, "[E_USER_NOT_CONSENTED] The user has disabled the required settings.");
145 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);
147 if (__locationUpdater.type == _LOCATION_UPDATE_TYPE_INTERVAL && __locationUpdater.updateInterval == interval)
151 const double INVALID_DISTANCE_THRESHOLD = 0.0;
152 return StartLocationUpdates(_LOCATION_UPDATE_TYPE_INTERVAL, interval, INVALID_DISTANCE_THRESHOLD);
156 _LocationProviderImpl::StartLocationUpdatesByDistance(double distance)
158 bool userConsent = GetUserPrivilege();
159 SysTryReturn(NID_LOC, userConsent, E_USER_NOT_CONSENTED, E_USER_NOT_CONSENTED, "[E_USER_NOT_CONSENTED] The user has disabled the required settings.");
160 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);
161 SysTryReturn(NID_LOC, Double::IsNaN(distance) == false, E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] The distance is NaN.");
163 if (__locationUpdater.type == _LOCATION_UPDATE_TYPE_DISTANCE && (Double::Compare(__locationUpdater.distanceThreshold, distance) == 0))
167 const int INVALID_INTERVAL = 0;
168 return StartLocationUpdates(_LOCATION_UPDATE_TYPE_DISTANCE, INVALID_INTERVAL, distance);
172 _LocationProviderImpl::StopLocationUpdates(void)
174 SysLog(NID_LOC, "Stopping the location updates for the request ID (%ld)", __locationUpdater.reqId);
175 SysTryReturn(NID_LOC, __locationUpdater.type != _LOCATION_UPDATE_TYPE_NONE, E_INVALID_OPERATION, E_INVALID_OPERATION, "[E_INVALID_OPERATION] Location update has not been requested.");
177 result r = __pLocationManager->StopLocationUpdates(__locationUpdater.reqId);
178 ResetLocationUpdates();
183 _LocationProviderImpl::KeepLocationUpdateAwake(bool enable)
185 if (__locationUpdater.awakeEnabled == enable)
189 __locationUpdater.awakeEnabled = enable;
191 UiApp* appInstance = Tizen::App::UiApp::GetInstance();
192 if (appInstance == null) // This is service APP. So should be handled now.
194 SysLog(NID_LOC, "Handling the request awake mode(%d) for the service application.", enable);
197 if (__locationUpdater.type != _LOCATION_UPDATE_TYPE_NONE && __locationUpdater.status == LOC_SVC_STATUS_PAUSED)
199 SysLog(NID_LOC, "Requesting to start the location updates as the update type is (%x)", __locationUpdater.type);
200 __locationUpdater.status = LOC_SVC_STATUS_NOT_FIXED;
201 __pLocationManager->StartLocationUpdates(__criteria.GetAccuracy(), __locationUpdater.updateInterval, this, __locationUpdater.reqId);
203 NotifyServiceStatus(_LOC_PRV_EVENT_SEND_LOC_SVC_CB, __locationUpdater.status);
208 if (__locationUpdater.type != _LOCATION_UPDATE_TYPE_NONE && (__locationUpdater.status == LOC_SVC_STATUS_RUNNING || __locationUpdater.status == LOC_SVC_STATUS_NOT_FIXED))
210 SysLog(NID_LOC, "Requesting to stop the location updates as the update type is (%x)", __locationUpdater.type);
211 __locationUpdater.status = LOC_SVC_STATUS_PAUSED;
212 __pLocationManager->StopLocationUpdates(__locationUpdater.reqId);
214 NotifyServiceStatus(_LOC_PRV_EVENT_SEND_LOC_SVC_CB, __locationUpdater.status);
221 _LocationProviderImpl::AddMonitoringRegion(const Coordinates& regionCenter, double radius, RegionId& regionId)
223 bool userConsent = GetUserPrivilege();
224 SysTryReturn(NID_LOC, userConsent, E_USER_NOT_CONSENTED, E_USER_NOT_CONSENTED, "[E_USER_NOT_CONSENTED] The user has disabled the required settings.");
225 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.");
226 SysTryReturn(NID_LOC, (!Double::IsNaN(radius) && !Double::IsNaN(regionCenter.GetLatitude()) && !Double::IsNaN(regionCenter.GetLongitude())),
227 E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] One of the value is NaN.");
228 SysLog(NID_LOC, "Requested to add the monitoring region with center (Latitude: %lf, Longitude %lf) and radius (%lf).", regionCenter.GetLatitude(), regionCenter.GetLongitude(), radius);
230 static int nextRegionId = 0;
232 std::unique_ptr< _RegionInfo > pRegionInfo(new (std::nothrow) _RegionInfo(regionCenter, radius, nextRegionId));
233 SysTryReturn(NID_LOC, pRegionInfo != null, E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY));
234 result r = __regionMonitor.pRegionList->Add(*pRegionInfo.get());
235 SysTryReturn(NID_LOC, r == E_SUCCESS, r, r, "[%s] Failed to add the Region info into the list. Propogated.", GetErrorMessage(r));
237 pRegionInfo.release();
238 regionId = nextRegionId;
241 if (__regionMonitor.status != LOC_SVC_STATUS_IDLE)
246 r = ActivateRegionMonitoring();
247 SysTryCatch(NID_LOC, r == E_SUCCESS, , r, "[%s] Failed to start the region monitoring. Propogating.", GetErrorMessage(r));
249 __regionMonitor.status = LOC_SVC_STATUS_NOT_FIXED;
250 NotifyServiceStatus(_LOC_PRV_EVENT_SEND_MONITOR_SVC_CB, __regionMonitor.status);
254 __regionMonitor.pRegionList->RemoveAt(0);
259 _LocationProviderImpl::RemoveMonitoringRegion(RegionId regionId)
261 int count = __regionMonitor.pRegionList->GetCount();
262 bool isIdValid = false;
263 SysLog(NID_LOC, "Total regions currently monitored is (%d).", count);
265 for (int i = 0; i < count; i++)
267 _RegionInfo* pRegionInfo = static_cast< _RegionInfo* >(__regionMonitor.pRegionList->GetAt(i));
268 if (regionId == pRegionInfo->GetRegionId())
270 __regionMonitor.pRegionList->RemoveAt(i, true);
276 SysTryReturn(NID_LOC, isIdValid == true, E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] The region ID is invalid.");
277 if (__regionMonitor.pRegionList->GetCount() == 0)
279 __regionMonitor.status = LOC_SVC_STATUS_IDLE;
280 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.
282 __lastLocationAccuracy = LOC_ACCURACY_INVALID;
284 StopRegionMonitoring();
290 _LocationProviderImpl::RemoveAllMonitoringRegions(void)
292 __regionMonitor.pRegionList->RemoveAll(true);
294 if (__regionMonitor.status != LOC_SVC_STATUS_IDLE)
296 __regionMonitor.status = LOC_SVC_STATUS_IDLE;
297 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.
299 __lastLocationAccuracy = LOC_ACCURACY_INVALID;
301 StopRegionMonitoring();
306 LocationServiceStatus
307 _LocationProviderImpl::GetLocationUpdateStatus(void) const
309 return __locationUpdater.status;
312 LocationServiceStatus
313 _LocationProviderImpl::GetRegionMonitoringStatus(void) const
315 return __regionMonitor.status;
319 _LocationProviderImpl::GetCurrentAccuracy(void) const
321 return __lastLocationAccuracy;
325 _LocationProviderImpl::GetLocation(const LocationCriteria& criteria)
327 Location retLocation(_LocationImpl::GetLocationInstance());
329 bool userConsent = GetUserPrivilege();
330 SysTryReturn(NID_LOC, userConsent, retLocation, E_USER_NOT_CONSENTED, "[E_USER_NOT_CONSENTED] The user has disabled the required settings.");
332 Location* pLocation = null;
333 const int MAX_TIMEOUT = 30;
334 result r = E_SUCCESS;
335 _LocationManager* pLocationManager = null;
337 SysLog(NID_LOC, "Requesting for single location with criteria (%x).", criteria.GetAccuracy());
339 std::unique_ptr< _LocationMonitor > pLocMonitor(new (std::nothrow) _LocationMonitor());
340 SysTryCatch(NID_LOC, pLocMonitor, , E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY));
341 r = pLocMonitor->Construct(MAX_TIMEOUT, criteria.GetAccuracy());
342 SysTryCatch(NID_LOC, r == E_SUCCESS, , r, "[%s] Failed to construct the Location Monitor.", GetErrorMessage(r));
344 pLocationManager = _LocationManager::GetInstance();
345 SysTryCatch(NID_LOC, pLocationManager, , r, "[%s] Failed to get the location manager instance.", GetErrorMessage(r));
346 r = pLocationManager->RegisterLocationMonitor(pLocMonitor.get());
347 SysTryCatch(NID_LOC, r == E_SUCCESS, , r, "[%s] Failed to register the location monitor.", GetErrorMessage(r));
349 r = pLocMonitor->Wait();
352 pLocation = pLocMonitor->GetLocationN();
356 retLocation = *pLocation;
360 SetLastResult(E_LOCATION_UNAVAILABLE);
370 _LocationProviderImpl::GetLastKnownLocation(void)
372 Location retLocation(_LocationImpl::GetLocationInstance());
374 bool userConsent = GetUserPrivilege();
375 SysTryReturn(NID_LOC, userConsent, retLocation, E_USER_NOT_CONSENTED, "[E_USER_NOT_CONSENTED] The user has disabled the required settings.");
377 _LocationManager* pLocationManager = _LocationManager::GetInstance();
378 SysTryReturn(NID_LOC, pLocationManager, retLocation, E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY));
380 retLocation = pLocationManager->GetLastKnownLocation();
381 if (!retLocation.IsValid())
383 SetLastResult(E_LOCATION_UNAVAILABLE);
395 _LocationProviderImpl::OnLocationUpdated(RequestId reqId, const Tizen::Locations::Location& location)
397 SysLog(NID_LOC, "Location is updated from Location Manager for the request ID (%ld).", reqId);
399 std::unique_ptr< Location > pLocation(new (std::nothrow) Location(location));
400 SysTryReturnVoidResult(NID_LOC, pLocation, E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY));
401 std::unique_ptr< _LocProviderEventArg > pLocProviderEventArg(new (std::nothrow) _LocProviderEventArg());
402 SysTryReturnVoidResult(NID_LOC, pLocProviderEventArg, E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY));
404 pLocProviderEventArg->SetEventType(_LOC_PRV_EVENT_SEND_LOC);
405 pLocProviderEventArg->SetLocation(pLocation.get());
406 pLocProviderEventArg->SetRequestId(reqId);
409 result r = _Event::FireAsync(*pLocProviderEventArg);
410 SysTryReturnVoidResult(NID_LOC, r == E_SUCCESS, r, "[%s] Failed to fire the event.", GetErrorMessage(r));
411 pLocProviderEventArg.release();
417 _LocationProviderImpl::OnLocationEventReceivedN(RequestId reqId, Tizen::Locations::Location& location)
419 SysLog(NID_LOC, "Location Event received.");
421 LocationAccuracy currentAccuracy = LOC_ACCURACY_INVALID;
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)
459 if (isNew) // Copy the location only if it is new.
461 *__regionMonitor.pLocation = location;
464 if (currentAccuracy != LOC_ACCURACY_INVALID && currentAccuracy <= __criteria.GetAccuracy())
466 SysLog(NID_LOC, "Location criteria (accuracy: %ld) is met for handling region monitoring.", currentAccuracy);
467 result r = __regionMonitor.pTimer->Cancel();
468 SysTryLog(NID_LOC, r == E_SUCCESS, "Failed to cancel the timer.");
470 r = __pLocationManager->StopLocationUpdates(__regionMonitor.reqId);
471 SysTryLog(NID_LOC, r == E_SUCCESS, "Failed to stop the location updates.");
472 HandleRegionMonitoring(location, isNew);
476 SysLog(NID_LOC, "Location criteria (accuracy: %ld) is not met for handling region monitoring.", currentAccuracy);
484 _LocationProviderImpl::OnLocationUpdateStatusChanged(Tizen::Locations::LocationServiceStatus locSvcStatus)
486 __pLocationListener->OnLocationUpdateStatusChanged(locSvcStatus);
490 _LocationProviderImpl::OnRegionMonitoringStatusChanged(Tizen::Locations::LocationServiceStatus locSvcStatus)
492 __pLocationListener->OnRegionMonitoringStatusChanged(locSvcStatus);
496 _LocationProviderImpl::OnActiveAppChanged(const Tizen::App::AppId& appId)
498 Tizen::App::App* pApp = Tizen::App::App::GetInstance();
499 Tizen::App::AppId currentAppId = pApp->GetAppId();
501 SysLog(NID_LOC, "Active App ID is (%ls) and the current app Id is (%ls)", appId.GetPointer(), currentAppId.GetPointer());
503 if (currentAppId == appId)
505 SysLog(NID_LOC, "Application is active.");
507 if (__locationUpdater.status == LOC_SVC_STATUS_PAUSED)
509 SysLog(NID_LOC, "Start the location updates as the location update status is PAUSED.");
510 __pLocationManager->StartLocationUpdates(__criteria.GetAccuracy(), __locationUpdater.updateInterval, this, __locationUpdater.reqId);
511 __locationUpdater.status = LOC_SVC_STATUS_NOT_FIXED;
512 __pLocationListener->OnLocationUpdateStatusChanged(__locationUpdater.status);
517 SysLog(NID_LOC, "Application is not active.");
519 if (__locationUpdater.awakeEnabled == false && (__locationUpdater.status == LOC_SVC_STATUS_RUNNING || __locationUpdater.status == LOC_SVC_STATUS_NOT_FIXED))
521 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);
522 __pLocationManager->StopLocationUpdates(__locationUpdater.reqId);
523 __locationUpdater.status = LOC_SVC_STATUS_PAUSED;
524 __pLocationListener->OnLocationUpdateStatusChanged(__locationUpdater.status);
530 _LocationProviderImpl::OnAlarmExpired(Alarm& alarm)
532 SysLog(NID_LOC, "Region Monitor Alarm expired.");
533 result r = ActivateRegionMonitoring();
534 SysTryReturnVoidResult(NID_LOC, r == E_SUCCESS, r, "[%s] Failed to start the region monitoring. Propogating.", GetErrorMessage(r));
538 _LocationProviderImpl::OnTimerExpired(Timer& timer)
540 SysLog(NID_LOC, "Region Monitor timer expired due to unavailability of location information.");
541 __pLocationManager->StopLocationUpdates(__regionMonitor.reqId);
542 HandleRegionMonitoring(*__regionMonitor.pLocation, __regionMonitor.pLocation->IsValid());
546 _LocationProviderImpl::StartLocationUpdates(LocationUpdateType updateType, int interval, double distance)
548 result r = E_SUCCESS;
549 bool startUpdate = true;
551 if (updateType == _LOCATION_UPDATE_TYPE_INTERVAL)
553 __locationUpdater.updateInterval = interval;
555 else if (updateType == _LOCATION_UPDATE_TYPE_DISTANCE)
557 __locationUpdater.updateInterval = DEFAULT_DISTANCE_CHECKING_INTERVAL;
558 __locationUpdater.distanceThreshold = distance;
561 if (!__locationUpdater.awakeEnabled)
563 UiApp* pAppInstance = Tizen::App::UiApp::GetInstance();
564 if (pAppInstance == null)
570 AppUiState appUiState = pAppInstance->GetAppUiState();
572 if (appUiState == APP_UI_STATE_BACKGROUND)
574 SysLog(NID_LOC, "App is background.");
582 if (__locationUpdater.type != _LOCATION_UPDATE_TYPE_NONE)
584 SysLog(NID_LOC, "Update session already running. Updating the interval to %d seconds", __locationUpdater.updateInterval);
585 r = __pLocationManager->ChangeUpdateInterval(__locationUpdater.reqId, __locationUpdater.updateInterval);
586 SysTryCatch(NID_LOC, r == E_SUCCESS, , r, "[%s] Failed to update the request interval. Propagating.", GetErrorMessage(r));
587 __locationUpdater.type = updateType;
592 r = __pLocationManager->StartLocationUpdates(__criteria.GetAccuracy(), __locationUpdater.updateInterval, this, __locationUpdater.reqId);
593 SysTryCatch(NID_LOC, r == E_SUCCESS, , r, "[%s] Failed to start the Native location updates. Propagating.", GetErrorMessage(r));
594 __locationUpdater.status = LOC_SVC_STATUS_NOT_FIXED;
599 __locationUpdater.status = LOC_SVC_STATUS_PAUSED;
602 __locationUpdater.type = updateType;
604 SysLog(NID_LOC, "Update type is (%x). The request Id is (%ld) and the update status is (%x).", __locationUpdater.type, __locationUpdater.reqId, __locationUpdater.status);
605 NotifyServiceStatus(_LOC_PRV_EVENT_SEND_LOC_SVC_CB, __locationUpdater.status);
610 __locationUpdater.type = _LOCATION_UPDATE_TYPE_NONE;
615 _LocationProviderImpl::CheckDistanceThreshold(const Location& oldPosition, const Location& newPosition)
617 double displacement = 0.0;
618 const Coordinates coordOld = oldPosition.GetCoordinates();
619 const Coordinates coordNew = newPosition.GetCoordinates();
621 if (__locationUpdater.firstLocationUpdate)
623 SysLog(NID_LOC, "First location update. So send true.");
624 __locationUpdater.firstLocationUpdate = false;
627 displacement = coordOld.GetDistanceTo(coordNew);
628 SysLog(NID_LOC, "Displacement is (%lf)", displacement);
629 return ((displacement > __locationUpdater.distanceThreshold) ? true : false);
633 _LocationProviderImpl::ResetLocationUpdates(void)
635 __locationUpdater.firstLocationUpdate = true;
636 __locationUpdater.reqId = -1;
637 __lastLocationAccuracy = LOC_ACCURACY_INVALID;
638 __locationUpdater.type = _LOCATION_UPDATE_TYPE_NONE;
639 __locationUpdater.status = LOC_SVC_STATUS_IDLE;
640 __locationUpdater.updateInterval = 0;
641 __locationUpdater.distanceThreshold = 0.0;
645 _LocationProviderImpl::FireImpl(Tizen::Base::Runtime::IEventListener& listener, const Tizen::Base::Runtime::IEventArg& arg)
647 _ILocProviderEventListener* pLocProviderEventListener = dynamic_cast< _ILocProviderEventListener* >(&listener);
648 SysTryReturnVoidResult(NID_LOC, pLocProviderEventListener, E_SYSTEM, "[E_INVALID_ARG] The listener is null.");
650 IEventArg* pArg = const_cast< IEventArg* >(&arg);
651 _LocProviderEventArg* pEventArg = dynamic_cast< _LocProviderEventArg* >(pArg);
652 SysTryReturnVoidResult(NID_LOC, pEventArg, E_SYSTEM, "[E_INVALID_ARG] Event argument is null.");
654 _LocProviderEventType eventType = pEventArg->GetEventType();
657 case _LOC_PRV_EVENT_SEND_LOC:
658 pLocProviderEventListener->OnLocationEventReceivedN(pEventArg->GetRequestId(), *pEventArg->GetLocationN());
661 case _LOC_PRV_EVENT_SEND_LOC_SVC_CB:
662 pLocProviderEventListener->OnLocationUpdateStatusChanged(pEventArg->GetLocServiceStatus());
665 case _LOC_PRV_EVENT_SEND_MONITOR_SVC_CB:
666 pLocProviderEventListener->OnRegionMonitoringStatusChanged(pEventArg->GetLocServiceStatus());
672 _LocationProviderImpl::HandleLocationUpdate(Tizen::Locations::Location& location, bool isNew)
674 LocationServiceStatus newLocationUpdateStatus = __locationUpdater.status;
678 if (__locationUpdater.type != _LOCATION_UPDATE_TYPE_NONE && __locationUpdater.status != LOC_SVC_STATUS_PAUSED)
680 newLocationUpdateStatus = LOC_SVC_STATUS_RUNNING;
683 else if (_LocationImpl::GetInstance(location)->IsDenied())
685 SysLog(NID_LOC, "User consent not available.");
686 if (__locationUpdater.type != _LOCATION_UPDATE_TYPE_NONE && __locationUpdater.status != LOC_SVC_STATUS_PAUSED)
688 newLocationUpdateStatus = LOC_SVC_STATUS_DENIED;
693 SysLog(NID_LOC, "Invalid Location Update.");
694 if (__locationUpdater.type != _LOCATION_UPDATE_TYPE_NONE && __locationUpdater.status != LOC_SVC_STATUS_PAUSED)
696 newLocationUpdateStatus = LOC_SVC_STATUS_NOT_FIXED;
700 if (newLocationUpdateStatus != __locationUpdater.status)
702 SysLog(NID_LOC, "Location Update Satus changed to (%x). Notify the status.", newLocationUpdateStatus);
703 __locationUpdater.status = newLocationUpdateStatus;
704 __pLocationListener->OnLocationUpdateStatusChanged(__locationUpdater.status);
707 if (newLocationUpdateStatus == LOC_SVC_STATUS_RUNNING)
709 if (__locationUpdater.type == _LOCATION_UPDATE_TYPE_DISTANCE)
711 if (CheckDistanceThreshold(*__locationUpdater.pLocation.get(), location) == true)
713 SysLog(NID_LOC, "Location displacement exceeds the distance threshold (%lf). Notify the location.", __locationUpdater.distanceThreshold);
714 __pLocationListener->OnLocationUpdated(location);
715 *__locationUpdater.pLocation.get() = location;
718 else if (__locationUpdater.type == _LOCATION_UPDATE_TYPE_INTERVAL)
720 SysLog(NID_LOC, "Location time interval expired. Notify the location.");
721 __pLocationListener->OnLocationUpdated(location);
722 *__locationUpdater.pLocation.get() = location;
728 _LocationProviderImpl::HandleRegionMonitoring(Tizen::Locations::Location& location, bool isNew)
730 LocationServiceStatus newRegionMonitorStatus = __regionMonitor.status;
734 newRegionMonitorStatus = LOC_SVC_STATUS_RUNNING;
736 else if (_LocationImpl::GetInstance(location)->IsDenied())
738 newRegionMonitorStatus = LOC_SVC_STATUS_DENIED;
742 newRegionMonitorStatus = LOC_SVC_STATUS_NOT_FIXED;
745 if (newRegionMonitorStatus != __regionMonitor.status)
747 SysLog(NID_LOC, "Region Monitoring Satus changed to (%x). Notify the status.", newRegionMonitorStatus);
748 __regionMonitor.status = newRegionMonitorStatus;
749 __pLocationListener->OnRegionMonitoringStatusChanged(__regionMonitor.status);
752 if (newRegionMonitorStatus == LOC_SVC_STATUS_RUNNING)
754 NotifyRegionCrossedStatus(location);
757 SetNextRegionMonitoringTime();
761 _LocationProviderImpl::NotifyRegionCrossedStatus(const Tizen::Locations::Location& location)
763 int count = __regionMonitor.pRegionList->GetCount();
765 SysLog(NID_LOC, "Number of regions currently monitored is (%d)", count);
767 for (int i = 0; i < count; i++)
769 _RegionInfo* pRegionInfo = static_cast< _RegionInfo* >(__regionMonitor.pRegionList->GetAt(i));
773 Coordinates regionCoordinate = pRegionInfo->GetCoordinate();
774 _RegionState currentState = REGION_STATE_UNKNOWN;
775 _RegionState previousState = pRegionInfo->GetPreviousValidState();
776 bool notifyStateChange = false;
778 currentState = GetRegionCurrentState(*pRegionInfo, location);
779 SysLog(NID_LOC, "Current Region state is (%d) and Previous Region state is (%d)", currentState, previousState);
781 if (currentState != REGION_STATE_UNKNOWN && previousState != currentState)
783 notifyStateChange = true;
784 pRegionInfo->SetValidPreviousState(currentState);
787 if ((pRegionInfo->GetRegionState() == REGION_STATE_INSIDE || pRegionInfo->GetRegionState() == REGION_STATE_UNKNOWN) && currentState == REGION_STATE_OUTSIDE)
789 if (notifyStateChange)
791 SysLog(NID_LOC, "Notify the boundary crossed event as previous valid region state is INSIDE and current state is OUTSIDE.");
792 __pLocationListener->OnRegionLeft(pRegionInfo->GetRegionId());
795 else if ((pRegionInfo->GetRegionState() == REGION_STATE_OUTSIDE || pRegionInfo->GetRegionState() == REGION_STATE_UNKNOWN) && currentState == REGION_STATE_INSIDE)
797 if (notifyStateChange)
799 SysLog(NID_LOC, "Notify the boundary crossed event as previous valid region state is OUTSIDE and current state is INSIDE.");
800 __pLocationListener->OnRegionEntered(pRegionInfo->GetRegionId());
803 pRegionInfo->SetRegionState(currentState);
809 _LocationProviderImpl::GetRegionCurrentState(const _RegionInfo& region, const Location& location)
811 TryReturn(location.GetHorizontalAccuracy() >= 0.0, REGION_STATE_UNKNOWN, "Location received with invalid accuracy");
813 SysLog(NID_LOC, "[RegionID %d] Region Information is (Center latitude: %lf, Center longitude: %lf, Region radius:%lf", region.GetRegionId(), region.GetCoordinate().GetLatitude(),
814 region.GetCoordinate().GetLongitude(), region.GetRadius());
815 SysLog(NID_LOC, "[RegionID %d] Location Information is (Latitude: %lf, Longitude: %lf, Horizontal accuracy:%lf", region.GetRegionId(), location.GetCoordinates().GetLatitude(),
816 location.GetCoordinates().GetLongitude(), location.GetHorizontalAccuracy());
818 _RegionState regionState = REGION_STATE_UNKNOWN;
819 double distanceBtwCenters = region.GetCoordinate().GetDistanceTo(location.GetCoordinates());
820 double regionRadius = region.GetRadius();
821 double locationRadius = location.GetHorizontalAccuracy();
823 SysLog(NID_LOC, "[RegionID %d] The distance between centers is (%lf)", region.GetRegionId(), distanceBtwCenters);
825 if (distanceBtwCenters >= (regionRadius + locationRadius))
827 regionState = REGION_STATE_OUTSIDE;
829 else if (distanceBtwCenters < regionRadius && Double::Compare(locationRadius, 0.0) == 0)
831 SysLog(NID_LOC, "[RegionID %d] Location Radius is 0 and distance < regionRadius", region.GetRegionId());
832 regionState = REGION_STATE_INSIDE;
836 double radiusThreshold = (1 / Math::Sqrt(2)) * locationRadius;
838 if (regionRadius < radiusThreshold)
840 SysLog(NID_LOC, "[RegionID %d] Region circle is less than 50 percent area of the location circle.", region.GetRegionId());
841 regionState = (distanceBtwCenters >= locationRadius) ? REGION_STATE_OUTSIDE : REGION_STATE_UNKNOWN;
847 double overlapRegion = _MathUtils::CalculateOverlapRegion(region, location);
848 double upperThreshold = 0;
849 double lowerThreshold = 0;
850 double occupancy = 0;
852 SysLog(NID_LOC, "[RegionID %d] OverlapRegion is (%lf)", region.GetRegionId(), overlapRegion);
854 if (regionRadius >= locationRadius)
856 // Calculate occupancy % with the location circle
857 SysLog(NID_LOC, "[RegionID %d] Region radius is bigger.", region.GetRegionId());
858 occupancy = (overlapRegion / (Math::GetPi() * locationRadius * locationRadius)) * 100;
863 else if (regionRadius >= radiusThreshold)
865 SysLog(NID_LOC, "[RegionID %d] The ratio of Region radius to location radius is between 0.707 and 1.", region.GetRegionId());
866 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)
868 SysLog(NID_LOC, "[RegionID %d] Threshold value is %lf.", region.GetRegionId(), thresholdValue);
870 occupancy = (overlapRegion / (Math::GetPi() * locationRadius * locationRadius)) * 100;
872 upperThreshold = 50 + thresholdValue;
873 lowerThreshold = 50 - thresholdValue;
876 // Decide the state with as per the inner and outer thresholds
877 SysLog(NID_LOC, "[RegionID %d] Occupancy is (%lf), Upper threshold is (%lf) and lower threshold is (%lf).", region.GetRegionId(), occupancy, upperThreshold, lowerThreshold);
878 regionState = (occupancy >= upperThreshold) ? REGION_STATE_INSIDE : ((occupancy <= lowerThreshold) ? REGION_STATE_OUTSIDE : REGION_STATE_UNKNOWN);
882 SysLog(NID_LOC, "[RegionID %d] Returning region state as (%d).", region.GetRegionId(), regionState);
887 _LocationProviderImpl::NotifyServiceStatus(_LocProviderEventType eventType, LocationServiceStatus svcStatus)
889 std::unique_ptr< _LocProviderEventArg > pLocProviderEventArg(new (std::nothrow) _LocProviderEventArg());
890 if (pLocProviderEventArg)
892 pLocProviderEventArg->SetEventType(eventType);
893 pLocProviderEventArg->SetLocServiceStatus(svcStatus);
895 result r = _Event::FireAsync(*pLocProviderEventArg.get());
896 SysTryReturnVoidResult(NID_LOC, r == E_SUCCESS, r, "[%s] Failed to fire the event.", GetErrorMessage(r));
898 pLocProviderEventArg.release();
905 _LocationProviderImpl::GetUserPrivilege(void)
907 _LocationManager* pLocMgr = _LocationManager::GetInstance();
908 SysTryReturn(NID_LOC, pLocMgr, false, E_SYSTEM, "[E_SYSTEM] Failed to get the location manager instance.");
910 bool appSettingEnabled = pLocMgr->IsAppEnabled();
911 if (appSettingEnabled == false)
916 bool hasPrivilege = false;
917 bool gpsEnabled = true;
918 bool wpsEnabled = true;
920 result gps = _SettingInfoImpl::GetValue(L"http://tizen.org/setting/location.gps", gpsEnabled);
921 result wps = _SettingInfoImpl::GetValue(L"http://tizen.org/setting/location.wps", wpsEnabled);
923 hasPrivilege = gpsEnabled | wpsEnabled;
924 if (gps != E_SUCCESS || wps != E_SUCCESS || hasPrivilege == false)
932 _LocationProviderImpl::ActivateRegionMonitoring(void)
934 long long currentTime;
935 SystemTime::GetTicks(currentTime);
937 SysLog(NID_LOC, "Current system time is %lld", currentTime);
939 _LocationImpl::GetInstance(*__regionMonitor.pLocation)->SetValidity(false);
940 _LocationImpl::GetInstance(*__regionMonitor.pLocation)->SetTimestamp(currentTime);
942 result r = __regionMonitor.pTimer->Start(DEFAULT_WAITING_TIME_FOR_FIXING_LOCATION * 1000);
943 SysTryReturn(NID_LOC, r == E_SUCCESS, r, r, "[%s] Failed to start the timer. Propogating.", GetErrorMessage(r));
945 r = __pLocationManager->StartLocationUpdates(__criteria.GetAccuracy(), MIN_LOCATION_UPDATE_INTERVAL, this, __regionMonitor.reqId);
946 SysTryReturn(NID_LOC, r == E_SUCCESS, r, r, "[%s] Failed to start the location updates. Propogating.", GetErrorMessage(r));
948 SysLog(NID_LOC, "Timer & Location updates are started.");
953 _LocationProviderImpl::StopRegionMonitoring(void)
955 result r = _AlarmImpl::GetInstance(__regionMonitor.pAlarm.get())->Cancel();
956 SysTryLog(NID_LOC, r == E_SUCCESS, "[%s] Failed to stop the alarm. Ignored.", GetErrorMessage(r));
958 r = __regionMonitor.pTimer->Cancel();
959 SysTryLog(NID_LOC, r == E_SUCCESS, "[%s] Failed to stop the timer. Ignored.", GetErrorMessage(r));
961 r = __pLocationManager->StopLocationUpdates(__regionMonitor.reqId);
962 SysTryReturnVoidResult(NID_LOC, r == E_SUCCESS, r, "[%s] All regions are removed but failed to stop the location updates. Ignored.", GetErrorMessage(r));
966 _LocationProviderImpl::SetNextRegionMonitoringTime(void)
968 DateTime alarmDateTime;
969 long long alarmTime = DEFAULT_REGION_MONITORING_CYCLE_INTERVAL;
970 SystemTime::GetCurrentTime(TIME_MODE_WALL, alarmDateTime);
972 SysLog(NID_LOC, "Current System Time is %ls", alarmDateTime.ToString().GetPointer());
974 if (__regionMonitor.pLocation->IsValid())
976 const int bufferTime = 5; //Buffer of 5 seconds for determining the alarmTime;
977 double minDistance = _MathUtils::GetShortestDistance(*__regionMonitor.pLocation, *__regionMonitor.pRegionList);
978 long long newAlarmTime = ((int) minDistance / DEFAULT_AVG_SPEED) - bufferTime; //Calculate the alarm time based on the shortest distance between current location and nearest region boundary.
980 if (newAlarmTime > alarmTime)
982 alarmTime = newAlarmTime;
985 alarmDateTime.AddSeconds(alarmTime);
986 result r = _AlarmImpl::GetInstance(__regionMonitor.pAlarm.get())->Set(alarmDateTime, 0, null);
987 SysTryLog(NID_LOC, r == E_SUCCESS, "Failed to set the alarm for next cycle.");
989 SysLog(NID_LOC, "Next alarm expires after %ld seconds.", alarmTime);