summaryrefslogtreecommitdiffstats
path: root/content/browser/gamepad
diff options
context:
space:
mode:
Diffstat (limited to 'content/browser/gamepad')
-rw-r--r--content/browser/gamepad/gamepad_data_fetcher.h (renamed from content/browser/gamepad/data_fetcher.h)10
-rw-r--r--content/browser/gamepad/gamepad_platform_data_fetcher.cc (renamed from content/browser/gamepad/platform_data_fetcher.cc)4
-rw-r--r--content/browser/gamepad/gamepad_platform_data_fetcher.h (renamed from content/browser/gamepad/platform_data_fetcher.h)14
-rw-r--r--content/browser/gamepad/gamepad_platform_data_fetcher_linux.cc (renamed from content/browser/gamepad/platform_data_fetcher_linux.cc)2
-rw-r--r--content/browser/gamepad/gamepad_platform_data_fetcher_linux.h (renamed from content/browser/gamepad/platform_data_fetcher_linux.h)8
-rw-r--r--content/browser/gamepad/gamepad_platform_data_fetcher_mac.h (renamed from content/browser/gamepad/platform_data_fetcher_mac.h)8
-rw-r--r--content/browser/gamepad/gamepad_platform_data_fetcher_mac.mm (renamed from content/browser/gamepad/platform_data_fetcher_mac.mm)2
-rw-r--r--content/browser/gamepad/gamepad_platform_data_fetcher_win.cc (renamed from content/browser/gamepad/platform_data_fetcher_win.cc)2
-rw-r--r--content/browser/gamepad/gamepad_platform_data_fetcher_win.h (renamed from content/browser/gamepad/platform_data_fetcher_win.h)8
-rw-r--r--content/browser/gamepad/gamepad_provider.cc101
-rw-r--r--content/browser/gamepad/gamepad_provider.h46
-rw-r--r--content/browser/gamepad/gamepad_provider_unittest.cc109
-rw-r--r--content/browser/gamepad/gamepad_service.cc82
-rw-r--r--content/browser/gamepad/gamepad_service.h72
-rw-r--r--content/browser/gamepad/gamepad_test_helpers.cc60
-rw-r--r--content/browser/gamepad/gamepad_test_helpers.h90
16 files changed, 434 insertions, 184 deletions
diff --git a/content/browser/gamepad/data_fetcher.h b/content/browser/gamepad/gamepad_data_fetcher.h
index 94bf4ae..e5e009d 100644
--- a/content/browser/gamepad/data_fetcher.h
+++ b/content/browser/gamepad/gamepad_data_fetcher.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CONTENT_BROWSER_GAMEPAD_DATA_FETCHER_H_
-#define CONTENT_BROWSER_GAMEPAD_DATA_FETCHER_H_
+#ifndef CONTENT_BROWSER_GAMEPAD_GAMEPAD_DATA_FETCHER_H_
+#define CONTENT_BROWSER_GAMEPAD_GAMEPAD_DATA_FETCHER_H_
namespace WebKit {
class WebGamepads;
@@ -11,6 +11,8 @@ class WebGamepads;
namespace content {
+// Abstract interface for imlementing platform- (and test-) specific behaviro
+// for getting the gamepad data.
class GamepadDataFetcher {
public:
virtual ~GamepadDataFetcher() {}
@@ -19,6 +21,6 @@ class GamepadDataFetcher {
virtual void PauseHint(bool paused) {}
};
-} // namespace content
+} // namespace content
-#endif // CONTENT_BROWSER_GAMEPAD_DATA_FETCHER_H_
+#endif // CONTENT_BROWSER_GAMEPAD_GAMEPAD_DATA_FETCHER_H_
diff --git a/content/browser/gamepad/platform_data_fetcher.cc b/content/browser/gamepad/gamepad_platform_data_fetcher.cc
index 1e80174..d14a3ca 100644
--- a/content/browser/gamepad/platform_data_fetcher.cc
+++ b/content/browser/gamepad/gamepad_platform_data_fetcher.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "content/browser/gamepad/platform_data_fetcher.h"
+#include "content/browser/gamepad/gamepad_platform_data_fetcher.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebGamepads.h"
@@ -16,4 +16,4 @@ void GamepadDataFetcherEmpty::GetGamepadData(WebKit::WebGamepads* pads,
pads->length = 0;
}
-} // content
+} // namespace content
diff --git a/content/browser/gamepad/platform_data_fetcher.h b/content/browser/gamepad/gamepad_platform_data_fetcher.h
index 178e478..f073a53 100644
--- a/content/browser/gamepad/platform_data_fetcher.h
+++ b/content/browser/gamepad/gamepad_platform_data_fetcher.h
@@ -5,19 +5,19 @@
// Define the default data fetcher that GamepadProvider will use if none is
// supplied. (GamepadPlatformDataFetcher).
-#ifndef CONTENT_BROWSER_GAMEPAD_PLATFORM_DATA_FETCHER_H_
-#define CONTENT_BROWSER_GAMEPAD_PLATFORM_DATA_FETCHER_H_
+#ifndef CONTENT_BROWSER_GAMEPAD_GAMEPAD_PLATFORM_DATA_FETCHER_H_
+#define CONTENT_BROWSER_GAMEPAD_GAMEPAD_PLATFORM_DATA_FETCHER_H_
#include "base/basictypes.h"
#include "base/compiler_specific.h"
-#include "content/browser/gamepad/data_fetcher.h"
+#include "content/browser/gamepad/gamepad_data_fetcher.h"
#if defined(OS_WIN)
-#include "content/browser/gamepad/platform_data_fetcher_win.h"
+#include "content/browser/gamepad/gamepad_platform_data_fetcher_win.h"
#elif defined(OS_MACOSX)
-#include "content/browser/gamepad/platform_data_fetcher_mac.h"
+#include "content/browser/gamepad/gamepad_platform_data_fetcher_mac.h"
#elif defined(OS_LINUX)
-#include "content/browser/gamepad/platform_data_fetcher_linux.h"
+#include "content/browser/gamepad/gamepad_platform_data_fetcher_linux.h"
#endif
namespace content {
@@ -52,4 +52,4 @@ typedef GamepadDataFetcherEmpty GamepadPlatformDataFetcher;
} // namespace content
-#endif // CONTENT_BROWSER_GAMEPAD_PLATFORM_DATA_FETCHER_H_
+#endif // CONTENT_BROWSER_GAMEPAD_GAMEPAD_PLATFORM_DATA_FETCHER_H_
diff --git a/content/browser/gamepad/platform_data_fetcher_linux.cc b/content/browser/gamepad/gamepad_platform_data_fetcher_linux.cc
index e364eac..0342917 100644
--- a/content/browser/gamepad/platform_data_fetcher_linux.cc
+++ b/content/browser/gamepad/gamepad_platform_data_fetcher_linux.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "content/browser/gamepad/platform_data_fetcher_linux.h"
+#include "content/browser/gamepad/gamepad_platform_data_fetcher_linux.h"
#include <fcntl.h>
#include <libudev.h>
diff --git a/content/browser/gamepad/platform_data_fetcher_linux.h b/content/browser/gamepad/gamepad_platform_data_fetcher_linux.h
index 55cb74e..681946f 100644
--- a/content/browser/gamepad/platform_data_fetcher_linux.h
+++ b/content/browser/gamepad/gamepad_platform_data_fetcher_linux.h
@@ -2,15 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CONTENT_BROWSER_GAMEPAD_PLATFORM_DATA_FETCHER_LINUX_H_
-#define CONTENT_BROWSER_GAMEPAD_PLATFORM_DATA_FETCHER_LINUX_H_
+#ifndef CONTENT_BROWSER_GAMEPAD_GAMEPAD_PLATFORM_DATA_FETCHER_LINUX_H_
+#define CONTENT_BROWSER_GAMEPAD_GAMEPAD_PLATFORM_DATA_FETCHER_LINUX_H_
#include <string>
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
-#include "content/browser/gamepad/data_fetcher.h"
+#include "content/browser/gamepad/gamepad_data_fetcher.h"
#include "content/browser/gamepad/gamepad_standard_mappings.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebGamepads.h"
@@ -53,4 +53,4 @@ class GamepadPlatformDataFetcherLinux : public GamepadDataFetcher {
} // namespace content
-#endif // CONTENT_BROWSER_GAMEPAD_PLATFORM_DATA_FETCHER_LINUX_H_
+#endif // CONTENT_BROWSER_GAMEPAD_GAMEPAD_PLATFORM_DATA_FETCHER_LINUX_H_
diff --git a/content/browser/gamepad/platform_data_fetcher_mac.h b/content/browser/gamepad/gamepad_platform_data_fetcher_mac.h
index c92307d..8bcc9c2 100644
--- a/content/browser/gamepad/platform_data_fetcher_mac.h
+++ b/content/browser/gamepad/gamepad_platform_data_fetcher_mac.h
@@ -2,14 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CONTENT_BROWSER_GAMEPAD_PLATFORM_DATA_FETCHER_MAC_H_
-#define CONTENT_BROWSER_GAMEPAD_PLATFORM_DATA_FETCHER_MAC_H_
+#ifndef CONTENT_BROWSER_GAMEPAD_GAMEPAD_PLATFORM_DATA_FETCHER_MAC_H_
+#define CONTENT_BROWSER_GAMEPAD_GAMEPAD_PLATFORM_DATA_FETCHER_MAC_H_
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/mac/scoped_cftyperef.h"
#include "build/build_config.h"
-#include "content/browser/gamepad/data_fetcher.h"
+#include "content/browser/gamepad/gamepad_data_fetcher.h"
#include "content/browser/gamepad/gamepad_standard_mappings.h"
#include "content/common/gamepad_hardware_buffer.h"
@@ -79,4 +79,4 @@ class GamepadPlatformDataFetcherMac : public GamepadDataFetcher {
} // namespace content
-#endif // CONTENT_BROWSER_GAMEPAD_PLATFORM_DATA_FETCHER_MAC_H_
+#endif // CONTENT_BROWSER_GAMEPAD_GAMEPAD_PLATFORM_DATA_FETCHER_MAC_H_
diff --git a/content/browser/gamepad/platform_data_fetcher_mac.mm b/content/browser/gamepad/gamepad_platform_data_fetcher_mac.mm
index 1d1bd72..8748730 100644
--- a/content/browser/gamepad/platform_data_fetcher_mac.mm
+++ b/content/browser/gamepad/gamepad_platform_data_fetcher_mac.mm
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "content/browser/gamepad/platform_data_fetcher_mac.h"
+#include "content/browser/gamepad/gamepad_platform_data_fetcher_mac.h"
#include "base/mac/foundation_util.h"
#include "base/memory/scoped_nsobject.h"
diff --git a/content/browser/gamepad/platform_data_fetcher_win.cc b/content/browser/gamepad/gamepad_platform_data_fetcher_win.cc
index 92587a4..838a626 100644
--- a/content/browser/gamepad/platform_data_fetcher_win.cc
+++ b/content/browser/gamepad/gamepad_platform_data_fetcher_win.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "content/browser/gamepad/platform_data_fetcher_win.h"
+#include "content/browser/gamepad/gamepad_platform_data_fetcher_win.h"
#include "base/debug/trace_event.h"
#include "content/common/gamepad_messages.h"
diff --git a/content/browser/gamepad/platform_data_fetcher_win.h b/content/browser/gamepad/gamepad_platform_data_fetcher_win.h
index 9cae9cc..92c44ff 100644
--- a/content/browser/gamepad/platform_data_fetcher_win.h
+++ b/content/browser/gamepad/gamepad_platform_data_fetcher_win.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CONTENT_BROWSER_GAMEPAD_PLATFORM_DATA_FETCHER_WIN_H_
-#define CONTENT_BROWSER_GAMEPAD_PLATFORM_DATA_FETCHER_WIN_H_
+#ifndef CONTENT_BROWSER_GAMEPAD_GAMEPAD_PLATFORM_DATA_FETCHER_WIN_H_
+#define CONTENT_BROWSER_GAMEPAD_GAMEPAD_PLATFORM_DATA_FETCHER_WIN_H_
#include "build/build_config.h"
@@ -16,7 +16,7 @@
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/scoped_native_library.h"
-#include "content/browser/gamepad/data_fetcher.h"
+#include "content/browser/gamepad/gamepad_data_fetcher.h"
namespace content {
@@ -54,4 +54,4 @@ class GamepadPlatformDataFetcherWin : public GamepadDataFetcher {
} // namespace content
-#endif // CONTENT_BROWSER_GAMEPAD_PLATFORM_DATA_FETCHER_WIN_H_
+#endif // CONTENT_BROWSER_GAMEPAD_GAMEPAD_PLATFORM_DATA_FETCHER_WIN_H_
diff --git a/content/browser/gamepad/gamepad_provider.cc b/content/browser/gamepad/gamepad_provider.cc
index 507c704..63a352f 100644
--- a/content/browser/gamepad/gamepad_provider.cc
+++ b/content/browser/gamepad/gamepad_provider.cc
@@ -9,42 +9,41 @@
#include "base/bind.h"
#include "base/logging.h"
#include "base/message_loop.h"
+#include "base/message_loop_proxy.h"
#include "base/threading/thread.h"
#include "base/threading/thread_restrictions.h"
-#include "content/browser/gamepad/data_fetcher.h"
+#include "content/browser/gamepad/gamepad_data_fetcher.h"
#include "content/browser/gamepad/gamepad_provider.h"
-#include "content/browser/gamepad/platform_data_fetcher.h"
+#include "content/browser/gamepad/gamepad_platform_data_fetcher.h"
#include "content/common/gamepad_hardware_buffer.h"
#include "content/common/gamepad_messages.h"
+#include "content/common/gamepad_user_gesture.h"
#include "content/public/browser/browser_thread.h"
namespace content {
+GamepadProvider::ClosureAndThread::ClosureAndThread(
+ const base::Closure& c,
+ const scoped_refptr<base::MessageLoopProxy>& m)
+ : closure(c),
+ message_loop(m) {
+}
+
+GamepadProvider::ClosureAndThread::~ClosureAndThread() {
+}
+
GamepadProvider::GamepadProvider()
: is_paused_(true),
have_scheduled_do_poll_(false),
devices_changed_(true) {
- size_t data_size = sizeof(GamepadHardwareBuffer);
- base::SystemMonitor* monitor = base::SystemMonitor::Get();
- if (monitor)
- monitor->AddDevicesChangedObserver(this);
- bool res = gamepad_shared_memory_.CreateAndMapAnonymous(data_size);
- CHECK(res);
- GamepadHardwareBuffer* hwbuf = SharedMemoryAsHardwareBuffer();
- memset(hwbuf, 0, sizeof(GamepadHardwareBuffer));
-
- polling_thread_.reset(new base::Thread("Gamepad polling thread"));
- polling_thread_->StartWithOptions(
- base::Thread::Options(MessageLoop::TYPE_IO, 0));
+ Initialize(scoped_ptr<GamepadDataFetcher>());
}
-void GamepadProvider::SetDataFetcher(GamepadDataFetcher* fetcher) {
- MessageLoop* polling_loop = polling_thread_->message_loop();
- polling_loop->PostTask(
- FROM_HERE,
- base::Bind(&GamepadProvider::DoInitializePollingThread,
- Unretained(this),
- fetcher));
+GamepadProvider::GamepadProvider(scoped_ptr<GamepadDataFetcher> fetcher)
+ : is_paused_(true),
+ have_scheduled_do_poll_(false),
+ devices_changed_(true) {
+ Initialize(fetcher.Pass());
}
GamepadProvider::~GamepadProvider() {
@@ -56,7 +55,7 @@ GamepadProvider::~GamepadProvider() {
data_fetcher_.reset();
}
-base::SharedMemoryHandle GamepadProvider::GetRendererSharedMemoryHandle(
+base::SharedMemoryHandle GamepadProvider::GetSharedMemoryHandleForProcess(
base::ProcessHandle process) {
base::SharedMemoryHandle renderer_handle;
gamepad_shared_memory_.ShareToProcess(process, &renderer_handle);
@@ -91,24 +90,46 @@ void GamepadProvider::Resume() {
base::Bind(&GamepadProvider::ScheduleDoPoll, Unretained(this)));
}
+void GamepadProvider::RegisterForUserGesture(const base::Closure& closure) {
+ base::AutoLock lock(user_gesture_lock_);
+ user_gesture_observers_.push_back(
+ ClosureAndThread(closure, MessageLoop::current()->message_loop_proxy()));
+}
+
void GamepadProvider::OnDevicesChanged(base::SystemMonitor::DeviceType type) {
base::AutoLock lock(devices_changed_lock_);
devices_changed_ = true;
}
-void GamepadProvider::DoInitializePollingThread(GamepadDataFetcher* fetcher) {
- DCHECK(MessageLoop::current() == polling_thread_->message_loop());
+void GamepadProvider::Initialize(scoped_ptr<GamepadDataFetcher> fetcher) {
+ size_t data_size = sizeof(GamepadHardwareBuffer);
+ base::SystemMonitor* monitor = base::SystemMonitor::Get();
+ if (monitor)
+ monitor->AddDevicesChangedObserver(this);
+ bool res = gamepad_shared_memory_.CreateAndMapAnonymous(data_size);
+ CHECK(res);
+ GamepadHardwareBuffer* hwbuf = SharedMemoryAsHardwareBuffer();
+ memset(hwbuf, 0, sizeof(GamepadHardwareBuffer));
- if (data_fetcher_ != NULL) {
- // Already initialized.
- return;
- }
+ polling_thread_.reset(new base::Thread("Gamepad polling thread"));
+ polling_thread_->StartWithOptions(
+ base::Thread::Options(MessageLoop::TYPE_IO, 0));
+
+ polling_thread_->message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&GamepadProvider::DoInitializePollingThread,
+ base::Unretained(this),
+ base::Passed(&fetcher)));
+}
- if (fetcher == NULL)
- fetcher = new GamepadPlatformDataFetcher;
+void GamepadProvider::DoInitializePollingThread(
+ scoped_ptr<GamepadDataFetcher> fetcher) {
+ DCHECK(MessageLoop::current() == polling_thread_->message_loop());
+ DCHECK(!data_fetcher_.get()); // Should only initialize once.
- // Pass ownership of fetcher to provider_.
- data_fetcher_.reset(fetcher);
+ if (!fetcher.get())
+ fetcher.reset(new GamepadPlatformDataFetcher);
+ data_fetcher_ = fetcher.Pass();
}
void GamepadProvider::SendPauseHint(bool paused) {
@@ -142,6 +163,8 @@ void GamepadProvider::DoPoll() {
data_fetcher_->GetGamepadData(&hwbuf->buffer, changed);
hwbuf->sequence.WriteEnd();
+ CheckForUserGesture();
+
// Schedule our next interval of polling.
ScheduleDoPoll();
}
@@ -170,4 +193,18 @@ GamepadHardwareBuffer* GamepadProvider::SharedMemoryAsHardwareBuffer() {
return static_cast<GamepadHardwareBuffer*>(mem);
}
+void GamepadProvider::CheckForUserGesture() {
+ base::AutoLock lock(user_gesture_lock_);
+ if (user_gesture_observers_.empty())
+ return; // Don't need to check if nobody is listening.
+
+ if (GamepadsHaveUserGesture(SharedMemoryAsHardwareBuffer()->buffer)) {
+ for (size_t i = 0; i < user_gesture_observers_.size(); i++) {
+ user_gesture_observers_[i].message_loop->PostTask(FROM_HERE,
+ user_gesture_observers_[i].closure);
+ }
+ user_gesture_observers_.clear();
+ }
+}
+
} // namespace content
diff --git a/content/browser/gamepad/gamepad_provider.h b/content/browser/gamepad/gamepad_provider.h
index 22c39c5..c4a7806 100644
--- a/content/browser/gamepad/gamepad_provider.h
+++ b/content/browser/gamepad/gamepad_provider.h
@@ -5,6 +5,11 @@
#ifndef CONTENT_BROWSER_GAMEPAD_GAMEPAD_PROVIDER_H_
#define CONTENT_BROWSER_GAMEPAD_GAMEPAD_PROVIDER_H_
+#include <utility>
+#include <vector>
+
+#include "base/callback_forward.h"
+#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop_proxy.h"
@@ -14,6 +19,7 @@
#include "content/common/content_export.h"
namespace base {
+class MessageLoopProxy;
class Thread;
}
@@ -25,13 +31,16 @@ struct GamepadHardwareBuffer;
class CONTENT_EXPORT GamepadProvider :
public base::SystemMonitor::DevicesChangedObserver {
public:
- explicit GamepadProvider();
- virtual ~GamepadProvider();
+ GamepadProvider();
- // Set the platform-specific data fetcher. Mostly used for testing.
- void SetDataFetcher(GamepadDataFetcher* fetcher);
+ // Manually specifies the data fetcher. Used for testing.
+ explicit GamepadProvider(scoped_ptr<GamepadDataFetcher> fetcher);
+
+ virtual ~GamepadProvider();
- base::SharedMemoryHandle GetRendererSharedMemoryHandle(
+ // Returns the shared memory handle of the gamepad data duplicated into the
+ // given process.
+ base::SharedMemoryHandle GetSharedMemoryHandleForProcess(
base::ProcessHandle renderer_process);
// Pause and resume the background polling thread. Can be called from any
@@ -39,14 +48,19 @@ class CONTENT_EXPORT GamepadProvider :
void Pause();
void Resume();
+ // Registers the given closure for calling when the user has interacted with
+ // the device. This callback will only be issued once.
+ void RegisterForUserGesture(const base::Closure& closure);
+
// base::SystemMonitor::DevicesChangedObserver implementation.
virtual void OnDevicesChanged(base::SystemMonitor::DeviceType type) OVERRIDE;
private:
+ void Initialize(scoped_ptr<GamepadDataFetcher> fetcher);
// Method for setting up the platform-specific data fetcher. Takes ownership
// of |fetcher|.
- void DoInitializePollingThread(GamepadDataFetcher* fetcher);
+ void DoInitializePollingThread(scoped_ptr<GamepadDataFetcher> fetcher);
// Method for sending pause hints to the low-level data fetcher. Runs on
// polling_thread_.
@@ -58,6 +72,9 @@ class CONTENT_EXPORT GamepadProvider :
GamepadHardwareBuffer* SharedMemoryAsHardwareBuffer();
+ // Checks the gamepad state to see if the user has interacted with it.
+ void CheckForUserGesture();
+
enum { kDesiredSamplingIntervalMs = 16 };
// Keeps track of when the background thread is paused. Access to is_paused_
@@ -70,6 +87,23 @@ class CONTENT_EXPORT GamepadProvider :
// |is_paused_|.
bool have_scheduled_do_poll_;
+ // Lists all observers registered for user gestures, and the thread which
+ // to issue the callbacks on. Since we always issue the callback on the
+ // thread which the registration happened, and this class lives on the I/O
+ // thread, the message loop proxies will normally just be the I/O thread.
+ // However, this will be the main thread for unit testing.
+ base::Lock user_gesture_lock_;
+ struct ClosureAndThread {
+ ClosureAndThread(const base::Closure& c,
+ const scoped_refptr<base::MessageLoopProxy>& m);
+ ~ClosureAndThread();
+
+ base::Closure closure;
+ scoped_refptr<base::MessageLoopProxy> message_loop;
+ };
+ typedef std::vector<ClosureAndThread> UserGestureObserverVector;
+ UserGestureObserverVector user_gesture_observers_;
+
// Updated based on notification from SystemMonitor when the system devices
// have been updated, and this notification is passed on to the data fetcher
// to enable it to avoid redundant (and possibly expensive) is-connected
diff --git a/content/browser/gamepad/gamepad_provider_unittest.cc b/content/browser/gamepad/gamepad_provider_unittest.cc
index d81b3f5..30f5e43 100644
--- a/content/browser/gamepad/gamepad_provider_unittest.cc
+++ b/content/browser/gamepad/gamepad_provider_unittest.cc
@@ -3,15 +3,14 @@
// found in the LICENSE file.
#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
#include "base/process_util.h"
-#include "base/synchronization/waitable_event.h"
-#include "base/system_monitor/system_monitor.h"
-#include "content/browser/gamepad/data_fetcher.h"
+#include "content/browser/gamepad/gamepad_data_fetcher.h"
#include "content/browser/gamepad/gamepad_provider.h"
+#include "content/browser/gamepad/gamepad_test_helpers.h"
#include "content/common/gamepad_hardware_buffer.h"
#include "content/common/gamepad_messages.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebGamepads.h"
namespace content {
@@ -19,35 +18,37 @@ namespace {
using WebKit::WebGamepads;
-class MockDataFetcher : public GamepadDataFetcher {
+// Helper class to generate and record user gesture callbacks.
+class UserGestureListener {
public:
- explicit MockDataFetcher(const WebGamepads& test_data)
- : test_data_(test_data),
- read_data_(false, false) {
+ UserGestureListener()
+ : weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
+ has_user_gesture_(false) {
}
- virtual void GetGamepadData(WebGamepads* pads,
- bool devices_changed_hint) OVERRIDE {
- *pads = test_data_;
- read_data_.Signal();
+
+ base::Closure GetClosure() {
+ return base::Bind(&UserGestureListener::GotUserGesture,
+ weak_factory_.GetWeakPtr());
}
- void WaitForDataRead() { return read_data_.Wait(); }
+ bool has_user_gesture() const { return has_user_gesture_; }
+
+ private:
+ void GotUserGesture() {
+ has_user_gesture_ = true;
+ }
- WebGamepads test_data_;
- base::WaitableEvent read_data_;
+ base::WeakPtrFactory<UserGestureListener> weak_factory_;
+ bool has_user_gesture_;
};
// Main test fixture
-class GamepadProviderTest : public testing::Test {
+class GamepadProviderTest : public testing::Test, public GamepadTestHelper {
public:
GamepadProvider* CreateProvider(const WebGamepads& test_data) {
-#if defined(OS_MACOSX)
- base::SystemMonitor::AllocateSystemIOPorts();
-#endif
- system_monitor_.reset(new base::SystemMonitor);
- mock_data_fetcher_ = new MockDataFetcher(test_data);
- provider_.reset(new GamepadProvider);
- provider_->SetDataFetcher(mock_data_fetcher_);
+ mock_data_fetcher_ = new MockGamepadDataFetcher(test_data);
+ provider_.reset(new GamepadProvider(
+ scoped_ptr<GamepadDataFetcher>(mock_data_fetcher_)));
return provider_.get();
}
@@ -55,14 +56,16 @@ class GamepadProviderTest : public testing::Test {
GamepadProviderTest() {
}
- MessageLoop main_message_loop_;
- scoped_ptr<base::SystemMonitor> system_monitor_;
- MockDataFetcher* mock_data_fetcher_;
scoped_ptr<GamepadProvider> provider_;
+
+ // Pointer owned by the provider.
+ MockGamepadDataFetcher* mock_data_fetcher_;
+
+ DISALLOW_COPY_AND_ASSIGN(GamepadProviderTest);
};
// Crashes. http://crbug.com/106163
-TEST_F(GamepadProviderTest, DISABLED_PollingAccess) {
+TEST_F(GamepadProviderTest, PollingAccess) {
WebGamepads test_data;
test_data.length = 1;
test_data.items[0].connected = true;
@@ -74,14 +77,15 @@ TEST_F(GamepadProviderTest, DISABLED_PollingAccess) {
test_data.items[0].axes[1] = .5f;
GamepadProvider* provider = CreateProvider(test_data);
+ provider->Resume();
- main_message_loop_.RunAllPending();
+ message_loop().RunAllPending();
mock_data_fetcher_->WaitForDataRead();
// Renderer-side, pull data out of poll buffer.
- base::SharedMemoryHandle handle =
- provider->GetRendererSharedMemoryHandle(base::GetCurrentProcessHandle());
+ base::SharedMemoryHandle handle = provider->GetSharedMemoryHandleForProcess(
+ base::GetCurrentProcessHandle());
scoped_ptr<base::SharedMemory> shared_memory(
new base::SharedMemory(handle, true));
EXPECT_TRUE(shared_memory->Map(sizeof(GamepadHardwareBuffer)));
@@ -105,6 +109,51 @@ TEST_F(GamepadProviderTest, DISABLED_PollingAccess) {
EXPECT_EQ(0.5f, output.items[0].axes[1]);
}
+// Tests that waiting for a user gesture works properly.
+TEST_F(GamepadProviderTest, UserGesture) {
+ WebGamepads no_button_data;
+ no_button_data.length = 1;
+ no_button_data.items[0].connected = true;
+ no_button_data.items[0].timestamp = 0;
+ no_button_data.items[0].buttonsLength = 1;
+ no_button_data.items[0].axesLength = 2;
+ no_button_data.items[0].buttons[0] = 0.f;
+ no_button_data.items[0].axes[0] = -1.f;
+ no_button_data.items[0].axes[1] = .5f;
+
+ WebGamepads button_down_data = no_button_data;
+ button_down_data.items[0].buttons[0] = 1.f;
+
+ UserGestureListener listener;
+ GamepadProvider* provider = CreateProvider(no_button_data);
+ provider->Resume();
+
+ // Register for a user gesture and make sure the provider reads it twice
+ // see below for why).
+ provider->RegisterForUserGesture(listener.GetClosure());
+ mock_data_fetcher_->WaitForDataRead();
+ mock_data_fetcher_->WaitForDataRead();
+
+ // It should not have issued our callback.
+ message_loop().RunAllPending();
+ EXPECT_FALSE(listener.has_user_gesture());
+
+ // Set a button down and wait for it to be read twice.
+ //
+ // We wait for two reads before calling RunAllPending because the provider
+ // will read the data on the background thread (setting the event) and *then*
+ // will issue the callback on our thread. Waiting for it to read twice
+ // ensures that it was able to issue callbacks for the first read (if it
+ // issued one) before we try to check for it.
+ mock_data_fetcher_->SetTestData(button_down_data);
+ mock_data_fetcher_->WaitForDataRead();
+ mock_data_fetcher_->WaitForDataRead();
+
+ // It should have issued our callback.
+ message_loop().RunAllPending();
+ EXPECT_TRUE(listener.has_user_gesture());
+}
+
} // namespace
} // namespace content
diff --git a/content/browser/gamepad/gamepad_service.cc b/content/browser/gamepad/gamepad_service.cc
index cb9206b..3b631ce 100644
--- a/content/browser/gamepad/gamepad_service.cc
+++ b/content/browser/gamepad/gamepad_service.cc
@@ -5,19 +5,22 @@
#include "content/browser/gamepad/gamepad_service.h"
#include "base/bind.h"
+#include "base/logging.h"
#include "base/memory/singleton.h"
-#include "content/browser/gamepad/data_fetcher.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/notification_service.h"
-#include "content/public/browser/notification_source.h"
-#include "content/public/browser/notification_types.h"
#include "content/public/browser/render_process_host.h"
namespace content {
-GamepadService::GamepadService() :
- num_readers_(0) {
+GamepadService::GamepadService() : num_readers_(0) {
+}
+
+GamepadService::GamepadService(scoped_ptr<GamepadDataFetcher> fetcher)
+ : num_readers_(0),
+ provider_(new GamepadProvider(fetcher.Pass())) {
+ thread_checker_.DetachFromThread();
}
GamepadService::~GamepadService() {
@@ -28,69 +31,40 @@ GamepadService* GamepadService::GetInstance() {
LeakySingletonTraits<GamepadService> >::get();
}
-void GamepadService::Start(
- GamepadDataFetcher* data_fetcher,
- RenderProcessHost* associated_rph) {
+void GamepadService::AddConsumer() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
num_readers_++;
DCHECK(num_readers_ > 0);
- if (provider_ == NULL) {
+ if (!provider_.get())
provider_.reset(new GamepadProvider);
- provider_->SetDataFetcher(data_fetcher);
- }
provider_->Resume();
-
- BrowserThread::PostTask(
- BrowserThread::UI,
- FROM_HERE,
- base::Bind(&GamepadService::RegisterForTerminationNotification,
- base::Unretained(this),
- associated_rph));
-}
-
-void GamepadService::Terminate() {
- provider_.reset();
}
-void GamepadService::RegisterForTerminationNotification(
- RenderProcessHost* rph) {
- registrar_.Add(this,
- NOTIFICATION_RENDERER_PROCESS_TERMINATED,
- Source<RenderProcessHost>(rph));
-}
+void GamepadService::RemoveConsumer() {
+ DCHECK(thread_checker_.CalledOnValidThread());
-base::SharedMemoryHandle GamepadService::GetSharedMemoryHandle(
- base::ProcessHandle handle) {
- return provider_->GetRendererSharedMemoryHandle(handle);
-}
-
-void GamepadService::Stop(const NotificationSource& source) {
--num_readers_;
DCHECK(num_readers_ >= 0);
- BrowserThread::PostTask(
- BrowserThread::UI,
- FROM_HERE,
- base::Bind(&GamepadService::UnregisterForTerminationNotification,
- base::Unretained(this),
- source));
-
if (num_readers_ == 0)
provider_->Pause();
}
-void GamepadService::UnregisterForTerminationNotification(
- const NotificationSource& source) {
- registrar_.Remove(this, NOTIFICATION_RENDERER_PROCESS_TERMINATED, source);
+void GamepadService::RegisterForUserGesture(const base::Closure& closure) {
+ DCHECK(num_readers_ > 0);
+ DCHECK(thread_checker_.CalledOnValidThread());
+ provider_->RegisterForUserGesture(closure);
}
-void GamepadService::Observe(int type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- DCHECK(type == NOTIFICATION_RENDERER_PROCESS_TERMINATED);
- BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
- base::Bind(&GamepadService::Stop, base::Unretained(this), source));
+void GamepadService::Terminate() {
+ provider_.reset();
+}
+
+base::SharedMemoryHandle GamepadService::GetSharedMemoryHandleForProcess(
+ base::ProcessHandle handle) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return provider_->GetSharedMemoryHandleForProcess(handle);
}
-} // namespace content
+} // namespace content
diff --git a/content/browser/gamepad/gamepad_service.h b/content/browser/gamepad/gamepad_service.h
index 4e10112..cc40c5d0 100644
--- a/content/browser/gamepad/gamepad_service.h
+++ b/content/browser/gamepad/gamepad_service.h
@@ -2,72 +2,76 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// Owns the GamepadProvider (the background polling thread) and keeps track of
-// the number of renderers currently using the data (and pausing the provider
-// when not in use).
-
#ifndef CONTENT_BROWSER_GAMEPAD_GAMEPAD_SERVICE_H
#define CONTENT_BROWSER_GAMEPAD_GAMEPAD_SERVICE_H
#include "base/basictypes.h"
+#include "base/callback_forward.h"
+#include "base/memory/scoped_ptr.h"
#include "base/memory/singleton.h"
#include "base/shared_memory.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
+#include "base/threading/thread_checker.h"
+#include "content/common/content_export.h"
namespace content {
class GamepadDataFetcher;
class GamepadProvider;
+class GamepadServiceTestConstructor;
class RenderProcessHost;
-class GamepadService : public NotificationObserver {
+// Owns the GamepadProvider (the background polling thread) and keeps track of
+// the number of consumers currently using the data (and pausing the provider
+// when not in use).
+class CONTENT_EXPORT GamepadService {
public:
// Returns the GamepadService singleton.
static GamepadService* GetInstance();
- // Called on IO thread from a renderer host. Increments the number of users
- // of the provider. The Provider is running when there's > 0 users, and is
- // paused when the count drops to 0. There is no stop, the gamepad service
- // registers with the RPH to be notified when the associated renderer closes
- // (or crashes).
- void Start(GamepadDataFetcher* fetcher,
- RenderProcessHost* associated_rph);
+ // Increments the number of users of the provider. The Provider is running
+ // when there's > 0 users, and is paused when the count drops to 0.
+ //
+ // Must be called on the I/O thread.
+ void AddConsumer();
+
+ // Removes a consumer. Should be matched with an AddConsumer call.
+ //
+ // Must be called on the I/O thread.
+ void RemoveConsumer();
+
+ // Registers the given closure for calling when the user has interacted with
+ // the device. This callback will only be issued once. Should only be called
+ // while a consumer is active.
+ void RegisterForUserGesture(const base::Closure& closure);
- base::SharedMemoryHandle GetSharedMemoryHandle(base::ProcessHandle handle);
+ // Returns the shared memory handle of the gamepad data duplicated into the
+ // given process.
+ base::SharedMemoryHandle GetSharedMemoryHandleForProcess(
+ base::ProcessHandle handle);
// Stop/join with the background thread in GamepadProvider |provider_|.
void Terminate();
private:
friend struct DefaultSingletonTraits<GamepadService>;
- GamepadService();
- virtual ~GamepadService();
-
- // Called when a renderer that Start'd us is closed/crashes.
- void Stop(const NotificationSource& source);
+ friend class GamepadServiceTestConstructor;
- // Run on UI thread to receive/stop notifications of renderer closes.
- void RegisterForTerminationNotification(RenderProcessHost* rph);
- void UnregisterForTerminationNotification(const NotificationSource& source);
+ GamepadService();
- // NotificationObserver overrides:
- virtual void Observe(int type,
- const NotificationSource& source,
- const NotificationDetails& details) OVERRIDE;
+ // Constructor for testing. This specifies the data fetcher to use for a
+ // provider, bypassing the default platform one.
+ GamepadService(scoped_ptr<GamepadDataFetcher> fetcher);
- // A registrar for listening notifications. Used to listen for when an
- // associated renderer has gone away (possibly crashed). We don't trust
- // the renderers to send a stop message because of the possibility of
- // crashing.
- NotificationRegistrar registrar_;
+ virtual ~GamepadService();
int num_readers_;
scoped_ptr<GamepadProvider> provider_;
+ base::ThreadChecker thread_checker_;
+
DISALLOW_COPY_AND_ASSIGN(GamepadService);
};
-} // namespace content
+} // namespace content
-#endif // CONTENT_BROWSER_GAMEPAD_GAMEPAD_SERVICE_H
+#endif // CONTENT_BROWSER_GAMEPAD_GAMEPAD_SERVICE_H_
diff --git a/content/browser/gamepad/gamepad_test_helpers.cc b/content/browser/gamepad/gamepad_test_helpers.cc
new file mode 100644
index 0000000..abf4187
--- /dev/null
+++ b/content/browser/gamepad/gamepad_test_helpers.cc
@@ -0,0 +1,60 @@
+// 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_test_helpers.h"
+
+#include "base/system_monitor/system_monitor.h"
+#include "content/browser/gamepad/gamepad_service.h"
+
+namespace content {
+
+MockGamepadDataFetcher::MockGamepadDataFetcher(
+ const WebKit::WebGamepads& test_data)
+ : test_data_(test_data),
+ read_data_(false, false) {
+}
+
+MockGamepadDataFetcher::~MockGamepadDataFetcher() {
+}
+
+void MockGamepadDataFetcher::GetGamepadData(WebKit::WebGamepads* pads,
+ bool devices_changed_hint) {
+ {
+ base::AutoLock lock(lock_);
+ *pads = test_data_;
+ }
+ read_data_.Signal();
+}
+
+void MockGamepadDataFetcher::WaitForDataRead() {
+ return read_data_.Wait();
+}
+
+void MockGamepadDataFetcher::SetTestData(const WebKit::WebGamepads& new_data) {
+ base::AutoLock lock(lock_);
+ test_data_ = new_data;
+}
+
+GamepadTestHelper::GamepadTestHelper() {
+#if defined(OS_MACOSX)
+ base::SystemMonitor::AllocateSystemIOPorts();
+#endif
+ system_monitor_.reset(new base::SystemMonitor);
+}
+
+GamepadTestHelper::~GamepadTestHelper() {
+}
+
+GamepadServiceTestConstructor::GamepadServiceTestConstructor(
+ const WebKit::WebGamepads& test_data) {
+ data_fetcher_ = new MockGamepadDataFetcher(test_data);
+ gamepad_service_ =
+ new GamepadService(scoped_ptr<GamepadDataFetcher>(data_fetcher_));
+}
+
+GamepadServiceTestConstructor::~GamepadServiceTestConstructor() {
+ delete gamepad_service_;
+}
+
+} // namespace content
diff --git a/content/browser/gamepad/gamepad_test_helpers.h b/content/browser/gamepad/gamepad_test_helpers.h
new file mode 100644
index 0000000..a31b147
--- /dev/null
+++ b/content/browser/gamepad/gamepad_test_helpers.h
@@ -0,0 +1,90 @@
+// 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.
+
+#ifndef CONTENT_BROWSER_GAMEPAD_GAMEPAD_TEST_HELPERS_H_
+#define CONTENT_BROWSER_GAMEPAD_GAMEPAD_TEST_HELPERS_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop.h"
+#include "base/synchronization/lock.h"
+#include "base/synchronization/waitable_event.h"
+#include "content/browser/gamepad/gamepad_data_fetcher.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebGamepads.h"
+
+namespace base {
+class SystemMonitor;
+}
+
+namespace content {
+
+class GamepadService;
+
+// Data fetcher that returns canned data for the gamepad provider.
+class MockGamepadDataFetcher : public GamepadDataFetcher {
+ public:
+ // Initializes the fetcher with the given gamepad data, which will be
+ // returned when the provider queries us.
+ explicit MockGamepadDataFetcher(const WebKit::WebGamepads& test_data);
+
+ virtual ~MockGamepadDataFetcher();
+
+ // GamepadDataFetcher.
+ virtual void GetGamepadData(WebKit::WebGamepads* pads,
+ bool devices_changed_hint) OVERRIDE;
+
+ // Blocks the current thread until the GamepadProvider reads from this
+ // fetcher on the background thread.
+ void WaitForDataRead();
+
+ // Updates the test data.
+ void SetTestData(const WebKit::WebGamepads& new_data);
+
+ private:
+ base::Lock lock_;
+ WebKit::WebGamepads test_data_;
+ base::WaitableEvent read_data_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockGamepadDataFetcher);
+};
+
+// Base class for the other test helpers. This just sets up the system monitor.
+class GamepadTestHelper {
+ public:
+ GamepadTestHelper();
+ virtual ~GamepadTestHelper();
+
+ MessageLoop& message_loop() { return message_loop_; }
+
+ private:
+ // This must be constructed before the system monitor.
+ MessageLoop message_loop_;
+
+ scoped_ptr<base::SystemMonitor> system_monitor_;
+
+ DISALLOW_COPY_AND_ASSIGN(GamepadTestHelper);
+};
+
+// Constructs a GamepadService with a mock data source. This bypasses the
+// global singleton for the gamepad service.
+class GamepadServiceTestConstructor : public GamepadTestHelper {
+ public:
+ GamepadServiceTestConstructor(const WebKit::WebGamepads& test_data);
+ virtual ~GamepadServiceTestConstructor();
+
+ GamepadService* gamepad_service() { return gamepad_service_; }
+ MockGamepadDataFetcher* data_fetcher() { return data_fetcher_; }
+
+ private:
+ // Owning pointer (can't be a scoped_ptr due to private destructor).
+ GamepadService* gamepad_service_;
+
+ // Pointer owned by the provider (which is owned by the gamepad service).
+ MockGamepadDataFetcher* data_fetcher_;
+
+ DISALLOW_COPY_AND_ASSIGN(GamepadServiceTestConstructor);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_GAMEPAD_GAMEPAD_TEST_HELPERS_H_