Commit de2de99a authored by skuhne's avatar skuhne Committed by Commit bot

Revert of Port Chromium OS touch noise filtering to Chromium (patchset #8...

Revert of Port Chromium OS touch noise filtering to Chromium (patchset #8 id:410001 of https://codereview.chromium.org/991533002/)

Reason for revert:
This patch breaks the PFQ for 32/64 bit due to some string conversion problems:

0.2346.0_rc-r1: ../../../../../../../home/chrome-bot/chrome_root/src/ui/events/ozone/evdev/touch_noise/single_position_touch_noise_filter.cc:100:63: error: format '%ld' expects argument of type 'long int', but argument 3 has type 'int64 {aka long long int}' [-Werror=format=] chromeos-chrome-43.0.2346.0_rc-r1: touch.tracking_id, max_duration.InMilliseconds());
should I revert this - or do you want to land a patch for it?
Oh - there is also another one:
0.2346.0_rc-r1: ../../../../../../../home/chrome-bot/chrome_root/src/ui/events/ozone/evdev/touch_noise/horizontally_aligned_touch_noise_filter.cc: In member function 'virtual void ui::HorizontallyAlignedTouchNoiseFilter::Filter(const std::vector<ui::InProgressTouchEvdev>&, base::TimeDelta, std::bitset<20u>*)': chromeos-chrome-43.0.2346.0_rc-r1: ../../../../../../../home/chrome-bot/chrome_root/src/ui/events/ozone/evdev/touch_noise/horizontally_aligned_touch_noise_filter.cc:39:66: error: format '%ld' expects argument of type 'long int', but argument 3 has type 'int64 {aka long long int}' [-Werror=format=] chromeos-chrome-43.0.2346.0_rc-r1: other_touch.tracking_id, other_touch.x, other_touch.y);

Original issue's description:
> Port Chromium OS touch noise filtering to Chromium. The Chromium OS
> touch noise filtering is at
> https://chromium.googlesource.com/chromiumos/platform/touch_noise_filter/+/master
>
> When a touch is detected as touch noise, an ET_TOUCH_CANCELLED event is sent and
> all of the subsequent events for that touch are dropped. A "touch press"
> initiates a new touch.
>
> BUG=407840
> TEST=TouchNoiseFinderTest.*, TouchEventConverterEvdevTouchNoiseTest.*
>
> Committed: https://crrev.com/1df4aa125090c601b1a18c4354b8ca9323cb4c79
> Cr-Commit-Position: refs/heads/master@{#322293}

TBR=flackr@chromium.org,spang@chromium.org,pkotwicz@google.com,sadrul@chromium.org,pkotwicz@chromium.org
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=407840

Review URL: https://codereview.chromium.org/1033933004

Cr-Commit-Position: refs/heads/master@{#322415}
parent d1421a5f
......@@ -338,7 +338,6 @@ test("events_unittests") {
"ozone/evdev/input_injector_evdev_unittest.cc",
"ozone/evdev/tablet_event_converter_evdev_unittest.cc",
"ozone/evdev/touch_event_converter_evdev_unittest.cc",
"ozone/evdev/touch_noise/touch_noise_finder_unittest.cc",
"ozone/layout/xkb/xkb_keyboard_layout_engine_unittest.cc",
]
deps += [
......
......@@ -35,10 +35,6 @@ const char kTouchDevices[] = "touch-devices";
#endif
#if defined(USE_X11) || defined(USE_OZONE)
// Tells Chrome to do additional touch noise filtering. Should only be used if
// the driver level filtering is insufficient.
const char kExtraTouchNoiseFiltering[] = "touch-noise-filtering";
// The calibration factors given as "<left>,<right>,<top>,<bottom>".
const char kTouchCalibration[] = "touch-calibration";
#endif
......
......@@ -22,7 +22,6 @@ EVENTS_BASE_EXPORT extern const char kTouchDevices[];
#endif
#if defined(USE_X11) || defined(USE_OZONE)
EVENTS_BASE_EXPORT extern const char kExtraTouchNoiseFiltering[];
EVENTS_BASE_EXPORT extern const char kTouchCalibration[];
#endif
......
......@@ -362,7 +362,6 @@
'ozone/evdev/input_injector_evdev_unittest.cc',
'ozone/evdev/tablet_event_converter_evdev_unittest.cc',
'ozone/evdev/touch_event_converter_evdev_unittest.cc',
'ozone/evdev/touch_noise/touch_noise_finder_unittest.cc',
],
'dependencies': [
'ozone/events_ozone.gyp:events_ozone',
......
// Copyright 2015 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 "ui/events/ozone/evdev/touch_evdev_types.h"
namespace ui {
InProgressTouchEvdev::InProgressTouchEvdev()
: altered(false),
cancelled(false),
was_touching(false),
touching(false),
x(0),
y(0),
tracking_id(-1),
slot(0),
radius_x(0),
radius_y(0),
pressure(0) {
}
InProgressTouchEvdev::~InProgressTouchEvdev() {}
} // namespace ui
// Copyright 2015 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 UI_EVENTS_OZONE_EVDEV_TOUCH_EVDEV_TYPES_H_
#define UI_EVENTS_OZONE_EVDEV_TOUCH_EVDEV_TYPES_H_
#include "base/basictypes.h"
#include "ui/events/event_constants.h"
#include "ui/events/ozone/evdev/events_ozone_evdev_export.h"
namespace ui {
// Number of supported touch slots. ABS_MT_SLOT messages with
// value >= kNumTouchEvdevSlots are ignored.
const int kNumTouchEvdevSlots = 20;
// Contains information about an in progress touch.
struct EVENTS_OZONE_EVDEV_EXPORT InProgressTouchEvdev {
InProgressTouchEvdev();
~InProgressTouchEvdev();
// Whether there is new information for the touch.
bool altered;
// Whether the touch was cancelled. Touch events should be ignored till a
// new touch is initiated.
bool cancelled;
bool was_touching;
bool touching;
float x;
float y;
int tracking_id;
size_t slot;
float radius_x;
float radius_y;
float pressure;
};
} // namespace ui
#endif // UI_EVENTS_OZONE_EVDEV_TOUCH_EVDEV_TYPES_H_
......@@ -29,8 +29,6 @@
#include "ui/events/event_constants.h"
#include "ui/events/event_switches.h"
#include "ui/events/ozone/evdev/device_event_dispatcher_evdev.h"
#include "ui/events/ozone/evdev/touch_evdev_types.h"
#include "ui/events/ozone/evdev/touch_noise/touch_noise_finder.h"
namespace {
......@@ -61,6 +59,18 @@ void GetTouchCalibration(TouchCalibration* cal) {
namespace ui {
TouchEventConverterEvdev::InProgressEvents::InProgressEvents()
: altered_(false),
x_(0),
y_(0),
id_(-1),
finger_(-1),
type_(ET_UNKNOWN),
radius_x_(0),
radius_y_(0),
pressure_(0) {
}
TouchEventConverterEvdev::TouchEventConverterEvdev(
int fd,
base::FilePath path,
......@@ -70,12 +80,9 @@ TouchEventConverterEvdev::TouchEventConverterEvdev(
: EventConverterEvdev(fd, path, id, type),
dispatcher_(dispatcher),
syn_dropped_(false),
is_type_a_(false),
touch_points_(0),
current_slot_(0) {
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kExtraTouchNoiseFiltering)) {
touch_noise_finder_.reset(new TouchNoiseFinder);
}
}
TouchEventConverterEvdev::~TouchEventConverterEvdev() {
......@@ -91,7 +98,7 @@ void TouchEventConverterEvdev::Initialize(const EventDeviceInfo& info) {
y_min_tuxels_ = info.GetAbsMinimum(ABS_MT_POSITION_Y);
y_num_tuxels_ = info.GetAbsMaximum(ABS_MT_POSITION_Y) - y_min_tuxels_ + 1;
touch_points_ =
std::min<int>(info.GetAbsMaximum(ABS_MT_SLOT) + 1, kNumTouchEvdevSlots);
std::min<int>(info.GetAbsMaximum(ABS_MT_SLOT) + 1, MAX_FINGERS);
// Apply --touch-calibration.
if (type() == INPUT_DEVICE_INTERNAL) {
......@@ -110,14 +117,14 @@ void TouchEventConverterEvdev::Initialize(const EventDeviceInfo& info) {
events_.resize(touch_points_);
for (size_t i = 0; i < events_.size(); ++i) {
events_[i].x = info.GetSlotValue(ABS_MT_POSITION_X, i);
events_[i].y = info.GetSlotValue(ABS_MT_POSITION_Y, i);
events_[i].tracking_id = info.GetSlotValue(ABS_MT_TRACKING_ID, i);
events_[i].touching = (events_[i].tracking_id >= 0);
events_[i].slot = i;
events_[i].radius_x = info.GetSlotValue(ABS_MT_TOUCH_MAJOR, i);
events_[i].radius_y = info.GetSlotValue(ABS_MT_TOUCH_MINOR, i);
events_[i].pressure = info.GetSlotValue(ABS_MT_PRESSURE, i);
events_[i].finger_ = info.GetSlotValue(ABS_MT_TRACKING_ID, i);
events_[i].type_ =
events_[i].finger_ < 0 ? ET_TOUCH_RELEASED : ET_TOUCH_PRESSED;
events_[i].x_ = info.GetSlotValue(ABS_MT_POSITION_X, i);
events_[i].y_ = info.GetSlotValue(ABS_MT_POSITION_Y, i);
events_[i].radius_x_ = info.GetSlotValue(ABS_MT_TOUCH_MAJOR, i);
events_[i].radius_y_ = info.GetSlotValue(ABS_MT_TOUCH_MINOR, i);
events_[i].pressure_ = info.GetSlotValue(ABS_MT_PRESSURE, i);
}
}
......@@ -143,7 +150,7 @@ int TouchEventConverterEvdev::GetTouchPoints() const {
}
void TouchEventConverterEvdev::OnFileCanReadWithoutBlocking(int fd) {
input_event inputs[kNumTouchEvdevSlots * 6 + 1];
input_event inputs[MAX_FINGERS * 6 + 1];
ssize_t read_size = read(fd, inputs, sizeof(inputs));
if (read_size < 0) {
if (errno == EINTR || errno == EAGAIN)
......@@ -165,7 +172,7 @@ void TouchEventConverterEvdev::OnFileCanReadWithoutBlocking(int fd) {
void TouchEventConverterEvdev::ProcessInputEvent(const input_event& input) {
if (input.type == EV_SYN) {
ProcessSyn(input);
} else if (syn_dropped_) {
} else if(syn_dropped_) {
// Do nothing. This branch indicates we have lost sync with the driver.
} else if (input.type == EV_ABS) {
if (events_.size() <= current_slot_) {
......@@ -192,29 +199,28 @@ void TouchEventConverterEvdev::ProcessAbs(const input_event& input) {
// TODO(spang): If we have all of major, minor, and orientation,
// we can scale the ellipse correctly. However on the Pixel we get
// neither minor nor orientation, so this is all we can do.
events_[current_slot_].radius_x = input.value / 2.0f;
events_[current_slot_].radius_x_ = input.value / 2.0f;
break;
case ABS_MT_TOUCH_MINOR:
events_[current_slot_].radius_y = input.value / 2.0f;
events_[current_slot_].radius_y_ = input.value / 2.0f;
break;
case ABS_MT_POSITION_X:
events_[current_slot_].x = input.value;
events_[current_slot_].x_ = input.value;
break;
case ABS_MT_POSITION_Y:
events_[current_slot_].y = input.value;
events_[current_slot_].y_ = input.value;
break;
case ABS_MT_TRACKING_ID:
if (input.value < 0) {
events_[current_slot_].touching = false;
events_[current_slot_].type_ = ET_TOUCH_RELEASED;
} else {
events_[current_slot_].touching = true;
events_[current_slot_].cancelled = false;
events_[current_slot_].finger_ = input.value;
events_[current_slot_].type_ = ET_TOUCH_PRESSED;
}
events_[current_slot_].tracking_id = input.value;
break;
case ABS_MT_PRESSURE:
events_[current_slot_].pressure = input.value - pressure_min_;
events_[current_slot_].pressure /= pressure_max_ - pressure_min_;
events_[current_slot_].pressure_ = input.value - pressure_min_;
events_[current_slot_].pressure_ /= pressure_max_ - pressure_min_;
break;
case ABS_MT_SLOT:
if (input.value >= 0 &&
......@@ -229,7 +235,7 @@ void TouchEventConverterEvdev::ProcessAbs(const input_event& input) {
DVLOG(5) << "unhandled code for EV_ABS: " << input.code;
return;
}
events_[current_slot_].altered = true;
events_[current_slot_].altered_ = true;
}
void TouchEventConverterEvdev::ProcessSyn(const input_event& input) {
......@@ -239,14 +245,24 @@ void TouchEventConverterEvdev::ProcessSyn(const input_event& input) {
// Have to re-initialize.
if (Reinitialize()) {
syn_dropped_ = false;
for(InProgressTouchEvdev& event : events_)
event.altered = false;
for(InProgressEvents& event: events_)
event.altered_ = false;
} else {
LOG(ERROR) << "failed to re-initialize device info";
}
} else {
ReportEvents(EventConverterEvdev::TimeDeltaFromInputEvent(input));
}
if (is_type_a_)
current_slot_ = 0;
break;
case SYN_MT_REPORT:
// For type A devices, we just get a stream of all current contacts,
// in some arbitrary order.
events_[current_slot_].type_ = ET_TOUCH_PRESSED;
if (events_.size() - 1 > current_slot_)
current_slot_++;
is_type_a_ = true;
break;
case SYN_DROPPED:
// Some buffer has overrun. We ignore all events up to and
......@@ -258,49 +274,25 @@ void TouchEventConverterEvdev::ProcessSyn(const input_event& input) {
}
}
EventType TouchEventConverterEvdev::GetEventTypeForTouch(
const InProgressTouchEvdev& touch) {
if (touch.cancelled)
return ET_UNKNOWN;
if (touch_noise_finder_ && touch_noise_finder_->SlotHasNoise(touch.slot)) {
if (touch.touching && !touch.was_touching)
return ET_UNKNOWN;
return ET_TOUCH_CANCELLED;
}
if (touch.touching)
return touch.was_touching ? ET_TOUCH_MOVED : ET_TOUCH_PRESSED;
return touch.was_touching ? ET_TOUCH_RELEASED : ET_UNKNOWN;
}
void TouchEventConverterEvdev::ReportEvent(const InProgressTouchEvdev& event,
EventType event_type,
void TouchEventConverterEvdev::ReportEvent(int touch_id,
const InProgressEvents& event,
const base::TimeDelta& timestamp) {
dispatcher_->DispatchTouchEvent(TouchEventParams(
id_, event.slot, event_type, gfx::PointF(event.x, event.y),
gfx::Vector2dF(event.radius_x, event.radius_y), event.pressure,
id_, touch_id, event.type_, gfx::PointF(event.x_, event.y_),
gfx::Vector2dF(event.radius_x_, event.radius_y_), event.pressure_,
timestamp));
}
void TouchEventConverterEvdev::ReportEvents(base::TimeDelta delta) {
if (touch_noise_finder_)
touch_noise_finder_->HandleTouches(events_, delta);
for (size_t i = 0; i < events_.size(); i++) {
InProgressTouchEvdev* event = &events_[i];
if (!event->altered)
continue;
if (events_[i].altered_) {
ReportEvent(i, events_[i], delta);
EventType event_type = GetEventTypeForTouch(*event);
if (event_type == ET_UNKNOWN || event_type == ET_TOUCH_CANCELLED)
event->cancelled = true;
if (event_type != ET_UNKNOWN)
ReportEvent(*event, event_type, delta);
event->was_touching = event->touching;
event->altered = false;
// Subsequent events for this finger will be touch-move until it
// is released.
events_[i].type_ = ET_TOUCH_MOVED;
events_[i].altered_ = false;
}
}
}
......
......@@ -9,7 +9,6 @@
#include "base/compiler_specific.h"
#include "base/files/file_path.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_pump_libevent.h"
#include "ui/events/event_constants.h"
#include "ui/events/ozone/evdev/event_converter_evdev.h"
......@@ -18,14 +17,14 @@
namespace ui {
class DeviceEventDispatcherEvdev;
class TouchEvent;
class TouchNoiseFinder;
struct InProgressTouchEvdev;
class DeviceEventDispatcherEvdev;
class EVENTS_OZONE_EVDEV_EXPORT TouchEventConverterEvdev
: public EventConverterEvdev {
public:
enum { MAX_FINGERS = 20 };
TouchEventConverterEvdev(int fd,
base::FilePath path,
int id,
......@@ -44,6 +43,21 @@ class EVENTS_OZONE_EVDEV_EXPORT TouchEventConverterEvdev
private:
friend class MockTouchEventConverterEvdev;
struct InProgressEvents {
InProgressEvents();
bool altered_;
float x_;
float y_;
int id_; // Device reported "unique" touch point id; -1 means not active
int finger_; // "Finger" id starting from 0; -1 means not active
EventType type_;
float radius_x_;
float radius_y_;
float pressure_;
};
// Overidden from base::MessagePumpLibevent::Watcher.
void OnFileCanReadWithoutBlocking(int fd) override;
......@@ -53,13 +67,8 @@ class EVENTS_OZONE_EVDEV_EXPORT TouchEventConverterEvdev
void ProcessAbs(const input_event& input);
void ProcessSyn(const input_event& input);
// Returns an EventType to dispatch for |touch|. Returns ET_UNKNOWN if an
// event should not be dispatched.
EventType GetEventTypeForTouch(const InProgressTouchEvdev& touch);
void ReportEvent(const InProgressTouchEvdev& event,
EventType event_type,
const base::TimeDelta& delta);
void ReportEvent(int touch_id,
const InProgressEvents& event, const base::TimeDelta& delta);
void ReportEvents(base::TimeDelta delta);
// Dispatcher for events.
......@@ -68,6 +77,9 @@ class EVENTS_OZONE_EVDEV_EXPORT TouchEventConverterEvdev
// Set if we have seen a SYN_DROPPED and not yet re-synced with the device.
bool syn_dropped_;
// Set if this is a type A device (uses SYN_MT_REPORT).
bool is_type_a_;
// Pressure values.
int pressure_min_;
int pressure_max_; // Used to normalize pressure values.
......@@ -87,10 +99,7 @@ class EVENTS_OZONE_EVDEV_EXPORT TouchEventConverterEvdev
size_t current_slot_;
// In-progress touch points.
std::vector<InProgressTouchEvdev> events_;
// Finds touch noise.
scoped_ptr<TouchNoiseFinder> touch_noise_finder_;
std::vector<InProgressEvents> events_;
DISALLOW_COPY_AND_ASSIGN(TouchEventConverterEvdev);
};
......
......@@ -10,7 +10,6 @@
#include <vector>
#include "base/bind.h"
#include "base/command_line.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/scoped_vector.h"
#include "base/posix/eintr_wrapper.h"
......@@ -18,17 +17,11 @@
#include "base/time/time.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/devices/device_data_manager.h"
#include "ui/events/event_switches.h"
#include "ui/events/ozone/evdev/device_event_dispatcher_evdev.h"
#include "ui/events/ozone/evdev/touch_evdev_types.h"
#include "ui/events/ozone/evdev/touch_event_converter_evdev.h"
#include "ui/events/ozone/evdev/touch_noise/touch_noise_filter.h"
#include "ui/events/ozone/evdev/touch_noise/touch_noise_finder.h"
#include "ui/events/platform/platform_event_dispatcher.h"
#include "ui/events/platform/platform_event_source.h"
namespace ui {
namespace {
static int SetNonBlocking(int fd) {
......@@ -42,6 +35,8 @@ const char kTestDevicePath[] = "/dev/input/test-device";
} // namespace
namespace ui {
class MockTouchEventConverterEvdev : public TouchEventConverterEvdev {
public:
MockTouchEventConverterEvdev(int fd,
......@@ -62,8 +57,6 @@ class MockTouchEventConverterEvdev : public TouchEventConverterEvdev {
void Initialize(const EventDeviceInfo& device_info) override {}
bool Reinitialize() override { return true; }
TouchNoiseFinder* touch_noise_finder() { return touch_noise_finder_.get(); }
private:
int read_pipe_;
int write_pipe_;
......@@ -127,9 +120,7 @@ MockTouchEventConverterEvdev::MockTouchEventConverterEvdev(
read_pipe_ = fds[0];
write_pipe_ = fds[1];
events_.resize(ui::kNumTouchEvdevSlots);
for (size_t i = 0; i < events_.size(); ++i)
events_[i].slot = i;
events_.resize(MAX_FINGERS);
}
void MockTouchEventConverterEvdev::ConfigureReadMock(struct input_event* queue,
......@@ -143,6 +134,8 @@ void MockTouchEventConverterEvdev::ConfigureReadMock(struct input_event* queue,
<< "write() failed, errno: " << errno;
}
} // namespace ui
// Test fixture.
class TouchEventConverterEvdevTest : public testing::Test {
public:
......@@ -183,10 +176,6 @@ class TouchEventConverterEvdevTest : public testing::Test {
return dispatched_events_[index];
}
void ClearDispatchedEvents() {
dispatched_events_.clear();
}
private:
base::MessageLoop* loop_;
ui::MockTouchEventConverterEvdev* device_;
......@@ -459,6 +448,28 @@ TEST_F(TouchEventConverterEvdevTest, TwoFingerGesture) {
EXPECT_FLOAT_EQ(.5f, ev1.pressure);
}
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, size());
}
TEST_F(TouchEventConverterEvdevTest, Unsync) {
ui::MockTouchEventConverterEvdev* dev = device();
......@@ -549,7 +560,7 @@ TEST_F(TouchEventConverterEvdevTest, CheckSlotLimit) {
{{0, 0}, EV_ABS, ABS_MT_TRACKING_ID, 100},
{{0, 0}, EV_ABS, ABS_MT_POSITION_X, 999},
{{0, 0}, EV_ABS, ABS_MT_POSITION_Y, 888},
{{0, 0}, EV_ABS, ABS_MT_SLOT, ui::kNumTouchEvdevSlots},
{{0, 0}, EV_ABS, ABS_MT_SLOT, ui::TouchEventConverterEvdev::MAX_FINGERS},
{{0, 0}, EV_ABS, ABS_MT_TRACKING_ID, 200},
{{0, 0}, EV_ABS, ABS_MT_POSITION_X, 777},
{{0, 0}, EV_ABS, ABS_MT_POSITION_Y, 666},
......@@ -561,170 +572,3 @@ TEST_F(TouchEventConverterEvdevTest, CheckSlotLimit) {
dev->ReadNow();
EXPECT_EQ(1u, size());
}
namespace {
// TouchNoiseFilter which:
// - Considers all events of type |noise_event_type| as noise.
// - Keeps track of the events that it receives.
class EventTypeTouchNoiseFilter : public TouchNoiseFilter {
public:
explicit EventTypeTouchNoiseFilter(EventType noise_event_type)
: noise_event_type_(noise_event_type) {}
~EventTypeTouchNoiseFilter() override {}
// TouchNoiseFilter:
void Filter(const std::vector<InProgressTouchEvdev>& touches,
base::TimeDelta time,
std::bitset<kNumTouchEvdevSlots>* slots_with_noise) override {
for (const InProgressTouchEvdev& touch : touches) {
EventType event_type = EventTypeFromTouch(touch);
++counts_[event_type];
if (event_type == noise_event_type_)
slots_with_noise->set(touch.slot);
}
}
// Returns the number of received events of |type|.
size_t num_events(EventType type) const {
std::map<EventType, size_t>::const_iterator it = counts_.find(type);
return it == counts_.end() ? 0u : it->second;
}
private:
EventType EventTypeFromTouch(const InProgressTouchEvdev& touch) const {
if (touch.touching)
return touch.was_touching ? ET_TOUCH_MOVED : ET_TOUCH_PRESSED;
return touch.was_touching ? ET_TOUCH_RELEASED : ET_UNKNOWN;
}
EventType noise_event_type_;
std::map<EventType, size_t> counts_;
DISALLOW_COPY_AND_ASSIGN(EventTypeTouchNoiseFilter);
};
} // namespace
class TouchEventConverterEvdevTouchNoiseTest
: public TouchEventConverterEvdevTest {
public:
TouchEventConverterEvdevTouchNoiseTest() {}
~TouchEventConverterEvdevTouchNoiseTest() override {}
// Makes the TouchNoiseFinder use |filter| and only |filter| to filter out
// touch noise.
void SetTouchNoiseFilter(scoped_ptr<TouchNoiseFilter> filter) {
TouchNoiseFinder* finder = device()->touch_noise_finder();
finder->filters_.clear();
finder->filters_.push_back(filter.release());
}
// Returns the first of TouchNoiseFinder's filters.
ui::TouchNoiseFilter* first_filter() {
TouchNoiseFinder* finder = device()->touch_noise_finder();
return finder->filters_.empty() ? nullptr : *finder->filters_.begin();
}
// TouchEventConverterEvdevTest:
void SetUp() override {
base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kExtraTouchNoiseFiltering);
TouchEventConverterEvdevTest::SetUp();
}
private:
DISALLOW_COPY_AND_ASSIGN(TouchEventConverterEvdevTouchNoiseTest);
};
// Test that if TouchNoiseFinder identifies an event for an in-progress touch as
// noise, that the event is converted to ET_TOUCH_CANCELLED and that all
// subsequent events for the in-progress touch are cancelled.
TEST_F(TouchEventConverterEvdevTouchNoiseTest, TouchNoiseFiltering) {
struct input_event mock_kernel_queue[] = {
{{0, 0}, EV_ABS, ABS_MT_TRACKING_ID, 684},
{{0, 0}, EV_ABS, ABS_MT_POSITION_X, 40},
{{0, 0}, EV_ABS, ABS_MT_POSITION_Y, 41},
{{0, 0}, EV_SYN, SYN_REPORT, 0},
{{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},
{{0, 0}, EV_ABS, ABS_MT_TRACKING_ID, -1},
{{0, 0}, EV_SYN, SYN_REPORT, 0}
};
MockTouchEventConverterEvdev* dev = device();
SetTouchNoiseFilter(scoped_ptr<TouchNoiseFilter>(
new EventTypeTouchNoiseFilter(ET_TOUCH_PRESSED)));
dev->ConfigureReadMock(mock_kernel_queue, arraysize(mock_kernel_queue), 0);
dev->ReadNow();
ASSERT_EQ(0u, size());
ClearDispatchedEvents();
SetTouchNoiseFilter(scoped_ptr<TouchNoiseFilter>(
new EventTypeTouchNoiseFilter(ET_TOUCH_MOVED)));
dev->ConfigureReadMock(mock_kernel_queue, arraysize(mock_kernel_queue), 0);
dev->ReadNow();
ASSERT_EQ(2u, size());
TouchEventParams event0 = dispatched_event(0);
EXPECT_EQ(ET_TOUCH_PRESSED, event0.type);
EXPECT_EQ(40, event0.location.x());
EXPECT_EQ(41, event0.location.y());
EXPECT_EQ(ET_TOUCH_CANCELLED, dispatched_event(1).type);
ClearDispatchedEvents();
SetTouchNoiseFilter(scoped_ptr<TouchNoiseFilter>(
new EventTypeTouchNoiseFilter(ET_TOUCH_RELEASED)));
dev->ConfigureReadMock(mock_kernel_queue, arraysize(mock_kernel_queue), 0);
dev->ReadNow();
ASSERT_EQ(3u, size());
event0 = dispatched_event(0);
EXPECT_EQ(ET_TOUCH_PRESSED, event0.type);
EXPECT_EQ(40, event0.location.x());
EXPECT_EQ(41, event0.location.y());
TouchEventParams event1 = dispatched_event(1);
EXPECT_EQ(ET_TOUCH_MOVED, event1.type);
EXPECT_EQ(42, event1.location.x());
EXPECT_EQ(43, event1.location.y());
EXPECT_EQ(ET_TOUCH_CANCELLED, dispatched_event(2).type);
}
// Test that TouchEventConverterEvdev keeps sending events to
// TouchNoiseFinder after the touch is canceled.
TEST_F(TouchEventConverterEvdevTouchNoiseTest,
DoNotSendTouchCancelsToTouchNoiseFinder) {
struct input_event mock_kernel_queue[] = {
{{0, 0}, EV_ABS, ABS_MT_TRACKING_ID, 684},
{{0, 0}, EV_ABS, ABS_MT_POSITION_X, 40},
{{0, 0}, EV_ABS, ABS_MT_POSITION_Y, 41},
{{0, 0}, EV_SYN, SYN_REPORT, 0},
{{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},
{{0, 0}, EV_ABS, ABS_MT_POSITION_X, 43},
{{0, 0}, EV_ABS, ABS_MT_POSITION_Y, 44},
{{0, 0}, EV_SYN, SYN_REPORT, 0},
{{0, 0}, EV_ABS, ABS_MT_TRACKING_ID, -1},
{{0, 0}, EV_SYN, SYN_REPORT, 0}
};
MockTouchEventConverterEvdev* dev = device();
SetTouchNoiseFilter(scoped_ptr<TouchNoiseFilter>(
new EventTypeTouchNoiseFilter(ET_TOUCH_PRESSED)));
dev->ConfigureReadMock(mock_kernel_queue, arraysize(mock_kernel_queue), 0);
dev->ReadNow();
ASSERT_EQ(0u, size());
EventTypeTouchNoiseFilter* filter =
static_cast<EventTypeTouchNoiseFilter*>(first_filter());
EXPECT_EQ(1u, filter->num_events(ET_TOUCH_PRESSED));
EXPECT_EQ(2u, filter->num_events(ET_TOUCH_MOVED));
EXPECT_EQ(1u, filter->num_events(ET_TOUCH_RELEASED));
}
} // namespace ui
// Copyright 2015 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 "ui/events/ozone/evdev/touch_noise/far_apart_taps_touch_noise_filter.h"
#include <cmath>
#include "base/logging.h"
#include "base/strings/stringprintf.h"
namespace ui {
namespace {
// Minimum squared distance between taps to be considered far apart.
const int kMinDistance2 = 1500 * 1500;
// Max time between taps considered.
const int kMaxTapDeltaMs = 30;
// Maximum squared movement of a touch to still be considered a tap.
const int kMaxTapMovement2 = 20 * 20;
// Returns the squared distance between (|x1|, |y1|) and (|x2|, |y2|).
int Distance2(int x1, int y1, int x2, int y2) {
int offset_x = x2 - x1;
int offset_y = y2 - y1;
return offset_x * offset_x + offset_y * offset_y;
}
} // namespace
void FarApartTapsTouchNoiseFilter::Filter(
const std::vector<InProgressTouchEvdev>& touches,
base::TimeDelta time,
std::bitset<kNumTouchEvdevSlots>* slots_with_noise) {
// Remove old taps.
base::TimeDelta tap_cutoff =
time - base::TimeDelta::FromMilliseconds(kMaxTapDeltaMs);
for (size_t i = 0; i < arraysize(tracked_taps_); ++i) {
if (tracked_taps_[i].start < tap_cutoff)
tracked_taps_[i].Invalidate();
}
for (const InProgressTouchEvdev& touch : touches) {
// Only look at slots with active touches.
if (!touch.touching && !touch.was_touching)
continue;
size_t slot = touch.slot;
if (!touch.was_touching) {
// Track new finger info.
tracked_taps_[slot] = Tap(time, touch.x, touch.y);
} else if (tracked_taps_[slot].is_valid()) {
// Check if this finger has moved too far to be considered a tap.
if (kMaxTapMovement2 < Distance2(touch.x, touch.y, tracked_taps_[slot].x,
tracked_taps_[slot].y)) {
tracked_taps_[slot].Invalidate();
}
}
if (tracked_taps_[slot].is_valid()) {
// Check distance from other tracked taps.
int min_distance2 = -1;
for (size_t i = 0; i < arraysize(tracked_taps_); ++i) {
if (i == slot || !tracked_taps_[i].is_valid())
continue;
int dist2 =
Distance2(tracked_taps_[i].x, tracked_taps_[i].y, touch.x, touch.y);
if (min_distance2 < 0 || dist2 < min_distance2)
min_distance2 = dist2;
}
if (min_distance2 > kMinDistance2) {
// The other finger should see this one on its next frame and also
// get canceled.
VLOG(2) << base::StringPrintf(
"Cancel tracking id %d %.0fpx from other current taps.",
touch.tracking_id, sqrt(min_distance2));
slots_with_noise->set(slot);
}
}
if (!touch.touching)
tracked_taps_[slot].Invalidate();
}
}
} // namespace ui
// Copyright 2015 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 UI_EVENTS_OZONE_EVDEV_TOUCH_NOISE_FAR_APART_TAPS_TOUCH_NOISE_FILTER_H_
#define UI_EVENTS_OZONE_EVDEV_TOUCH_NOISE_FAR_APART_TAPS_TOUCH_NOISE_FILTER_H_
#include "base/macros.h"
#include "base/time/time.h"
#include "ui/events/ozone/evdev/touch_noise/touch_noise_filter.h"
namespace ui {
class FarApartTapsTouchNoiseFilter : public TouchNoiseFilter {
public:
FarApartTapsTouchNoiseFilter() {}
~FarApartTapsTouchNoiseFilter() override {}
// TouchNoiseFilter:
void Filter(const std::vector<InProgressTouchEvdev>& touches,
base::TimeDelta time,
std::bitset<kNumTouchEvdevSlots>* slots_with_noise) override;
private:
struct Tap {
Tap() : x(0), y(0) {}
Tap(base::TimeDelta start, int x, int y)
: start(start), x(x), y(y) {}
bool is_valid() const { return start != base::TimeDelta(); }
void Invalidate() { start = base::TimeDelta(); }
base::TimeDelta start;
float x;
float y;
};
// Tracks in progress taps in slots.
Tap tracked_taps_[kNumTouchEvdevSlots];
DISALLOW_COPY_AND_ASSIGN(FarApartTapsTouchNoiseFilter);
};
} // namespace ui
#endif // UI_EVENTS_OZONE_EVDEV_TOUCH_NOISE_FAR_APART_TAPS_TOUCH_NOISE_FILTER_H_
// Copyright 2015 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 "ui/events/ozone/evdev/touch_noise/horizontally_aligned_touch_noise_filter.h"
#include <cmath>
#include "base/logging.h"
#include "base/strings/stringprintf.h"
namespace ui {
namespace {
// The maximum horizontal distance between touches considered aligned.
int kMaxDistance = 3;
} // namespace
void HorizontallyAlignedTouchNoiseFilter::Filter(
const std::vector<InProgressTouchEvdev>& touches,
base::TimeDelta time,
std::bitset<kNumTouchEvdevSlots>* slots_with_noise) {
for (const InProgressTouchEvdev& touch : touches) {
// Only consider new touches.
if (!touch.touching || touch.was_touching)
continue;
// Check if within kMaxDistance of an existing touch.
for (const InProgressTouchEvdev& other_touch : touches) {
if (touch.slot == other_touch.slot || !other_touch.touching)
continue;
if (std::abs(other_touch.x - touch.x) <= kMaxDistance) {
VLOG(2) << base::StringPrintf(
"Cancel tracking id %d, down at %ld at %f,%f near touch %d at "
"%f,%f",
touch.tracking_id, time.ToInternalValue(), touch.x, touch.y,
other_touch.tracking_id, other_touch.x, other_touch.y);
slots_with_noise->set(touch.slot);
}
}
}
}
} // namespace ui
// Copyright 2015 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 UI_EVENTS_OZONE_EVDEV_TOUCH_NOISE_HORIZONTALLY_ALIGNED_TOUCH_NOISE_FILTER_H_
#define UI_EVENTS_OZONE_EVDEV_TOUCH_NOISE_HORIZONTALLY_ALIGNED_TOUCH_NOISE_FILTER_H_
#include "base/macros.h"
#include "ui/events/ozone/evdev/touch_noise/touch_noise_filter.h"
namespace ui {
class HorizontallyAlignedTouchNoiseFilter : public TouchNoiseFilter {
public:
HorizontallyAlignedTouchNoiseFilter() {}
~HorizontallyAlignedTouchNoiseFilter() override {}
// TouchNoiseFilter:
void Filter(const std::vector<InProgressTouchEvdev>& touches,
base::TimeDelta time,
std::bitset<kNumTouchEvdevSlots>* slots_with_noise) override;
private:
DISALLOW_COPY_AND_ASSIGN(HorizontallyAlignedTouchNoiseFilter);
};
} // namespace ui
#endif // UI_EVENTS_OZONE_EVDEV_TOUCH_NOISE_HORIZONTALLY_ALIGNED_TOUCH_NOISE_FILTER_H_
// Copyright 2015 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 "ui/events/ozone/evdev/touch_noise/single_position_touch_noise_filter.h"
#include "base/logging.h"
#include "base/strings/stringprintf.h"
namespace ui {
namespace {
// Max squared distance between fingers for the fingers to be considered in the
// same position.
const int kSamePositionMaxDistance2 = 2 * 2;
// Max squared movement of a finger before it's no longer considered noise.
const int kNoiseMaxMovement2 = 2 * 2;
// Min duration in milliseconds after which touches in the same position are
// considered noise.
const int kMinDurationMs = 2000;
// Max duration in milliseconds to check for common positions with previous
// touches.
const int kMaxDurationMs = 4000;
// Returns the squared distance between (|x1|, |y1|) and (|x2|, |y2|)
int Distance2(int x1, int y1, int x2, int y2) {
int offset_x = x2 - x1;
int offset_y = y2 - y1;
return offset_x * offset_x + offset_y * offset_y;
}
} // namespace
SinglePositionTouchNoiseFilter::SinglePositionTouchNoiseFilter()
: tracked_touches_start_(0), tracked_touches_end_(0) {
for (size_t i = 0; i < kNumTouchEvdevSlots; ++i)
tracked_slots_[i] = kNumTrackedTouches;
}
void SinglePositionTouchNoiseFilter::Filter(
const std::vector<InProgressTouchEvdev>& touches,
base::TimeDelta time,
std::bitset<kNumTouchEvdevSlots>* slots_with_noise) {
// Forget old touches which will no longer be considered for overlap.
base::TimeDelta touch_cutoff =
time - base::TimeDelta::FromMilliseconds(kMaxDurationMs);
for (size_t i = tracked_touches_start_; i != tracked_touches_end_;
i = (i + 1) % kNumTrackedTouches) {
if (!tracked_touches_[i].valid)
continue;
if (tracked_touches_[i].end < touch_cutoff)
StopTrackingTouch(i);
}
for (const InProgressTouchEvdev& touch : touches) {
size_t slot = touch.slot;
bool arrived = touch.touching && !touch.was_touching;
bool departed = !touch.touching && touch.was_touching;
if (departed)
tracked_slots_[slot] = kNumTrackedTouches;
if (!touch.touching)
continue;
// Track all new touches until they move too far.
if (arrived)
TrackTouch(touch, time);
size_t t_ind = tracked_slots_[slot];
if (t_ind != kNumTrackedTouches) {
tracked_touches_[t_ind].end = time;
// Stop tracking if touch moves more than sqrt(kNoiseMaxMovement2).
if (Distance2(touch.x, touch.y, tracked_touches_[t_ind].x,
tracked_touches_[t_ind].y) > kNoiseMaxMovement2) {
StopTrackingTouch(t_ind);
} else {
// Determine duration over which touches have been occuring in this
// position.
base::TimeDelta max_duration;
for (size_t i = tracked_touches_start_; i != tracked_touches_end_;
i = (i + 1) % kNumTrackedTouches) {
TrackedTouch* tracked_touch = &tracked_touches_[i];
if (!tracked_touch->valid)
continue;
if (Distance2(touch.x, touch.y, tracked_touch->x, tracked_touch->y) <=
kSamePositionMaxDistance2) {
base::TimeDelta duration = time - tracked_touch->begin;
if (duration > max_duration)
max_duration = duration;
}
}
if (max_duration.InMilliseconds() > kMinDurationMs) {
VLOG(2) << base::StringPrintf(
"Cancel tracking id %d, in position occurring for %ldms",
touch.tracking_id, max_duration.InMilliseconds());
slots_with_noise->set(slot);
}
}
}
}
}
void SinglePositionTouchNoiseFilter::StopTrackingTouch(size_t index) {
size_t slot = tracked_touches_[index].slot;
if (tracked_slots_[slot] == index)
tracked_slots_[slot] = kNumTrackedTouches;
tracked_touches_[index].valid = false;
// If first touch is canceled, remove all dead touches.
if (index == tracked_touches_start_) {
while (!tracked_touches_[tracked_touches_start_].valid &&
tracked_touches_start_ != tracked_touches_end_) {
tracked_touches_start_ =
(tracked_touches_start_ + 1) % kNumTrackedTouches;
}
}
}
void SinglePositionTouchNoiseFilter::TrackTouch(
const InProgressTouchEvdev& touch,
base::TimeDelta time) {
size_t index = (tracked_touches_end_ + 1) % kNumTrackedTouches;
// If we would reach the start touch index, we cannot track any more touches.
if (index == tracked_touches_start_)
return;
tracked_touches_end_ = index;
tracked_touches_[index].valid = true;
tracked_touches_[index].slot = touch.slot;
tracked_touches_[index].x = touch.x;
tracked_touches_[index].y = touch.y;
tracked_touches_[index].begin = time;
tracked_touches_[index].end = time;
tracked_slots_[touch.slot] = index;
}
SinglePositionTouchNoiseFilter::SinglePositionTouchNoiseFilter::TrackedTouch::
TrackedTouch()
: valid(false), slot(0), x(0), y(0) {
}
SinglePositionTouchNoiseFilter::SinglePositionTouchNoiseFilter::TrackedTouch::
~TrackedTouch() {
}
} // namespace ui
// Copyright 2015 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 UI_EVENTS_OZONE_EVDEV_TOUCH_NOISE_SINGLE_POSITION_TOUCH_NOISE_FILTER_H_
#define UI_EVENTS_OZONE_EVDEV_TOUCH_NOISE_SINGLE_POSITION_TOUCH_NOISE_FILTER_H_
#include "base/macros.h"
#include "base/time/time.h"
#include "ui/events/ozone/evdev/touch_noise/touch_noise_filter.h"
namespace ui {
class SinglePositionTouchNoiseFilter : public TouchNoiseFilter {
public:
SinglePositionTouchNoiseFilter();
~SinglePositionTouchNoiseFilter() override {}
// TouchNoiseFilter:
void Filter(const std::vector<InProgressTouchEvdev>& touches,
base::TimeDelta time,
std::bitset<kNumTouchEvdevSlots>* slots_with_noise) override;
private:
struct TrackedTouch {
TrackedTouch();
~TrackedTouch();
bool valid;
size_t slot;
int x;
int y;
base::TimeDelta begin;
base::TimeDelta end;
};
void StopTrackingTouch(size_t index);
void TrackTouch(const InProgressTouchEvdev& touch,
base::TimeDelta time);
// A mapping of slot to tracked touch index in |tracked_touches_|.
size_t tracked_slots_[kNumTouchEvdevSlots];
// A circular buffer of tracked touches
// [|tracked_touches_start_|, |tracked_touches_end_|).
static const int kNumTrackedTouches = 100;
TrackedTouch tracked_touches_[kNumTrackedTouches];
size_t tracked_touches_start_;
size_t tracked_touches_end_;
};
} // namespace ui
#endif // UI_EVENTS_OZONE_EVDEV_TOUCH_NOISE_SINGLE_POSITION_TOUCH_NOISE_FILTER_H_
// Copyright 2015 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 UI_EVENTS_OZONE_EVDEV_TOUCH_NOISE_TOUCH_NOISE_FILTER_H_
#define UI_EVENTS_OZONE_EVDEV_TOUCH_NOISE_TOUCH_NOISE_FILTER_H_
#include <bitset>
#include <vector>
#include "base/time/time.h"
#include "ui/events/ozone/evdev/touch_evdev_types.h"
namespace ui {
class TouchNoiseFilter {
public:
virtual ~TouchNoiseFilter() {}
virtual void Filter(const std::vector<InProgressTouchEvdev>& touches,
base::TimeDelta time,
std::bitset<kNumTouchEvdevSlots>* slots_with_noise) = 0;
};
} // namespace ui
#endif // UI_EVENTS_OZONE_EVDEV_TOUCH_NOISE_TOUCH_NOISE_FILTER_H_
// Copyright 2015 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 "ui/events/ozone/evdev/touch_noise/touch_noise_finder.h"
#include "base/stl_util.h"
#include "ui/events/ozone/evdev/touch_noise/far_apart_taps_touch_noise_filter.h"
#include "ui/events/ozone/evdev/touch_noise/horizontally_aligned_touch_noise_filter.h"
#include "ui/events/ozone/evdev/touch_noise/single_position_touch_noise_filter.h"
#include "ui/events/ozone/evdev/touch_noise/touch_noise_filter.h"
namespace ui {
TouchNoiseFinder::TouchNoiseFinder() {
filters_.push_back(new FarApartTapsTouchNoiseFilter);
filters_.push_back(new HorizontallyAlignedTouchNoiseFilter);
filters_.push_back(new SinglePositionTouchNoiseFilter);
}
TouchNoiseFinder::~TouchNoiseFinder() {
STLDeleteElements(&filters_);
}
void TouchNoiseFinder::HandleTouches(
const std::vector<InProgressTouchEvdev>& touches,
base::TimeDelta time) {
for (const InProgressTouchEvdev& touch : touches) {
if (!touch.was_touching)
slots_with_noise_.set(touch.slot, false);
}
for (TouchNoiseFilter* filter : filters_)
filter->Filter(touches, time, &slots_with_noise_);
}
bool TouchNoiseFinder::SlotHasNoise(size_t slot) const {
return slots_with_noise_.test(slot);
}
} // namespace ui
// Copyright 2015 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 UI_EVENTS_OZONE_EVDEV_TOUCH_NOISE_TOUCH_NOISE_FINDER_H_
#define UI_EVENTS_OZONE_EVDEV_TOUCH_NOISE_TOUCH_NOISE_FINDER_H_
#include <bitset>
#include <vector>
#include "base/basictypes.h"
#include "base/time/time.h"
#include "ui/events/ozone/evdev/events_ozone_evdev_export.h"
#include "ui/events/ozone/evdev/touch_evdev_types.h"
namespace ui {
class TouchNoiseFilter;
// Finds touches which are likely touch noise.
class EVENTS_OZONE_EVDEV_EXPORT TouchNoiseFinder {
public:
TouchNoiseFinder();
~TouchNoiseFinder();
// Updates which ABS_MT_SLOTs are likely noise. |touches| should contain all
// of the in-progress touches at |time| (including suspected noisy touches).
// |touches| should have at most one entry per ABS_MT_SLOT.
void HandleTouches(const std::vector<InProgressTouchEvdev>& touches,
base::TimeDelta time);
// Returns whether the in-progress touch at ABS_MT_SLOT |slot| is likely
// noise.
bool SlotHasNoise(size_t slot) const;
private:
friend class TouchEventConverterEvdevTouchNoiseTest;
// The slots which are likely noise.
std::bitset<kNumTouchEvdevSlots> slots_with_noise_;
std::vector<TouchNoiseFilter*> filters_;
DISALLOW_COPY_AND_ASSIGN(TouchNoiseFinder);
};
} // namespace ui
#endif // UI_EVENTS_OZONE_EVDEV_TOUCH_NOISE_TOUCH_NOISE_FINDER_H_
// Copyright 2015 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 "ui/events/ozone/evdev/touch_noise/touch_noise_finder.h"
#include <algorithm>
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/stringprintf.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/ozone/evdev/touch_evdev_types.h"
#include "ui/gfx/geometry/point_f.h"
namespace ui {
class TouchNoiseFinderTest : public testing::Test {
public:
struct TouchEntry {
int time_ms;
size_t slot;
bool touching;
gfx::PointF location;
bool expect_noise;
};
TouchNoiseFinderTest() {}
~TouchNoiseFinderTest() override {}
bool FilterAndCheck(const TouchEntry entries[], size_t count) {
std::vector<InProgressTouchEvdev> touches;
size_t start_index = 0u;
bool was_touching = false;
for (size_t i = 0; i < count; ++i) {
const TouchEntry& entry = entries[i];
InProgressTouchEvdev touch;
touch.x = entry.location.x();
touch.y = entry.location.y();
touch.tracking_id = entry.slot;
touch.slot = entry.slot;
touch.was_touching = was_touching;
touch.touching = entry.touching;
if (i == count - 1 || entry.time_ms != entries[i + 1].time_ms) {
touch_noise_finder_->HandleTouches(
touches, base::TimeDelta::FromMilliseconds(entry.time_ms));
for (size_t j = 0; j < touches.size(); ++j) {
bool expect_noise = entries[j + start_index].expect_noise;
size_t slot = touches[j].slot;
if (touch_noise_finder_->SlotHasNoise(slot) != expect_noise)
LOG(ERROR) << base::StringPrintf(
"Incorrect filtering at %dms for slot %lu", entry.time_ms,
slot);
return false;
}
start_index = i + 1;
touches.clear();
}
was_touching = entry.touching;
}
return true;
}
private:
// testing::Test:
void SetUp() override {
touch_noise_finder_.reset(new TouchNoiseFinder);
}
scoped_ptr<TouchNoiseFinder> touch_noise_finder_;
DISALLOW_COPY_AND_ASSIGN(TouchNoiseFinderTest);
};
// Test that taps which are far apart in quick succession are considered noise.
TEST_F(TouchNoiseFinderTest, FarApartTaps) {
const TouchEntry kTestData[] = {
{10, 1, true, gfx::PointF(10, 10), false},
{20, 1, true, gfx::PointF(10, 11), false},
{30, 1, true, gfx::PointF(10, 12), false},
{30, 2, true, gfx::PointF(2500, 1000), true},
{40, 1, true, gfx::PointF(10, 13), true},
{40, 2, true, gfx::PointF(2500, 1001), true},
{50, 1, true, gfx::PointF(10, 14), true},
{50, 2, false, gfx::PointF(2500, 1002), true},
{60, 1, false, gfx::PointF(10, 15), true}};
EXPECT_TRUE(FilterAndCheck(kTestData, arraysize(kTestData)));
}
// Test that taps which are far apart but do not occur in quick succession are
// not considered noise.
TEST_F(TouchNoiseFinderTest, FarApartTapsSlow) {
const TouchEntry kTestData[] = {
{1000, 1, true, gfx::PointF(10, 10), false},
{1500, 1, true, gfx::PointF(10, 11), false},
{2000, 1, true, gfx::PointF(10, 12), false},
{2500, 1, true, gfx::PointF(10, 13), false},
{2500, 2, true, gfx::PointF(2500, 1000), false},
{3000, 1, true, gfx::PointF(10, 14), false},
{3000, 2, false, gfx::PointF(2500, 1001), false},
{3500, 1, false, gfx::PointF(10, 15), false}};
EXPECT_TRUE(FilterAndCheck(kTestData, arraysize(kTestData)));
}
// Test that touches which are horizontally aligned are considered noise.
TEST_F(TouchNoiseFinderTest, HorizontallyAligned) {
const TouchEntry kTestData[] = {
{10, 1, true, gfx::PointF(10, 10), false},
{20, 1, true, gfx::PointF(10, 10), false},
{20, 2, true, gfx::PointF(10, 25), true},
{30, 1, false, gfx::PointF(10, 10), false},
{30, 2, true, gfx::PointF(10, 25), true},
{40, 2, false, gfx::PointF(10, 25), true}};
EXPECT_TRUE(FilterAndCheck(kTestData, arraysize(kTestData)));
}
// Test that touches in the same position are considered noise.
TEST_F(TouchNoiseFinderTest, SamePosition) {
const TouchEntry kTestData[] = {
{1000, 1, true, gfx::PointF(10, 10), false},
{1500, 1, false, gfx::PointF(10, 10), false},
{2000, 1, true, gfx::PointF(10, 10), false},
{2500, 1, false, gfx::PointF(10, 10), false},
{3000, 1, true, gfx::PointF(50, 50), false},
{3500, 1, true, gfx::PointF(50, 51), false},
{3500, 2, true, gfx::PointF(10, 10), true},
{4000, 1, false, gfx::PointF(50, 52), false},
{4000, 2, false, gfx::PointF(10, 10), true},
{4500, 1, true, gfx::PointF(10, 10), true},
{5000, 1, false, gfx::PointF(10, 10), true}};
EXPECT_TRUE(FilterAndCheck(kTestData, arraysize(kTestData)));
}
} // namespace ui
......@@ -112,19 +112,8 @@
'evdev/mouse_button_map_evdev.h',
'evdev/tablet_event_converter_evdev.cc',
'evdev/tablet_event_converter_evdev.h',
'evdev/touch_evdev_types.cc',
'evdev/touch_evdev_types.h',
'evdev/touch_event_converter_evdev.cc',
'evdev/touch_event_converter_evdev.h',
'evdev/touch_noise/far_apart_taps_touch_noise_filter.cc',
'evdev/touch_noise/far_apart_taps_touch_noise_filter.h',
'evdev/touch_noise/horizontally_aligned_touch_noise_filter.cc',
'evdev/touch_noise/horizontally_aligned_touch_noise_filter.h',
'evdev/touch_noise/single_position_touch_noise_filter.cc',
'evdev/touch_noise/single_position_touch_noise_filter.h',
'evdev/touch_noise/touch_noise_filter.h',
'evdev/touch_noise/touch_noise_finder.cc',
'evdev/touch_noise/touch_noise_finder.h',
],
'conditions': [
['use_ozone_evdev==1 and use_evdev_gestures==1', {
......
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