Geo-fencing optimization
[platform/framework/native/locations.git] / src / FLoc_LocationProviderImpl.cpp
1 //
2 // Open Service Platform
3 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
4 //
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
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
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.
16 //
17
18 /**
19  * @file        FLoc_LocationProviderImpl.cpp
20  * @brief       This is the implementation file for the %_LocationProviderImpl class.
21  *
22  * This implementation file contains the definitions of the %_LocationProviderImpl class methods.
23  */
24
25 #include <unique_ptr.h>
26 #include <FApp_AppManagerImpl.h>
27 #include <FAppApp.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"
50
51 using namespace std;
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;
58
59 namespace Tizen { namespace Locations
60 {
61
62 _LocationProviderImpl::_LocationProviderImpl(void)
63         : Tizen::Base::Runtime::_Event()
64         , __lastLocationAccuracy(LOC_ACCURACY_INVALID)
65         , __pLocationListener(null)
66         , __pLocationManager(null)
67 {
68 }
69
70 _LocationProviderImpl::~_LocationProviderImpl(void)
71 {
72         UiApp* pAppInstance = Tizen::App::UiApp::GetInstance();
73         if (pAppInstance)
74         {
75                 _AppManagerImpl* pAppManager = _AppManagerImpl::GetInstance();
76                 if (pAppManager)
77                 {
78                         pAppManager->RemoveActiveAppEventListener(*this);
79                 }
80         }
81
82         StopLocationUpdates();
83         RemoveAllMonitoringRegions();
84 }
85
86 result
87 _LocationProviderImpl::Construct(const LocationCriteria& criteria, ILocationProviderListener& listener)
88 {
89         _LocationManager* pLocationManager = _LocationManager::GetInstance();
90         SysTryReturn(NID_LOC, pLocationManager != null, GetLastResult(), GetLastResult(), "[%s] Failed to get the location manager instance.", GetErrorMessage(GetLastResult()));
91
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));
96
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));
101
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));
106
107         UiApp* pAppInstance = Tizen::App::UiApp::GetInstance();
108         if (pAppInstance != null)
109         {
110                 _AppManagerImpl* pAppManager = _AppManagerImpl::GetInstance();
111                 SysTryReturn(NID_LOC, pAppManager, E_SYSTEM, E_SYSTEM, "[E_SYSTEM] System error occured.");
112
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));
115         }
116
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));
121
122         _Event::Initialize();
123         _Event::AddListener(*this);
124
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);
130         
131         __criteria = criteria;
132         __pLocationListener = &listener;
133         __pLocationManager = pLocationManager;
134
135         SysLog(NID_LOC, "Location provider constructed with the accuracy (%x).", criteria.GetAccuracy());
136         return E_SUCCESS;
137 }
138
139 result
140 _LocationProviderImpl::StartLocationUpdatesByInterval(int interval)
141 {
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);
145
146         if (__locationUpdater.type == _LOCATION_UPDATE_TYPE_INTERVAL && __locationUpdater.updateInterval == interval)
147         {
148                 return E_SUCCESS;
149         }
150         const double INVALID_DISTANCE_THRESHOLD = 0.0;
151         return StartLocationUpdates(_LOCATION_UPDATE_TYPE_INTERVAL, interval, INVALID_DISTANCE_THRESHOLD);
152 }
153
154 result
155 _LocationProviderImpl::StartLocationUpdatesByDistance(double distance)
156 {
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.");
161
162         if (__locationUpdater.type == _LOCATION_UPDATE_TYPE_DISTANCE && (Double::Compare(__locationUpdater.distanceThreshold, distance) == 0))
163         {
164                 return E_SUCCESS;
165         }
166         const int INVALID_INTERVAL = 0;
167         return StartLocationUpdates(_LOCATION_UPDATE_TYPE_DISTANCE, INVALID_INTERVAL, distance);
168 }
169
170 result
171 _LocationProviderImpl::StopLocationUpdates(void)
172 {
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.");
175
176         result r = __pLocationManager->StopLocationUpdates(__locationUpdater.reqId);
177         ResetLocationUpdates();
178         return r;
179 }
180
181 void
182 _LocationProviderImpl::KeepLocationUpdateAwake(bool enable)
183 {
184         if (__locationUpdater.awakeEnabled == enable)
185         {
186                 return;
187         }
188         __locationUpdater.awakeEnabled = enable;
189
190         UiApp* appInstance = Tizen::App::UiApp::GetInstance();
191         if (appInstance == null)        // This is service APP. So should be handled now.
192         {
193                 SysLog(NID_LOC, "Handling the request awake mode(%d) for the service application.", enable);
194                 if (enable == true)
195                 {
196                         if (__locationUpdater.type != _LOCATION_UPDATE_TYPE_NONE && __locationUpdater.status == LOC_SVC_STATUS_PAUSED)
197                         {
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);
201
202                                 NotifyServiceStatus(_LOC_PRV_EVENT_SEND_LOC_SVC_CB, __locationUpdater.status);
203                         }
204                 }
205                 else
206                 {
207                         if (__locationUpdater.type != _LOCATION_UPDATE_TYPE_NONE && (__locationUpdater.status == LOC_SVC_STATUS_RUNNING || __locationUpdater.status == LOC_SVC_STATUS_NOT_FIXED))
208                         {
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);
212
213                                 NotifyServiceStatus(_LOC_PRV_EVENT_SEND_LOC_SVC_CB, __locationUpdater.status);
214                         }
215                 }
216         }
217 }
218
219 result
220 _LocationProviderImpl::AddMonitoringRegion(const Coordinates& regionCenter, double radius, RegionId& regionId)
221 {
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);
228
229         static int nextRegionId = 0;
230
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));
235
236         pRegionInfo.release();
237         regionId = nextRegionId;
238         nextRegionId++;
239
240         if (__regionMonitor.status != LOC_SVC_STATUS_IDLE)
241         {
242                 return E_SUCCESS;
243         }
244
245         r = ActivateRegionMonitoring(true);
246         SysTryCatch(NID_LOC, r == E_SUCCESS, , r, "[%s] Failed to start the region monitoring. Propogating.", GetErrorMessage(r));
247
248         __regionMonitor.status = LOC_SVC_STATUS_NOT_FIXED;
249         NotifyServiceStatus(_LOC_PRV_EVENT_SEND_MONITOR_SVC_CB, __regionMonitor.status);
250         return E_SUCCESS;
251
252 CATCH:
253         __regionMonitor.pRegionList->RemoveAt(0);
254         return r;
255 }
256
257 result
258 _LocationProviderImpl::RemoveMonitoringRegion(RegionId regionId)
259 {
260         int count = __regionMonitor.pRegionList->GetCount();
261         bool isIdValid = false;
262         SysLog(NID_LOC, "Total regions currently monitored is (%d).", count);
263
264         for (int i = 0; i < count; i++)
265         {
266                 _RegionInfo* pRegionInfo = static_cast< _RegionInfo* >(__regionMonitor.pRegionList->GetAt(i));
267                 if (regionId == pRegionInfo->GetRegionId())
268                 {
269                         __regionMonitor.pRegionList->RemoveAt(i, true);
270                         isIdValid = true;
271                         break;
272                 }
273         }
274
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)
277         {
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.
280                 {
281                         __lastLocationAccuracy = LOC_ACCURACY_INVALID;
282                 }
283                 StopRegionMonitoring();
284         }
285         return E_SUCCESS;
286 }
287
288 void
289 _LocationProviderImpl::RemoveAllMonitoringRegions(void)
290 {
291         __regionMonitor.pRegionList->RemoveAll(true);
292
293         if (__regionMonitor.status != LOC_SVC_STATUS_IDLE)
294         {
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.
297                 {
298                         __lastLocationAccuracy = LOC_ACCURACY_INVALID;
299                 }
300                 StopRegionMonitoring();
301         }
302         return;
303 }
304
305 LocationServiceStatus
306 _LocationProviderImpl::GetLocationUpdateStatus(void) const
307 {
308         return __locationUpdater.status;
309 }
310
311 LocationServiceStatus
312 _LocationProviderImpl::GetRegionMonitoringStatus(void) const
313 {
314         return __regionMonitor.status;
315 }
316
317 LocationAccuracy
318 _LocationProviderImpl::GetCurrentAccuracy(void) const
319 {
320         return __lastLocationAccuracy;
321 }
322
323 Location
324 _LocationProviderImpl::GetLocation(const LocationCriteria& criteria)
325 {
326         Location retLocation(_LocationImpl::GetLocationInstance());
327
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.");
330
331         Location* pLocation = null;
332         const int MAX_TIMEOUT = 30;
333         result r = E_SUCCESS;
334         _LocationManager* pLocationManager = null;
335
336         SysLog(NID_LOC, "Requesting for single location with criteria (%x).", criteria.GetAccuracy());
337
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));
342
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));
347
348         r = pLocMonitor->Wait();
349         if (!IsFailed(r))
350         {
351                 pLocation = pLocMonitor->GetLocationN();
352         }
353         if (pLocation)
354         {
355                 retLocation = *pLocation;
356         }
357         else
358         {
359                 SetLastResult(E_LOCATION_UNAVAILABLE);
360         }
361         delete pLocation;
362         return retLocation;
363
364 CATCH:
365         return retLocation;
366 }
367
368 Location
369 _LocationProviderImpl::GetLastKnownLocation(void)
370 {
371         Location retLocation(_LocationImpl::GetLocationInstance());
372
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.");
375
376         _LocationManager* pLocationManager = _LocationManager::GetInstance();
377         SysTryReturn(NID_LOC, pLocationManager, retLocation, E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY));
378
379         retLocation = pLocationManager->GetLastKnownLocation();
380         if (!retLocation.IsValid())
381         {
382                 SetLastResult(E_LOCATION_UNAVAILABLE);
383         }
384         else
385         {
386                 ClearLastResult();
387         }
388         return retLocation;
389 }
390
391 // Private members
392
393 void
394 _LocationProviderImpl::OnLocationUpdated(RequestId reqId, const Tizen::Locations::Location& location)
395 {
396         SysLog(NID_LOC, "Location is updated from Location Manager for the request ID (%ld).", reqId);
397
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));
402
403         pLocProviderEventArg->SetEventType(_LOC_PRV_EVENT_SEND_LOC);
404         pLocProviderEventArg->SetLocation(pLocation.get());
405         pLocProviderEventArg->SetRequestId(reqId);
406         pLocation.release();
407
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();
411
412         return;
413 }
414
415 void
416 _LocationProviderImpl::OnLocationEventReceivedN(RequestId reqId, Tizen::Locations::Location& location)
417 {
418         SysLog(NID_LOC, "Location Event received.");
419         bool isNew = false;
420         LocationAccuracy currentAccuracy = LOC_ACCURACY_INVALID;
421         LocationAccuracy lastLocAccuracy = __lastLocationAccuracy;
422         long long lastLocationTime = 0;
423
424         Location* pLocation = &location;
425         _LocationImpl* pLocationImpl = _LocationImpl::GetInstance(*pLocation);
426
427         if (reqId == __locationUpdater.reqId)
428         {
429                 SysLog(NID_LOC, "The location is updated for Location request.");
430                 lastLocationTime = _LocationImpl::GetInstance(*__locationUpdater.pLocation.get())->GetTimestampInMs();
431         }
432         else if (reqId == __regionMonitor.reqId)
433         {
434                 SysLog(NID_LOC, "The location is updated for Region monitoring.");
435                 lastLocationTime = _LocationImpl::GetInstance(*__regionMonitor.pLocation.get())->GetTimestampInMs();
436         }
437
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)
441         {
442                 isNew = true;
443                 currentAccuracy = __pLocationManager->GetAccuracyLevel(pLocation->GetHorizontalAccuracy());
444         }
445
446         if (currentAccuracy != __lastLocationAccuracy)
447         {
448                 SysLog(NID_LOC, "Notify the accuracy change.");
449                 __lastLocationAccuracy = currentAccuracy;
450                 __pLocationListener->OnAccuracyChanged(currentAccuracy);
451         }
452
453         if (reqId == __locationUpdater.reqId)
454         {
455                 HandleLocationUpdate(location, isNew);
456         }
457         else if (reqId == __regionMonitor.reqId)
458         {
459                 if (isNew)
460                 {
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);
464                         
465                         __regionMonitor.speed = location.GetSpeed() * 0.2777778;
466
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.
468                         {
469                                 *__regionMonitor.pLocation = location;
470                         }
471
472                         if ((currentAccuracy != LOC_ACCURACY_INVALID && currentAccuracy <= __criteria.GetAccuracy()) || !gpsEnabled)
473                         {
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.");
477
478                                 HandleRegionMonitoring(location, isNew);
479                         }
480                         else
481                         {
482                                 SysLog(NID_LOC, "Location criteria (accuracy: %ld) is not met for handling region monitoring.", currentAccuracy);
483                         }                       
484                 }
485         }
486
487         delete pLocation;
488 }
489
490 void
491 _LocationProviderImpl::OnLocationUpdateStatusChanged(Tizen::Locations::LocationServiceStatus locSvcStatus)
492 {
493         __pLocationListener->OnLocationUpdateStatusChanged(locSvcStatus);
494 }
495
496 void
497 _LocationProviderImpl::OnRegionMonitoringStatusChanged(Tizen::Locations::LocationServiceStatus locSvcStatus)
498 {
499         __pLocationListener->OnRegionMonitoringStatusChanged(locSvcStatus);
500 }
501
502 void
503 _LocationProviderImpl::OnActiveAppChanged(const Tizen::App::AppId& appId)
504 {
505         Tizen::App::App* pApp = Tizen::App::App::GetInstance();
506         Tizen::App::AppId currentAppId = pApp->GetAppId();
507
508         SysLog(NID_LOC, "Active App ID is (%ls) and the current app Id is (%ls)", appId.GetPointer(), currentAppId.GetPointer());
509
510         if (currentAppId == appId)
511         {
512                 SysLog(NID_LOC, "Application is active.");
513
514                 if (__locationUpdater.status == LOC_SVC_STATUS_PAUSED)
515                 {
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);
520                 }
521         }
522         else
523         {
524                 SysLog(NID_LOC, "Application is not active.");
525
526                 if (__locationUpdater.awakeEnabled == false && (__locationUpdater.status == LOC_SVC_STATUS_RUNNING || __locationUpdater.status == LOC_SVC_STATUS_NOT_FIXED))
527                 {
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);
532                 }
533         }
534 }
535
536 void
537 _LocationProviderImpl::OnAlarmExpired(Alarm& alarm)
538 {
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));
542 }
543
544 void
545 _LocationProviderImpl::OnTimerExpired(Timer& timer)
546 {
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());
550 }
551
552 result
553 _LocationProviderImpl::StartLocationUpdates(LocationUpdateType updateType, int interval, double distance)
554 {
555         result r = E_SUCCESS;
556         bool startUpdate = true;
557
558         if (updateType == _LOCATION_UPDATE_TYPE_INTERVAL)
559         {
560                 __locationUpdater.updateInterval = interval;
561         }
562         else if (updateType == _LOCATION_UPDATE_TYPE_DISTANCE)
563         {
564                 __locationUpdater.updateInterval = DEFAULT_DISTANCE_CHECKING_INTERVAL;
565                 __locationUpdater.distanceThreshold = distance;
566         }
567
568         if  (!__locationUpdater.awakeEnabled)
569         {
570                 UiApp* pAppInstance = Tizen::App::UiApp::GetInstance();
571                 if (pAppInstance == null)
572                 {
573                         startUpdate = false;
574                 }
575                 else
576                 {
577                         AppUiState appUiState = pAppInstance->GetAppUiState();
578
579                         if (appUiState == APP_UI_STATE_BACKGROUND)
580                         {
581                                 SysLog(NID_LOC, "App is background.");
582                                 startUpdate = false;
583                         }
584                 }
585         }
586
587         if (startUpdate)
588         {
589                 if (__locationUpdater.type != _LOCATION_UPDATE_TYPE_NONE)
590                 {
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;
595                         return E_SUCCESS;
596                 }
597                 else
598                 {
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;
602                 }       
603         }
604         else
605         {
606                 __locationUpdater.status = LOC_SVC_STATUS_PAUSED;       
607         }
608
609         __locationUpdater.type = updateType;
610
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);
613
614         return E_SUCCESS;
615
616 CATCH:
617         __locationUpdater.type = _LOCATION_UPDATE_TYPE_NONE;
618         return r;
619 }
620
621 bool
622 _LocationProviderImpl::CheckDistanceThreshold(const Location& oldPosition, const Location& newPosition)
623 {
624         double displacement = 0.0;
625         const Coordinates coordOld = oldPosition.GetCoordinates();
626         const Coordinates coordNew = newPosition.GetCoordinates();
627
628         if (__locationUpdater.firstLocationUpdate)
629         {
630                 SysLog(NID_LOC, "First location update. So send true.");
631                 __locationUpdater.firstLocationUpdate = false;
632                 return true;
633         }
634         displacement = coordOld.GetDistanceTo(coordNew);
635         SysLog(NID_LOC, "Displacement is (%lf)", displacement);
636         return ((displacement > __locationUpdater.distanceThreshold) ? true : false);
637 }
638
639 void
640 _LocationProviderImpl::ResetLocationUpdates(void)
641 {
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;
649 }
650
651 void
652 _LocationProviderImpl::FireImpl(Tizen::Base::Runtime::IEventListener& listener, const Tizen::Base::Runtime::IEventArg& arg)
653 {
654         _ILocProviderEventListener* pLocProviderEventListener = dynamic_cast< _ILocProviderEventListener* >(&listener);
655         SysTryReturnVoidResult(NID_LOC, pLocProviderEventListener, E_SYSTEM, "[E_INVALID_ARG] The listener is null.");
656
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.");
660
661         _LocProviderEventType eventType = pEventArg->GetEventType();
662         switch (eventType)
663         {
664         case _LOC_PRV_EVENT_SEND_LOC:
665                 pLocProviderEventListener->OnLocationEventReceivedN(pEventArg->GetRequestId(), *pEventArg->GetLocationN());
666                 break;
667
668         case _LOC_PRV_EVENT_SEND_LOC_SVC_CB:
669                 pLocProviderEventListener->OnLocationUpdateStatusChanged(pEventArg->GetLocServiceStatus());
670                 break;
671
672         case _LOC_PRV_EVENT_SEND_MONITOR_SVC_CB:
673                 pLocProviderEventListener->OnRegionMonitoringStatusChanged(pEventArg->GetLocServiceStatus());
674                 break;
675         }
676 }
677
678 void
679 _LocationProviderImpl::HandleLocationUpdate(Tizen::Locations::Location& location, bool isNew)
680 {
681         LocationServiceStatus newLocationUpdateStatus = __locationUpdater.status;
682
683         if (isNew)
684         {
685                 if (__locationUpdater.type != _LOCATION_UPDATE_TYPE_NONE && __locationUpdater.status != LOC_SVC_STATUS_PAUSED)
686                 {
687                         newLocationUpdateStatus = LOC_SVC_STATUS_RUNNING;
688                 }
689         }
690         else if (!GetUserPrivilege())
691         {
692                 SysLog(NID_LOC, "User consent not available.");
693                 if (__locationUpdater.type != _LOCATION_UPDATE_TYPE_NONE && __locationUpdater.status != LOC_SVC_STATUS_PAUSED)
694                 {
695                         newLocationUpdateStatus = LOC_SVC_STATUS_DENIED;
696                 }
697         }
698         else
699         {
700                 SysLog(NID_LOC, "Invalid Location Update.");
701                 if (__locationUpdater.type != _LOCATION_UPDATE_TYPE_NONE && __locationUpdater.status != LOC_SVC_STATUS_PAUSED)
702                 {
703                         newLocationUpdateStatus = LOC_SVC_STATUS_NOT_FIXED;
704                 }
705         }
706
707         if (newLocationUpdateStatus != __locationUpdater.status)
708         {
709                 SysLog(NID_LOC, "Location Update Satus changed to (%x). Notify the status.", newLocationUpdateStatus);
710                 __locationUpdater.status = newLocationUpdateStatus;
711                 __pLocationListener->OnLocationUpdateStatusChanged(__locationUpdater.status);
712         }
713
714         if (newLocationUpdateStatus == LOC_SVC_STATUS_RUNNING)
715         {
716                 if (__locationUpdater.type == _LOCATION_UPDATE_TYPE_DISTANCE)
717                 {
718                         if (CheckDistanceThreshold(*__locationUpdater.pLocation.get(), location) == true)
719                         {
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;
723                         }
724                 }
725                 else if (__locationUpdater.type == _LOCATION_UPDATE_TYPE_INTERVAL)
726                 {
727                         SysLog(NID_LOC, "Location time interval expired. Notify the location.");
728                         __pLocationListener->OnLocationUpdated(location);
729                         *__locationUpdater.pLocation.get() = location;
730                 }
731         }
732 }
733
734 void
735 _LocationProviderImpl::HandleRegionMonitoring(Tizen::Locations::Location& location, bool isNew)
736 {
737         LocationServiceStatus newRegionMonitorStatus = __regionMonitor.status;
738
739         if (isNew)
740         {
741                 newRegionMonitorStatus = LOC_SVC_STATUS_RUNNING;
742         }
743         else if (!GetUserPrivilege())
744         {
745                 newRegionMonitorStatus = LOC_SVC_STATUS_DENIED;
746         }
747         else
748         {
749                 newRegionMonitorStatus = LOC_SVC_STATUS_NOT_FIXED;
750         }
751
752         if (newRegionMonitorStatus != __regionMonitor.status)
753         {
754                 SysLog(NID_LOC, "Region Monitoring Satus changed to (%x). Notify the status.", newRegionMonitorStatus);
755                 __regionMonitor.status = newRegionMonitorStatus;
756                 __pLocationListener->OnRegionMonitoringStatusChanged(__regionMonitor.status);
757         }
758
759         if (newRegionMonitorStatus == LOC_SVC_STATUS_RUNNING)
760         {
761                 NotifyRegionCrossedStatus(location);
762         }
763
764         SetNextRegionMonitoringTime();
765 }
766
767 void
768 _LocationProviderImpl::NotifyRegionCrossedStatus(const Tizen::Locations::Location& location)
769 {
770         int count = __regionMonitor.pRegionList->GetCount();
771
772         SysLog(NID_LOC, "Number of regions currently monitored is (%d)", count);
773
774         for (int i = 0; i < count; i++)
775         {
776                 _RegionInfo* pRegionInfo = static_cast< _RegionInfo* >(__regionMonitor.pRegionList->GetAt(i));
777
778                 if (pRegionInfo)
779                 {
780                         Coordinates regionCoordinate = pRegionInfo->GetCoordinate();
781                         _RegionState currentState = REGION_STATE_UNKNOWN;
782                         _RegionState previousState = pRegionInfo->GetPreviousValidState();
783                         bool notifyStateChange = false;
784
785                         currentState = GetRegionCurrentState(*pRegionInfo, location);
786                         SysLog(NID_LOC, "Current Region state is (%d) and Previous Region state is (%d)", currentState, previousState);
787
788                         if (currentState != REGION_STATE_UNKNOWN && previousState != currentState)
789                         {
790                                 notifyStateChange = true;
791                                 pRegionInfo->SetValidPreviousState(currentState);
792                         }
793
794                         if ((pRegionInfo->GetRegionState() == REGION_STATE_INSIDE || pRegionInfo->GetRegionState() == REGION_STATE_UNKNOWN) && currentState == REGION_STATE_OUTSIDE)
795                         {
796                                 if (notifyStateChange)
797                                 {
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());
800                                 }
801                         }
802                         else if ((pRegionInfo->GetRegionState() == REGION_STATE_OUTSIDE || pRegionInfo->GetRegionState() == REGION_STATE_UNKNOWN) && currentState == REGION_STATE_INSIDE)
803                         {
804                                 if (notifyStateChange)
805                                 {
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());
808                                 }
809                         }
810                         pRegionInfo->SetRegionState(currentState);
811                 }
812         }
813 }
814
815 _RegionState
816 _LocationProviderImpl::GetRegionCurrentState(const _RegionInfo& region, const Location& location)
817 {
818         TryReturn(location.GetHorizontalAccuracy() >= 0.0, REGION_STATE_UNKNOWN, "Location received with invalid accuracy");
819
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());
824
825         _RegionState regionState = REGION_STATE_UNKNOWN;
826         double distanceBtwCenters = region.GetCoordinate().GetDistanceTo(location.GetCoordinates());
827         double regionRadius = region.GetRadius();
828         double locationRadius = location.GetHorizontalAccuracy();
829
830         SysLog(NID_LOC, "[RegionID %d]  The distance between centers is (%lf)", region.GetRegionId(), distanceBtwCenters);
831
832         if (distanceBtwCenters >= (regionRadius + locationRadius))
833         {
834                 regionState = REGION_STATE_OUTSIDE;
835         }
836         else if (distanceBtwCenters < regionRadius && Double::Compare(locationRadius, 0.0) == 0)
837         {
838                 SysLog(NID_LOC, "[RegionID %d] Location Radius is 0 and distance < regionRadius", region.GetRegionId());
839                 regionState = REGION_STATE_INSIDE;
840         }
841         else
842         {
843                 double radiusThreshold = (1 / Math::Sqrt(2)) * locationRadius;
844
845                 if (regionRadius < radiusThreshold)
846                 {
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;
849
850                         return regionState;
851                 }
852                 else
853                 {
854                         double overlapRegion = _MathUtils::CalculateOverlapRegion(region, location);
855                         double upperThreshold = 0;
856                         double lowerThreshold = 0;
857                         double occupancy = 0;
858
859                         SysLog(NID_LOC, "[RegionID %d] OverlapRegion is (%lf)", region.GetRegionId(), overlapRegion);
860
861                         if (regionRadius >= locationRadius)
862                         {
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;
866
867                                 upperThreshold = 60;
868                                 lowerThreshold = 40;
869                         }
870                         else if (regionRadius >= radiusThreshold)
871                         {
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)
874
875                                 SysLog(NID_LOC, "[RegionID %d] Threshold value is %lf.", region.GetRegionId(), thresholdValue);
876
877                                 occupancy = (overlapRegion / (Math::GetPi() * locationRadius * locationRadius)) * 100;
878
879                                 upperThreshold = 50 + thresholdValue;
880                                 lowerThreshold = 50 - thresholdValue;
881                         }
882
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);
886                 }
887         }
888
889         SysLog(NID_LOC, "[RegionID %d] Returning region state as (%d).", region.GetRegionId(), regionState);
890         return regionState;
891 }
892
893 void
894 _LocationProviderImpl::NotifyServiceStatus(_LocProviderEventType eventType, LocationServiceStatus svcStatus)
895 {
896         std::unique_ptr< _LocProviderEventArg > pLocProviderEventArg(new (std::nothrow) _LocProviderEventArg());
897         if (pLocProviderEventArg)
898         {
899                 pLocProviderEventArg->SetEventType(eventType);
900                 pLocProviderEventArg->SetLocServiceStatus(svcStatus);
901
902                 result r = _Event::FireAsync(*pLocProviderEventArg.get());
903                 SysTryReturnVoidResult(NID_LOC, r == E_SUCCESS, r, "[%s] Failed to fire the event.", GetErrorMessage(r));
904
905                 pLocProviderEventArg.release();
906         }
907
908         return;
909 }
910
911 bool
912 _LocationProviderImpl::GetUserPrivilege(void)
913 {
914         bool hasPrivilege = false;
915         bool gpsEnabled = true;
916         bool wpsEnabled = true;
917
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);
920
921         hasPrivilege = gpsEnabled | wpsEnabled;
922         if (gps != E_SUCCESS || wps != E_SUCCESS || hasPrivilege == false)
923         {
924                 return false;
925         }
926         return true;
927 }
928
929 result
930 _LocationProviderImpl::ActivateRegionMonitoring(bool startUpdate)
931 {
932         long long currentTime;
933         SystemTime::GetTicks(currentTime);
934         int DEFAULT_WAITING_TIME = DEFAULT_WAITING_TIME_FOR_FIXING_GPS_LOCATION;
935
936         SysLog(NID_LOC, "Current system time is %lld and location update request is %d", currentTime, startUpdate);
937
938         bool gpsEnabled = false;
939         result gps = _SettingInfoImpl::GetValue(L"http://tizen.org/setting/location.gps", gpsEnabled);
940         if (gps == E_SUCCESS && !gpsEnabled)
941         {
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;
944         }
945
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));        
948
949         if (startUpdate)
950         {
951                 _LocationImpl::GetInstance(*__regionMonitor.pLocation)->SetValidity(false);
952                 _LocationImpl::GetInstance(*__regionMonitor.pLocation)->SetTimestamp(currentTime);      
953
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.");
957         }
958         
959         return E_SUCCESS;
960 }
961
962 void
963 _LocationProviderImpl::StopRegionMonitoring(void)
964 {
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));
967
968         r = __regionMonitor.pTimer->Cancel();
969         SysTryLog(NID_LOC, r == E_SUCCESS, "[%s] Failed to stop the timer. Ignored.", GetErrorMessage(r));
970
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));
973 }
974
975 void
976 _LocationProviderImpl::SetNextRegionMonitoringTime(void)
977 {
978         DateTime alarmDateTime;
979         long long alarmTime = DEFAULT_REGION_MONITORING_CYCLE_INTERVAL;
980         SystemTime::GetCurrentTime(TIME_MODE_WALL, alarmDateTime);
981
982         SysLog(NID_LOC, "Current System Time is %ls", alarmDateTime.ToString().GetPointer());
983
984         double speed = DEFAULT_AVG_SPEED;
985         if (__regionMonitor.speed > DEFAULT_AVG_SPEED)
986         {
987                 SysLog(NID_LOC, "The speed of the user is greater than the default speed. So updating the value.");
988                 speed = __regionMonitor.speed;
989         }
990         if (__regionMonitor.pLocation->IsValid())
991         {
992                 const int bufferTime = 5;   //Buffer of 5 seconds for determining the alarmTime;
993                 double minDistance = _MathUtils::GetShortestDistance(*__regionMonitor.pLocation, *__regionMonitor.pRegionList);
994
995                 long long newAlarmTime = ((int) minDistance / speed) - bufferTime;      //Calculate the alarm time based on the shortest distance between current location and nearest region boundary.
996
997                 if (newAlarmTime < DEFAULT_REGION_MONITORING_CYCLE_INTERVAL)
998                 {
999                         SysLog(NID_LOC, "The alarm time is less than 5 seconds. So do not stop the location updates.");
1000                         ActivateRegionMonitoring(false);
1001                         return;
1002                 }
1003                 else
1004                 {
1005                         alarmTime = newAlarmTime;
1006                 }
1007         }
1008
1009         result r = __pLocationManager->StopLocationUpdates(__regionMonitor.reqId);
1010         SysTryLog(NID_LOC, r == E_SUCCESS, "Failed to stop the location updates.");
1011         
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.");
1015         
1016         SysLog(NID_LOC, "Next alarm expires after %ld seconds.", alarmTime);
1017 }
1018 }}