Remove PlatformFile from profile_browsertest
[chromium-blink-merge.git] / content / browser / geolocation / geolocation_provider_impl.cc
blobf343c2920ff527466011c87b469a48a93f475f3d
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_impl.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/message_loop.h"
14 #include "content/browser/geolocation/location_arbitrator_impl.h"
15 #include "content/public/browser/browser_thread.h"
17 namespace content {
19 namespace {
20 void OverrideLocationForTestingOnIOThread(
21 const Geoposition& position,
22 const base::Closure& completion_callback,
23 scoped_refptr<base::MessageLoopProxy> callback_loop) {
24 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
25 GeolocationProviderImpl::GetInstance()->OverrideLocationForTesting(position);
26 callback_loop->PostTask(FROM_HERE, completion_callback);
28 } // namespace
30 GeolocationProvider* GeolocationProvider::GetInstance() {
31 return GeolocationProviderImpl::GetInstance();
34 void GeolocationProvider::OverrideLocationForTesting(
35 const Geoposition& position,
36 const base::Closure& completion_callback) {
37 base::Closure closure = base::Bind(&OverrideLocationForTestingOnIOThread,
38 position,
39 completion_callback,
40 base::MessageLoopProxy::current());
41 if (!BrowserThread::CurrentlyOn(BrowserThread::IO))
42 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, closure);
43 else
44 closure.Run();
47 void GeolocationProviderImpl::AddLocationUpdateCallback(
48 const LocationUpdateCallback& callback, bool use_high_accuracy) {
49 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
50 bool found = false;
51 CallbackList::iterator i = callbacks_.begin();
52 for (; i != callbacks_.end(); ++i) {
53 if (i->first.Equals(callback)) {
54 i->second = use_high_accuracy;
55 found = true;
56 break;
59 if (!found)
60 callbacks_.push_back(std::make_pair(callback, use_high_accuracy));
62 OnClientsChanged();
63 if (position_.Validate() ||
64 position_.error_code != Geoposition::ERROR_CODE_NONE) {
65 callback.Run(position_);
69 bool GeolocationProviderImpl::RemoveLocationUpdateCallback(
70 const LocationUpdateCallback& callback) {
71 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
72 bool removed = false;
73 CallbackList::iterator i = callbacks_.begin();
74 for (; i != callbacks_.end(); ++i) {
75 if (i->first.Equals(callback)) {
76 callbacks_.erase(i);
77 removed = true;
78 break;
81 if (removed)
82 OnClientsChanged();
83 return removed;
86 void GeolocationProviderImpl::UserDidOptIntoLocationServices() {
87 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
88 bool was_permission_granted = user_did_opt_into_location_services_;
89 user_did_opt_into_location_services_ = true;
90 if (IsRunning() && !was_permission_granted)
91 InformProvidersPermissionGranted();
94 bool GeolocationProviderImpl::LocationServicesOptedIn() const {
95 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
96 return user_did_opt_into_location_services_;
99 void GeolocationProviderImpl::OnLocationUpdate(const Geoposition& position) {
100 DCHECK(OnGeolocationThread());
101 // Will be true only in testing.
102 if (ignore_location_updates_)
103 return;
104 BrowserThread::PostTask(BrowserThread::IO,
105 FROM_HERE,
106 base::Bind(&GeolocationProviderImpl::NotifyClients,
107 base::Unretained(this), position));
110 void GeolocationProviderImpl::OverrideLocationForTesting(
111 const Geoposition& position) {
112 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
113 position_ = position;
114 ignore_location_updates_ = true;
115 NotifyClients(position);
118 GeolocationProviderImpl* GeolocationProviderImpl::GetInstance() {
119 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
120 return Singleton<GeolocationProviderImpl>::get();
123 GeolocationProviderImpl::GeolocationProviderImpl()
124 : base::Thread("Geolocation"),
125 user_did_opt_into_location_services_(false),
126 ignore_location_updates_(false),
127 arbitrator_(NULL) {
128 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
131 GeolocationProviderImpl::~GeolocationProviderImpl() {
132 // All callbacks should have unregistered before this singleton is destructed.
133 DCHECK(callbacks_.empty());
134 Stop();
135 DCHECK(!arbitrator_);
138 bool GeolocationProviderImpl::OnGeolocationThread() const {
139 return base::MessageLoop::current() == message_loop();
142 void GeolocationProviderImpl::OnClientsChanged() {
143 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
144 base::Closure task;
145 if (callbacks_.empty()) {
146 DCHECK(IsRunning());
147 // We have no more observers, so we clear the cached geoposition so that
148 // when the next observer is added we will not provide a stale position.
149 position_ = Geoposition();
150 task = base::Bind(&GeolocationProviderImpl::StopProviders,
151 base::Unretained(this));
152 } else {
153 if (!IsRunning()) {
154 Start();
155 if (LocationServicesOptedIn())
156 InformProvidersPermissionGranted();
158 // Determine a set of options that satisfies all clients.
159 bool use_high_accuracy = false;
160 CallbackList::iterator i = callbacks_.begin();
161 for (; i != callbacks_.end(); ++i) {
162 if (i->second) {
163 use_high_accuracy = true;
164 break;
168 // Send the current options to the providers as they may have changed.
169 task = base::Bind(&GeolocationProviderImpl::StartProviders,
170 base::Unretained(this),
171 use_high_accuracy);
174 message_loop()->PostTask(FROM_HERE, task);
177 void GeolocationProviderImpl::StopProviders() {
178 DCHECK(OnGeolocationThread());
179 DCHECK(arbitrator_);
180 arbitrator_->StopProviders();
183 void GeolocationProviderImpl::StartProviders(bool use_high_accuracy) {
184 DCHECK(OnGeolocationThread());
185 DCHECK(arbitrator_);
186 arbitrator_->StartProviders(use_high_accuracy);
189 void GeolocationProviderImpl::InformProvidersPermissionGranted() {
190 DCHECK(IsRunning());
191 if (!OnGeolocationThread()) {
192 message_loop()->PostTask(
193 FROM_HERE,
194 base::Bind(&GeolocationProviderImpl::InformProvidersPermissionGranted,
195 base::Unretained(this)));
196 return;
198 DCHECK(OnGeolocationThread());
199 DCHECK(arbitrator_);
200 arbitrator_->OnPermissionGranted();
203 void GeolocationProviderImpl::NotifyClients(const Geoposition& position) {
204 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
205 DCHECK(position.Validate() ||
206 position.error_code != Geoposition::ERROR_CODE_NONE);
207 position_ = position;
208 CallbackList::const_iterator it = callbacks_.begin();
209 while (it != callbacks_.end()) {
210 // Advance iterator before calling the observer to guard against synchronous
211 // unregister.
212 LocationUpdateCallback callback = it->first;
213 ++it;
214 callback.Run(position_);
218 void GeolocationProviderImpl::Init() {
219 DCHECK(OnGeolocationThread());
220 DCHECK(!arbitrator_);
221 arbitrator_ = CreateArbitrator();
224 void GeolocationProviderImpl::CleanUp() {
225 DCHECK(OnGeolocationThread());
226 delete arbitrator_;
227 arbitrator_ = NULL;
230 LocationArbitrator* GeolocationProviderImpl::CreateArbitrator() {
231 LocationArbitratorImpl::LocationUpdateCallback callback = base::Bind(
232 &GeolocationProviderImpl::OnLocationUpdate, base::Unretained(this));
233 return new LocationArbitratorImpl(callback);
236 } // namespace content