Commit f72a28a6 authored by jkwang's avatar jkwang Committed by Commit Bot

Allow gaming_seat to use ozone gamepad as back-end

This patch enable gaming_seat to use ozone gamepad as back-end. It is
protected by build args. If enable_exo_ozone_gamepad is turned off,
gaming_seat will fallback use old joydev implementation.

BUG=717246

Review-Url: https://codereview.chromium.org/2900773003
Cr-Commit-Position: refs/heads/master@{#478834}
parent 57f1f0bb
......@@ -49,6 +49,10 @@ declare_args() {
enable_one_click_signin =
is_win || is_mac || (is_linux && !is_chromeos && !is_chromecast)
# Indicates if Exo should use ozone gamepad. If this is false, exo will use
# /device/gamepad as backend.
enable_exo_ozone_gamepad = use_ozone
# Set to true to bundle all the mash related mojo services into chrome.
# Specify --mash to chrome to have chrome start the mash environment.
enable_package_mash_services = is_chromeos
......
......@@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//chrome/common/features.gni")
import("//build/config/ui.gni")
import("//testing/test.gni")
......@@ -13,7 +14,6 @@ source_set("exo") {
"compositor_frame_sink_holder.h",
"display.cc",
"display.h",
"gaming_seat.cc",
"gaming_seat.h",
"keyboard.cc",
"keyboard.h",
......@@ -71,8 +71,13 @@ source_set("exo") {
"//ui/wm/public",
]
if (use_ozone) {
if (enable_exo_ozone_gamepad) {
defines = [ "USE_OZONE_GAMEPAD" ]
sources += [ "gaming_seat_ozone.cc" ]
deps += [ "//ui/ozone" ]
deps += [ "//ui/events/ozone:events_ozone_evdev" ]
} else {
sources += [ "gaming_seat.cc" ]
}
if (is_chromeos) {
......@@ -112,7 +117,6 @@ source_set("unit_tests") {
sources = [
"buffer_unittest.cc",
"display_unittest.cc",
"gaming_seat_unittest.cc",
"keyboard_unittest.cc",
"pointer_unittest.cc",
"shared_memory_unittest.cc",
......@@ -152,6 +156,14 @@ source_set("unit_tests") {
if (use_ozone) {
deps += [ "//ui/ozone" ]
}
if (enable_exo_ozone_gamepad) {
sources += [
"../../ui/events/ozone/gamepad/gamepad_event.cc",
"gaming_seat_unittest.cc",
]
deps += [ "//ui/events/ozone:events_ozone_evdev" ]
}
}
test("exo_unittests") {
......
......@@ -7,10 +7,6 @@
#include <cmath>
#include "base/bind.h"
#include "base/location.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/exo/gamepad_delegate.h"
#include "components/exo/gaming_seat_delegate.h"
#include "components/exo/shell_surface.h"
......@@ -60,7 +56,7 @@ class GamingSeat::ThreadSafeGamepadChangeFetcher
create_fetcher_callback_(create_fetcher_callback),
polling_task_runner_(task_runner),
origin_task_runner_(base::ThreadTaskRunnerHandle::Get()) {
thread_checker_.DetachFromThread();
DETACH_FROM_THREAD(thread_checker_);
}
// Enable or disable gamepad polling. Can be called from any thread.
......@@ -79,7 +75,7 @@ class GamingSeat::ThreadSafeGamepadChangeFetcher
// Enables or disables polling.
void EnablePollingOnPollingThread(bool enabled) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
is_enabled_ = enabled;
if (is_enabled_) {
......@@ -96,7 +92,7 @@ class GamingSeat::ThreadSafeGamepadChangeFetcher
// Schedules the next poll on the polling thread.
void SchedulePollOnPollingThread() {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(fetcher_);
if (!is_enabled_ || has_poll_scheduled_)
......@@ -112,7 +108,7 @@ class GamingSeat::ThreadSafeGamepadChangeFetcher
// Polls devices for new data and posts gamepad changes back to origin thread.
void PollOnPollingThread() {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
has_poll_scheduled_ = false;
if (!is_enabled_)
......@@ -180,7 +176,7 @@ class GamingSeat::ThreadSafeGamepadChangeFetcher
bool is_enabled_ = false;
// ThreadChecker for the polling thread.
base::ThreadChecker thread_checker_;
THREAD_CHECKER(thread_checker_);
DISALLOW_COPY_AND_ASSIGN(ThreadSafeGamepadChangeFetcher);
};
......@@ -190,20 +186,13 @@ class GamingSeat::ThreadSafeGamepadChangeFetcher
GamingSeat::GamingSeat(GamingSeatDelegate* gaming_seat_delegate,
base::SingleThreadTaskRunner* polling_task_runner)
: GamingSeat(gaming_seat_delegate,
polling_task_runner,
base::Bind(CreateGamepadPlatformDataFetcher)) {}
GamingSeat::GamingSeat(GamingSeatDelegate* gaming_seat_delegate,
base::SingleThreadTaskRunner* polling_task_runner,
CreateGamepadDataFetcherCallback create_fetcher_callback)
: delegate_(gaming_seat_delegate),
gamepad_delegates_{nullptr},
weak_ptr_factory_(this) {
gamepad_change_fetcher_ = new ThreadSafeGamepadChangeFetcher(
base::Bind(&GamingSeat::ProcessGamepadChanges,
weak_ptr_factory_.GetWeakPtr()),
create_fetcher_callback, polling_task_runner);
base::Bind(CreateGamepadPlatformDataFetcher), polling_task_runner);
auto* helper = WMHelper::GetInstance();
helper->AddFocusObserver(this);
......@@ -229,7 +218,7 @@ GamingSeat::~GamingSeat() {
void GamingSeat::OnWindowFocused(aura::Window* gained_focus,
aura::Window* lost_focus) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
Surface* target = nullptr;
if (gained_focus) {
target = Surface::AsSurface(gained_focus);
......@@ -250,7 +239,7 @@ void GamingSeat::OnWindowFocused(aura::Window* gained_focus,
void GamingSeat::ProcessGamepadChanges(int index,
const device::Gamepad new_pad) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
bool send_frame = false;
device::Gamepad& pad_state = pad_state_.items[index];
......
......@@ -7,6 +7,7 @@
#include <memory>
#include "base/containers/flat_map.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/sequenced_task_runner.h"
......@@ -17,6 +18,10 @@
#include "device/gamepad/gamepad_data_fetcher.h"
#include "ui/aura/client/focus_change_observer.h"
#if defined(USE_OZONE_GAMEPAD)
#include "ui/events/ozone/gamepad/gamepad_observer.h"
#endif
namespace exo {
class GamingSeatDelegate;
class GamepadDelegate;
......@@ -24,29 +29,43 @@ class GamepadDelegate;
using CreateGamepadDataFetcherCallback =
base::Callback<std::unique_ptr<device::GamepadDataFetcher>()>;
// This class represents one gaming seat, it uses a background thread
// for polling gamepad devices and notifies the corresponding GampadDelegate of
// any changes.
class GamingSeat : public WMHelper::FocusObserver {
// TODO(jkwang): always use ozone_gamepad when ozone is default for all Chrome
// OS builds. https://crbug.com/717246
// This class represents one gaming seat. It uses /device/gamepad or
// ozone/gamepad as backend and notifies corresponding GamepadDelegate of any
// gamepad changes.
class GamingSeat : public WMHelper::FocusObserver
#if defined(USE_OZONE_GAMEPAD)
,
public ui::GamepadObserver
#endif
{
public:
// This class will post tasks to invoke the delegate on the thread runner
// which is associated with the thread that is creating this instance.
// This class will monitor gamepad connection changes and manage gamepad
// returned by gaming_seat_delegate.
GamingSeat(GamingSeatDelegate* gaming_seat_delegate,
base::SingleThreadTaskRunner* polling_task_runner);
// Allows test cases to specify a CreateGamepadDataFetcherCallback that
// overrides the default GamepadPlatformDataFetcher.
GamingSeat(GamingSeatDelegate* gaming_seat_delegate,
base::SingleThreadTaskRunner* polling_task_runner,
CreateGamepadDataFetcherCallback create_fetcher_callback);
~GamingSeat() override;
// Overridden WMHelper::FocusObserver:
// Overridden from WMHelper::FocusObserver:
void OnWindowFocused(aura::Window* gained_focus,
aura::Window* lost_focus) override;
#if defined(USE_OZONE_GAMEPAD)
// Overridden from ui::GamepadObserver:
void OnGamepadDevicesUpdated() override;
void OnGamepadEvent(const ui::GamepadEvent& event) override;
#endif
private:
// The delegate that handles gamepad_added.
GamingSeatDelegate* const delegate_;
#if defined(USE_OZONE_GAMEPAD)
// Contains the delegate for each gamepad device.
base::flat_map<int, GamepadDelegate*> gamepads_;
#else
class ThreadSafeGamepadChangeFetcher;
// Processes updates of gamepad data and passes changes on to delegate.
......@@ -56,9 +75,6 @@ class GamingSeat : public WMHelper::FocusObserver {
// polling thread.
scoped_refptr<ThreadSafeGamepadChangeFetcher> gamepad_change_fetcher_;
// The delegate that handles gamepad_added.
GamingSeatDelegate* const delegate_;
// The delegate instances that all other events are dispatched to.
GamepadDelegate* gamepad_delegates_[device::Gamepads::kItemsLengthCap];
......@@ -66,9 +82,10 @@ class GamingSeat : public WMHelper::FocusObserver {
device::Gamepads pad_state_;
// ThreadChecker for the origin thread.
base::ThreadChecker thread_checker_;
THREAD_CHECKER(thread_checker_);
base::WeakPtrFactory<GamingSeat> weak_ptr_factory_;
#endif
DISALLOW_COPY_AND_ASSIGN(GamingSeat);
};
......
// Copyright 2017 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 "components/exo/gamepad_delegate.h"
#include "components/exo/gaming_seat.h"
#include "components/exo/gaming_seat_delegate.h"
#include "components/exo/shell_surface.h"
#include "components/exo/surface.h"
#include "ui/events/ozone/gamepad/gamepad_provider_ozone.h"
namespace exo {
////////////////////////////////////////////////////////////////////////////////
// GamingSeat, public:
GamingSeat::GamingSeat(GamingSeatDelegate* delegate,
base::SingleThreadTaskRunner* task_runner)
: delegate_(delegate) {
auto* helper = WMHelper::GetInstance();
helper->AddFocusObserver(this);
OnWindowFocused(helper->GetFocusedWindow(), nullptr);
}
GamingSeat::~GamingSeat() {
ui::GamepadProviderOzone::GetInstance()->RemoveGamepadObserver(this);
delegate_->OnGamingSeatDestroying(this);
// Disconnect all the gamepads.
for (auto& entry : gamepads_)
entry.second->OnRemoved();
WMHelper::GetInstance()->RemoveFocusObserver(this);
}
////////////////////////////////////////////////////////////////////////////////
// WMHelper::FocusObserver overrides:
void GamingSeat::OnWindowFocused(aura::Window* gained_focus,
aura::Window* lost_focus) {
Surface* target = nullptr;
if (gained_focus) {
target = Surface::AsSurface(gained_focus);
if (!target) {
aura::Window* top_level_window = gained_focus->GetToplevelWindow();
if (top_level_window)
target = ShellSurface::GetMainSurface(top_level_window);
}
}
bool focused = target && delegate_->CanAcceptGamepadEventsForSurface(target);
if (focused) {
ui::GamepadProviderOzone::GetInstance()->AddGamepadObserver(this);
OnGamepadDevicesUpdated();
} else {
ui::GamepadProviderOzone::GetInstance()->RemoveGamepadObserver(this);
}
}
////////////////////////////////////////////////////////////////////////////////
// ui::GamepadObserver overrides:
void GamingSeat::OnGamepadDevicesUpdated() {
std::vector<ui::InputDevice> gamepad_devices =
ui::GamepadProviderOzone::GetInstance()->GetGamepadDevices();
base::flat_map<int, GamepadDelegate*> new_gamepads;
// Copy the "still connected gamepads".
for (auto& device : gamepad_devices) {
auto it = gamepads_.find(device.id);
if (it != gamepads_.end()) {
new_gamepads[device.id] = it->second;
gamepads_.erase(it);
}
}
// Remove each disconected gamepad.
for (auto& entry : gamepads_)
entry.second->OnRemoved();
// Add each new connected gamepad.
for (auto& device : gamepad_devices) {
if (new_gamepads.find(device.id) == new_gamepads.end())
new_gamepads[device.id] = delegate_->GamepadAdded();
}
new_gamepads.swap(gamepads_);
}
void GamingSeat::OnGamepadEvent(const ui::GamepadEvent& event) {
auto it = gamepads_.find(event.device_id());
if (it == gamepads_.end())
return;
switch (event.type()) {
case ui::GamepadEventType::BUTTON:
it->second->OnButton(event.code(), event.value(), event.value());
break;
case ui::GamepadEventType::AXIS:
it->second->OnAxis(event.code(), event.value());
break;
case ui::GamepadEventType::FRAME:
it->second->OnFrame();
break;
}
}
} // namespace exo
......@@ -6,7 +6,6 @@
#include "ash/shell.h"
#include "base/command_line.h"
#include "base/run_loop.h"
#include "base/test/test_simple_task_runner.h"
#include "components/exo/buffer.h"
#include "components/exo/gamepad_delegate.h"
#include "components/exo/gaming_seat_delegate.h"
......@@ -18,6 +17,7 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/aura/client/focus_client.h"
#include "ui/events/ozone/gamepad/gamepad_provider_ozone.h"
namespace exo {
namespace {
......@@ -45,54 +45,36 @@ class MockGamepadDelegate : public GamepadDelegate {
class GamingSeatTest : public test::ExoTestBase {
public:
GamingSeatTest() {}
std::unique_ptr<device::GamepadDataFetcher> MockDataFetcherFactory() {
device::Gamepads initial_data;
std::unique_ptr<device::MockGamepadDataFetcher> fetcher(
new device::MockGamepadDataFetcher(initial_data));
mock_data_fetcher_ = fetcher.get();
return std::move(fetcher);
}
void InitializeGamingSeat(MockGamingSeatDelegate* delegate) {
polling_task_runner_ = new base::TestSimpleTaskRunner();
gaming_seat_.reset(
new GamingSeat(delegate, polling_task_runner_.get(),
base::Bind(&GamingSeatTest::MockDataFetcherFactory,
base::Unretained(this))));
// Run the polling task runner to have it create the data fetcher.
polling_task_runner_->RunPendingTasks();
gaming_seat_.reset(new GamingSeat(delegate, nullptr));
}
void DestroyGamingSeat(MockGamingSeatDelegate* delegate) {
EXPECT_CALL(*delegate, Die()).Times(1);
mock_data_fetcher_ = nullptr;
gaming_seat_.reset();
// Process tasks until polling is shut down.
polling_task_runner_->RunPendingTasks();
polling_task_runner_ = nullptr;
}
void SetDataAndPostToDelegate(const device::Gamepads& new_data) {
ASSERT_TRUE(mock_data_fetcher_ != nullptr);
mock_data_fetcher_->SetTestData(new_data);
// Run one polling cycle, which will post a task to the origin task runner.
polling_task_runner_->RunPendingTasks();
// Run origin task runner to invoke delegate.
base::RunLoop().RunUntilIdle();
void UpdateGamepadDevice(const std::vector<int>& gamepad_device_ids) {
std::vector<ui::InputDevice> gamepad_devices;
for (auto& id : gamepad_device_ids) {
gamepad_devices.push_back(ui::InputDevice(
id, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, "gamepad"));
}
ui::GamepadProviderOzone::GetInstance()->DispatchGamepadDevicesUpdated(
gamepad_devices);
}
void SendFrameToGamepads(const std::vector<int>& gamepad_device_ids) {
for (auto& id : gamepad_device_ids) {
ui::GamepadEvent event(id, ui::GamepadEventType::FRAME, 0, 0,
base::TimeTicks());
ui::GamepadProviderOzone::GetInstance()->DispatchGamepadEvent(event);
}
}
protected:
std::unique_ptr<GamingSeat> gaming_seat_;
// Task runner to simulate the polling thread.
scoped_refptr<base::TestSimpleTaskRunner> polling_task_runner_;
// Weak reference to the mock data fetcher provided by MockDataFetcherFactory.
// This instance is valid until both gamepad_ and polling_task_runner_ are
// shut down.
device::MockGamepadDataFetcher* mock_data_fetcher_;
DISALLOW_COPY_AND_ASSIGN(GamingSeatTest);
};
......@@ -112,212 +94,51 @@ TEST_F(GamingSeatTest, ConnectionChange) {
.WillOnce(testing::Return(true));
InitializeGamingSeat(gaming_seat_delegate);
testing::StrictMock<MockGamepadDelegate> gamepad_delegate0;
testing::StrictMock<MockGamepadDelegate> gamepad_delegate1;
testing::StrictMock<MockGamepadDelegate> gamepad_delegate2;
testing::StrictMock<MockGamepadDelegate> gamepad_delegate[6];
{ // Test sequence
testing::InSequence s;
// connect gamepad 0
// connect gamepad 2
// connect gamepad 1
// Connect 2 gamepads.
EXPECT_CALL(*gaming_seat_delegate, GamepadAdded())
.WillOnce(testing::Return(&gamepad_delegate[0]))
.WillOnce(testing::Return(&gamepad_delegate[1]));
// Send frame to connected gamepad.
EXPECT_CALL(gamepad_delegate[0], OnFrame()).Times(1);
EXPECT_CALL(gamepad_delegate[1], OnFrame()).Times(1);
// Connect 3 more.
EXPECT_CALL(*gaming_seat_delegate, GamepadAdded())
.WillOnce(testing::Return(&gamepad_delegate[2]))
.WillOnce(testing::Return(&gamepad_delegate[3]))
.WillOnce(testing::Return(&gamepad_delegate[4]));
// Send frame to all gamepads.
EXPECT_CALL(gamepad_delegate[0], OnFrame()).Times(1);
EXPECT_CALL(gamepad_delegate[1], OnFrame()).Times(1);
EXPECT_CALL(gamepad_delegate[2], OnFrame()).Times(1);
EXPECT_CALL(gamepad_delegate[3], OnFrame()).Times(1);
EXPECT_CALL(gamepad_delegate[4], OnFrame()).Times(1);
// Disconnect gamepad 0 and gamepad 2 and connect a new gamepad.
EXPECT_CALL(gamepad_delegate[0], OnRemoved()).Times(1);
EXPECT_CALL(gamepad_delegate[2], OnRemoved()).Times(1);
EXPECT_CALL(gamepad_delegate[4], OnRemoved()).Times(1);
EXPECT_CALL(*gaming_seat_delegate, GamepadAdded())
.WillOnce(testing::Return(&gamepad_delegate0))
.WillOnce(testing::Return(&gamepad_delegate2))
.WillOnce(testing::Return(&gamepad_delegate1));
// disconnect gamepad 1
EXPECT_CALL(gamepad_delegate1, OnRemoved()).Times(1);
.WillOnce(testing::Return(&gamepad_delegate[5]));
// Send frame to all gamepads.
EXPECT_CALL(gamepad_delegate[1], OnFrame()).Times(1);
EXPECT_CALL(gamepad_delegate[3], OnFrame()).Times(1);
EXPECT_CALL(gamepad_delegate[5], OnFrame()).Times(1);
// disconnect other gamepads
EXPECT_CALL(gamepad_delegate0, OnRemoved()).Times(1);
EXPECT_CALL(gamepad_delegate2, OnRemoved()).Times(1);
EXPECT_CALL(gamepad_delegate[1], OnRemoved()).Times(1);
EXPECT_CALL(gamepad_delegate[3], OnRemoved()).Times(1);
EXPECT_CALL(gamepad_delegate[5], OnRemoved()).Times(1);
}
// Gamepad connected.
device::Gamepads gamepad_connected;
gamepad_connected.items[0].connected = true;
gamepad_connected.items[0].timestamp = 1;
SetDataAndPostToDelegate(gamepad_connected);
gamepad_connected.items[2].connected = true;
gamepad_connected.items[2].timestamp = 1;
SetDataAndPostToDelegate(gamepad_connected);
gamepad_connected.items[1].connected = true;
gamepad_connected.items[1].timestamp = 1;
SetDataAndPostToDelegate(gamepad_connected);
// Gamepad 1 is dis connected
gamepad_connected.items[1].connected = false;
gamepad_connected.items[1].timestamp = 2;
SetDataAndPostToDelegate(gamepad_connected);
// Gamepad disconnected.
device::Gamepads all_disconnected;
SetDataAndPostToDelegate(all_disconnected);
DestroyGamingSeat(gaming_seat_delegate);
}
TEST_F(GamingSeatTest, OnAxis) {
std::unique_ptr<Surface> surface(new Surface);
std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
gfx::Size buffer_size(10, 10);
std::unique_ptr<Buffer> buffer(
new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
surface->Attach(buffer.get());
surface->Commit();
testing::StrictMock<MockGamingSeatDelegate>* gaming_seat_delegate =
new testing::StrictMock<MockGamingSeatDelegate>();
EXPECT_CALL(*gaming_seat_delegate,
CanAcceptGamepadEventsForSurface(testing::_))
.WillOnce(testing::Return(true));
InitializeGamingSeat(gaming_seat_delegate);
testing::StrictMock<MockGamepadDelegate> gamepad_delegate0;
testing::StrictMock<MockGamepadDelegate> gamepad_delegate2;
// connect gamepad 0 and 2
EXPECT_CALL(*gaming_seat_delegate, GamepadAdded())
.WillOnce(testing::Return(&gamepad_delegate0))
.WillOnce(testing::Return(&gamepad_delegate2));
device::Gamepads gamepad_connected;
gamepad_connected.items[0].connected = true;
gamepad_connected.items[0].timestamp = 1;
SetDataAndPostToDelegate(gamepad_connected);
gamepad_connected.items[2].connected = true;
gamepad_connected.items[2].timestamp = 1;
SetDataAndPostToDelegate(gamepad_connected);
// send axis event to 2 and then 0
device::Gamepads axis_moved;
axis_moved.items[0].connected = true;
axis_moved.items[0].timestamp = 1;
axis_moved.items[2].connected = true;
axis_moved.items[2].timestamp = 2;
axis_moved.items[2].axes_length = 1;
axis_moved.items[2].axes[0] = 1.0;
EXPECT_CALL(gamepad_delegate2, OnAxis(0, 1.0)).Times(1);
EXPECT_CALL(gamepad_delegate2, OnFrame()).Times(1);
SetDataAndPostToDelegate(axis_moved);
axis_moved.items[0].timestamp = 2;
axis_moved.items[0].axes_length = 1;
axis_moved.items[0].axes[0] = 2.0;
EXPECT_CALL(gamepad_delegate0, OnAxis(0, 2.0)).Times(1);
EXPECT_CALL(gamepad_delegate0, OnFrame()).Times(1);
SetDataAndPostToDelegate(axis_moved);
EXPECT_CALL(gamepad_delegate0, OnRemoved()).Times(1);
EXPECT_CALL(gamepad_delegate2, OnRemoved()).Times(1);
DestroyGamingSeat(gaming_seat_delegate);
}
TEST_F(GamingSeatTest, OnButton) {
std::unique_ptr<Surface> surface(new Surface);
std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
gfx::Size buffer_size(10, 10);
std::unique_ptr<Buffer> buffer(
new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
surface->Attach(buffer.get());
surface->Commit();
testing::StrictMock<MockGamingSeatDelegate>* gaming_seat_delegate =
new testing::StrictMock<MockGamingSeatDelegate>();
EXPECT_CALL(*gaming_seat_delegate,
CanAcceptGamepadEventsForSurface(testing::_))
.WillOnce(testing::Return(true));
InitializeGamingSeat(gaming_seat_delegate);
testing::StrictMock<MockGamepadDelegate> gamepad_delegate0;
testing::StrictMock<MockGamepadDelegate> gamepad_delegate2;
// connect gamepad 0 and 2
EXPECT_CALL(*gaming_seat_delegate, GamepadAdded())
.WillOnce(testing::Return(&gamepad_delegate0))
.WillOnce(testing::Return(&gamepad_delegate2));
device::Gamepads gamepad_connected;
gamepad_connected.items[0].connected = true;
gamepad_connected.items[0].timestamp = 1;
SetDataAndPostToDelegate(gamepad_connected);
gamepad_connected.items[2].connected = true;
gamepad_connected.items[2].timestamp = 1;
SetDataAndPostToDelegate(gamepad_connected);
// send axis event to 2 and then 0
device::Gamepads axis_moved;
axis_moved.items[0].connected = true;
axis_moved.items[0].timestamp = 1;
axis_moved.items[2].connected = true;
axis_moved.items[2].timestamp = 2;
axis_moved.items[2].buttons_length = 1;
axis_moved.items[2].buttons[0].pressed = true;
axis_moved.items[2].buttons[0].value = 1.0;
EXPECT_CALL(gamepad_delegate2, OnButton(0, true, 1.0)).Times(1);
EXPECT_CALL(gamepad_delegate2, OnFrame()).Times(1);
SetDataAndPostToDelegate(axis_moved);
axis_moved.items[0].timestamp = 2;
axis_moved.items[0].buttons_length = 1;
axis_moved.items[0].buttons[0].pressed = true;
axis_moved.items[0].buttons[0].value = 2.0;
EXPECT_CALL(gamepad_delegate0, OnButton(0, true, 2.0)).Times(1);
EXPECT_CALL(gamepad_delegate0, OnFrame()).Times(1);
SetDataAndPostToDelegate(axis_moved);
EXPECT_CALL(gamepad_delegate0, OnRemoved()).Times(1);
EXPECT_CALL(gamepad_delegate2, OnRemoved()).Times(1);
DestroyGamingSeat(gaming_seat_delegate);
}
TEST_F(GamingSeatTest, OnWindowFocused) {
// Create surface and move focus to it.
std::unique_ptr<Surface> surface(new Surface);
std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
gfx::Size buffer_size(10, 10);
std::unique_ptr<Buffer> buffer(
new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
surface->Attach(buffer.get());
surface->Commit();
testing::StrictMock<MockGamingSeatDelegate>* gaming_seat_delegate =
new testing::StrictMock<MockGamingSeatDelegate>();
EXPECT_CALL(*gaming_seat_delegate,
CanAcceptGamepadEventsForSurface(testing::_))
.WillOnce(testing::Return(true));
InitializeGamingSeat(gaming_seat_delegate);
// In focus. Should be polling indefinitely, check a couple of time that the
// poll task is re-posted.
for (size_t i = 0; i < 5; ++i) {
polling_task_runner_->RunPendingTasks();
ASSERT_TRUE(polling_task_runner_->HasPendingTask());
}
// Remove focus from window.
aura::client::FocusClient* focus_client =
aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow());
focus_client->FocusWindow(nullptr);
// Run EnablePolling and OnPoll task, no more polls should be scheduled.
// In the first round of RunPendingTasks we will execute
// EnablePollingOnPollingThread, which will cause the polling to stop being
// scheduled in the next round.
polling_task_runner_->RunPendingTasks();
polling_task_runner_->RunPendingTasks();
ASSERT_FALSE(polling_task_runner_->HasPendingTask());
UpdateGamepadDevice({0, 1});
SendFrameToGamepads({0, 1});
UpdateGamepadDevice({0, 1, 2, 3, 4});
SendFrameToGamepads({0, 1, 2, 3, 4});
UpdateGamepadDevice({1, 3, 5});
SendFrameToGamepads({1, 2, 3, 4, 5});
DestroyGamingSeat(gaming_seat_delegate);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment