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