Home | History | Annotate | Download | only in gamepad
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "content/browser/gamepad/gamepad_service.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/logging.h"
      9 #include "base/memory/singleton.h"
     10 #include "content/browser/gamepad/gamepad_consumer.h"
     11 #include "content/browser/gamepad/gamepad_data_fetcher.h"
     12 #include "content/browser/gamepad/gamepad_provider.h"
     13 #include "content/public/browser/browser_thread.h"
     14 #include "content/public/browser/render_process_host.h"
     15 
     16 namespace content {
     17 
     18 namespace {
     19 GamepadService* g_gamepad_service = 0;
     20 }
     21 
     22 GamepadService::GamepadService()
     23     : num_active_consumers_(0),
     24       gesture_callback_pending_(false) {
     25   SetInstance(this);
     26 }
     27 
     28 GamepadService::GamepadService(scoped_ptr<GamepadDataFetcher> fetcher)
     29     : provider_(new GamepadProvider(fetcher.Pass())),
     30       num_active_consumers_(0),
     31       gesture_callback_pending_(false) {
     32   SetInstance(this);
     33   thread_checker_.DetachFromThread();
     34 }
     35 
     36 GamepadService::~GamepadService() {
     37   SetInstance(NULL);
     38 }
     39 
     40 void GamepadService::SetInstance(GamepadService* instance) {
     41   // Unit tests can create multiple instances but only one should exist at any
     42   // given time so g_gamepad_service should only go from NULL to non-NULL and
     43   // vica versa.
     44   CHECK(!!instance != !!g_gamepad_service);
     45   g_gamepad_service = instance;
     46 }
     47 
     48 GamepadService* GamepadService::GetInstance() {
     49   if (!g_gamepad_service)
     50     g_gamepad_service = new GamepadService;
     51   return g_gamepad_service;
     52 }
     53 
     54 void GamepadService::ConsumerBecameActive(GamepadConsumer* consumer) {
     55   DCHECK(thread_checker_.CalledOnValidThread());
     56 
     57   if (!provider_)
     58     provider_.reset(new GamepadProvider);
     59 
     60   std::pair<ConsumerSet::iterator, bool> insert_result =
     61       consumers_.insert(consumer);
     62   insert_result.first->is_active = true;
     63   if (!insert_result.first->did_observe_user_gesture &&
     64       !gesture_callback_pending_) {
     65     gesture_callback_pending_ = true;
     66     provider_->RegisterForUserGesture(
     67           base::Bind(&GamepadService::OnUserGesture,
     68                      base::Unretained(this)));
     69   }
     70 
     71   if (num_active_consumers_++ == 0)
     72     provider_->Resume();
     73 }
     74 
     75 void GamepadService::ConsumerBecameInactive(GamepadConsumer* consumer) {
     76   DCHECK(provider_);
     77   DCHECK(num_active_consumers_ > 0);
     78   DCHECK(consumers_.count(consumer) > 0);
     79   DCHECK(consumers_.find(consumer)->is_active);
     80 
     81   consumers_.find(consumer)->is_active = false;
     82   if (--num_active_consumers_ == 0)
     83     provider_->Pause();
     84 }
     85 
     86 void GamepadService::RemoveConsumer(GamepadConsumer* consumer) {
     87   DCHECK(thread_checker_.CalledOnValidThread());
     88 
     89   ConsumerSet::iterator it = consumers_.find(consumer);
     90   if (it->is_active && --num_active_consumers_ == 0)
     91     provider_->Pause();
     92   consumers_.erase(it);
     93 }
     94 
     95 void GamepadService::RegisterForUserGesture(const base::Closure& closure) {
     96   DCHECK(consumers_.size() > 0);
     97   DCHECK(thread_checker_.CalledOnValidThread());
     98   provider_->RegisterForUserGesture(closure);
     99 }
    100 
    101 void GamepadService::Terminate() {
    102   provider_.reset();
    103 }
    104 
    105 void GamepadService::OnGamepadConnected(
    106     int index,
    107     const blink::WebGamepad& pad) {
    108   DCHECK(thread_checker_.CalledOnValidThread());
    109 
    110   for (ConsumerSet::iterator it = consumers_.begin();
    111        it != consumers_.end(); ++it) {
    112     if (it->did_observe_user_gesture && it->is_active)
    113       it->consumer->OnGamepadConnected(index, pad);
    114   }
    115 }
    116 
    117 void GamepadService::OnGamepadDisconnected(
    118     int index,
    119     const blink::WebGamepad& pad) {
    120   DCHECK(thread_checker_.CalledOnValidThread());
    121 
    122   for (ConsumerSet::iterator it = consumers_.begin();
    123        it != consumers_.end(); ++it) {
    124     if (it->did_observe_user_gesture && it->is_active)
    125       it->consumer->OnGamepadDisconnected(index, pad);
    126   }
    127 }
    128 
    129 base::SharedMemoryHandle GamepadService::GetSharedMemoryHandleForProcess(
    130     base::ProcessHandle handle) {
    131   DCHECK(thread_checker_.CalledOnValidThread());
    132   return provider_->GetSharedMemoryHandleForProcess(handle);
    133 }
    134 
    135 void GamepadService::OnUserGesture() {
    136   DCHECK(thread_checker_.CalledOnValidThread());
    137 
    138   gesture_callback_pending_ = false;
    139 
    140   if (!provider_ ||
    141       num_active_consumers_ == 0)
    142     return;
    143 
    144   for (ConsumerSet::iterator it = consumers_.begin();
    145        it != consumers_.end(); ++it) {
    146     if (!it->did_observe_user_gesture && it->is_active) {
    147       const ConsumerInfo& info = *it;
    148       info.did_observe_user_gesture = true;
    149       blink::WebGamepads gamepads;
    150       provider_->GetCurrentGamepadData(&gamepads);
    151       for (unsigned i = 0; i < blink::WebGamepads::itemsLengthCap; ++i) {
    152         const blink::WebGamepad& pad = gamepads.items[i];
    153         if (pad.connected)
    154           info.consumer->OnGamepadConnected(i, pad);
    155       }
    156     }
    157   }
    158 }
    159 
    160 }  // namespace content
    161