By moving the call to Load() up in SearchProvider::Start(), we are giving a chance...
[chromium-blink-merge.git] / content / browser / geolocation / geolocation_provider.cc
blob80420b9cca360660b16d5aaec76d92630b3fad7f
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"
7 #include "base/bind.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"
17 namespace content {
19 void GeolocationProvider::AddObserver(GeolocationObserver* observer,
20 const GeolocationObserverOptions& update_options) {
21 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
22 observers_[observer] = update_options;
23 OnClientsChanged();
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);
32 if (removed)
33 OnClientsChanged();
34 return removed > 0;
37 void GeolocationProvider::RequestCallback(
38 const GeolocationUpdateCallback& callback) {
39 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
40 callbacks_.push_back(callback);
41 OnClientsChanged();
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_)
62 return;
63 BrowserThread::PostTask(BrowserThread::IO,
64 FROM_HERE,
65 base::Bind(&GeolocationProvider::NotifyClients,
66 base::Unretained(this), position));
69 void GeolocationProvider::OverrideLocationForTesting(
70 const Geoposition& position) {
71 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
72 position_ = position;
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),
86 arbitrator_(NULL) {
87 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
90 GeolocationProvider::~GeolocationProvider() {
91 // All observers should have unregistered before this singleton is destructed.
92 DCHECK(observers_.empty());
93 Stop();
94 DCHECK(!arbitrator_);
97 bool GeolocationProvider::OnGeolocationThread() const {
98 return MessageLoop::current() == message_loop();
101 void GeolocationProvider::OnClientsChanged() {
102 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
103 base::Closure task;
104 if (observers_.empty() && callbacks_.empty()) {
105 DCHECK(IsRunning());
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));
111 } else {
112 if (!IsRunning()) {
113 Start();
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),
127 options);
130 message_loop()->PostTask(FROM_HERE, task);
133 void GeolocationProvider::StopProviders() {
134 DCHECK(OnGeolocationThread());
135 DCHECK(arbitrator_);
136 arbitrator_->StopProviders();
139 void GeolocationProvider::StartProviders(
140 const GeolocationObserverOptions& options) {
141 DCHECK(OnGeolocationThread());
142 DCHECK(arbitrator_);
143 arbitrator_->StartProviders(options);
146 void GeolocationProvider::InformProvidersPermissionGranted() {
147 DCHECK(IsRunning());
148 if (!OnGeolocationThread()) {
149 message_loop()->PostTask(
150 FROM_HERE,
151 base::Bind(&GeolocationProvider::InformProvidersPermissionGranted,
152 base::Unretained(this)));
153 return;
155 DCHECK(OnGeolocationThread());
156 DCHECK(arbitrator_);
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
168 // unregister.
169 GeolocationObserver* observer = it->first;
170 ++it;
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_;
177 callbacks_.clear();
178 for (CallbackList::iterator it = callbacks.begin();
179 it != callbacks.end();
180 ++it)
181 it->Run(position);
182 OnClientsChanged();
186 void GeolocationProvider::Init() {
187 DCHECK(OnGeolocationThread());
188 DCHECK(!arbitrator_);
189 arbitrator_ = CreateArbitrator();
192 void GeolocationProvider::CleanUp() {
193 DCHECK(OnGeolocationThread());
194 delete arbitrator_;
195 arbitrator_ = NULL;
198 GeolocationArbitrator* GeolocationProvider::CreateArbitrator() {
199 return new GeolocationArbitratorImpl(this);
202 } // namespace content