// Copyright (c) 2012 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/gamepad/gamepad_service.h" #include "base/bind.h" #include "base/logging.h" #include "base/memory/singleton.h" #include "content/browser/gamepad/gamepad_consumer.h" #include "content/browser/gamepad/gamepad_data_fetcher.h" #include "content/browser/gamepad/gamepad_provider.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/render_process_host.h" namespace content { namespace { GamepadService* g_gamepad_service = 0; } GamepadService::GamepadService() : num_active_consumers_(0), gesture_callback_pending_(false) { SetInstance(this); } GamepadService::GamepadService(scoped_ptr<GamepadDataFetcher> fetcher) : provider_(new GamepadProvider(fetcher.Pass())), num_active_consumers_(0), gesture_callback_pending_(false) { SetInstance(this); thread_checker_.DetachFromThread(); } GamepadService::~GamepadService() { SetInstance(NULL); } void GamepadService::SetInstance(GamepadService* instance) { // Unit tests can create multiple instances but only one should exist at any // given time so g_gamepad_service should only go from NULL to non-NULL and // vica versa. CHECK(!!instance != !!g_gamepad_service); g_gamepad_service = instance; } GamepadService* GamepadService::GetInstance() { if (!g_gamepad_service) g_gamepad_service = new GamepadService; return g_gamepad_service; } void GamepadService::ConsumerBecameActive(GamepadConsumer* consumer) { DCHECK(thread_checker_.CalledOnValidThread()); if (!provider_) provider_.reset(new GamepadProvider); std::pair<ConsumerSet::iterator, bool> insert_result = consumers_.insert(consumer); insert_result.first->is_active = true; if (!insert_result.first->did_observe_user_gesture && !gesture_callback_pending_) { gesture_callback_pending_ = true; provider_->RegisterForUserGesture( base::Bind(&GamepadService::OnUserGesture, base::Unretained(this))); } if (num_active_consumers_++ == 0) provider_->Resume(); } void GamepadService::ConsumerBecameInactive(GamepadConsumer* consumer) { DCHECK(provider_); DCHECK(num_active_consumers_ > 0); DCHECK(consumers_.count(consumer) > 0); DCHECK(consumers_.find(consumer)->is_active); consumers_.find(consumer)->is_active = false; if (--num_active_consumers_ == 0) provider_->Pause(); } void GamepadService::RemoveConsumer(GamepadConsumer* consumer) { DCHECK(thread_checker_.CalledOnValidThread()); ConsumerSet::iterator it = consumers_.find(consumer); if (it->is_active && --num_active_consumers_ == 0) provider_->Pause(); consumers_.erase(it); } void GamepadService::RegisterForUserGesture(const base::Closure& closure) { DCHECK(consumers_.size() > 0); DCHECK(thread_checker_.CalledOnValidThread()); provider_->RegisterForUserGesture(closure); } void GamepadService::Terminate() { provider_.reset(); } void GamepadService::OnGamepadConnected( int index, const blink::WebGamepad& pad) { DCHECK(thread_checker_.CalledOnValidThread()); for (ConsumerSet::iterator it = consumers_.begin(); it != consumers_.end(); ++it) { if (it->did_observe_user_gesture && it->is_active) it->consumer->OnGamepadConnected(index, pad); } } void GamepadService::OnGamepadDisconnected( int index, const blink::WebGamepad& pad) { DCHECK(thread_checker_.CalledOnValidThread()); for (ConsumerSet::iterator it = consumers_.begin(); it != consumers_.end(); ++it) { if (it->did_observe_user_gesture && it->is_active) it->consumer->OnGamepadDisconnected(index, pad); } } base::SharedMemoryHandle GamepadService::GetSharedMemoryHandleForProcess( base::ProcessHandle handle) { DCHECK(thread_checker_.CalledOnValidThread()); return provider_->GetSharedMemoryHandleForProcess(handle); } void GamepadService::OnUserGesture() { DCHECK(thread_checker_.CalledOnValidThread()); gesture_callback_pending_ = false; if (!provider_ || num_active_consumers_ == 0) return; for (ConsumerSet::iterator it = consumers_.begin(); it != consumers_.end(); ++it) { if (!it->did_observe_user_gesture && it->is_active) { const ConsumerInfo& info = *it; info.did_observe_user_gesture = true; blink::WebGamepads gamepads; provider_->GetCurrentGamepadData(&gamepads); for (unsigned i = 0; i < blink::WebGamepads::itemsLengthCap; ++i) { const blink::WebGamepad& pad = gamepads.items[i]; if (pad.connected) info.consumer->OnGamepadConnected(i, pad); } } } } } // namespace content