// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "content/browser/geolocation/geolocation_provider.h" #include "base/bind.h" #include "base/bind_helpers.h" #include "base/memory/singleton.h" #include "base/threading/thread_restrictions.h" #include "content/browser/geolocation/location_arbitrator.h" GeolocationProvider* GeolocationProvider::GetInstance() { return Singleton::get(); } GeolocationProvider::GeolocationProvider() : base::Thread("Geolocation"), client_loop_(base::MessageLoopProxy::current()), arbitrator_(NULL) { } GeolocationProvider::~GeolocationProvider() { DCHECK(observers_.empty()); // observers must unregister. Stop(); DCHECK(!arbitrator_); } void GeolocationProvider::AddObserver(GeolocationObserver* observer, const GeolocationObserverOptions& update_options) { DCHECK(OnClientThread()); observers_[observer] = update_options; OnObserversChanged(); if (position_.IsInitialized()) observer->OnLocationUpdate(position_); } bool GeolocationProvider::RemoveObserver(GeolocationObserver* observer) { DCHECK(OnClientThread()); size_t remove = observers_.erase(observer); OnObserversChanged(); return remove > 0; } void GeolocationProvider::OnObserversChanged() { DCHECK(OnClientThread()); base::Closure task; if (observers_.empty()) { DCHECK(IsRunning()); task = base::Bind(&GeolocationProvider::StopProviders, base::Unretained(this)); } else { if (!IsRunning()) { Start(); if (HasPermissionBeenGranted()) InformProvidersPermissionGranted(most_recent_authorized_frame_); } // The high accuracy requirement may have changed. task = base::Bind(&GeolocationProvider::StartProviders, base::Unretained(this), GeolocationObserverOptions::Collapse(observers_)); } message_loop()->PostTask(FROM_HERE, task); } void GeolocationProvider::NotifyObservers(const Geoposition& position) { DCHECK(OnClientThread()); DCHECK(position.IsInitialized()); position_ = position; ObserverMap::const_iterator it = observers_.begin(); while (it != observers_.end()) { // Advance iterator before callback to guard against synchronous unregister. GeolocationObserver* observer = it->first; ++it; observer->OnLocationUpdate(position_); } } void GeolocationProvider::StartProviders( const GeolocationObserverOptions& options) { DCHECK(OnGeolocationThread()); DCHECK(arbitrator_); arbitrator_->StartProviders(options); } void GeolocationProvider::StopProviders() { DCHECK(OnGeolocationThread()); DCHECK(arbitrator_); arbitrator_->StopProviders(); } void GeolocationProvider::OnPermissionGranted(const GURL& requesting_frame) { DCHECK(OnClientThread()); most_recent_authorized_frame_ = requesting_frame; if (IsRunning()) InformProvidersPermissionGranted(requesting_frame); } void GeolocationProvider::InformProvidersPermissionGranted( const GURL& requesting_frame) { DCHECK(IsRunning()); DCHECK(requesting_frame.is_valid()); if (!OnGeolocationThread()) { message_loop()->PostTask( FROM_HERE, base::Bind(&GeolocationProvider::InformProvidersPermissionGranted, base::Unretained(this), requesting_frame)); return; } DCHECK(OnGeolocationThread()); DCHECK(arbitrator_); arbitrator_->OnPermissionGranted(requesting_frame); } void GeolocationProvider::Init() { DCHECK(OnGeolocationThread()); DCHECK(!arbitrator_); arbitrator_ = GeolocationArbitrator::Create(this); } void GeolocationProvider::CleanUp() { DCHECK(OnGeolocationThread()); delete arbitrator_; arbitrator_ = NULL; } void GeolocationProvider::OnLocationUpdate(const Geoposition& position) { DCHECK(OnGeolocationThread()); client_loop_->PostTask( FROM_HERE, base::Bind(&GeolocationProvider::NotifyObservers, base::Unretained(this), position)); } bool GeolocationProvider::HasPermissionBeenGranted() const { DCHECK(OnClientThread()); return most_recent_authorized_frame_.is_valid(); } bool GeolocationProvider::OnClientThread() const { return client_loop_->BelongsToCurrentThread(); } bool GeolocationProvider::OnGeolocationThread() const { return MessageLoop::current() == message_loop(); }