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