Commit bcf7beb2 authored by Rob Schonberger's avatar Rob Schonberger Committed by Commit Bot

Add Feature for Single-Slot cancel in Touch. Unit test new behavior.

This can be tested and enabled in conjunction with other features and
experiments for users in the future.

Default behavior is completely unchanged, and unit test thoroughly
tests new behavior.


Bug: 1009290
Change-Id: I57076270b2272831376c9b5ee787d9eecfa8d28f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1861914Reviewed-by: default avatarMichael Spang <spang@chromium.org>
Commit-Queue: Rob Schonberger <robsc@chromium.org>
Cr-Commit-Position: refs/heads/master@{#706156}
parent f881db12
......@@ -117,6 +117,9 @@ const int kTrackingIdForUnusedSlot = -1;
namespace ui {
const base::Feature kEnableSingleCancelTouch{"EnableSingleTouchCancel",
base::FEATURE_DISABLED_BY_DEFAULT};
TouchEventConverterEvdev::TouchEventConverterEvdev(
base::ScopedFD fd,
base::FilePath path,
......@@ -528,7 +531,8 @@ bool TouchEventConverterEvdev::MaybeCancelAllTouches() {
// TODO(denniskempin): Remove once upper layers properly handle single
// cancelled touches.
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableCancelAllTouches)) {
switches::kDisableCancelAllTouches) ||
base::FeatureList::IsEnabled(kEnableSingleCancelTouch)) {
return false;
}
for (size_t i = 0; i < events_.size(); i++) {
......
......@@ -5,14 +5,13 @@
#ifndef UI_EVENTS_OZONE_EVDEV_TOUCH_EVENT_CONVERTER_EVDEV_H_
#define UI_EVENTS_OZONE_EVDEV_TOUCH_EVENT_CONVERTER_EVDEV_H_
#include <linux/input.h>
#include <stddef.h>
#include <stdint.h>
#include <bitset>
#include <memory>
#include <queue>
#include <linux/input.h>
// See if we compile against new enough headers and add missing definition
// if the headers are too old.
#ifndef MT_TOOL_PALM
......@@ -24,6 +23,7 @@
#include "base/files/scoped_file.h"
#include "base/macros.h"
#include "base/message_loop/message_pump_libevent.h"
#include "base/metrics/field_trial_params.h"
#include "ui/events/event_constants.h"
#include "ui/events/ozone/evdev/event_converter_evdev.h"
#include "ui/events/ozone/evdev/event_device_info.h"
......@@ -37,6 +37,8 @@ class DeviceEventDispatcherEvdev;
class FalseTouchFinder;
struct InProgressTouchEvdev;
extern const EVENTS_OZONE_EVDEV_EXPORT base::Feature kEnableSingleCancelTouch;
class EVENTS_OZONE_EVDEV_EXPORT TouchEventConverterEvdev
: public EventConverterEvdev {
public:
......
......@@ -20,6 +20,7 @@
#include "base/run_loop.h"
#include "base/stl_util.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "base/time/time.h"
#include "testing/gmock/include/gmock/gmock.h"
......@@ -254,6 +255,10 @@ class TouchEventConverterEvdevTest : public testing::Test {
test_clock_ = std::make_unique<ui::test::ScopedEventTestTickClock>();
ui::DeviceDataManager::CreateInstance();
// By default, tests disable single-cancel.
scoped_feature_list_.reset(new base::test::ScopedFeatureList);
scoped_feature_list_->InitAndDisableFeature(kEnableSingleCancelTouch);
}
void TearDown() override {
......@@ -302,6 +307,7 @@ class TouchEventConverterEvdevTest : public testing::Test {
protected:
base::HistogramTester histogram_tester_;
std::unique_ptr<base::test::ScopedFeatureList> scoped_feature_list_;
private:
base::test::SingleThreadTaskEnvironment task_environment_{
......@@ -889,7 +895,7 @@ TEST_F(TouchEventConverterEvdevTest, TrackingIdShouldNotResetCancelByPalm) {
{time, EV_ABS, ABS_MT_TRACKING_ID, -1},
{time, EV_SYN, SYN_REPORT, 0},
};
// No events will be generated from the following queue. Here is why:
// A few events will be generated, but not for slot 0. Here is why:
// The touch in SLOT 0 was identified as a palm in previous events, thus it
// was cancelled. In the following events, there is new trcking id for slot
// 0, but there is no MT_TOOL_FINGER and TOUCH_MAJOR saying it's a finger.
......@@ -1018,6 +1024,190 @@ TEST_F(TouchEventConverterEvdevTest, TrackingIdShouldNotResetCancelByPalm) {
EXPECT_EQ(1, ev2_4.slot);
}
TEST_F(TouchEventConverterEvdevTest,
TrackingIdShouldNotResetCancelByPalmSingleCancel) {
// Flip field to true.
scoped_feature_list_.reset(new base::test::ScopedFeatureList);
scoped_feature_list_->InitAndEnableFeature(kEnableSingleCancelTouch);
ui::MockTouchEventConverterEvdev* dev = device();
EventDeviceInfo devinfo;
EXPECT_TRUE(CapabilitiesToDeviceInfo(kLinkWithToolTypeTouchscreen, &devinfo));
timeval time;
time = {1429651083, 686882};
int major_max = devinfo.GetAbsMaximum(ABS_MT_TOUCH_MAJOR);
struct input_event mock_kernel_queue_max_major[] = {
{time, EV_ABS, ABS_MT_SLOT, 0},
{time, EV_ABS, ABS_MT_TRACKING_ID, 0},
{time, EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_FINGER},
{time, EV_ABS, ABS_MT_POSITION_X, 1003},
{time, EV_ABS, ABS_MT_POSITION_Y, 749},
{time, EV_ABS, ABS_MT_PRESSURE, 50},
{time, EV_ABS, ABS_MT_TOUCH_MAJOR, 116},
{time, EV_ABS, ABS_MT_SLOT, 1},
{time, EV_ABS, ABS_MT_TRACKING_ID, 1},
{time, EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_FINGER},
{time, EV_ABS, ABS_MT_POSITION_X, 1103},
{time, EV_ABS, ABS_MT_POSITION_Y, 649},
{time, EV_ABS, ABS_MT_PRESSURE, 50},
{time, EV_ABS, ABS_MT_TOUCH_MAJOR, 116},
{time, EV_KEY, BTN_TOUCH, 1},
{time, EV_ABS, ABS_X, 1003},
{time, EV_ABS, ABS_Y, 749},
{time, EV_ABS, ABS_PRESSURE, 50},
{time, EV_SYN, SYN_REPORT, 0},
{time, EV_ABS, ABS_MT_SLOT, 0},
{time, EV_ABS, ABS_MT_TOUCH_MAJOR, major_max},
{time, EV_SYN, SYN_REPORT, 0},
{time, EV_ABS, ABS_MT_TRACKING_ID, -1},
{time, EV_ABS, ABS_MT_SLOT, 1},
{time, EV_ABS, ABS_MT_TRACKING_ID, -1},
{time, EV_SYN, SYN_REPORT, 0},
};
// No events will be generated from the following queue. Here is why:
// The touch in SLOT 0 was identified as a palm in previous events, thus it
// was cancelled. In the following events, there is new trcking id for slot
// 0, but there is no MT_TOOL_FINGER and TOUCH_MAJOR saying it's a finger.
// Thus the slot will continue to be a palm and its events will be cancelled.
struct input_event mock_kernel_new_touch_without_new_major[] = {
{time, EV_ABS, ABS_MT_SLOT, 0},
{time, EV_ABS, ABS_MT_TRACKING_ID, 3},
{time, EV_ABS, ABS_MT_POSITION_X, 1003},
{time, EV_ABS, ABS_MT_POSITION_Y, 749},
{time, EV_ABS, ABS_MT_PRESSURE, 50},
{time, EV_ABS, ABS_MT_SLOT, 1},
{time, EV_ABS, ABS_MT_TRACKING_ID, 4},
{time, EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_FINGER},
{time, EV_ABS, ABS_MT_POSITION_X, 1103},
{time, EV_ABS, ABS_MT_POSITION_Y, 649},
{time, EV_ABS, ABS_MT_PRESSURE, 50},
{time, EV_ABS, ABS_MT_TOUCH_MAJOR, 116},
{time, EV_KEY, BTN_TOUCH, 1},
{time, EV_ABS, ABS_X, 1003},
{time, EV_ABS, ABS_Y, 749},
{time, EV_ABS, ABS_PRESSURE, 50},
{time, EV_SYN, SYN_REPORT, 0},
{time, EV_ABS, ABS_MT_SLOT, 0},
{time, EV_SYN, SYN_REPORT, 0},
{time, EV_ABS, ABS_MT_TRACKING_ID, -1},
{time, EV_SYN, SYN_REPORT, 0},
{time, EV_ABS, ABS_MT_SLOT, 1},
{time, EV_SYN, SYN_REPORT, 0},
{time, EV_ABS, ABS_MT_TRACKING_ID, -1},
{time, EV_SYN, SYN_REPORT, 0},
};
// This time, there is MT_TOOL_FINGER for slot 0, thus events should be
// dispatched. Note that slot 0 is reported palm, and then both terminate.
struct input_event mock_kernel_queue_tool_palm[] = {
{time, EV_ABS, ABS_MT_SLOT, 0},
{time, EV_ABS, ABS_MT_TRACKING_ID, 2},
{time, EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_FINGER},
{time, EV_ABS, ABS_MT_POSITION_X, 1003},
{time, EV_ABS, ABS_MT_POSITION_Y, 749},
{time, EV_ABS, ABS_MT_PRESSURE, 50},
{time, EV_ABS, ABS_MT_TOUCH_MAJOR, 116},
{time, EV_ABS, ABS_MT_SLOT, 1},
{time, EV_ABS, ABS_MT_TRACKING_ID, 3},
{time, EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_FINGER},
{time, EV_ABS, ABS_MT_POSITION_X, 1103},
{time, EV_ABS, ABS_MT_POSITION_Y, 649},
{time, EV_ABS, ABS_MT_PRESSURE, 50},
{time, EV_ABS, ABS_MT_TOUCH_MAJOR, 116},
{time, EV_KEY, BTN_TOUCH, 1},
{time, EV_ABS, ABS_X, 1003},
{time, EV_ABS, ABS_Y, 749},
{time, EV_ABS, ABS_PRESSURE, 50},
{time, EV_SYN, SYN_REPORT, 0},
{time, EV_ABS, ABS_MT_SLOT, 0},
{time, EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_PALM},
{time, EV_SYN, SYN_REPORT, 0},
{time, EV_ABS, ABS_MT_TRACKING_ID, -1},
{time, EV_SYN, SYN_REPORT, 0},
};
// Set test now time to ensure above timestamps are in the past.
SetTestNowTime(time);
// Initialize the device.
dev->Initialize(devinfo);
dev->ConfigureReadMock(mock_kernel_queue_max_major,
base::size(mock_kernel_queue_max_major), 0);
dev->ReadNow();
EXPECT_EQ(4u, size());
{
ui::TouchEventParams ev1_1 = dispatched_touch_event(0);
EXPECT_EQ(ET_TOUCH_PRESSED, ev1_1.type);
EXPECT_EQ(0, ev1_1.slot);
EXPECT_EQ(1003, ev1_1.location.x());
EXPECT_EQ(749, ev1_1.location.y());
ui::TouchEventParams ev1_2 = dispatched_touch_event(1);
EXPECT_EQ(ET_TOUCH_PRESSED, ev1_2.type);
EXPECT_EQ(1, ev1_2.slot);
EXPECT_EQ(1103, ev1_2.location.x());
EXPECT_EQ(649, ev1_2.location.y());
ui::TouchEventParams ev1_3 = dispatched_touch_event(2);
EXPECT_EQ(ET_TOUCH_CANCELLED, ev1_3.type);
EXPECT_EQ(0, ev1_3.slot);
// We do not expect this to be cancelled.
ui::TouchEventParams ev1_4 = dispatched_touch_event(3);
EXPECT_EQ(ET_TOUCH_RELEASED, ev1_4.type);
EXPECT_EQ(1, ev1_4.slot);
}
// We expect 3 touches to be read: fine: touch at slot 1 is pressed and then
// moved and then lifted. touch 0 ignored.
dev->ConfigureReadMock(mock_kernel_new_touch_without_new_major,
base::size(mock_kernel_new_touch_without_new_major),
0);
dev->ReadNow();
EXPECT_EQ(7u, size());
{
ui::TouchEventParams ev2_1 = dispatched_touch_event(4);
EXPECT_EQ(ET_TOUCH_PRESSED, ev2_1.type);
EXPECT_EQ(1, ev2_1.slot);
EXPECT_EQ(1103, ev2_1.location.x());
EXPECT_EQ(649, ev2_1.location.y());
ui::TouchEventParams ev2_2 = dispatched_touch_event(5);
EXPECT_EQ(ET_TOUCH_MOVED, ev2_2.type);
EXPECT_EQ(1, ev2_2.slot);
EXPECT_EQ(1103, ev2_2.location.x());
EXPECT_EQ(649, ev2_2.location.y());
ui::TouchEventParams ev2_3 = dispatched_touch_event(6);
EXPECT_EQ(ET_TOUCH_RELEASED, ev2_3.type);
EXPECT_EQ(1, ev2_3.slot);
}
dev->ConfigureReadMock(mock_kernel_queue_tool_palm,
base::size(mock_kernel_queue_tool_palm), 0);
dev->ReadNow();
EXPECT_EQ(10u, size());
{
ui::TouchEventParams ev3_1 = dispatched_touch_event(7);
EXPECT_EQ(ET_TOUCH_PRESSED, ev3_1.type);
EXPECT_EQ(0, ev3_1.slot);
EXPECT_EQ(1003, ev3_1.location.x());
EXPECT_EQ(749, ev3_1.location.y());
ui::TouchEventParams ev3_2 = dispatched_touch_event(8);
EXPECT_EQ(ET_TOUCH_PRESSED, ev3_2.type);
EXPECT_EQ(1, ev3_2.slot);
EXPECT_EQ(1103, ev3_2.location.x());
EXPECT_EQ(649, ev3_2.location.y());
ui::TouchEventParams ev3_3 = dispatched_touch_event(9);
EXPECT_EQ(ET_TOUCH_CANCELLED, ev3_3.type);
EXPECT_EQ(0, ev3_3.slot);
// Touch at slot 1: it's still going!
}
}
// crbug.com/477695
TEST_F(TouchEventConverterEvdevTest, ShouldUseLeftButtonIfNoTouchButton) {
ui::MockTouchEventConverterEvdev* dev = device();
......
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