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/memory/singleton.h"
8 #include "base/message_loop/message_loop.h"
9 #include "content/browser/geofencing/geofencing_provider.h"
10 #include "content/browser/geofencing/geofencing_registration_delegate.h"
11 #include "content/public/browser/browser_thread.h"
12 #include "third_party/WebKit/public/platform/WebCircularGeofencingRegion.h"
18 void RunSoon(const base::Closure
& callback
) {
19 if (!callback
.is_null())
20 base::MessageLoop::current()->PostTask(FROM_HERE
, callback
);
25 struct GeofencingServiceImpl::Registration
{
27 Registration(const blink::WebCircularGeofencingRegion
& region
,
28 int64 geofencing_registration_id
,
29 GeofencingRegistrationDelegate
* delegate
);
31 blink::WebCircularGeofencingRegion region
;
32 int64 geofencing_registration_id
;
33 GeofencingRegistrationDelegate
* delegate
;
35 enum RegistrationState
{
36 // In progress of being registered with provider.
38 // Currently registered with provider.
40 // In progress of being registered with provider, but should be unregistered
42 STATE_SHOULD_UNREGISTER_AND_DELETE
,
43 // Not currently registered with provider, but still an active registration.
46 RegistrationState state
;
49 GeofencingServiceImpl::Registration::Registration()
50 : geofencing_registration_id(-1),
52 state(STATE_UNREGISTERED
) {
55 GeofencingServiceImpl::Registration::Registration(
56 const blink::WebCircularGeofencingRegion
& region
,
57 int64 geofencing_registration_id
,
58 GeofencingRegistrationDelegate
* delegate
)
60 geofencing_registration_id(geofencing_registration_id
),
62 state(STATE_REGISTERING
) {
65 GeofencingServiceImpl::GeofencingServiceImpl() : next_registration_id_(0) {
68 GeofencingServiceImpl::~GeofencingServiceImpl() {
71 GeofencingServiceImpl
* GeofencingServiceImpl::GetInstance() {
72 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
73 return Singleton
<GeofencingServiceImpl
>::get();
76 bool GeofencingServiceImpl::IsServiceAvailable() {
77 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
78 return EnsureProvider();
81 int64
GeofencingServiceImpl::RegisterRegion(
82 const blink::WebCircularGeofencingRegion
& region
,
83 GeofencingRegistrationDelegate
* delegate
) {
84 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
86 int64 geofencing_registration_id
= GetNextId();
87 registrations_
[geofencing_registration_id
] =
88 Registration(region
, geofencing_registration_id
, delegate
);
90 if (!EnsureProvider()) {
92 base::Bind(&GeofencingServiceImpl::NotifyRegistrationFinished
,
93 base::Unretained(this),
94 geofencing_registration_id
,
95 GEOFENCING_STATUS_OPERATION_FAILED_SERVICE_NOT_AVAILABLE
));
96 return geofencing_registration_id
;
99 provider_
->RegisterRegion(
100 geofencing_registration_id
,
102 base::Bind(&GeofencingServiceImpl::NotifyRegistrationFinished
,
103 base::Unretained(this),
104 geofencing_registration_id
));
105 return geofencing_registration_id
;
108 void GeofencingServiceImpl::UnregisterRegion(int64 geofencing_registration_id
) {
109 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
111 RegistrationsMap::iterator registration_iterator
=
112 registrations_
.find(geofencing_registration_id
);
113 DCHECK(registration_iterator
!= registrations_
.end());
115 if (!EnsureProvider())
118 switch (registration_iterator
->second
.state
) {
119 case Registration::STATE_REGISTERED
:
120 provider_
->UnregisterRegion(geofencing_registration_id
);
122 case Registration::STATE_UNREGISTERED
:
123 registrations_
.erase(registration_iterator
);
125 case Registration::STATE_REGISTERING
:
126 // Update state, NotifyRegistrationFinished will take care of actually
128 registration_iterator
->second
.state
=
129 Registration::STATE_SHOULD_UNREGISTER_AND_DELETE
;
131 case Registration::STATE_SHOULD_UNREGISTER_AND_DELETE
:
132 // Should not happen.
138 void GeofencingServiceImpl::SetProviderForTesting(
139 scoped_ptr
<GeofencingProvider
> provider
) {
140 DCHECK(!provider_
.get());
141 provider_
= provider
.Pass();
144 int GeofencingServiceImpl::RegistrationCountForTesting() {
145 return registrations_
.size();
148 bool GeofencingServiceImpl::EnsureProvider() {
149 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
152 // TODO(mek): Create platform specific provider.
158 int64
GeofencingServiceImpl::GetNextId() {
159 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
161 return next_registration_id_
++;
164 void GeofencingServiceImpl::NotifyRegistrationFinished(
165 int64 geofencing_registration_id
,
166 GeofencingStatus status
) {
167 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
169 RegistrationsMap::iterator registration_iterator
=
170 registrations_
.find(geofencing_registration_id
);
171 DCHECK(registration_iterator
!= registrations_
.end());
172 DCHECK(registration_iterator
->second
.state
==
173 Registration::STATE_REGISTERING
||
174 registration_iterator
->second
.state
==
175 Registration::STATE_SHOULD_UNREGISTER_AND_DELETE
);
177 if (registration_iterator
->second
.state
==
178 Registration::STATE_SHOULD_UNREGISTER_AND_DELETE
) {
179 // Don't call delegate, but unregister with provider if registration was
181 if (status
== GEOFENCING_STATUS_OK
) {
182 provider_
->UnregisterRegion(geofencing_registration_id
);
184 registrations_
.erase(registration_iterator
);
188 // Normal case, mark as registered and call delegate.
189 registration_iterator
->second
.state
= Registration::STATE_REGISTERED
;
190 registration_iterator
->second
.delegate
->RegistrationFinished(
191 geofencing_registration_id
, status
);
193 if (status
!= GEOFENCING_STATUS_OK
) {
194 // Registration failed, remove from our book-keeping.
195 registrations_
.erase(registration_iterator
);
199 } // namespace content