1b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)// found in the LICENSE file.
4b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
5b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "content/browser/geolocation/geolocation_provider_impl.h"
6b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
7b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "base/bind.h"
8b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "base/bind_helpers.h"
9b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "base/callback.h"
10b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "base/location.h"
11b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "base/logging.h"
12b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "base/memory/singleton.h"
139ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h"
14b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "content/browser/geolocation/location_arbitrator_impl.h"
15b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "content/public/browser/browser_thread.h"
16b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
17b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)namespace content {
18b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
19b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)GeolocationProvider* GeolocationProvider::GetInstance() {
20b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  return GeolocationProviderImpl::GetInstance();
21b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
22b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
23cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)scoped_ptr<GeolocationProvider::Subscription>
24cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)GeolocationProviderImpl::AddLocationUpdateCallback(
25b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    const LocationUpdateCallback& callback, bool use_high_accuracy) {
26cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
27cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_ptr<GeolocationProvider::Subscription> subscription;
28cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (use_high_accuracy) {
29cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    subscription = high_accuracy_callbacks_.Add(callback);
30cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  } else {
31cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    subscription = low_accuracy_callbacks_.Add(callback);
32b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  }
33b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
34b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  OnClientsChanged();
35b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (position_.Validate() ||
36b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      position_.error_code != Geoposition::ERROR_CODE_NONE) {
37b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    callback.Run(position_);
38b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  }
39b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
40cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return subscription.Pass();
41b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
42b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
43b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void GeolocationProviderImpl::UserDidOptIntoLocationServices() {
44cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
45b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  bool was_permission_granted = user_did_opt_into_location_services_;
46b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  user_did_opt_into_location_services_ = true;
47b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (IsRunning() && !was_permission_granted)
48b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    InformProvidersPermissionGranted();
49b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
50b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
51cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void GeolocationProviderImpl::OverrideLocationForTesting(
52cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const Geoposition& position) {
53cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
54cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ignore_location_updates_ = true;
55cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  NotifyClients(position);
56b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
57b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
58b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void GeolocationProviderImpl::OnLocationUpdate(const Geoposition& position) {
59b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  DCHECK(OnGeolocationThread());
60b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // Will be true only in testing.
61b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (ignore_location_updates_)
62b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    return;
63cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  BrowserThread::PostTask(BrowserThread::UI,
64b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                          FROM_HERE,
65b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                          base::Bind(&GeolocationProviderImpl::NotifyClients,
66b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                     base::Unretained(this), position));
67b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
68b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
69b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)GeolocationProviderImpl* GeolocationProviderImpl::GetInstance() {
70cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
71b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  return Singleton<GeolocationProviderImpl>::get();
72b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
73b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
74b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)GeolocationProviderImpl::GeolocationProviderImpl()
75b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    : base::Thread("Geolocation"),
76b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      user_did_opt_into_location_services_(false),
77b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      ignore_location_updates_(false),
78b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      arbitrator_(NULL) {
79cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
80cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  high_accuracy_callbacks_.set_removal_callback(
81cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      base::Bind(&GeolocationProviderImpl::OnClientsChanged,
82cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                 base::Unretained(this)));
83cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  low_accuracy_callbacks_.set_removal_callback(
84cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      base::Bind(&GeolocationProviderImpl::OnClientsChanged,
85cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                 base::Unretained(this)));
86b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
87b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
88b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)GeolocationProviderImpl::~GeolocationProviderImpl() {
89b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  Stop();
90b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  DCHECK(!arbitrator_);
91b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
92b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
93b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)bool GeolocationProviderImpl::OnGeolocationThread() const {
94b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  return base::MessageLoop::current() == message_loop();
95b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
96b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
97b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void GeolocationProviderImpl::OnClientsChanged() {
98cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
99b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  base::Closure task;
100cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (high_accuracy_callbacks_.empty() && low_accuracy_callbacks_.empty()) {
101b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    DCHECK(IsRunning());
10246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (!ignore_location_updates_) {
10346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      // We have no more observers, so we clear the cached geoposition so that
10446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      // when the next observer is added we will not provide a stale position.
10546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      position_ = Geoposition();
10646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    }
107b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    task = base::Bind(&GeolocationProviderImpl::StopProviders,
108b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                      base::Unretained(this));
109b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  } else {
110b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (!IsRunning()) {
111b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      Start();
112cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      if (user_did_opt_into_location_services_)
113b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        InformProvidersPermissionGranted();
114b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    }
115b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // Determine a set of options that satisfies all clients.
116cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    bool use_high_accuracy = !high_accuracy_callbacks_.empty();
117b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
118b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // Send the current options to the providers as they may have changed.
119b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    task = base::Bind(&GeolocationProviderImpl::StartProviders,
120b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                      base::Unretained(this),
121b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                      use_high_accuracy);
122b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  }
123b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
124b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  message_loop()->PostTask(FROM_HERE, task);
125b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
126b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
127b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void GeolocationProviderImpl::StopProviders() {
128b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  DCHECK(OnGeolocationThread());
129b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  DCHECK(arbitrator_);
130b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  arbitrator_->StopProviders();
131b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
132b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
133b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void GeolocationProviderImpl::StartProviders(bool use_high_accuracy) {
134b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  DCHECK(OnGeolocationThread());
135b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  DCHECK(arbitrator_);
136b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  arbitrator_->StartProviders(use_high_accuracy);
137b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
138b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
139b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void GeolocationProviderImpl::InformProvidersPermissionGranted() {
140b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  DCHECK(IsRunning());
141b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!OnGeolocationThread()) {
142b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    message_loop()->PostTask(
143b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        FROM_HERE,
144b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        base::Bind(&GeolocationProviderImpl::InformProvidersPermissionGranted,
145b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                   base::Unretained(this)));
146b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    return;
147b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  }
148b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  DCHECK(OnGeolocationThread());
149b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  DCHECK(arbitrator_);
150b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  arbitrator_->OnPermissionGranted();
151b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
152b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
153b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void GeolocationProviderImpl::NotifyClients(const Geoposition& position) {
154cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
155b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  DCHECK(position.Validate() ||
156b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)         position.error_code != Geoposition::ERROR_CODE_NONE);
157b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  position_ = position;
158cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  high_accuracy_callbacks_.Notify(position_);
159cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  low_accuracy_callbacks_.Notify(position_);
160b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
161b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
162b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void GeolocationProviderImpl::Init() {
163b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  DCHECK(OnGeolocationThread());
164b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  DCHECK(!arbitrator_);
165b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  arbitrator_ = CreateArbitrator();
166b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
167b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
168b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void GeolocationProviderImpl::CleanUp() {
169b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  DCHECK(OnGeolocationThread());
170b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  delete arbitrator_;
171b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  arbitrator_ = NULL;
172b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
173b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
17458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)LocationArbitrator* GeolocationProviderImpl::CreateArbitrator() {
17558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  LocationArbitratorImpl::LocationUpdateCallback callback = base::Bind(
176b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      &GeolocationProviderImpl::OnLocationUpdate, base::Unretained(this));
17758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return new LocationArbitratorImpl(callback);
178b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
179b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
180b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}  // namespace content
181