Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / content / browser / geofencing / geofencing_service.cc
blob11df9529e4d34ce6646d507d48605ccdb34935ab
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"
14 namespace content {
16 namespace {
18 void RunSoon(const base::Closure& callback) {
19 if (!callback.is_null())
20 base::MessageLoop::current()->PostTask(FROM_HERE, callback);
23 } // namespace
25 struct GeofencingServiceImpl::Registration {
26 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.
37 STATE_REGISTERING,
38 // Currently registered with provider.
39 STATE_REGISTERED,
40 // In progress of being registered with provider, but should be unregistered
41 // and deleted.
42 STATE_SHOULD_UNREGISTER_AND_DELETE,
43 // Not currently registered with provider, but still an active registration.
44 STATE_UNREGISTERED
46 RegistrationState state;
49 GeofencingServiceImpl::Registration::Registration()
50 : geofencing_registration_id(-1),
51 delegate(nullptr),
52 state(STATE_UNREGISTERED) {
55 GeofencingServiceImpl::Registration::Registration(
56 const blink::WebCircularGeofencingRegion& region,
57 int64 geofencing_registration_id,
58 GeofencingRegistrationDelegate* delegate)
59 : region(region),
60 geofencing_registration_id(geofencing_registration_id),
61 delegate(delegate),
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()) {
91 RunSoon(
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,
101 region,
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())
116 return;
118 switch (registration_iterator->second.state) {
119 case Registration::STATE_REGISTERED:
120 provider_->UnregisterRegion(geofencing_registration_id);
121 // fallthru
122 case Registration::STATE_UNREGISTERED:
123 registrations_.erase(registration_iterator);
124 break;
125 case Registration::STATE_REGISTERING:
126 // Update state, NotifyRegistrationFinished will take care of actually
127 // unregistering.
128 registration_iterator->second.state =
129 Registration::STATE_SHOULD_UNREGISTER_AND_DELETE;
130 break;
131 case Registration::STATE_SHOULD_UNREGISTER_AND_DELETE:
132 // Should not happen.
133 NOTREACHED();
134 break;
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);
151 if (!provider_) {
152 // TODO(mek): Create platform specific provider.
153 return false;
155 return true;
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
180 // succesfull.
181 if (status == GEOFENCING_STATUS_OK) {
182 provider_->UnregisterRegion(geofencing_registration_id);
184 registrations_.erase(registration_iterator);
185 return;
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