// Copyright 2013 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/wifi_data_provider.h" namespace content { // static WifiDataProvider* WifiDataProvider::instance_ = NULL; // static WifiDataProvider::ImplFactoryFunction WifiDataProvider::factory_function_ = DefaultFactoryFunction; // static void WifiDataProvider::SetFactory(ImplFactoryFunction factory_function_in) { factory_function_ = factory_function_in; } // static void WifiDataProvider::ResetFactory() { factory_function_ = DefaultFactoryFunction; } // static WifiDataProvider* WifiDataProvider::Register(WifiDataUpdateCallback* callback) { bool need_to_start_data_provider = false; if (!instance_) { instance_ = new WifiDataProvider(); need_to_start_data_provider = true; } DCHECK(instance_); instance_->AddCallback(callback); // Start the provider after adding the callback, to avoid any race in // it running early. if (need_to_start_data_provider) instance_->StartDataProvider(); return instance_; } // static bool WifiDataProvider::Unregister(WifiDataUpdateCallback* callback) { DCHECK(instance_); DCHECK(instance_->has_callbacks()); if (!instance_->RemoveCallback(callback)) { return false; } if (!instance_->has_callbacks()) { // Must stop the data provider (and any implementation threads) before // destroying to avoid any race conditions in access to the provider in // the destructor chain. instance_->StopDataProvider(); delete instance_; instance_ = NULL; } return true; } WifiDataProviderImplBase::WifiDataProviderImplBase() : container_(NULL), client_loop_(base::MessageLoop::current()) { DCHECK(client_loop_); } WifiDataProviderImplBase::~WifiDataProviderImplBase() { } void WifiDataProviderImplBase::SetContainer(WifiDataProvider* container) { container_ = container; } void WifiDataProviderImplBase::AddCallback(WifiDataUpdateCallback* callback) { callbacks_.insert(callback); } bool WifiDataProviderImplBase::RemoveCallback( WifiDataUpdateCallback* callback) { return callbacks_.erase(callback) == 1; } bool WifiDataProviderImplBase::has_callbacks() const { return !callbacks_.empty(); } void WifiDataProviderImplBase::RunCallbacks() { client_loop_->PostTask(FROM_HERE, base::Bind( &WifiDataProviderImplBase::DoRunCallbacks, this)); } bool WifiDataProviderImplBase::CalledOnClientThread() const { return base::MessageLoop::current() == this->client_loop_; } base::MessageLoop* WifiDataProviderImplBase::client_loop() const { return client_loop_; } void WifiDataProviderImplBase::DoRunCallbacks() { // It's possible that all the callbacks (and the container) went away // whilst this task was pending. This is fine; the loop will be a no-op. CallbackSet::const_iterator iter = callbacks_.begin(); while (iter != callbacks_.end()) { WifiDataUpdateCallback* callback = *iter; ++iter; // Advance iter before running, in case callback unregisters. callback->Run(container_); } } WifiDataProvider::WifiDataProvider() { DCHECK(factory_function_); impl_ = (*factory_function_)(); DCHECK(impl_.get()); impl_->SetContainer(this); } WifiDataProvider::~WifiDataProvider() { DCHECK(impl_.get()); impl_->SetContainer(NULL); } bool WifiDataProvider::GetData(WifiData* data) { return impl_->GetData(data); } void WifiDataProvider::AddCallback(WifiDataUpdateCallback* callback) { impl_->AddCallback(callback); } bool WifiDataProvider::RemoveCallback(WifiDataUpdateCallback* callback) { return impl_->RemoveCallback(callback); } bool WifiDataProvider::has_callbacks() const { return impl_->has_callbacks(); } void WifiDataProvider::StartDataProvider() { impl_->StartDataProvider(); } void WifiDataProvider::StopDataProvider() { impl_->StopDataProvider(); } } // namespace content