Tizen 2.0 Release
[framework/osp/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_SettingInfoImpl.h>
43 #include "FLoc_LocationImpl.h"
44 #include "FLoc_LocationManager.h"
45 #include "FLoc_LocationMonitor.h"
46 #include "FLoc_LocationProviderImpl.h"
47 #include "FLoc_MathUtils.h"
48 #include "FLoc_Types.h"
49
50 using namespace Tizen::App;
51 using namespace Tizen::Base;
52 using namespace Tizen::Base::Collection;
53 using namespace Tizen::Base::Runtime;
54 using namespace Tizen::Base::Utility;
55 using namespace Tizen::System;
56 using namespace std;
57
58 namespace Tizen { namespace Locations
59 {
60
61 _LocationProviderImpl::_LocationProviderImpl(void)
62         : Tizen::Base::Runtime::_Event()
63         , __firstLocationUpdate(true)
64         , __regionMonitoringActive(false)
65         , __awakeEnabled(false)
66         , __updateInterval(0)
67         , __locationUpdateType(_LOCATION_UPDATE_TYPE_NONE)
68         , __locationUpdateStatus(LOC_SVC_STATUS_IDLE)
69         , __regionMonitorStatus(LOC_SVC_STATUS_IDLE)
70         , __lastLocationAccuracy(LOC_ACCURACY_INVALID)
71         , __reqId(-1)
72         , __regionReqId(-1)
73         , __distanceThreshold(0.0)
74         , __pLocationListener(null)
75         , __pLocationManager(null)
76         , __pLastLocation(null)
77         , __pRegionList(null)
78 {
79 }
80
81 _LocationProviderImpl::~_LocationProviderImpl(void)
82 {
83         UiApp* pAppInstance = Tizen::App::UiApp::GetInstance();
84         if (pAppInstance)
85         {
86                 _AppManagerImpl* pAppManager = _AppManagerImpl::GetInstance();
87                 if (pAppManager)
88                 {
89                         pAppManager->RemoveActiveAppEventListener(*this);
90                 }
91         }
92
93         StopLocationUpdates();
94         RemoveAllMonitoringRegions();
95 }
96
97 result
98 _LocationProviderImpl::Construct(const LocationCriteria& criteria, ILocationProviderListener& listener)
99 {
100         result r = E_SUCCESS;
101         _LocationManager* pLocationManager = null;
102
103         pLocationManager = _LocationManager::GetInstance();
104         SysTryReturn(NID_LOC, pLocationManager != null, GetLastResult(), GetLastResult(), "[%s] Failed to get the location manager instance.", GetErrorMessage(GetLastResult()));
105
106         std::unique_ptr< Tizen::Base::Collection::ArrayList, AllElementsDeleter > pRegionList(new (std::nothrow) ArrayList());
107         SysTryReturn(NID_LOC, pRegionList != null, E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY));
108
109         r = pRegionList->Construct();
110         SysTryReturn(NID_LOC, r == E_SUCCESS, r, r, "[%s] Failed to construct the list. Propagating.", GetErrorMessage(r));
111
112         UiApp* pAppInstance = Tizen::App::UiApp::GetInstance();
113         if (pAppInstance != null)
114         {
115                 _AppManagerImpl* pAppManager = _AppManagerImpl::GetInstance();
116                 SysTryReturn(NID_LOC, pAppManager, E_SYSTEM, E_SYSTEM, "[E_SYSTEM] System error occured.");
117
118                 r = pAppManager->AddActiveAppEventListener(*this);
119                 SysTryReturn(NID_LOC, r == E_SUCCESS, r, r, "[%s] Error occured during adding the event listener to app manager. Propagating.", GetErrorMessage(r));
120         }
121
122         std::unique_ptr< Tizen::Locations::Location > pLocation(_LocationImpl::GetLocationInstanceN());
123         SysTryReturn(NID_LOC, pLocation != null, E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY));
124
125         _Event::Initialize();
126         _Event::AddListener(*this);
127
128         __pRegionList = std::move(pRegionList);
129         __pLastLocation = std::move(pLocation);
130         __criteria = criteria;
131         __pLocationListener = &listener;
132         __pLocationManager = pLocationManager;
133
134         SysLog(NID_LOC, "Location provider constructed with the accuracy (%x).", criteria.GetAccuracy());
135
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
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);
146
147         if (__locationUpdateType == _LOCATION_UPDATE_TYPE_INTERVAL && __updateInterval == interval)
148         {
149                 return E_SUCCESS;
150         }
151         else if (__locationUpdateType == _LOCATION_UPDATE_TYPE_DISTANCE || __locationUpdateType == _LOCATION_UPDATE_TYPE_INTERVAL)
152         {
153                 __pLocationManager->StopLocationUpdates(__reqId);
154                 __locationUpdateStatus = LOC_SVC_STATUS_IDLE;
155         }
156
157         const double INVALID_DISTANCE_THRESHOLD = 0.0;
158         return StartLocationUpdates(_LOCATION_UPDATE_TYPE_INTERVAL, interval, INVALID_DISTANCE_THRESHOLD);
159 }
160
161 result
162 _LocationProviderImpl::StartLocationUpdatesByDistance(double distance)
163 {
164         bool userConsent = GetUserPrivilege();
165         SysTryReturn(NID_LOC, userConsent, E_USER_NOT_CONSENTED, E_USER_NOT_CONSENTED, "[E_USER_NOT_CONSENTED] The user has disabled the required settings.");
166
167         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);
168
169         SysTryReturn(NID_LOC, Double::IsNaN(distance) == false, E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] The distance is NaN.");
170
171         if (__locationUpdateType == _LOCATION_UPDATE_TYPE_DISTANCE && (Double::Compare(__distanceThreshold, distance) == 0))
172         {
173                 return E_SUCCESS;
174         }
175         else if (__locationUpdateType == _LOCATION_UPDATE_TYPE_DISTANCE || __locationUpdateType == _LOCATION_UPDATE_TYPE_INTERVAL)
176         {
177                 __pLocationManager->StopLocationUpdates(__reqId);
178                 __locationUpdateStatus = LOC_SVC_STATUS_IDLE;
179         }
180
181         const int INVALID_INTERVAL = 0;
182         return StartLocationUpdates(_LOCATION_UPDATE_TYPE_DISTANCE, INVALID_INTERVAL, distance);
183 }
184
185 result
186 _LocationProviderImpl::StopLocationUpdates(void)
187 {
188         SysLog(NID_LOC, "Stopping the location updates for the request ID (%ld)", __reqId);
189
190         SysTryReturn(NID_LOC, __locationUpdateType != _LOCATION_UPDATE_TYPE_NONE, E_INVALID_OPERATION, E_INVALID_OPERATION, "[E_INVALID_OPERATION] Location update has not been requested.");
191
192         result r = __pLocationManager->StopLocationUpdates(__reqId);
193
194         ResetLocationUpdates();
195
196         return r;
197 }
198
199 void
200 _LocationProviderImpl::KeepLocationUpdateAwake(bool enable)
201 {
202         if (__awakeEnabled == enable)
203         {
204                 return;
205         }
206         __awakeEnabled = enable;
207
208         UiApp* appInstance = Tizen::App::UiApp::GetInstance();
209         if (appInstance == null)        // This is service APP. So should be handled now.
210         {
211                 SysLog(NID_LOC, "Handling the request awake mode(%d) for the service application.", enable);
212                 if (enable == true)
213                 {
214                         if (__locationUpdateType != _LOCATION_UPDATE_TYPE_NONE && __locationUpdateStatus == LOC_SVC_STATUS_PAUSED)
215                         {
216                                 SysLog(NID_LOC, "Requesting to start the location updates as the update type is (%x)", __locationUpdateType);
217                                 __locationUpdateStatus = LOC_SVC_STATUS_NOT_FIXED;
218                                 __pLocationManager->StartLocationUpdates(__criteria.GetAccuracy(), __updateInterval, this, __reqId);
219
220                                 NotifyServiceStatus(_LOC_PRV_EVENT_SEND_LOC_SVC_CB, __locationUpdateStatus);
221                         }
222                 }
223                 else
224                 {
225                         if (__locationUpdateType != _LOCATION_UPDATE_TYPE_NONE && (__locationUpdateStatus == LOC_SVC_STATUS_RUNNING || __locationUpdateStatus == LOC_SVC_STATUS_NOT_FIXED))
226                         {
227                                 SysLog(NID_LOC, "Requesting to stop the location updates as the update type is (%x)", __locationUpdateType);
228                                 __locationUpdateStatus = LOC_SVC_STATUS_PAUSED;
229                                 __pLocationManager->StopLocationUpdates(__reqId);
230
231                                 NotifyServiceStatus(_LOC_PRV_EVENT_SEND_LOC_SVC_CB, __locationUpdateStatus);
232                         }
233                 }
234         }
235 }
236
237 result
238 _LocationProviderImpl::AddMonitoringRegion(const Coordinates& regionCenter, double radius, RegionId& regionId)
239 {
240         bool userConsent = GetUserPrivilege();
241         SysTryReturn(NID_LOC, userConsent, E_USER_NOT_CONSENTED, E_USER_NOT_CONSENTED, "[E_USER_NOT_CONSENTED] The user has disabled the required settings.");
242
243         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
245         SysTryReturn(NID_LOC, (!Double::IsNaN(radius) && !Double::IsNaN(regionCenter.GetLatitude()) && !Double::IsNaN(regionCenter.GetLongitude())),
246                                  E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] One of the value is NaN.");
247
248         SysLog(NID_LOC, "Requested to add the monitoring region with center (Latitude: %lf, Longitude %lf) and radius (%lf).", regionCenter.GetLatitude(), regionCenter.GetLongitude(), radius);
249
250         const int DEAULT_REGION_MONITOR_INTERVAL = 5;
251         static int nextRegionId = 0;
252         result r = E_SUCCESS;
253
254         std::unique_ptr< _RegionInfo > pRegionInfo(new (std::nothrow) _RegionInfo(regionCenter, radius, nextRegionId));
255         SysTryReturn(NID_LOC, pRegionInfo != null, E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY));
256
257         r = __pRegionList->Add(*pRegionInfo.get());
258         SysTryReturn(NID_LOC, r == E_SUCCESS, r, r, "[%s] Failed to add the Region info into the list. Propogated.", GetErrorMessage(r));
259
260         pRegionInfo.release();
261         regionId = nextRegionId;
262         nextRegionId++;
263
264         if (__regionMonitoringActive == true)
265         {
266                 return E_SUCCESS;
267         }
268
269         r = __pLocationManager->StartLocationUpdates(__criteria.GetAccuracy(), DEAULT_REGION_MONITOR_INTERVAL, this, __regionReqId);
270         SysTryReturn(NID_LOC, r == E_SUCCESS, r, r, "[%s] Failed to start the location updates. Propogating.", GetErrorMessage(r));
271
272         __regionMonitoringActive = true;
273         __regionMonitorStatus = LOC_SVC_STATUS_NOT_FIXED;
274         NotifyServiceStatus(_LOC_PRV_EVENT_SEND_MONITOR_SVC_CB, __regionMonitorStatus);
275
276         return E_SUCCESS;
277 }
278
279 result
280 _LocationProviderImpl::RemoveMonitoringRegion(RegionId regionId)
281 {
282         int count = __pRegionList->GetCount();
283         result r = E_SUCCESS;
284         bool isIdValid = false;
285
286         SysLog(NID_LOC, "Total regions currently monitored is (%d).", count);
287
288         for (int i = 0; i < count; i++)
289         {
290                 _RegionInfo* pRegionInfo = static_cast< _RegionInfo* >(__pRegionList->GetAt(i));
291                 if (regionId == pRegionInfo->GetRegionId())
292                 {
293                         __pRegionList->RemoveAt(i, true);
294                         isIdValid = true;
295                         break;
296                 }
297         }
298
299         SysTryReturn(NID_LOC, isIdValid == true, E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] The region ID is invalid.");
300
301         if (__pRegionList->GetCount() == 0)
302         {
303                 __regionMonitoringActive = false;
304                 __regionMonitorStatus = LOC_SVC_STATUS_IDLE;
305                 if (__locationUpdateStatus == LOC_SVC_STATUS_IDLE)  // As we are using the same variable for both region monitoring and location updates, this set is required here.
306                 {
307                         __lastLocationAccuracy = LOC_ACCURACY_INVALID;
308                 }
309                 r = __pLocationManager->StopLocationUpdates(__regionReqId);
310                 SysTryReturn(NID_LOC, r == E_SUCCESS, r, r, "[%s] All regions are removed but failed to stop the location updates. Propagating.", GetErrorMessage(r));
311         }
312
313         return E_SUCCESS;
314 }
315
316 void
317 _LocationProviderImpl::RemoveAllMonitoringRegions(void)
318 {
319         result r = E_SUCCESS;
320
321         __pRegionList->RemoveAll(true);
322
323         if (__regionMonitoringActive == true)
324         {
325                 __regionMonitoringActive = false;
326                 __regionMonitorStatus = LOC_SVC_STATUS_IDLE;
327                 if (__locationUpdateStatus == LOC_SVC_STATUS_IDLE)  // As we are using the same variable for both region monitoring and location updates, this set is required here.
328                 {
329                         __lastLocationAccuracy = LOC_ACCURACY_INVALID;
330                 }
331                 r = __pLocationManager->StopLocationUpdates(__regionReqId);
332                 SysTryReturnVoidResult(NID_LOC, r == E_SUCCESS, r, "[%s] All regions are removed but failed to stop the location updates. Ignored.", GetErrorMessage(r));
333         }
334
335         return;
336 }
337
338 LocationServiceStatus
339 _LocationProviderImpl::GetLocationUpdateStatus(void) const
340 {
341         return __locationUpdateStatus;
342 }
343
344 LocationServiceStatus
345 _LocationProviderImpl::GetRegionMonitoringStatus(void) const
346 {
347         return __regionMonitorStatus;
348 }
349
350 LocationAccuracy
351 _LocationProviderImpl::GetCurrentAccuracy(void) const
352 {
353         return __lastLocationAccuracy;
354 }
355
356 Location
357 _LocationProviderImpl::GetLocation(const LocationCriteria& criteria)
358 {
359         Location retLocation(_LocationImpl::GetLocationInstance());
360
361         bool userConsent = GetUserPrivilege();
362         SysTryReturn(NID_LOC, userConsent, retLocation, E_USER_NOT_CONSENTED, "[E_USER_NOT_CONSENTED] The user has disabled the required settings.");
363
364         Location* pLocation = null;
365         const int MAX_TIMEOUT = 30;
366         result r = E_SUCCESS;
367         _LocationManager* pLocationManager = null;
368
369         SysLog(NID_LOC, "Requesting for single location with criteria (%x).", criteria.GetAccuracy());
370
371         std::unique_ptr< _LocationMonitor > pLocMonitor(new (std::nothrow) _LocationMonitor());
372         SysTryCatch(NID_LOC, pLocMonitor, , E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY));
373
374         r = pLocMonitor->Construct(MAX_TIMEOUT, criteria.GetAccuracy());
375         SysTryCatch(NID_LOC, r == E_SUCCESS, , r, "[%s] Failed to construct the Location Monitor.", GetErrorMessage(r));
376
377         pLocationManager = _LocationManager::GetInstance();
378         SysTryCatch(NID_LOC, pLocationManager, , r, "[%s] Failed to get the location manager instance.", GetErrorMessage(r));
379
380         r = pLocationManager->RegisterLocationMonitor(pLocMonitor.get());
381         SysTryCatch(NID_LOC, r == E_SUCCESS, , r, "[%s] Failed to register the location monitor.", GetErrorMessage(r));
382
383         r = pLocMonitor->Wait();
384
385         if (!IsFailed(r))
386         {
387                 pLocation = pLocMonitor->GetLocationN();
388         }
389
390         if (pLocation)
391         {
392                 retLocation = *pLocation;
393         }
394         else
395         {
396                 SetLastResult(E_LOCATION_UNAVAILABLE);
397         }
398
399         delete pLocation;
400
401         return retLocation;
402
403 CATCH:
404         return retLocation;
405 }
406
407 Location
408 _LocationProviderImpl::GetLastKnownLocation(void)
409 {
410         Location retLocation(_LocationImpl::GetLocationInstance());
411
412         bool userConsent = GetUserPrivilege();
413         SysTryReturn(NID_LOC, userConsent, retLocation, E_USER_NOT_CONSENTED, "[E_USER_NOT_CONSENTED] The user has disabled the required settings.");
414
415         _LocationManager* pLocationManager = _LocationManager::GetInstance();
416         SysTryReturn(NID_LOC, pLocationManager, retLocation, E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY));
417
418         retLocation = pLocationManager->GetLastKnownLocation();
419
420         if (!retLocation.IsValid())
421         {
422                 SetLastResult(E_LOCATION_UNAVAILABLE);
423         }
424         else
425         {
426                 ClearLastResult();
427         }
428
429         return retLocation;
430 }
431
432 // Private members
433
434 void
435 _LocationProviderImpl::OnLocationUpdated(RequestId reqId, const Tizen::Locations::Location& location)
436 {
437         SysLog(NID_LOC, "Location is updated from Location Manager for the request ID (%ld).", reqId);
438
439         std::unique_ptr< Location > pLocation(new (std::nothrow) Location(location));
440         SysTryReturnVoidResult(NID_LOC, pLocation, E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY));
441
442         std::unique_ptr< _LocProviderEventArg > pLocProviderEventArg(new (std::nothrow) _LocProviderEventArg());
443         SysTryReturnVoidResult(NID_LOC, pLocProviderEventArg, E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY));
444
445         pLocProviderEventArg->SetEventType(_LOC_PRV_EVENT_SEND_LOC);
446         pLocProviderEventArg->SetLocation(pLocation.get());
447         pLocProviderEventArg->SetRequestId(reqId);
448         pLocation.release();
449
450         result r = _Event::FireAsync(*pLocProviderEventArg);
451         SysTryReturnVoidResult(NID_LOC, r == E_SUCCESS, r, "[%s] Failed to fire the event.", GetErrorMessage(r));
452         pLocProviderEventArg.release();
453
454         return;
455 }
456
457 void
458 _LocationProviderImpl::OnLocationEventReceivedN(RequestId reqId, Tizen::Locations::Location& location)
459 {
460         SysLog(NID_LOC, "Location Event received.");
461         bool isNew = false;
462         LocationAccuracy currentAccuracy = LOC_ACCURACY_INVALID;
463         long long lastLocationTime = 0;
464
465         Location* pLocation = &location;
466         _LocationImpl* pLocationImpl = _LocationImpl::GetInstance(*pLocation);
467         if (__pLastLocation)
468         {
469                 lastLocationTime = _LocationImpl::GetInstance(*__pLastLocation.get())->GetTimestampInMs();
470         }
471
472         long long timeDifference = abs(pLocationImpl->GetTimestampInMs() - lastLocationTime);
473         SysLog(NID_LOC, "Time difference between last location timestamp (%lld) and current location timestamp (%lld) is (%lld).", lastLocationTime, pLocationImpl->GetTimestampInMs(), timeDifference);
474         if (timeDifference > 0)
475         {
476                 isNew = true;
477                 currentAccuracy = __pLocationManager->GetAccuracyLevel(pLocation->GetHorizontalAccuracy());
478         }
479
480         if (currentAccuracy != __lastLocationAccuracy)
481         {
482                 SysLog(NID_LOC, "Notify the accuracy change.");
483                 __lastLocationAccuracy = currentAccuracy;
484                 __pLocationListener->OnAccuracyChanged(currentAccuracy);
485         }
486
487         if (reqId == __reqId)
488         {
489                 HandleLocationUpdate(location, isNew);
490         }
491         else if (reqId == __regionReqId)
492         {
493                 HandleRegionMonitoring(location, isNew);
494         }
495
496         delete pLocation;
497 }
498
499 void
500 _LocationProviderImpl::OnLocationUpdateStatusChanged(Tizen::Locations::LocationServiceStatus locSvcStatus)
501 {
502         __pLocationListener->OnLocationUpdateStatusChanged(locSvcStatus);
503 }
504
505 void
506 _LocationProviderImpl::OnRegionMonitoringStatusChanged(Tizen::Locations::LocationServiceStatus locSvcStatus)
507 {
508         __pLocationListener->OnRegionMonitoringStatusChanged(locSvcStatus);
509 }
510
511 void
512 _LocationProviderImpl::OnActiveAppChanged(const Tizen::App::AppId& appId)
513 {
514         Tizen::App::App* pApp = Tizen::App::App::GetInstance();
515         Tizen::App::AppId currentAppId = pApp->GetAppId();
516
517         SysLog(NID_LOC, "Active App ID is (%ls) and the current app Id is (%ls)", appId.GetPointer(), currentAppId.GetPointer());
518
519         if (currentAppId == appId)
520         {
521                 SysLog(NID_LOC, "Application is active.");
522
523                 if (__locationUpdateStatus == LOC_SVC_STATUS_PAUSED)
524                 {
525                         SysLog(NID_LOC, "Start the location updates as the location update status is PAUSED.");
526                         __pLocationManager->StartLocationUpdates(__criteria.GetAccuracy(), __updateInterval, this, __reqId);
527                         __locationUpdateStatus = LOC_SVC_STATUS_NOT_FIXED;
528                         __pLocationListener->OnLocationUpdateStatusChanged(__locationUpdateStatus);
529                 }
530         }
531         else
532         {
533                 SysLog(NID_LOC, "Application is not active.");
534                 if (__awakeEnabled == false && (__locationUpdateStatus == LOC_SVC_STATUS_RUNNING || __locationUpdateStatus == LOC_SVC_STATUS_NOT_FIXED))
535                 {
536                         SysLog(NID_LOC, "Stop the location updates as application is not active with awake mode as (%d) and location update state as (%x).", __awakeEnabled, __locationUpdateStatus);
537                         __pLocationManager->StopLocationUpdates(__reqId);
538                         __locationUpdateStatus = LOC_SVC_STATUS_PAUSED;
539                         __pLocationListener->OnLocationUpdateStatusChanged(__locationUpdateStatus);
540                 }
541         }
542 }
543
544 result
545 _LocationProviderImpl::StartLocationUpdates(LocationUpdateType updateType, int interval, double distance)
546 {
547         result r = E_SUCCESS;
548         const int CHECKING_INTERVAL = 10;
549
550         if (updateType == _LOCATION_UPDATE_TYPE_INTERVAL)
551         {
552                 __updateInterval = interval;
553         }
554         else if (updateType == _LOCATION_UPDATE_TYPE_DISTANCE)
555         {
556                 __updateInterval = CHECKING_INTERVAL;
557                 __distanceThreshold = distance;
558         }
559
560         __locationUpdateType = updateType;
561
562         if (__awakeEnabled == true)
563         {
564                 r = __pLocationManager->StartLocationUpdates(__criteria.GetAccuracy(), __updateInterval, this, __reqId);
565                 SysTryReturn(NID_LOC, r == E_SUCCESS, r, r, "[%s] Failed to start the Native location updates.", GetErrorMessage(r));
566                 __locationUpdateStatus = LOC_SVC_STATUS_NOT_FIXED;
567         }
568         else
569         {
570                 UiApp* pAppInstance = Tizen::App::UiApp::GetInstance();
571                 if (pAppInstance == null)
572                 {
573                         __locationUpdateStatus = LOC_SVC_STATUS_PAUSED;
574                 }
575                 else
576                 {
577                         AppUiState appUiState = pAppInstance->GetAppUiState();
578                         if (appUiState == APP_UI_STATE_FOREGROUND || appUiState == APP_UI_STATE_PARTIAL_BACKGROUND)
579                         {
580                                 r = __pLocationManager->StartLocationUpdates(__criteria.GetAccuracy(), __updateInterval, this, __reqId);
581                                 SysTryCatch(NID_LOC, r == E_SUCCESS, , r, "[%s] Failed to start the location updates. Propagating.", GetErrorMessage(r));
582                                 __locationUpdateStatus = LOC_SVC_STATUS_NOT_FIXED;
583                         }
584                         else
585                         {
586                                 __locationUpdateStatus = LOC_SVC_STATUS_PAUSED;
587                         }
588                 }
589         }
590
591         SysLog(NID_LOC, "Update type is (%x). The request Id is (%ld) and the update status is (%x).", __locationUpdateType, __reqId, __locationUpdateStatus);
592         NotifyServiceStatus(_LOC_PRV_EVENT_SEND_LOC_SVC_CB, __locationUpdateStatus);
593
594         return E_SUCCESS;
595
596 CATCH:
597         __locationUpdateType = _LOCATION_UPDATE_TYPE_NONE;
598         return r;
599 }
600
601 bool
602 _LocationProviderImpl::CheckDistanceThreshold(const Location& oldPosition, const Location& newPosition)
603 {
604         double displacement = 0.0;
605         const Coordinates coordOld = oldPosition.GetCoordinates();
606         const Coordinates coordNew = newPosition.GetCoordinates();
607
608         if (__firstLocationUpdate)
609         {
610                 SysLog(NID_LOC, "First location update. So send true.");
611                 __firstLocationUpdate = false;
612                 return true;
613         }
614
615         displacement = coordOld.GetDistanceTo(coordNew);
616         SysLog(NID_LOC, "Displacement is (%lf)", displacement);
617         return ((displacement > __distanceThreshold) ? true : false);
618 }
619
620 void
621 _LocationProviderImpl::ResetLocationUpdates(void)
622 {
623         __firstLocationUpdate = true;
624         __reqId = -1;
625         __lastLocationAccuracy = LOC_ACCURACY_INVALID;
626         __locationUpdateType = _LOCATION_UPDATE_TYPE_NONE;
627         __locationUpdateStatus = LOC_SVC_STATUS_IDLE;
628         __updateInterval = 0;
629         __distanceThreshold = 0.0;
630 }
631
632 void
633 _LocationProviderImpl::FireImpl(Tizen::Base::Runtime::IEventListener& listener, const Tizen::Base::Runtime::IEventArg& arg)
634 {
635         _ILocProviderEventListener* pLocProviderEventListener = dynamic_cast< _ILocProviderEventListener* >(&listener);
636         SysTryReturnVoidResult(NID_LOC, pLocProviderEventListener, E_SYSTEM, "[E_INVALID_ARG] The listener is null.");
637
638         IEventArg* pArg = const_cast< IEventArg* >(&arg);
639         _LocProviderEventArg* pEventArg = dynamic_cast< _LocProviderEventArg* >(pArg);
640         SysTryReturnVoidResult(NID_LOC, pEventArg, E_SYSTEM, "[E_INVALID_ARG] Event argument is null.");
641
642         _LocProviderEventType eventType = pEventArg->GetEventType();
643         switch (eventType)
644         {
645         case _LOC_PRV_EVENT_SEND_LOC:
646                 pLocProviderEventListener->OnLocationEventReceivedN(pEventArg->GetRequestId(), *pEventArg->GetLocationN());
647                 break;
648
649         case _LOC_PRV_EVENT_SEND_LOC_SVC_CB:
650                 pLocProviderEventListener->OnLocationUpdateStatusChanged(pEventArg->GetLocServiceStatus());
651                 break;
652
653         case _LOC_PRV_EVENT_SEND_MONITOR_SVC_CB:
654                 pLocProviderEventListener->OnRegionMonitoringStatusChanged(pEventArg->GetLocServiceStatus());
655                 break;
656         }
657 }
658
659 void
660 _LocationProviderImpl::HandleLocationUpdate(Tizen::Locations::Location& location, bool isNew)
661 {
662         LocationServiceStatus newLocationUpdateStatus = __locationUpdateStatus;
663
664         if (isNew)
665         {
666                 if (__locationUpdateType != _LOCATION_UPDATE_TYPE_NONE && __locationUpdateStatus != LOC_SVC_STATUS_PAUSED)
667                 {
668                         newLocationUpdateStatus = LOC_SVC_STATUS_RUNNING;
669                 }
670         }
671         else if (_LocationImpl::GetInstance(location)->IsDenied())
672         {
673                 SysLog(NID_LOC, "User consent not available.");
674                 if (__locationUpdateType != _LOCATION_UPDATE_TYPE_NONE && __locationUpdateStatus != LOC_SVC_STATUS_PAUSED)
675                 {
676                         newLocationUpdateStatus = LOC_SVC_STATUS_DENIED;
677                 }
678         }
679         else
680         {
681                 SysLog(NID_LOC, "Invalid Location Update.");
682                 if (__locationUpdateType != _LOCATION_UPDATE_TYPE_NONE && __locationUpdateStatus != LOC_SVC_STATUS_PAUSED)
683                 {
684                         newLocationUpdateStatus = LOC_SVC_STATUS_NOT_FIXED;
685                 }
686         }
687
688         if (newLocationUpdateStatus != __locationUpdateStatus)
689         {
690                 SysLog(NID_LOC, "Location Update Satus changed to (%x). Notify the status.", newLocationUpdateStatus);
691                 __locationUpdateStatus = newLocationUpdateStatus;
692                 __pLocationListener->OnLocationUpdateStatusChanged(__locationUpdateStatus);
693         }
694
695         if (newLocationUpdateStatus == LOC_SVC_STATUS_RUNNING)
696         {
697                 if (__locationUpdateType == _LOCATION_UPDATE_TYPE_DISTANCE)
698                 {
699                         if (CheckDistanceThreshold(*__pLastLocation.get(), location) == true)
700                         {
701                                 SysLog(NID_LOC, "Location displacement exceeds the distance threshold (%lf). Notify the location.", __distanceThreshold);
702                                 __pLocationListener->OnLocationUpdated(location);
703                                 *__pLastLocation.get() = location;
704                         }
705                 }
706                 else if (__locationUpdateType == _LOCATION_UPDATE_TYPE_INTERVAL)
707                 {
708                         SysLog(NID_LOC, "Location time interval expired. Notify the location.");
709                         __pLocationListener->OnLocationUpdated(location);
710                         *__pLastLocation.get() = location;
711                 }
712         }
713 }
714
715 void
716 _LocationProviderImpl::HandleRegionMonitoring(Tizen::Locations::Location& location, bool isNew)
717 {
718         LocationServiceStatus newRegionMonitorStatus = __regionMonitorStatus;
719
720         if (isNew)
721         {
722                 newRegionMonitorStatus = LOC_SVC_STATUS_RUNNING;
723         }
724         else if (_LocationImpl::GetInstance(location)->IsDenied())
725         {
726                 newRegionMonitorStatus = LOC_SVC_STATUS_DENIED;
727         }
728         else
729         {
730                 newRegionMonitorStatus = LOC_SVC_STATUS_NOT_FIXED;
731         }
732
733         if (newRegionMonitorStatus != __regionMonitorStatus)
734         {
735                 SysLog(NID_LOC, "Region Monitoring Satus changed to (%x). Notify the status.", newRegionMonitorStatus);
736                 __regionMonitorStatus = newRegionMonitorStatus;
737                 __pLocationListener->OnRegionMonitoringStatusChanged(__regionMonitorStatus);
738         }
739
740         if (newRegionMonitorStatus == LOC_SVC_STATUS_RUNNING)
741         {
742                 NotifyRegionCrossedStatus(location);
743                 *__pLastLocation.get() = location;
744         }
745 }
746
747 void
748 _LocationProviderImpl::NotifyRegionCrossedStatus(const Tizen::Locations::Location& location)
749 {
750         int count = __pRegionList->GetCount();
751
752         SysLog(NID_LOC, "Number of regions currently monitored is (%d)", count);
753
754         for (int i = 0; i < count; i++)
755         {
756                 _RegionInfo* pRegionInfo = static_cast< _RegionInfo* >(__pRegionList->GetAt(i));
757
758                 if (pRegionInfo)
759                 {
760                         Coordinates regionCoordinate = pRegionInfo->GetCoordinate();
761                         _RegionState currentState = REGION_STATE_UNKNOWN;
762                         _RegionState previousState = pRegionInfo->GetPreviousValidState();
763                         bool notifyStateChange = false;
764
765                         currentState = GetRegionCurrentState(*pRegionInfo, location);
766                         SysLog(NID_LOC, "Current Region state is (%d) and Previous Region state is (%d)", currentState, previousState);
767
768                         if (currentState != REGION_STATE_UNKNOWN && previousState != currentState)
769                         {
770                                 notifyStateChange = true;
771                                 pRegionInfo->SetValidPreviousState(currentState);
772                         }
773
774                         if ((pRegionInfo->GetRegionState() == REGION_STATE_INSIDE || pRegionInfo->GetRegionState() == REGION_STATE_UNKNOWN) && currentState == REGION_STATE_OUTSIDE)
775                         {
776                                 if (notifyStateChange)
777                                 {
778                                         SysLog(NID_LOC, "Notify the boundary crossed event as previous valid region state is INSIDE and current state is OUTSIDE.");
779                                         __pLocationListener->OnRegionLeft(pRegionInfo->GetRegionId());
780                                 }
781                         }
782                         else if ((pRegionInfo->GetRegionState() == REGION_STATE_OUTSIDE || pRegionInfo->GetRegionState() == REGION_STATE_UNKNOWN) && currentState == REGION_STATE_INSIDE)
783                         {
784                                 if (notifyStateChange)
785                                 {
786                                         SysLog(NID_LOC, "Notify the boundary crossed event as previous valid region state is OUTSIDE and current state is INSIDE.");
787                                         __pLocationListener->OnRegionEntered(pRegionInfo->GetRegionId());
788                                 }
789                         }
790                         pRegionInfo->SetRegionState(currentState);
791                 }
792         }
793 }
794
795 _RegionState
796 _LocationProviderImpl::GetRegionCurrentState(const _RegionInfo& region, const Location& location)
797 {
798         TryReturn(location.GetHorizontalAccuracy() >= 0.0, REGION_STATE_UNKNOWN, "Location received with invalid accuracy");
799
800         SysLog(NID_LOC, "[RegionID %d] Region Information is (Center latitude: %lf, Center longitude: %lf, Region radius:%lf", region.GetRegionId(), region.GetCoordinate().GetLatitude(),
801                    region.GetCoordinate().GetLongitude(), region.GetRadius());
802         SysLog(NID_LOC, "[RegionID %d] Location Information is (Latitude: %lf, Longitude: %lf, Horizontal accuracy:%lf", region.GetRegionId(), location.GetCoordinates().GetLatitude(),
803                    location.GetCoordinates().GetLongitude(), location.GetHorizontalAccuracy());
804
805         _RegionState regionState = REGION_STATE_UNKNOWN;
806
807         double distanceBtwCenters = region.GetCoordinate().GetDistanceTo(location.GetCoordinates());
808         double regionRadius = region.GetRadius();
809         double locationRadius = location.GetHorizontalAccuracy();
810
811         SysLog(NID_LOC, "[RegionID %d]  The distance between centers is (%lf)", region.GetRegionId(), distanceBtwCenters);
812
813         if (distanceBtwCenters >= (regionRadius + locationRadius))
814         {
815                 regionState = REGION_STATE_OUTSIDE;
816         }
817         else if (distanceBtwCenters < regionRadius && Double::Compare(locationRadius, 0.0) == 0)
818         {
819                 SysLog(NID_LOC, "[RegionID %d] Location Radius is 0 and distance < regionRadius", region.GetRegionId());
820                 regionState = REGION_STATE_INSIDE;
821         }
822         else
823         {
824                 double radiusThreshold = (1 / Math::Sqrt(2)) * locationRadius;
825
826                 if (regionRadius < radiusThreshold)
827                 {
828                         SysLog(NID_LOC, "[RegionID %d] Region circle is less than 50 percent area of the location circle.", region.GetRegionId());
829                         regionState = (distanceBtwCenters >= locationRadius) ? REGION_STATE_OUTSIDE : REGION_STATE_UNKNOWN;
830
831                         return regionState;
832                 }
833                 else
834                 {
835                         double overlapRegion = _MathUtils::CalculateOverlapRegion(region, location);
836                         double upperThreshold = 0;
837                         double lowerThreshold = 0;
838                         double occupancy = 0;
839
840                         SysLog(NID_LOC, "[RegionID %d] OverlapRegion is (%lf)", region.GetRegionId(), overlapRegion);
841
842                         if (regionRadius >= locationRadius)
843                         {
844                                 // Calculate occupancy % with the location circle
845                                 SysLog(NID_LOC, "[RegionID %d] Region radius is bigger.", region.GetRegionId());
846                                 occupancy = (overlapRegion / (Math::GetPi() * locationRadius * locationRadius)) * 100;
847
848                                 upperThreshold = 60;
849                                 lowerThreshold = 40;
850                         }
851                         else if (regionRadius >= radiusThreshold)
852                         {
853                                 SysLog(NID_LOC, "[RegionID %d] The ratio of Region radius to location radius is between 0.707 and 1.", region.GetRegionId());
854                                 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)
855
856                                 SysLog(NID_LOC, "[RegionID %d] Threshold value is %lf.", region.GetRegionId(), thresholdValue);
857
858                                 occupancy = (overlapRegion / (Math::GetPi() * locationRadius * locationRadius)) * 100;
859
860                                 upperThreshold = 50 + thresholdValue;
861                                 lowerThreshold = 50 - thresholdValue;
862                         }
863
864                         // Decide the state with as per the inner and outer thresholds
865                         SysLog(NID_LOC, "[RegionID %d] Occupancy is (%lf), Upper threshold is (%lf) and lower threshold is (%lf).", region.GetRegionId(), occupancy, upperThreshold, lowerThreshold);
866                         regionState = (occupancy >= upperThreshold) ? REGION_STATE_INSIDE : ((occupancy <= lowerThreshold) ? REGION_STATE_OUTSIDE : REGION_STATE_UNKNOWN);
867                 }
868         }
869
870         SysLog(NID_LOC, "[RegionID %d] Returning region state as (%d).", region.GetRegionId(), regionState);
871         return regionState;
872 }
873
874 void
875 _LocationProviderImpl::NotifyServiceStatus(_LocProviderEventType eventType, LocationServiceStatus svcStatus)
876 {
877         std::unique_ptr< _LocProviderEventArg > pLocProviderEventArg(new (std::nothrow) _LocProviderEventArg());
878         if (pLocProviderEventArg)
879         {
880                 pLocProviderEventArg->SetEventType(eventType);
881                 pLocProviderEventArg->SetLocServiceStatus(svcStatus);
882
883                 result r = _Event::FireAsync(*pLocProviderEventArg.get());
884                 SysTryReturnVoidResult(NID_LOC, r == E_SUCCESS, r, "[%s] Failed to fire the event.", GetErrorMessage(r));
885
886                 pLocProviderEventArg.release();
887         }
888
889         return;
890 }
891
892 bool
893 _LocationProviderImpl::GetUserPrivilege(void)
894 {
895         _LocationManager* pLocMgr = _LocationManager::GetInstance();
896         SysTryReturn(NID_LOC, pLocMgr, false, E_SYSTEM, "[E_SYSTEM] Failed to get the location manager instance.");
897
898         bool appSettingEnabled = pLocMgr->IsAppEnabled();
899         if (appSettingEnabled == false)
900         {
901                 return false;
902         }
903
904         bool hasPrivilege = false;
905         result gps = E_SUCCESS;
906         result wps = E_SUCCESS;
907
908         bool gpsEnabled = true;
909         bool wpsEnabled = true;
910
911         gps = _SettingInfoImpl::GetValue(L"http://tizen.org/setting/location.gps", gpsEnabled);
912         wps = _SettingInfoImpl::GetValue(L"http://tizen.org/setting/location.wps", wpsEnabled);
913
914         hasPrivilege = gpsEnabled | wpsEnabled;
915
916         if (gps != E_SUCCESS || wps != E_SUCCESS || hasPrivilege == false)
917         {
918                 return false;
919         }
920
921         return true;
922 }
923 }}