OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "content/browser/geolocation/geolocation_provider_impl.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/bind_helpers.h" | |
9 #include "base/callback.h" | |
10 #include "base/lazy_instance.h" | |
11 #include "base/location.h" | |
12 #include "base/logging.h" | |
13 #include "base/memory/ptr_util.h" | |
14 #include "base/memory/singleton.h" | |
15 #include "base/single_thread_task_runner.h" | |
16 #include "content/browser/geolocation/location_arbitrator_impl.h" | |
17 #include "content/public/browser/browser_thread.h" | |
18 #include "content/public/browser/content_browser_client.h" | |
19 #include "content/public/browser/geolocation_delegate.h" | |
20 | |
21 namespace content { | |
22 | |
23 namespace { | |
24 base::LazyInstance<std::unique_ptr<GeolocationDelegate>>::Leaky g_delegate = | |
25 LAZY_INSTANCE_INITIALIZER; | |
26 } // anonymous namespace | |
27 | |
28 // static | |
29 GeolocationProvider* GeolocationProvider::GetInstance() { | |
30 return GeolocationProviderImpl::GetInstance(); | |
31 } | |
32 | |
33 // static | |
34 void GeolocationProvider::SetGeolocationDelegate( | |
35 GeolocationDelegate* delegate) { | |
36 DCHECK(!g_delegate.Get()); | |
37 g_delegate.Get().reset(delegate); | |
38 } | |
39 | |
40 std::unique_ptr<GeolocationProvider::Subscription> | |
41 GeolocationProviderImpl::AddLocationUpdateCallback( | |
42 const LocationUpdateCallback& callback, | |
43 bool enable_high_accuracy) { | |
44 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
45 std::unique_ptr<GeolocationProvider::Subscription> subscription; | |
46 if (enable_high_accuracy) { | |
47 subscription = high_accuracy_callbacks_.Add(callback); | |
48 } else { | |
49 subscription = low_accuracy_callbacks_.Add(callback); | |
50 } | |
51 | |
52 OnClientsChanged(); | |
53 if (position_.Validate() || | |
54 position_.error_code != Geoposition::ERROR_CODE_NONE) { | |
55 callback.Run(position_); | |
56 } | |
57 | |
58 return subscription; | |
59 } | |
60 | |
61 void GeolocationProviderImpl::UserDidOptIntoLocationServices() { | |
62 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
63 bool was_permission_granted = user_did_opt_into_location_services_; | |
64 user_did_opt_into_location_services_ = true; | |
65 if (IsRunning() && !was_permission_granted) | |
66 InformProvidersPermissionGranted(); | |
67 } | |
68 | |
69 void GeolocationProviderImpl::OverrideLocationForTesting( | |
70 const Geoposition& position) { | |
71 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
72 ignore_location_updates_ = true; | |
73 NotifyClients(position); | |
74 } | |
75 | |
76 void GeolocationProviderImpl::OnLocationUpdate(const Geoposition& position) { | |
77 DCHECK(OnGeolocationThread()); | |
78 // Will be true only in testing. | |
79 if (ignore_location_updates_) | |
80 return; | |
81 BrowserThread::PostTask(BrowserThread::UI, | |
82 FROM_HERE, | |
83 base::Bind(&GeolocationProviderImpl::NotifyClients, | |
84 base::Unretained(this), position)); | |
85 } | |
86 | |
87 // static | |
88 GeolocationProviderImpl* GeolocationProviderImpl::GetInstance() { | |
89 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
90 return base::Singleton<GeolocationProviderImpl>::get(); | |
91 } | |
92 | |
93 GeolocationProviderImpl::GeolocationProviderImpl() | |
94 : base::Thread("Geolocation"), | |
95 user_did_opt_into_location_services_(false), | |
96 ignore_location_updates_(false) { | |
97 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
98 high_accuracy_callbacks_.set_removal_callback( | |
99 base::Bind(&GeolocationProviderImpl::OnClientsChanged, | |
100 base::Unretained(this))); | |
101 low_accuracy_callbacks_.set_removal_callback( | |
102 base::Bind(&GeolocationProviderImpl::OnClientsChanged, | |
103 base::Unretained(this))); | |
104 } | |
105 | |
106 GeolocationProviderImpl::~GeolocationProviderImpl() { | |
107 Stop(); | |
108 DCHECK(!arbitrator_); | |
109 } | |
110 | |
111 bool GeolocationProviderImpl::OnGeolocationThread() const { | |
112 return task_runner()->BelongsToCurrentThread(); | |
113 } | |
114 | |
115 void GeolocationProviderImpl::OnClientsChanged() { | |
116 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
117 base::Closure task; | |
118 if (high_accuracy_callbacks_.empty() && low_accuracy_callbacks_.empty()) { | |
119 DCHECK(IsRunning()); | |
120 if (!ignore_location_updates_) { | |
121 // We have no more observers, so we clear the cached geoposition so that | |
122 // when the next observer is added we will not provide a stale position. | |
123 position_ = Geoposition(); | |
124 } | |
125 task = base::Bind(&GeolocationProviderImpl::StopProviders, | |
126 base::Unretained(this)); | |
127 } else { | |
128 if (!IsRunning()) { | |
129 Start(); | |
130 if (user_did_opt_into_location_services_) | |
131 InformProvidersPermissionGranted(); | |
132 } | |
133 // Determine a set of options that satisfies all clients. | |
134 bool enable_high_accuracy = !high_accuracy_callbacks_.empty(); | |
135 | |
136 // Send the current options to the providers as they may have changed. | |
137 task = base::Bind(&GeolocationProviderImpl::StartProviders, | |
138 base::Unretained(this), enable_high_accuracy); | |
139 } | |
140 | |
141 task_runner()->PostTask(FROM_HERE, task); | |
142 } | |
143 | |
144 void GeolocationProviderImpl::StopProviders() { | |
145 DCHECK(OnGeolocationThread()); | |
146 DCHECK(arbitrator_); | |
147 arbitrator_->StopProviders(); | |
148 } | |
149 | |
150 void GeolocationProviderImpl::StartProviders(bool enable_high_accuracy) { | |
151 DCHECK(OnGeolocationThread()); | |
152 DCHECK(arbitrator_); | |
153 arbitrator_->StartProviders(enable_high_accuracy); | |
154 } | |
155 | |
156 void GeolocationProviderImpl::InformProvidersPermissionGranted() { | |
157 DCHECK(IsRunning()); | |
158 if (!OnGeolocationThread()) { | |
159 task_runner()->PostTask( | |
160 FROM_HERE, | |
161 base::Bind(&GeolocationProviderImpl::InformProvidersPermissionGranted, | |
162 base::Unretained(this))); | |
163 return; | |
164 } | |
165 DCHECK(OnGeolocationThread()); | |
166 DCHECK(arbitrator_); | |
167 arbitrator_->OnPermissionGranted(); | |
168 } | |
169 | |
170 void GeolocationProviderImpl::NotifyClients(const Geoposition& position) { | |
171 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
172 DCHECK(position.Validate() || | |
173 position.error_code != Geoposition::ERROR_CODE_NONE); | |
174 position_ = position; | |
175 high_accuracy_callbacks_.Notify(position_); | |
176 low_accuracy_callbacks_.Notify(position_); | |
177 } | |
178 | |
179 void GeolocationProviderImpl::Init() { | |
180 DCHECK(OnGeolocationThread()); | |
181 DCHECK(!arbitrator_); | |
182 arbitrator_ = CreateArbitrator(); | |
183 } | |
184 | |
185 void GeolocationProviderImpl::CleanUp() { | |
186 DCHECK(OnGeolocationThread()); | |
187 arbitrator_.reset(); | |
188 } | |
189 | |
190 std::unique_ptr<LocationArbitrator> | |
191 GeolocationProviderImpl::CreateArbitrator() { | |
192 LocationArbitratorImpl::LocationUpdateCallback callback = base::Bind( | |
193 &GeolocationProviderImpl::OnLocationUpdate, base::Unretained(this)); | |
194 // Use the embedder's |g_delegate| or fall back to the default one. | |
195 if (!g_delegate.Get()) | |
196 g_delegate.Get().reset(new GeolocationDelegate); | |
197 | |
198 return base::WrapUnique( | |
199 new LocationArbitratorImpl(callback, g_delegate.Get().get())); | |
200 } | |
201 | |
202 } // namespace content | |
OLD | NEW |