1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/geofencing/geofencing_service.h"
7 #include "base/location.h"
8 #include "base/memory/singleton.h"
9 #include "base/single_thread_task_runner.h"
10 #include "base/thread_task_runner_handle.h"
11 #include "content/browser/geofencing/geofencing_provider.h"
12 #include "content/browser/geofencing/geofencing_registration_delegate.h"
13 #include "content/public/browser/browser_thread.h"
14 #include "third_party/WebKit/public/platform/WebCircularGeofencingRegion.h"
20 void RunSoon(const base::Closure
& callback
) {
21 if (!callback
.is_null())
22 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE
, callback
);
27 struct GeofencingServiceImpl::Registration
{
29 Registration(const blink::WebCircularGeofencingRegion
& region
,
30 int64 geofencing_registration_id
,
31 GeofencingRegistrationDelegate
* delegate
);
33 blink::WebCircularGeofencingRegion region
;
34 int64 geofencing_registration_id
;
35 GeofencingRegistrationDelegate
* delegate
;
37 enum RegistrationState
{
38 // In progress of being registered with provider.
40 // Currently registered with provider.
42 // In progress of being registered with provider, but should be unregistered
44 STATE_SHOULD_UNREGISTER_AND_DELETE
,
45 // Not currently registered with provider, but still an active registration.
48 RegistrationState state
;
51 GeofencingServiceImpl::Registration::Registration()
52 : geofencing_registration_id(-1),
54 state(STATE_UNREGISTERED
) {
57 GeofencingServiceImpl::Registration::Registration(
58 const blink::WebCircularGeofencingRegion
& region
,
59 int64 geofencing_registration_id
,
60 GeofencingRegistrationDelegate
* delegate
)
62 geofencing_registration_id(geofencing_registration_id
),
64 state(STATE_REGISTERING
) {
67 GeofencingServiceImpl::GeofencingServiceImpl() : next_registration_id_(0) {
70 GeofencingServiceImpl::~GeofencingServiceImpl() {
73 GeofencingServiceImpl
* GeofencingServiceImpl::GetInstance() {
74 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
75 return Singleton
<GeofencingServiceImpl
>::get();
78 bool GeofencingServiceImpl::IsServiceAvailable() {
79 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
80 return EnsureProvider();
83 int64
GeofencingServiceImpl::RegisterRegion(
84 const blink::WebCircularGeofencingRegion
& region
,
85 GeofencingRegistrationDelegate
* delegate
) {
86 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
88 int64 geofencing_registration_id
= GetNextId();
89 registrations_
[geofencing_registration_id
] =
90 Registration(region
, geofencing_registration_id
, delegate
);
92 if (!EnsureProvider()) {
94 base::Bind(&GeofencingServiceImpl::NotifyRegistrationFinished
,
95 base::Unretained(this),
96 geofencing_registration_id
,
97 GEOFENCING_STATUS_OPERATION_FAILED_SERVICE_NOT_AVAILABLE
));
98 return geofencing_registration_id
;
101 provider_
->RegisterRegion(
102 geofencing_registration_id
,
104 base::Bind(&GeofencingServiceImpl::NotifyRegistrationFinished
,
105 base::Unretained(this),
106 geofencing_registration_id
));
107 return geofencing_registration_id
;
110 void GeofencingServiceImpl::UnregisterRegion(int64 geofencing_registration_id
) {
111 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
113 RegistrationsMap::iterator registration_iterator
=
114 registrations_
.find(geofencing_registration_id
);
115 DCHECK(registration_iterator
!= registrations_
.end());
117 if (!EnsureProvider())
120 switch (registration_iterator
->second
.state
) {
121 case Registration::STATE_REGISTERED
:
122 provider_
->UnregisterRegion(geofencing_registration_id
);
124 case Registration::STATE_UNREGISTERED
:
125 registrations_
.erase(registration_iterator
);
127 case Registration::STATE_REGISTERING
:
128 // Update state, NotifyRegistrationFinished will take care of actually
130 registration_iterator
->second
.state
=
131 Registration::STATE_SHOULD_UNREGISTER_AND_DELETE
;
133 case Registration::STATE_SHOULD_UNREGISTER_AND_DELETE
:
134 // Should not happen.
140 void GeofencingServiceImpl::SetProviderForTesting(
141 scoped_ptr
<GeofencingProvider
> provider
) {
142 DCHECK(!provider_
.get());
143 provider_
= provider
.Pass();
146 int GeofencingServiceImpl::RegistrationCountForTesting() {
147 return registrations_
.size();
150 bool GeofencingServiceImpl::EnsureProvider() {
151 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
154 // TODO(mek): Create platform specific provider.
160 int64
GeofencingServiceImpl::GetNextId() {
161 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
163 return next_registration_id_
++;
166 void GeofencingServiceImpl::NotifyRegistrationFinished(
167 int64 geofencing_registration_id
,
168 GeofencingStatus status
) {
169 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
171 RegistrationsMap::iterator registration_iterator
=
172 registrations_
.find(geofencing_registration_id
);
173 DCHECK(registration_iterator
!= registrations_
.end());
174 DCHECK(registration_iterator
->second
.state
==
175 Registration::STATE_REGISTERING
||
176 registration_iterator
->second
.state
==
177 Registration::STATE_SHOULD_UNREGISTER_AND_DELETE
);
179 if (registration_iterator
->second
.state
==
180 Registration::STATE_SHOULD_UNREGISTER_AND_DELETE
) {
181 // Don't call delegate, but unregister with provider if registration was
183 if (status
== GEOFENCING_STATUS_OK
) {
184 provider_
->UnregisterRegion(geofencing_registration_id
);
186 registrations_
.erase(registration_iterator
);
190 // Normal case, mark as registered and call delegate.
191 registration_iterator
->second
.state
= Registration::STATE_REGISTERED
;
192 registration_iterator
->second
.delegate
->RegistrationFinished(
193 geofencing_registration_id
, status
);
195 if (status
!= GEOFENCING_STATUS_OK
) {
196 // Registration failed, remove from our book-keeping.
197 registrations_
.erase(registration_iterator
);
201 } // namespace content