1 // Copyright (c) 2012 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/geolocation/geolocation_provider.h"
8 #include "base/bind_helpers.h"
9 #include "base/callback.h"
10 #include "base/location.h"
11 #include "base/logging.h"
12 #include "base/memory/singleton.h"
13 #include "base/message_loop.h"
14 #include "content/browser/geolocation/location_arbitrator_impl.h"
15 #include "content/public/browser/browser_thread.h"
19 void GeolocationProvider::AddObserver(GeolocationObserver
* observer
,
20 const GeolocationObserverOptions
& update_options
) {
21 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
22 observers_
[observer
] = update_options
;
24 if (position_
.Validate() ||
25 position_
.error_code
!= Geoposition::ERROR_CODE_NONE
)
26 observer
->OnLocationUpdate(position_
);
29 bool GeolocationProvider::RemoveObserver(GeolocationObserver
* observer
) {
30 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
31 size_t removed
= observers_
.erase(observer
);
37 void GeolocationProvider::RequestCallback(
38 const GeolocationUpdateCallback
& callback
) {
39 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
40 callbacks_
.push_back(callback
);
42 OnPermissionGranted();
45 void GeolocationProvider::OnPermissionGranted() {
46 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
47 bool was_permission_granted
= is_permission_granted_
;
48 is_permission_granted_
= true;
49 if (IsRunning() && !was_permission_granted
)
50 InformProvidersPermissionGranted();
53 bool GeolocationProvider::HasPermissionBeenGranted() const {
54 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
55 return is_permission_granted_
;
58 void GeolocationProvider::OnLocationUpdate(const Geoposition
& position
) {
59 DCHECK(OnGeolocationThread());
60 // Will be true only in testing.
61 if (ignore_location_updates_
)
63 BrowserThread::PostTask(BrowserThread::IO
,
65 base::Bind(&GeolocationProvider::NotifyClients
,
66 base::Unretained(this), position
));
69 void GeolocationProvider::OverrideLocationForTesting(
70 const Geoposition
& position
) {
71 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
73 ignore_location_updates_
= true;
74 NotifyClients(position
);
77 GeolocationProvider
* GeolocationProvider::GetInstance() {
78 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
79 return Singleton
<GeolocationProvider
>::get();
82 GeolocationProvider::GeolocationProvider()
83 : base::Thread("Geolocation"),
84 is_permission_granted_(false),
85 ignore_location_updates_(false),
87 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
90 GeolocationProvider::~GeolocationProvider() {
91 // All observers should have unregistered before this singleton is destructed.
92 DCHECK(observers_
.empty());
97 bool GeolocationProvider::OnGeolocationThread() const {
98 return MessageLoop::current() == message_loop();
101 void GeolocationProvider::OnClientsChanged() {
102 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
104 if (observers_
.empty() && callbacks_
.empty()) {
106 // We have no more observers, so we clear the cached geoposition so that
107 // when the next observer is added we will not provide a stale position.
108 position_
= Geoposition();
109 task
= base::Bind(&GeolocationProvider::StopProviders
,
110 base::Unretained(this));
114 if (HasPermissionBeenGranted())
115 InformProvidersPermissionGranted();
117 // Determine a set of options that satisfies all clients.
118 GeolocationObserverOptions options
=
119 GeolocationObserverOptions::Collapse(observers_
);
120 // For callbacks, high accuracy position information is always requested.
121 if (!callbacks_
.empty())
122 options
.Collapse(GeolocationObserverOptions(true));
124 // Send the current options to the providers as they may have changed.
125 task
= base::Bind(&GeolocationProvider::StartProviders
,
126 base::Unretained(this),
130 message_loop()->PostTask(FROM_HERE
, task
);
133 void GeolocationProvider::StopProviders() {
134 DCHECK(OnGeolocationThread());
136 arbitrator_
->StopProviders();
139 void GeolocationProvider::StartProviders(
140 const GeolocationObserverOptions
& options
) {
141 DCHECK(OnGeolocationThread());
143 arbitrator_
->StartProviders(options
);
146 void GeolocationProvider::InformProvidersPermissionGranted() {
148 if (!OnGeolocationThread()) {
149 message_loop()->PostTask(
151 base::Bind(&GeolocationProvider::InformProvidersPermissionGranted
,
152 base::Unretained(this)));
155 DCHECK(OnGeolocationThread());
157 arbitrator_
->OnPermissionGranted();
160 void GeolocationProvider::NotifyClients(const Geoposition
& position
) {
161 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
162 DCHECK(position
.Validate() ||
163 position
.error_code
!= Geoposition::ERROR_CODE_NONE
);
164 position_
= position
;
165 ObserverMap::const_iterator it
= observers_
.begin();
166 while (it
!= observers_
.end()) {
167 // Advance iterator before calling the observer to guard against synchronous
169 GeolocationObserver
* observer
= it
->first
;
171 observer
->OnLocationUpdate(position_
);
173 if (!callbacks_
.empty()) {
174 // Copy the callback list to guard against synchronous callback requests
175 // reallocating the vector and invalidating the iterator.
176 CallbackList callbacks
= callbacks_
;
178 for (CallbackList::iterator it
= callbacks
.begin();
179 it
!= callbacks
.end();
186 void GeolocationProvider::Init() {
187 DCHECK(OnGeolocationThread());
188 DCHECK(!arbitrator_
);
189 arbitrator_
= CreateArbitrator();
192 void GeolocationProvider::CleanUp() {
193 DCHECK(OnGeolocationThread());
198 GeolocationArbitrator
* GeolocationProvider::CreateArbitrator() {
199 return new GeolocationArbitratorImpl(this);
202 } // namespace content