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"
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/single_thread_task_runner.h"
14 #include "content/browser/geolocation/location_arbitrator_impl.h"
15 #include "content/public/browser/browser_thread.h"
19 GeolocationProvider
* GeolocationProvider::GetInstance() {
20 return GeolocationProviderImpl::GetInstance();
23 scoped_ptr
<GeolocationProvider::Subscription
>
24 GeolocationProviderImpl::AddLocationUpdateCallback(
25 const LocationUpdateCallback
& callback
, bool use_high_accuracy
) {
26 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
27 scoped_ptr
<GeolocationProvider::Subscription
> subscription
;
28 if (use_high_accuracy
) {
29 subscription
= high_accuracy_callbacks_
.Add(callback
);
31 subscription
= low_accuracy_callbacks_
.Add(callback
);
35 if (position_
.Validate() ||
36 position_
.error_code
!= Geoposition::ERROR_CODE_NONE
) {
37 callback
.Run(position_
);
40 return subscription
.Pass();
43 void GeolocationProviderImpl::UserDidOptIntoLocationServices() {
44 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
45 bool was_permission_granted
= user_did_opt_into_location_services_
;
46 user_did_opt_into_location_services_
= true;
47 if (IsRunning() && !was_permission_granted
)
48 InformProvidersPermissionGranted();
51 void GeolocationProviderImpl::OverrideLocationForTesting(
52 const Geoposition
& position
) {
53 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
54 ignore_location_updates_
= true;
55 NotifyClients(position
);
58 void GeolocationProviderImpl::OnLocationUpdate(const Geoposition
& position
) {
59 DCHECK(OnGeolocationThread());
60 // Will be true only in testing.
61 if (ignore_location_updates_
)
63 BrowserThread::PostTask(BrowserThread::UI
,
65 base::Bind(&GeolocationProviderImpl::NotifyClients
,
66 base::Unretained(this), position
));
69 GeolocationProviderImpl
* GeolocationProviderImpl::GetInstance() {
70 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
71 return base::Singleton
<GeolocationProviderImpl
>::get();
74 GeolocationProviderImpl::GeolocationProviderImpl()
75 : base::Thread("Geolocation"),
76 user_did_opt_into_location_services_(false),
77 ignore_location_updates_(false),
79 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
80 high_accuracy_callbacks_
.set_removal_callback(
81 base::Bind(&GeolocationProviderImpl::OnClientsChanged
,
82 base::Unretained(this)));
83 low_accuracy_callbacks_
.set_removal_callback(
84 base::Bind(&GeolocationProviderImpl::OnClientsChanged
,
85 base::Unretained(this)));
88 GeolocationProviderImpl::~GeolocationProviderImpl() {
93 bool GeolocationProviderImpl::OnGeolocationThread() const {
94 return base::MessageLoop::current() == message_loop();
97 void GeolocationProviderImpl::OnClientsChanged() {
98 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
100 if (high_accuracy_callbacks_
.empty() && low_accuracy_callbacks_
.empty()) {
102 if (!ignore_location_updates_
) {
103 // We have no more observers, so we clear the cached geoposition so that
104 // when the next observer is added we will not provide a stale position.
105 position_
= Geoposition();
107 task
= base::Bind(&GeolocationProviderImpl::StopProviders
,
108 base::Unretained(this));
112 if (user_did_opt_into_location_services_
)
113 InformProvidersPermissionGranted();
115 // Determine a set of options that satisfies all clients.
116 bool use_high_accuracy
= !high_accuracy_callbacks_
.empty();
118 // Send the current options to the providers as they may have changed.
119 task
= base::Bind(&GeolocationProviderImpl::StartProviders
,
120 base::Unretained(this),
124 task_runner()->PostTask(FROM_HERE
, task
);
127 void GeolocationProviderImpl::StopProviders() {
128 DCHECK(OnGeolocationThread());
130 arbitrator_
->StopProviders();
133 void GeolocationProviderImpl::StartProviders(bool use_high_accuracy
) {
134 DCHECK(OnGeolocationThread());
136 arbitrator_
->StartProviders(use_high_accuracy
);
139 void GeolocationProviderImpl::InformProvidersPermissionGranted() {
141 if (!OnGeolocationThread()) {
142 task_runner()->PostTask(
144 base::Bind(&GeolocationProviderImpl::InformProvidersPermissionGranted
,
145 base::Unretained(this)));
148 DCHECK(OnGeolocationThread());
150 arbitrator_
->OnPermissionGranted();
153 void GeolocationProviderImpl::NotifyClients(const Geoposition
& position
) {
154 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
155 DCHECK(position
.Validate() ||
156 position
.error_code
!= Geoposition::ERROR_CODE_NONE
);
157 position_
= position
;
158 high_accuracy_callbacks_
.Notify(position_
);
159 low_accuracy_callbacks_
.Notify(position_
);
162 void GeolocationProviderImpl::Init() {
163 DCHECK(OnGeolocationThread());
164 DCHECK(!arbitrator_
);
165 arbitrator_
= CreateArbitrator();
168 void GeolocationProviderImpl::CleanUp() {
169 DCHECK(OnGeolocationThread());
174 LocationArbitrator
* GeolocationProviderImpl::CreateArbitrator() {
175 LocationArbitratorImpl::LocationUpdateCallback callback
= base::Bind(
176 &GeolocationProviderImpl::OnLocationUpdate
, base::Unretained(this));
177 return new LocationArbitratorImpl(callback
);
180 } // namespace content