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)
91 _LocationManager* pLocationManager = null;
93 pLocationManager = _LocationManager::GetInstance();
94 SysTryReturn(NID_LOC, pLocationManager != null, GetLastResult(), GetLastResult(), "[%s] Failed to get the location manager instance.", GetErrorMessage(GetLastResult()));
96 std::unique_ptr< Tizen::Base::Collection::ArrayList, AllElementsDeleter > pRegionList(new (std::nothrow) ArrayList());
97 SysTryReturn(NID_LOC, pRegionList != null, E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY));
99 r = pRegionList->Construct();
100 SysTryReturn(NID_LOC, r == E_SUCCESS, r, r, "[%s] Failed to construct the list. Propagating.", GetErrorMessage(r));
102 std::unique_ptr< Tizen::Base::Runtime::Timer> pTimer (new (std::nothrow) Timer());
103 SysTryReturn(NID_LOC, pTimer != null, E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY));
105 r = pTimer->Construct(*this);
106 SysTryReturn(NID_LOC, r == E_SUCCESS, r, r, "[%s] Failed to construct the timer. Propagating.", GetErrorMessage(r));
108 std::unique_ptr< Tizen::System::Alarm> pAlarm (new (std::nothrow) Alarm());
109 SysTryReturn(NID_LOC, pAlarm != null, E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY));
111 r = pAlarm->Construct(*this);
112 SysTryReturn(NID_LOC, r == E_SUCCESS, r, r, "[%s] Failed to construct the alarm. Propagating.", GetErrorMessage(r));
114 UiApp* pAppInstance = Tizen::App::UiApp::GetInstance();
115 if (pAppInstance != null)
117 _AppManagerImpl* pAppManager = _AppManagerImpl::GetInstance();
118 SysTryReturn(NID_LOC, pAppManager, E_SYSTEM, E_SYSTEM, "[E_SYSTEM] System error occured.");
120 r = pAppManager->AddActiveAppEventListener(*this);
121 SysTryReturn(NID_LOC, r == E_SUCCESS, r, r, "[%s] Error occured during adding the event listener to app manager. Propagating.", GetErrorMessage(r));
124 std::unique_ptr< Tizen::Locations::Location > pLastLocation(_LocationImpl::GetLocationInstanceN());
125 SysTryReturn(NID_LOC, pLastLocation != null, E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY));
127 std::unique_ptr<Tizen::Locations::Location> pLastRegionLocation (_LocationImpl::GetLocationInstanceN());
128 SysTryReturn(NID_LOC, pLastRegionLocation != null, E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY));
130 _Event::Initialize();
131 _Event::AddListener(*this);
133 __regionMonitor.pRegionList = std::move(pRegionList);
134 __regionMonitor.pTimer = std::move(pTimer);
135 __regionMonitor.pAlarm = std::move(pAlarm);
136 __regionMonitor.pLocation = std::move(pLastRegionLocation);
137 __locationUpdater.pLocation = std::move(pLastLocation);
139 __criteria = criteria;
140 __pLocationListener = &listener;
141 __pLocationManager = pLocationManager;
143 SysLog(NID_LOC, "Location provider constructed with the accuracy (%x).", criteria.GetAccuracy());
149 _LocationProviderImpl::StartLocationUpdatesByInterval(int interval)
151 bool userConsent = GetUserPrivilege();
152 SysTryReturn(NID_LOC, userConsent, E_USER_NOT_CONSENTED, E_USER_NOT_CONSENTED, "[E_USER_NOT_CONSENTED] The user has disabled the required settings.");
154 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);
156 if (__locationUpdater.type == _LOCATION_UPDATE_TYPE_INTERVAL && __locationUpdater.updateInterval == interval)
161 const double INVALID_DISTANCE_THRESHOLD = 0.0;
162 return StartLocationUpdates(_LOCATION_UPDATE_TYPE_INTERVAL, interval, INVALID_DISTANCE_THRESHOLD);
166 _LocationProviderImpl::StartLocationUpdatesByDistance(double distance)
168 bool userConsent = GetUserPrivilege();
169 SysTryReturn(NID_LOC, userConsent, E_USER_NOT_CONSENTED, E_USER_NOT_CONSENTED, "[E_USER_NOT_CONSENTED] The user has disabled the required settings.");
171 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);
173 SysTryReturn(NID_LOC, Double::IsNaN(distance) == false, E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] The distance is NaN.");
175 if (__locationUpdater.type == _LOCATION_UPDATE_TYPE_DISTANCE && (Double::Compare(__locationUpdater.distanceThreshold, distance) == 0))
180 const int INVALID_INTERVAL = 0;
181 return StartLocationUpdates(_LOCATION_UPDATE_TYPE_DISTANCE, INVALID_INTERVAL, distance);
185 _LocationProviderImpl::StopLocationUpdates(void)
187 SysLog(NID_LOC, "Stopping the location updates for the request ID (%ld)", __locationUpdater.reqId);
189 SysTryReturn(NID_LOC, __locationUpdater.type != _LOCATION_UPDATE_TYPE_NONE, E_INVALID_OPERATION, E_INVALID_OPERATION, "[E_INVALID_OPERATION] Location update has not been requested.");
191 result r = __pLocationManager->StopLocationUpdates(__locationUpdater.reqId);
193 ResetLocationUpdates();
199 _LocationProviderImpl::KeepLocationUpdateAwake(bool enable)
201 if (__locationUpdater.awakeEnabled == enable)
205 __locationUpdater.awakeEnabled = enable;
207 UiApp* appInstance = Tizen::App::UiApp::GetInstance();
208 if (appInstance == null) // This is service APP. So should be handled now.
210 SysLog(NID_LOC, "Handling the request awake mode(%d) for the service application.", enable);
213 if (__locationUpdater.type != _LOCATION_UPDATE_TYPE_NONE && __locationUpdater.status == LOC_SVC_STATUS_PAUSED)
215 SysLog(NID_LOC, "Requesting to start the location updates as the update type is (%x)", __locationUpdater.type);
216 __locationUpdater.status = LOC_SVC_STATUS_NOT_FIXED;
217 __pLocationManager->StartLocationUpdates(__criteria.GetAccuracy(), __locationUpdater.updateInterval, this, __locationUpdater.reqId);
219 NotifyServiceStatus(_LOC_PRV_EVENT_SEND_LOC_SVC_CB, __locationUpdater.status);
224 if (__locationUpdater.type != _LOCATION_UPDATE_TYPE_NONE && (__locationUpdater.status == LOC_SVC_STATUS_RUNNING || __locationUpdater.status == LOC_SVC_STATUS_NOT_FIXED))
226 SysLog(NID_LOC, "Requesting to stop the location updates as the update type is (%x)", __locationUpdater.type);
227 __locationUpdater.status = LOC_SVC_STATUS_PAUSED;
228 __pLocationManager->StopLocationUpdates(__locationUpdater.reqId);
230 NotifyServiceStatus(_LOC_PRV_EVENT_SEND_LOC_SVC_CB, __locationUpdater.status);
237 _LocationProviderImpl::AddMonitoringRegion(const Coordinates& regionCenter, double radius, RegionId& regionId)
239 bool userConsent = GetUserPrivilege();
240 SysTryReturn(NID_LOC, userConsent, E_USER_NOT_CONSENTED, E_USER_NOT_CONSENTED, "[E_USER_NOT_CONSENTED] The user has disabled the required settings.");
242 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.");
244 SysTryReturn(NID_LOC, (!Double::IsNaN(radius) && !Double::IsNaN(regionCenter.GetLatitude()) && !Double::IsNaN(regionCenter.GetLongitude())),
245 E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] One of the value is NaN.");
247 SysLog(NID_LOC, "Requested to add the monitoring region with center (Latitude: %lf, Longitude %lf) and radius (%lf).", regionCenter.GetLatitude(), regionCenter.GetLongitude(), radius);
249 static int nextRegionId = 0;
250 result r = E_SUCCESS;
252 std::unique_ptr< _RegionInfo > pRegionInfo(new (std::nothrow) _RegionInfo(regionCenter, radius, nextRegionId));
253 SysTryReturn(NID_LOC, pRegionInfo != null, E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY));
255 r = __regionMonitor.pRegionList->Add(*pRegionInfo.get());
256 SysTryReturn(NID_LOC, r == E_SUCCESS, r, r, "[%s] Failed to add the Region info into the list. Propogated.", GetErrorMessage(r));
258 pRegionInfo.release();
259 regionId = nextRegionId;
262 if (__regionMonitor.status != LOC_SVC_STATUS_IDLE)
267 r = ActivateRegionMonitoring();
268 SysTryCatch(NID_LOC, r == E_SUCCESS, , r, "[%s] Failed to start the region monitoring. Propogating.", GetErrorMessage(r));
270 __regionMonitor.status = LOC_SVC_STATUS_NOT_FIXED;
271 NotifyServiceStatus(_LOC_PRV_EVENT_SEND_MONITOR_SVC_CB, __regionMonitor.status);
276 __regionMonitor.pRegionList->RemoveAt(0);
281 _LocationProviderImpl::RemoveMonitoringRegion(RegionId regionId)
283 int count = __regionMonitor.pRegionList->GetCount();
284 bool isIdValid = false;
286 SysLog(NID_LOC, "Total regions currently monitored is (%d).", count);
288 for (int i = 0; i < count; i++)
290 _RegionInfo* pRegionInfo = static_cast< _RegionInfo* >(__regionMonitor.pRegionList->GetAt(i));
291 if (regionId == pRegionInfo->GetRegionId())
293 __regionMonitor.pRegionList->RemoveAt(i, true);
299 SysTryReturn(NID_LOC, isIdValid == true, E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] The region ID is invalid.");
301 if (__regionMonitor.pRegionList->GetCount() == 0)
303 __regionMonitor.status = LOC_SVC_STATUS_IDLE;
304 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.
306 __lastLocationAccuracy = LOC_ACCURACY_INVALID;
308 StopRegionMonitoring();
315 _LocationProviderImpl::RemoveAllMonitoringRegions(void)
317 __regionMonitor.pRegionList->RemoveAll(true);
319 if (__regionMonitor.status != LOC_SVC_STATUS_IDLE)
321 __regionMonitor.status = LOC_SVC_STATUS_IDLE;
322 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.
324 __lastLocationAccuracy = LOC_ACCURACY_INVALID;
326 StopRegionMonitoring();
332 LocationServiceStatus
333 _LocationProviderImpl::GetLocationUpdateStatus(void) const
335 return __locationUpdater.status;
338 LocationServiceStatus
339 _LocationProviderImpl::GetRegionMonitoringStatus(void) const
341 return __regionMonitor.status;
345 _LocationProviderImpl::GetCurrentAccuracy(void) const
347 return __lastLocationAccuracy;
351 _LocationProviderImpl::GetLocation(const LocationCriteria& criteria)
353 Location retLocation(_LocationImpl::GetLocationInstance());
355 bool userConsent = GetUserPrivilege();
356 SysTryReturn(NID_LOC, userConsent, retLocation, E_USER_NOT_CONSENTED, "[E_USER_NOT_CONSENTED] The user has disabled the required settings.");
358 Location* pLocation = null;
359 const int MAX_TIMEOUT = 30;
360 result r = E_SUCCESS;
361 _LocationManager* pLocationManager = null;
363 SysLog(NID_LOC, "Requesting for single location with criteria (%x).", criteria.GetAccuracy());
365 std::unique_ptr< _LocationMonitor > pLocMonitor(new (std::nothrow) _LocationMonitor());
366 SysTryCatch(NID_LOC, pLocMonitor, , E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY));
368 r = pLocMonitor->Construct(MAX_TIMEOUT, criteria.GetAccuracy());
369 SysTryCatch(NID_LOC, r == E_SUCCESS, , r, "[%s] Failed to construct the Location Monitor.", GetErrorMessage(r));
371 pLocationManager = _LocationManager::GetInstance();
372 SysTryCatch(NID_LOC, pLocationManager, , r, "[%s] Failed to get the location manager instance.", GetErrorMessage(r));
374 r = pLocationManager->RegisterLocationMonitor(pLocMonitor.get());
375 SysTryCatch(NID_LOC, r == E_SUCCESS, , r, "[%s] Failed to register the location monitor.", GetErrorMessage(r));
377 r = pLocMonitor->Wait();
381 pLocation = pLocMonitor->GetLocationN();
386 retLocation = *pLocation;
390 SetLastResult(E_LOCATION_UNAVAILABLE);
402 _LocationProviderImpl::GetLastKnownLocation(void)
404 Location retLocation(_LocationImpl::GetLocationInstance());
406 bool userConsent = GetUserPrivilege();
407 SysTryReturn(NID_LOC, userConsent, retLocation, E_USER_NOT_CONSENTED, "[E_USER_NOT_CONSENTED] The user has disabled the required settings.");
409 _LocationManager* pLocationManager = _LocationManager::GetInstance();
410 SysTryReturn(NID_LOC, pLocationManager, retLocation, E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY));
412 retLocation = pLocationManager->GetLastKnownLocation();
414 if (!retLocation.IsValid())
416 SetLastResult(E_LOCATION_UNAVAILABLE);
429 _LocationProviderImpl::OnLocationUpdated(RequestId reqId, const Tizen::Locations::Location& location)
431 SysLog(NID_LOC, "Location is updated from Location Manager for the request ID (%ld).", reqId);
433 std::unique_ptr< Location > pLocation(new (std::nothrow) Location(location));
434 SysTryReturnVoidResult(NID_LOC, pLocation, E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY));
436 std::unique_ptr< _LocProviderEventArg > pLocProviderEventArg(new (std::nothrow) _LocProviderEventArg());
437 SysTryReturnVoidResult(NID_LOC, pLocProviderEventArg, E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY));
439 pLocProviderEventArg->SetEventType(_LOC_PRV_EVENT_SEND_LOC);
440 pLocProviderEventArg->SetLocation(pLocation.get());
441 pLocProviderEventArg->SetRequestId(reqId);
444 result r = _Event::FireAsync(*pLocProviderEventArg);
445 SysTryReturnVoidResult(NID_LOC, r == E_SUCCESS, r, "[%s] Failed to fire the event.", GetErrorMessage(r));
446 pLocProviderEventArg.release();
452 _LocationProviderImpl::OnLocationEventReceivedN(RequestId reqId, Tizen::Locations::Location& location)
454 SysLog(NID_LOC, "Location Event received.");
456 LocationAccuracy currentAccuracy = LOC_ACCURACY_INVALID;
457 long long lastLocationTime = 0;
459 Location* pLocation = &location;
460 _LocationImpl* pLocationImpl = _LocationImpl::GetInstance(*pLocation);
462 if (reqId == __locationUpdater.reqId)
464 SysLog(NID_LOC, "The location is updated for Location request.");
465 lastLocationTime = _LocationImpl::GetInstance(*__locationUpdater.pLocation.get())->GetTimestampInMs();
467 else if (reqId == __regionMonitor.reqId)
469 SysLog(NID_LOC, "The location is updated for Region monitoring.");
470 lastLocationTime = _LocationImpl::GetInstance(*__regionMonitor.pLocation.get())->GetTimestampInMs();
473 long long timeDifference = pLocationImpl->GetTimestampInMs() - lastLocationTime;
474 SysLog(NID_LOC, "Time difference between last location timestamp (%lld) and current location timestamp (%lld) is (%lld).", lastLocationTime, pLocationImpl->GetTimestampInMs(), timeDifference);
475 if (timeDifference > 0)
478 currentAccuracy = __pLocationManager->GetAccuracyLevel(pLocation->GetHorizontalAccuracy());
481 if (currentAccuracy != __lastLocationAccuracy)
483 SysLog(NID_LOC, "Notify the accuracy change.");
484 __lastLocationAccuracy = currentAccuracy;
485 __pLocationListener->OnAccuracyChanged(currentAccuracy);
488 if (reqId == __locationUpdater.reqId)
490 HandleLocationUpdate(location, isNew);
492 else if (reqId == __regionMonitor.reqId)
494 if (isNew) // Copy the location only if it is new.
496 *__regionMonitor.pLocation = location;
499 if (currentAccuracy != LOC_ACCURACY_INVALID && currentAccuracy <= __criteria.GetAccuracy())
501 SysLog(NID_LOC, "Location criteria (accuracy: %ld) is met for handling region monitoring.", currentAccuracy);
502 result r = __regionMonitor.pTimer->Cancel();
503 SysTryLog(NID_LOC, r == E_SUCCESS, "Failed to cancel the timer.");
505 r = __pLocationManager->StopLocationUpdates(__regionMonitor.reqId);
506 SysTryLog(NID_LOC, r == E_SUCCESS, "Failed to stop the location updates.");
507 HandleRegionMonitoring(location, isNew);
511 SysLog(NID_LOC, "Location criteria (accuracy: %ld) is not met for handling region monitoring.", currentAccuracy);
519 _LocationProviderImpl::OnLocationUpdateStatusChanged(Tizen::Locations::LocationServiceStatus locSvcStatus)
521 __pLocationListener->OnLocationUpdateStatusChanged(locSvcStatus);
525 _LocationProviderImpl::OnRegionMonitoringStatusChanged(Tizen::Locations::LocationServiceStatus locSvcStatus)
527 __pLocationListener->OnRegionMonitoringStatusChanged(locSvcStatus);
531 _LocationProviderImpl::OnActiveAppChanged(const Tizen::App::AppId& appId)
533 Tizen::App::App* pApp = Tizen::App::App::GetInstance();
534 Tizen::App::AppId currentAppId = pApp->GetAppId();
536 SysLog(NID_LOC, "Active App ID is (%ls) and the current app Id is (%ls)", appId.GetPointer(), currentAppId.GetPointer());
538 if (currentAppId == appId)
540 SysLog(NID_LOC, "Application is active.");
542 if (__locationUpdater.status == LOC_SVC_STATUS_PAUSED)
544 SysLog(NID_LOC, "Start the location updates as the location update status is PAUSED.");
545 __pLocationManager->StartLocationUpdates(__criteria.GetAccuracy(), __locationUpdater.updateInterval, this, __locationUpdater.reqId);
546 __locationUpdater.status = LOC_SVC_STATUS_NOT_FIXED;
547 __pLocationListener->OnLocationUpdateStatusChanged(__locationUpdater.status);
552 SysLog(NID_LOC, "Application is not active.");
554 if (__locationUpdater.awakeEnabled == false && (__locationUpdater.status == LOC_SVC_STATUS_RUNNING || __locationUpdater.status == LOC_SVC_STATUS_NOT_FIXED))
556 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);
557 __pLocationManager->StopLocationUpdates(__locationUpdater.reqId);
558 __locationUpdater.status = LOC_SVC_STATUS_PAUSED;
559 __pLocationListener->OnLocationUpdateStatusChanged(__locationUpdater.status);
565 _LocationProviderImpl::OnAlarmExpired(Alarm& alarm)
567 SysLog(NID_LOC, "Region Monitor Alarm expired.");
569 result r = ActivateRegionMonitoring();
570 SysTryReturnVoidResult(NID_LOC, r == E_SUCCESS, r, "[%s] Failed to start the region monitoring. Propogating.", GetErrorMessage(r));
574 _LocationProviderImpl::OnTimerExpired(Timer& timer)
576 SysLog(NID_LOC, "Region Monitor timer expired due to unavailability of location information.");
577 __pLocationManager->StopLocationUpdates(__regionMonitor.reqId);
578 HandleRegionMonitoring(*__regionMonitor.pLocation, __regionMonitor.pLocation->IsValid());
582 _LocationProviderImpl::StartLocationUpdates(LocationUpdateType updateType, int interval, double distance)
584 result r = E_SUCCESS;
585 bool startUpdate = true;
587 if (updateType == _LOCATION_UPDATE_TYPE_INTERVAL)
589 __locationUpdater.updateInterval = interval;
591 else if (updateType == _LOCATION_UPDATE_TYPE_DISTANCE)
593 __locationUpdater.updateInterval = DEFAULT_DISTANCE_CHECKING_INTERVAL;
594 __locationUpdater.distanceThreshold = distance;
597 if (!__locationUpdater.awakeEnabled)
599 UiApp* pAppInstance = Tizen::App::UiApp::GetInstance();
600 if (pAppInstance == null)
606 AppUiState appUiState = pAppInstance->GetAppUiState();
608 if (appUiState == APP_UI_STATE_BACKGROUND)
610 SysLog(NID_LOC, "App is background.");
618 if (__locationUpdater.type != _LOCATION_UPDATE_TYPE_NONE)
620 SysLog(NID_LOC, "Update session already running. Updating the interval to %d seconds", __locationUpdater.updateInterval);
621 r = __pLocationManager->ChangeUpdateInterval(__locationUpdater.reqId, __locationUpdater.updateInterval);
622 SysTryCatch(NID_LOC, r == E_SUCCESS, , r, "[%s] Failed to update the request interval. Propagating.", GetErrorMessage(r));
623 __locationUpdater.type = updateType;
628 r = __pLocationManager->StartLocationUpdates(__criteria.GetAccuracy(), __locationUpdater.updateInterval, this, __locationUpdater.reqId);
629 SysTryCatch(NID_LOC, r == E_SUCCESS, , r, "[%s] Failed to start the Native location updates. Propagating.", GetErrorMessage(r));
630 __locationUpdater.status = LOC_SVC_STATUS_NOT_FIXED;
635 __locationUpdater.status = LOC_SVC_STATUS_PAUSED;
638 __locationUpdater.type = updateType;
640 SysLog(NID_LOC, "Update type is (%x). The request Id is (%ld) and the update status is (%x).", __locationUpdater.type, __locationUpdater.reqId, __locationUpdater.status);
641 NotifyServiceStatus(_LOC_PRV_EVENT_SEND_LOC_SVC_CB, __locationUpdater.status);
646 __locationUpdater.type = _LOCATION_UPDATE_TYPE_NONE;
651 _LocationProviderImpl::CheckDistanceThreshold(const Location& oldPosition, const Location& newPosition)
653 double displacement = 0.0;
654 const Coordinates coordOld = oldPosition.GetCoordinates();
655 const Coordinates coordNew = newPosition.GetCoordinates();
657 if (__locationUpdater.firstLocationUpdate)
659 SysLog(NID_LOC, "First location update. So send true.");
660 __locationUpdater.firstLocationUpdate = false;
664 displacement = coordOld.GetDistanceTo(coordNew);
665 SysLog(NID_LOC, "Displacement is (%lf)", displacement);
666 return ((displacement > __locationUpdater.distanceThreshold) ? true : false);
670 _LocationProviderImpl::ResetLocationUpdates(void)
672 __locationUpdater.firstLocationUpdate = true;
673 __locationUpdater.reqId = -1;
674 __lastLocationAccuracy = LOC_ACCURACY_INVALID;
675 __locationUpdater.type = _LOCATION_UPDATE_TYPE_NONE;
676 __locationUpdater.status = LOC_SVC_STATUS_IDLE;
677 __locationUpdater.updateInterval = 0;
678 __locationUpdater.distanceThreshold = 0.0;
682 _LocationProviderImpl::FireImpl(Tizen::Base::Runtime::IEventListener& listener, const Tizen::Base::Runtime::IEventArg& arg)
684 _ILocProviderEventListener* pLocProviderEventListener = dynamic_cast< _ILocProviderEventListener* >(&listener);
685 SysTryReturnVoidResult(NID_LOC, pLocProviderEventListener, E_SYSTEM, "[E_INVALID_ARG] The listener is null.");
687 IEventArg* pArg = const_cast< IEventArg* >(&arg);
688 _LocProviderEventArg* pEventArg = dynamic_cast< _LocProviderEventArg* >(pArg);
689 SysTryReturnVoidResult(NID_LOC, pEventArg, E_SYSTEM, "[E_INVALID_ARG] Event argument is null.");
691 _LocProviderEventType eventType = pEventArg->GetEventType();
694 case _LOC_PRV_EVENT_SEND_LOC:
695 pLocProviderEventListener->OnLocationEventReceivedN(pEventArg->GetRequestId(), *pEventArg->GetLocationN());
698 case _LOC_PRV_EVENT_SEND_LOC_SVC_CB:
699 pLocProviderEventListener->OnLocationUpdateStatusChanged(pEventArg->GetLocServiceStatus());
702 case _LOC_PRV_EVENT_SEND_MONITOR_SVC_CB:
703 pLocProviderEventListener->OnRegionMonitoringStatusChanged(pEventArg->GetLocServiceStatus());
709 _LocationProviderImpl::HandleLocationUpdate(Tizen::Locations::Location& location, bool isNew)
711 LocationServiceStatus newLocationUpdateStatus = __locationUpdater.status;
715 if (__locationUpdater.type != _LOCATION_UPDATE_TYPE_NONE && __locationUpdater.status != LOC_SVC_STATUS_PAUSED)
717 newLocationUpdateStatus = LOC_SVC_STATUS_RUNNING;
720 else if (_LocationImpl::GetInstance(location)->IsDenied())
722 SysLog(NID_LOC, "User consent not available.");
723 if (__locationUpdater.type != _LOCATION_UPDATE_TYPE_NONE && __locationUpdater.status != LOC_SVC_STATUS_PAUSED)
725 newLocationUpdateStatus = LOC_SVC_STATUS_DENIED;
730 SysLog(NID_LOC, "Invalid Location Update.");
731 if (__locationUpdater.type != _LOCATION_UPDATE_TYPE_NONE && __locationUpdater.status != LOC_SVC_STATUS_PAUSED)
733 newLocationUpdateStatus = LOC_SVC_STATUS_NOT_FIXED;
737 if (newLocationUpdateStatus != __locationUpdater.status)
739 SysLog(NID_LOC, "Location Update Satus changed to (%x). Notify the status.", newLocationUpdateStatus);
740 __locationUpdater.status = newLocationUpdateStatus;
741 __pLocationListener->OnLocationUpdateStatusChanged(__locationUpdater.status);
744 if (newLocationUpdateStatus == LOC_SVC_STATUS_RUNNING)
746 if (__locationUpdater.type == _LOCATION_UPDATE_TYPE_DISTANCE)
748 if (CheckDistanceThreshold(*__locationUpdater.pLocation.get(), location) == true)
750 SysLog(NID_LOC, "Location displacement exceeds the distance threshold (%lf). Notify the location.", __locationUpdater.distanceThreshold);
751 __pLocationListener->OnLocationUpdated(location);
752 *__locationUpdater.pLocation.get() = location;
755 else if (__locationUpdater.type == _LOCATION_UPDATE_TYPE_INTERVAL)
757 SysLog(NID_LOC, "Location time interval expired. Notify the location.");
758 __pLocationListener->OnLocationUpdated(location);
759 *__locationUpdater.pLocation.get() = location;
765 _LocationProviderImpl::HandleRegionMonitoring(Tizen::Locations::Location& location, bool isNew)
767 LocationServiceStatus newRegionMonitorStatus = __regionMonitor.status;
771 newRegionMonitorStatus = LOC_SVC_STATUS_RUNNING;
773 else if (_LocationImpl::GetInstance(location)->IsDenied())
775 newRegionMonitorStatus = LOC_SVC_STATUS_DENIED;
779 newRegionMonitorStatus = LOC_SVC_STATUS_NOT_FIXED;
782 if (newRegionMonitorStatus != __regionMonitor.status)
784 SysLog(NID_LOC, "Region Monitoring Satus changed to (%x). Notify the status.", newRegionMonitorStatus);
785 __regionMonitor.status = newRegionMonitorStatus;
786 __pLocationListener->OnRegionMonitoringStatusChanged(__regionMonitor.status);
789 if (newRegionMonitorStatus == LOC_SVC_STATUS_RUNNING)
791 NotifyRegionCrossedStatus(location);
794 SetNextRegionMonitoringTime();
798 _LocationProviderImpl::NotifyRegionCrossedStatus(const Tizen::Locations::Location& location)
800 int count = __regionMonitor.pRegionList->GetCount();
802 SysLog(NID_LOC, "Number of regions currently monitored is (%d)", count);
804 for (int i = 0; i < count; i++)
806 _RegionInfo* pRegionInfo = static_cast< _RegionInfo* >(__regionMonitor.pRegionList->GetAt(i));
810 Coordinates regionCoordinate = pRegionInfo->GetCoordinate();
811 _RegionState currentState = REGION_STATE_UNKNOWN;
812 _RegionState previousState = pRegionInfo->GetPreviousValidState();
813 bool notifyStateChange = false;
815 currentState = GetRegionCurrentState(*pRegionInfo, location);
816 SysLog(NID_LOC, "Current Region state is (%d) and Previous Region state is (%d)", currentState, previousState);
818 if (currentState != REGION_STATE_UNKNOWN && previousState != currentState)
820 notifyStateChange = true;
821 pRegionInfo->SetValidPreviousState(currentState);
824 if ((pRegionInfo->GetRegionState() == REGION_STATE_INSIDE || pRegionInfo->GetRegionState() == REGION_STATE_UNKNOWN) && currentState == REGION_STATE_OUTSIDE)
826 if (notifyStateChange)
828 SysLog(NID_LOC, "Notify the boundary crossed event as previous valid region state is INSIDE and current state is OUTSIDE.");
829 __pLocationListener->OnRegionLeft(pRegionInfo->GetRegionId());
832 else if ((pRegionInfo->GetRegionState() == REGION_STATE_OUTSIDE || pRegionInfo->GetRegionState() == REGION_STATE_UNKNOWN) && currentState == REGION_STATE_INSIDE)
834 if (notifyStateChange)
836 SysLog(NID_LOC, "Notify the boundary crossed event as previous valid region state is OUTSIDE and current state is INSIDE.");
837 __pLocationListener->OnRegionEntered(pRegionInfo->GetRegionId());
840 pRegionInfo->SetRegionState(currentState);
846 _LocationProviderImpl::GetRegionCurrentState(const _RegionInfo& region, const Location& location)
848 TryReturn(location.GetHorizontalAccuracy() >= 0.0, REGION_STATE_UNKNOWN, "Location received with invalid accuracy");
850 SysLog(NID_LOC, "[RegionID %d] Region Information is (Center latitude: %lf, Center longitude: %lf, Region radius:%lf", region.GetRegionId(), region.GetCoordinate().GetLatitude(),
851 region.GetCoordinate().GetLongitude(), region.GetRadius());
852 SysLog(NID_LOC, "[RegionID %d] Location Information is (Latitude: %lf, Longitude: %lf, Horizontal accuracy:%lf", region.GetRegionId(), location.GetCoordinates().GetLatitude(),
853 location.GetCoordinates().GetLongitude(), location.GetHorizontalAccuracy());
855 _RegionState regionState = REGION_STATE_UNKNOWN;
857 double distanceBtwCenters = region.GetCoordinate().GetDistanceTo(location.GetCoordinates());
858 double regionRadius = region.GetRadius();
859 double locationRadius = location.GetHorizontalAccuracy();
861 SysLog(NID_LOC, "[RegionID %d] The distance between centers is (%lf)", region.GetRegionId(), distanceBtwCenters);
863 if (distanceBtwCenters >= (regionRadius + locationRadius))
865 regionState = REGION_STATE_OUTSIDE;
867 else if (distanceBtwCenters < regionRadius && Double::Compare(locationRadius, 0.0) == 0)
869 SysLog(NID_LOC, "[RegionID %d] Location Radius is 0 and distance < regionRadius", region.GetRegionId());
870 regionState = REGION_STATE_INSIDE;
874 double radiusThreshold = (1 / Math::Sqrt(2)) * locationRadius;
876 if (regionRadius < radiusThreshold)
878 SysLog(NID_LOC, "[RegionID %d] Region circle is less than 50 percent area of the location circle.", region.GetRegionId());
879 regionState = (distanceBtwCenters >= locationRadius) ? REGION_STATE_OUTSIDE : REGION_STATE_UNKNOWN;
885 double overlapRegion = _MathUtils::CalculateOverlapRegion(region, location);
886 double upperThreshold = 0;
887 double lowerThreshold = 0;
888 double occupancy = 0;
890 SysLog(NID_LOC, "[RegionID %d] OverlapRegion is (%lf)", region.GetRegionId(), overlapRegion);
892 if (regionRadius >= locationRadius)
894 // Calculate occupancy % with the location circle
895 SysLog(NID_LOC, "[RegionID %d] Region radius is bigger.", region.GetRegionId());
896 occupancy = (overlapRegion / (Math::GetPi() * locationRadius * locationRadius)) * 100;
901 else if (regionRadius >= radiusThreshold)
903 SysLog(NID_LOC, "[RegionID %d] The ratio of Region radius to location radius is between 0.707 and 1.", region.GetRegionId());
904 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)
906 SysLog(NID_LOC, "[RegionID %d] Threshold value is %lf.", region.GetRegionId(), thresholdValue);
908 occupancy = (overlapRegion / (Math::GetPi() * locationRadius * locationRadius)) * 100;
910 upperThreshold = 50 + thresholdValue;
911 lowerThreshold = 50 - thresholdValue;
914 // Decide the state with as per the inner and outer thresholds
915 SysLog(NID_LOC, "[RegionID %d] Occupancy is (%lf), Upper threshold is (%lf) and lower threshold is (%lf).", region.GetRegionId(), occupancy, upperThreshold, lowerThreshold);
916 regionState = (occupancy >= upperThreshold) ? REGION_STATE_INSIDE : ((occupancy <= lowerThreshold) ? REGION_STATE_OUTSIDE : REGION_STATE_UNKNOWN);
920 SysLog(NID_LOC, "[RegionID %d] Returning region state as (%d).", region.GetRegionId(), regionState);
925 _LocationProviderImpl::NotifyServiceStatus(_LocProviderEventType eventType, LocationServiceStatus svcStatus)
927 std::unique_ptr< _LocProviderEventArg > pLocProviderEventArg(new (std::nothrow) _LocProviderEventArg());
928 if (pLocProviderEventArg)
930 pLocProviderEventArg->SetEventType(eventType);
931 pLocProviderEventArg->SetLocServiceStatus(svcStatus);
933 result r = _Event::FireAsync(*pLocProviderEventArg.get());
934 SysTryReturnVoidResult(NID_LOC, r == E_SUCCESS, r, "[%s] Failed to fire the event.", GetErrorMessage(r));
936 pLocProviderEventArg.release();
943 _LocationProviderImpl::GetUserPrivilege(void)
945 _LocationManager* pLocMgr = _LocationManager::GetInstance();
946 SysTryReturn(NID_LOC, pLocMgr, false, E_SYSTEM, "[E_SYSTEM] Failed to get the location manager instance.");
948 bool appSettingEnabled = pLocMgr->IsAppEnabled();
949 if (appSettingEnabled == false)
954 bool hasPrivilege = false;
955 result gps = E_SUCCESS;
956 result wps = E_SUCCESS;
958 bool gpsEnabled = true;
959 bool wpsEnabled = true;
961 gps = _SettingInfoImpl::GetValue(L"http://tizen.org/setting/location.gps", gpsEnabled);
962 wps = _SettingInfoImpl::GetValue(L"http://tizen.org/setting/location.wps", wpsEnabled);
964 hasPrivilege = gpsEnabled | wpsEnabled;
966 if (gps != E_SUCCESS || wps != E_SUCCESS || hasPrivilege == false)
975 _LocationProviderImpl::ActivateRegionMonitoring(void)
977 long long currentTime;
978 SystemTime::GetTicks(currentTime);
980 SysLog(NID_LOC, "Current system time is %lld", currentTime);
982 _LocationImpl::GetInstance(*__regionMonitor.pLocation)->SetValidity(false);
983 _LocationImpl::GetInstance(*__regionMonitor.pLocation)->SetTimestamp(currentTime);
985 result r = __regionMonitor.pTimer->Start(DEFAULT_WAITING_TIME_FOR_FIXING_LOCATION * 1000);
986 SysTryReturn(NID_LOC, r == E_SUCCESS, r, r, "[%s] Failed to start the timer. Propogating.", GetErrorMessage(r));
988 r = __pLocationManager->StartLocationUpdates(__criteria.GetAccuracy(), MIN_LOCATION_UPDATE_INTERVAL, this, __regionMonitor.reqId);
989 SysTryReturn(NID_LOC, r == E_SUCCESS, r, r, "[%s] Failed to start the location updates. Propogating.", GetErrorMessage(r));
991 SysLog(NID_LOC, "Timer & Location updates are started.");
996 _LocationProviderImpl::StopRegionMonitoring(void)
998 result r = _AlarmImpl::GetInstance(__regionMonitor.pAlarm.get())->Cancel();
999 SysTryReturnVoidResult(NID_LOC, r == E_SUCCESS, r, "[%s] Failed to stop the alarm. Ignored.", GetErrorMessage(r));
1001 r = __regionMonitor.pTimer->Cancel();
1002 SysTryReturnVoidResult(NID_LOC, r == E_SUCCESS, r, "[%s] Failed to stop the timer. Ignored.", GetErrorMessage(r));
1004 r = __pLocationManager->StopLocationUpdates(__regionMonitor.reqId);
1005 SysTryReturnVoidResult(NID_LOC, r == E_SUCCESS, r, "[%s] All regions are removed but failed to stop the location updates. Ignored.", GetErrorMessage(r));
1009 _LocationProviderImpl::SetNextRegionMonitoringTime(void)
1011 DateTime alarmDateTime;
1012 long long alarmTime = DEFAULT_REGION_MONITORING_CYCLE_INTERVAL;
1013 SystemTime::GetCurrentTime(TIME_MODE_WALL, alarmDateTime);
1015 SysLog(NID_LOC, "Current System Time is %ls", alarmDateTime.ToString().GetPointer());
1017 if (__regionMonitor.pLocation->IsValid())
1019 const int bufferTime = 5; //Buffer of 5 seconds for determining the alarmTime;
1020 double minDistance = _MathUtils::GetShortestDistance(*__regionMonitor.pLocation, *__regionMonitor.pRegionList);
1021 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.
1023 if (newAlarmTime > alarmTime)
1025 alarmTime = newAlarmTime;
1029 alarmDateTime.AddSeconds(alarmTime);
1030 result r = _AlarmImpl::GetInstance(__regionMonitor.pAlarm.get())->Set(alarmDateTime, 0, null);
1031 SysTryLog(NID_LOC, r == E_SUCCESS, "Failed to set the alarm for next cycle.");
1033 SysLog(NID_LOC, "Next alarm expires after %ld seconds.", alarmTime);