diff options
Diffstat (limited to 'chromium/ui/events/ozone/evdev/touch_event_converter_evdev_unittest.cc')
-rw-r--r-- | chromium/ui/events/ozone/evdev/touch_event_converter_evdev_unittest.cc | 481 |
1 files changed, 481 insertions, 0 deletions
diff --git a/chromium/ui/events/ozone/evdev/touch_event_converter_evdev_unittest.cc b/chromium/ui/events/ozone/evdev/touch_event_converter_evdev_unittest.cc new file mode 100644 index 00000000000..ce2957a1ece --- /dev/null +++ b/chromium/ui/events/ozone/evdev/touch_event_converter_evdev_unittest.cc @@ -0,0 +1,481 @@ +// Copyright 2014 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 <errno.h> +#include <fcntl.h> +#include <linux/input.h> +#include <unistd.h> + +#include <vector> + +#include "base/memory/scoped_ptr.h" +#include "base/memory/scoped_vector.h" +#include "base/posix/eintr_wrapper.h" +#include "base/run_loop.h" +#include "base/time/time.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/events/event.h" +#include "ui/events/ozone/evdev/touch_event_converter_evdev.h" +#include "ui/events/platform/platform_event_dispatcher.h" +#include "ui/events/platform/platform_event_source.h" + +namespace { + +static int SetNonBlocking(int fd) { + int flags = fcntl(fd, F_GETFL, 0); + if (flags == -1) + flags = 0; + return fcntl(fd, F_SETFL, flags | O_NONBLOCK); +} + +const char kTestDevicePath[] = "/dev/input/test-device"; + +} // namespace + +namespace ui { + +class MockTouchEventConverterEvdev : public TouchEventConverterEvdev { + public: + MockTouchEventConverterEvdev(int fd, base::FilePath path); + virtual ~MockTouchEventConverterEvdev() {}; + + void ConfigureReadMock(struct input_event* queue, + long read_this_many, + long queue_index); + + unsigned size() { return dispatched_events_.size(); } + TouchEvent* event(unsigned index) { return dispatched_events_[index]; } + + // Actually dispatch the event reader code. + void ReadNow() { + OnFileCanReadWithoutBlocking(read_pipe_); + base::RunLoop().RunUntilIdle(); + } + + void DispatchCallback(Event* event) { + dispatched_events_.push_back( + new TouchEvent(*static_cast<TouchEvent*>(event))); + } + + virtual bool Reinitialize() OVERRIDE { return true; } + + private: + int read_pipe_; + int write_pipe_; + + ScopedVector<TouchEvent> dispatched_events_; + + DISALLOW_COPY_AND_ASSIGN(MockTouchEventConverterEvdev); +}; + +MockTouchEventConverterEvdev::MockTouchEventConverterEvdev(int fd, + base::FilePath path) + : TouchEventConverterEvdev( + fd, + path, + EventDeviceInfo(), + base::Bind(&MockTouchEventConverterEvdev::DispatchCallback, + base::Unretained(this))) { + pressure_min_ = 30; + pressure_max_ = 60; + + // TODO(rjkroege): Check test axes. + x_min_pixels_ = x_min_tuxels_ = 0; + x_num_pixels_ = x_num_tuxels_ = std::numeric_limits<int>::max(); + y_min_pixels_ = y_min_tuxels_ = 0; + y_num_pixels_ = y_num_tuxels_ = std::numeric_limits<int>::max(); + + int fds[2]; + + if (pipe(fds)) + PLOG(FATAL) << "failed pipe"; + + DCHECK(SetNonBlocking(fds[0]) == 0) + << "SetNonBlocking for pipe fd[0] failed, errno: " << errno; + DCHECK(SetNonBlocking(fds[1]) == 0) + << "SetNonBlocking for pipe fd[0] failed, errno: " << errno; + read_pipe_ = fds[0]; + write_pipe_ = fds[1]; +} + +void MockTouchEventConverterEvdev::ConfigureReadMock(struct input_event* queue, + long read_this_many, + long queue_index) { + int nwrite = HANDLE_EINTR(write(write_pipe_, + queue + queue_index, + sizeof(struct input_event) * read_this_many)); + DCHECK(nwrite == + static_cast<int>(sizeof(struct input_event) * read_this_many)) + << "write() failed, errno: " << errno; +} + +} // namespace ui + +// Test fixture. +class TouchEventConverterEvdevTest : public testing::Test { + public: + TouchEventConverterEvdevTest() {} + + // Overridden from testing::Test: + virtual void SetUp() OVERRIDE { + // Set up pipe to satisfy message pump (unused). + int evdev_io[2]; + if (pipe(evdev_io)) + PLOG(FATAL) << "failed pipe"; + events_in_ = evdev_io[0]; + events_out_ = evdev_io[1]; + + loop_ = new base::MessageLoopForUI; + device_ = new ui::MockTouchEventConverterEvdev( + events_in_, base::FilePath(kTestDevicePath)); + } + + virtual void TearDown() OVERRIDE { + delete device_; + delete loop_; + } + + ui::MockTouchEventConverterEvdev* device() { return device_; } + + private: + base::MessageLoop* loop_; + ui::MockTouchEventConverterEvdev* device_; + + int events_out_; + int events_in_; + + DISALLOW_COPY_AND_ASSIGN(TouchEventConverterEvdevTest); +}; + +// TODO(rjkroege): Test for valid handling of time stamps. +TEST_F(TouchEventConverterEvdevTest, TouchDown) { + ui::MockTouchEventConverterEvdev* dev = device(); + + struct input_event mock_kernel_queue[] = { + {{0, 0}, EV_ABS, ABS_MT_TRACKING_ID, 684}, + {{0, 0}, EV_ABS, ABS_MT_TOUCH_MAJOR, 3}, + {{0, 0}, EV_ABS, ABS_MT_PRESSURE, 45}, + {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 42}, + {{0, 0}, EV_ABS, ABS_MT_POSITION_Y, 51}, {{0, 0}, EV_SYN, SYN_REPORT, 0} + }; + + dev->ConfigureReadMock(mock_kernel_queue, 1, 0); + dev->ReadNow(); + EXPECT_EQ(0u, dev->size()); + + dev->ConfigureReadMock(mock_kernel_queue, 2, 1); + dev->ReadNow(); + EXPECT_EQ(0u, dev->size()); + + dev->ConfigureReadMock(mock_kernel_queue, 3, 3); + dev->ReadNow(); + EXPECT_EQ(1u, dev->size()); + + ui::TouchEvent* event = dev->event(0); + EXPECT_FALSE(event == NULL); + + EXPECT_EQ(ui::ET_TOUCH_PRESSED, event->type()); + EXPECT_EQ(base::TimeDelta::FromMicroseconds(0), event->time_stamp()); + EXPECT_EQ(42, event->x()); + EXPECT_EQ(51, event->y()); + EXPECT_EQ(0, event->touch_id()); + EXPECT_FLOAT_EQ(.5f, event->force()); + EXPECT_FLOAT_EQ(0.f, event->rotation_angle()); +} + +TEST_F(TouchEventConverterEvdevTest, NoEvents) { + ui::MockTouchEventConverterEvdev* dev = device(); + dev->ConfigureReadMock(NULL, 0, 0); + EXPECT_EQ(0u, dev->size()); +} + +TEST_F(TouchEventConverterEvdevTest, TouchMove) { + ui::MockTouchEventConverterEvdev* dev = device(); + + struct input_event mock_kernel_queue_press[] = { + {{0, 0}, EV_ABS, ABS_MT_TRACKING_ID, 684}, + {{0, 0}, EV_ABS, ABS_MT_TOUCH_MAJOR, 3}, + {{0, 0}, EV_ABS, ABS_MT_PRESSURE, 45}, + {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 42}, + {{0, 0}, EV_ABS, ABS_MT_POSITION_Y, 51}, {{0, 0}, EV_SYN, SYN_REPORT, 0} + }; + + struct input_event mock_kernel_queue_move1[] = { + {{0, 0}, EV_ABS, ABS_MT_PRESSURE, 50}, + {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 42}, + {{0, 0}, EV_ABS, ABS_MT_POSITION_Y, 43}, {{0, 0}, EV_SYN, SYN_REPORT, 0} + }; + + struct input_event mock_kernel_queue_move2[] = { + {{0, 0}, EV_ABS, ABS_MT_POSITION_Y, 42}, {{0, 0}, EV_SYN, SYN_REPORT, 0} + }; + + // Setup and discard a press. + dev->ConfigureReadMock(mock_kernel_queue_press, 6, 0); + dev->ReadNow(); + EXPECT_EQ(1u, dev->size()); + + dev->ConfigureReadMock(mock_kernel_queue_move1, 4, 0); + dev->ReadNow(); + EXPECT_EQ(2u, dev->size()); + ui::TouchEvent* event = dev->event(1); + EXPECT_FALSE(event == NULL); + + EXPECT_EQ(ui::ET_TOUCH_MOVED, event->type()); + EXPECT_EQ(base::TimeDelta::FromMicroseconds(0), event->time_stamp()); + EXPECT_EQ(42, event->x()); + EXPECT_EQ(43, event->y()); + EXPECT_EQ(0, event->touch_id()); + EXPECT_FLOAT_EQ(2.f / 3.f, event->force()); + EXPECT_FLOAT_EQ(0.f, event->rotation_angle()); + + dev->ConfigureReadMock(mock_kernel_queue_move2, 2, 0); + dev->ReadNow(); + EXPECT_EQ(3u, dev->size()); + event = dev->event(2); + EXPECT_FALSE(event == NULL); + + EXPECT_EQ(ui::ET_TOUCH_MOVED, event->type()); + EXPECT_EQ(base::TimeDelta::FromMicroseconds(0), event->time_stamp()); + EXPECT_EQ(42, event->x()); + EXPECT_EQ(42, event->y()); + EXPECT_EQ(0, event->touch_id()); + EXPECT_FLOAT_EQ(2.f / 3.f, event->force()); + EXPECT_FLOAT_EQ(0.f, event->rotation_angle()); +} + +TEST_F(TouchEventConverterEvdevTest, TouchRelease) { + ui::MockTouchEventConverterEvdev* dev = device(); + + struct input_event mock_kernel_queue_press[] = { + {{0, 0}, EV_ABS, ABS_MT_TRACKING_ID, 684}, + {{0, 0}, EV_ABS, ABS_MT_TOUCH_MAJOR, 3}, + {{0, 0}, EV_ABS, ABS_MT_PRESSURE, 45}, + {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 42}, + {{0, 0}, EV_ABS, ABS_MT_POSITION_Y, 51}, {{0, 0}, EV_SYN, SYN_REPORT, 0} + }; + + struct input_event mock_kernel_queue_release[] = { + {{0, 0}, EV_ABS, ABS_MT_TRACKING_ID, -1}, {{0, 0}, EV_SYN, SYN_REPORT, 0} + }; + + // Setup and discard a press. + dev->ConfigureReadMock(mock_kernel_queue_press, 6, 0); + dev->ReadNow(); + EXPECT_EQ(1u, dev->size()); + ui::TouchEvent* event = dev->event(0); + EXPECT_FALSE(event == NULL); + + dev->ConfigureReadMock(mock_kernel_queue_release, 2, 0); + dev->ReadNow(); + EXPECT_EQ(2u, dev->size()); + event = dev->event(1); + EXPECT_FALSE(event == NULL); + + EXPECT_EQ(ui::ET_TOUCH_RELEASED, event->type()); + EXPECT_EQ(base::TimeDelta::FromMicroseconds(0), event->time_stamp()); + EXPECT_EQ(42, event->x()); + EXPECT_EQ(51, event->y()); + EXPECT_EQ(0, event->touch_id()); + EXPECT_FLOAT_EQ(.5f, event->force()); + EXPECT_FLOAT_EQ(0.f, event->rotation_angle()); +} + +TEST_F(TouchEventConverterEvdevTest, TwoFingerGesture) { + ui::MockTouchEventConverterEvdev* dev = device(); + + ui::TouchEvent* ev0; + ui::TouchEvent* ev1; + + struct input_event mock_kernel_queue_press0[] = { + {{0, 0}, EV_ABS, ABS_MT_TRACKING_ID, 684}, + {{0, 0}, EV_ABS, ABS_MT_TOUCH_MAJOR, 3}, + {{0, 0}, EV_ABS, ABS_MT_PRESSURE, 45}, + {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 42}, + {{0, 0}, EV_ABS, ABS_MT_POSITION_Y, 51}, {{0, 0}, EV_SYN, SYN_REPORT, 0} + }; + // Setup and discard a press. + dev->ConfigureReadMock(mock_kernel_queue_press0, 6, 0); + dev->ReadNow(); + EXPECT_EQ(1u, dev->size()); + + struct input_event mock_kernel_queue_move0[] = { + {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 40}, {{0, 0}, EV_SYN, SYN_REPORT, 0} + }; + // Setup and discard a move. + dev->ConfigureReadMock(mock_kernel_queue_move0, 2, 0); + dev->ReadNow(); + EXPECT_EQ(2u, dev->size()); + + struct input_event mock_kernel_queue_move0press1[] = { + {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 40}, {{0, 0}, EV_SYN, SYN_REPORT, 0}, + {{0, 0}, EV_ABS, ABS_MT_SLOT, 1}, {{0, 0}, EV_ABS, ABS_MT_TRACKING_ID, 686}, + {{0, 0}, EV_ABS, ABS_MT_TOUCH_MAJOR, 3}, + {{0, 0}, EV_ABS, ABS_MT_PRESSURE, 45}, + {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 101}, + {{0, 0}, EV_ABS, ABS_MT_POSITION_Y, 102}, {{0, 0}, EV_SYN, SYN_REPORT, 0} + }; + // Move on 0, press on 1. + dev->ConfigureReadMock(mock_kernel_queue_move0press1, 9, 0); + dev->ReadNow(); + EXPECT_EQ(4u, dev->size()); + ev0 = dev->event(2); + ev1 = dev->event(3); + + // Move + EXPECT_EQ(ui::ET_TOUCH_MOVED, ev0->type()); + EXPECT_EQ(base::TimeDelta::FromMicroseconds(0), ev0->time_stamp()); + EXPECT_EQ(40, ev0->x()); + EXPECT_EQ(51, ev0->y()); + EXPECT_EQ(0, ev0->touch_id()); + EXPECT_FLOAT_EQ(.5f, ev0->force()); + EXPECT_FLOAT_EQ(0.f, ev0->rotation_angle()); + + // Press + EXPECT_EQ(ui::ET_TOUCH_PRESSED, ev1->type()); + EXPECT_EQ(base::TimeDelta::FromMicroseconds(0), ev1->time_stamp()); + EXPECT_EQ(101, ev1->x()); + EXPECT_EQ(102, ev1->y()); + EXPECT_EQ(1, ev1->touch_id()); + EXPECT_FLOAT_EQ(.5f, ev1->force()); + EXPECT_FLOAT_EQ(0.f, ev1->rotation_angle()); + + // Stationary 0, Moves 1. + struct input_event mock_kernel_queue_stationary0_move1[] = { + {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 40}, {{0, 0}, EV_SYN, SYN_REPORT, 0} + }; + dev->ConfigureReadMock(mock_kernel_queue_stationary0_move1, 2, 0); + dev->ReadNow(); + EXPECT_EQ(5u, dev->size()); + ev1 = dev->event(4); + + EXPECT_EQ(ui::ET_TOUCH_MOVED, ev1->type()); + EXPECT_EQ(base::TimeDelta::FromMicroseconds(0), ev1->time_stamp()); + EXPECT_EQ(40, ev1->x()); + EXPECT_EQ(102, ev1->y()); + EXPECT_EQ(1, ev1->touch_id()); + + EXPECT_FLOAT_EQ(.5f, ev1->force()); + EXPECT_FLOAT_EQ(0.f, ev1->rotation_angle()); + + // Move 0, stationary 1. + struct input_event mock_kernel_queue_move0_stationary1[] = { + {{0, 0}, EV_ABS, ABS_MT_SLOT, 0}, {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 39}, + {{0, 0}, EV_SYN, SYN_REPORT, 0} + }; + dev->ConfigureReadMock(mock_kernel_queue_move0_stationary1, 3, 0); + dev->ReadNow(); + EXPECT_EQ(6u, dev->size()); + ev0 = dev->event(5); + + EXPECT_EQ(ui::ET_TOUCH_MOVED, ev0->type()); + EXPECT_EQ(base::TimeDelta::FromMicroseconds(0), ev0->time_stamp()); + EXPECT_EQ(39, ev0->x()); + EXPECT_EQ(51, ev0->y()); + EXPECT_EQ(0, ev0->touch_id()); + EXPECT_FLOAT_EQ(.5f, ev0->force()); + EXPECT_FLOAT_EQ(0.f, ev0->rotation_angle()); + + // Release 0, move 1. + struct input_event mock_kernel_queue_release0_move1[] = { + {{0, 0}, EV_ABS, ABS_MT_TRACKING_ID, -1}, {{0, 0}, EV_ABS, ABS_MT_SLOT, 1}, + {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 38}, {{0, 0}, EV_SYN, SYN_REPORT, 0} + }; + dev->ConfigureReadMock(mock_kernel_queue_release0_move1, 4, 0); + dev->ReadNow(); + EXPECT_EQ(8u, dev->size()); + ev0 = dev->event(6); + ev1 = dev->event(7); + + EXPECT_EQ(ui::ET_TOUCH_RELEASED, ev0->type()); + EXPECT_EQ(base::TimeDelta::FromMicroseconds(0), ev0->time_stamp()); + EXPECT_EQ(39, ev0->x()); + EXPECT_EQ(51, ev0->y()); + EXPECT_EQ(0, ev0->touch_id()); + EXPECT_FLOAT_EQ(.5f, ev0->force()); + EXPECT_FLOAT_EQ(0.f, ev0->rotation_angle()); + + EXPECT_EQ(ui::ET_TOUCH_MOVED, ev1->type()); + EXPECT_EQ(base::TimeDelta::FromMicroseconds(0), ev1->time_stamp()); + EXPECT_EQ(38, ev1->x()); + EXPECT_EQ(102, ev1->y()); + EXPECT_EQ(1, ev1->touch_id()); + EXPECT_FLOAT_EQ(.5f, ev1->force()); + EXPECT_FLOAT_EQ(0.f, ev1->rotation_angle()); + + // Release 1. + struct input_event mock_kernel_queue_release1[] = { + {{0, 0}, EV_ABS, ABS_MT_TRACKING_ID, -1}, {{0, 0}, EV_SYN, SYN_REPORT, 0}, + }; + dev->ConfigureReadMock(mock_kernel_queue_release1, 2, 0); + dev->ReadNow(); + EXPECT_EQ(9u, dev->size()); + ev1 = dev->event(8); + + EXPECT_EQ(ui::ET_TOUCH_RELEASED, ev1->type()); + EXPECT_EQ(base::TimeDelta::FromMicroseconds(0), ev1->time_stamp()); + EXPECT_EQ(38, ev1->x()); + EXPECT_EQ(102, ev1->y()); + EXPECT_EQ(1, ev1->touch_id()); + EXPECT_FLOAT_EQ(.5f, ev1->force()); + EXPECT_FLOAT_EQ(0.f, ev1->rotation_angle()); +} + +TEST_F(TouchEventConverterEvdevTest, TypeA) { + ui::MockTouchEventConverterEvdev* dev = device(); + + struct input_event mock_kernel_queue_press0[] = { + {{0, 0}, EV_ABS, ABS_MT_TOUCH_MAJOR, 3}, + {{0, 0}, EV_ABS, ABS_MT_PRESSURE, 45}, + {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 42}, + {{0, 0}, EV_ABS, ABS_MT_POSITION_Y, 51}, + {{0, 0}, EV_SYN, SYN_MT_REPORT, 0}, + {{0, 0}, EV_ABS, ABS_MT_PRESSURE, 45}, + {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 61}, + {{0, 0}, EV_ABS, ABS_MT_POSITION_Y, 71}, + {{0, 0}, EV_SYN, SYN_MT_REPORT, 0}, + {{0, 0}, EV_SYN, SYN_REPORT, 0} + }; + + // Check that two events are generated. + dev->ConfigureReadMock(mock_kernel_queue_press0, 10, 0); + dev->ReadNow(); + EXPECT_EQ(2u, dev->size()); +} + +TEST_F(TouchEventConverterEvdevTest, Unsync) { + ui::MockTouchEventConverterEvdev* dev = device(); + + struct input_event mock_kernel_queue_press0[] = { + {{0, 0}, EV_ABS, ABS_MT_TRACKING_ID, 684}, + {{0, 0}, EV_ABS, ABS_MT_TOUCH_MAJOR, 3}, + {{0, 0}, EV_ABS, ABS_MT_PRESSURE, 45}, + {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 42}, + {{0, 0}, EV_ABS, ABS_MT_POSITION_Y, 51}, {{0, 0}, EV_SYN, SYN_REPORT, 0} + }; + + dev->ConfigureReadMock(mock_kernel_queue_press0, 6, 0); + dev->ReadNow(); + EXPECT_EQ(1u, dev->size()); + + // Prepare a move with a drop. + struct input_event mock_kernel_queue_move0[] = { + {{0, 0}, EV_SYN, SYN_DROPPED, 0}, + {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 40}, {{0, 0}, EV_SYN, SYN_REPORT, 0} + }; + + // Verify that we didn't receive it/ + dev->ConfigureReadMock(mock_kernel_queue_move0, 3, 0); + dev->ReadNow(); + EXPECT_EQ(1u, dev->size()); + + struct input_event mock_kernel_queue_move1[] = { + {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 40}, {{0, 0}, EV_SYN, SYN_REPORT, 0} + }; + + // Verify that it re-syncs after a SYN_REPORT. + dev->ConfigureReadMock(mock_kernel_queue_move1, 2, 0); + dev->ReadNow(); + EXPECT_EQ(2u, dev->size()); +} |