1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "ui/events/ozone/evdev/touch_filter/heuristic_stylus_palm_detection_filter.h"
6
7 #include <linux/input.h>
8
9 #include "base/macros.h"
10 #include "base/test/gtest_util.h"
11 #include "testing/gtest/include/gtest/gtest.h"
12 #include "ui/events/ozone/evdev/touch_filter/palm_detection_filter.h"
13 #include "ui/events/ozone/evdev/touch_filter/shared_palm_detection_filter_state.h"
14
15 namespace ui {
16
17 class HeuristicStylusPalmDetectionFilterTest : public testing::Test {
18 public:
19 HeuristicStylusPalmDetectionFilterTest() = default;
SetUp()20 void SetUp() override {
21 shared_palm_state = std::make_unique<SharedPalmDetectionFilterState>();
22 palm_detection_filter_ =
23 std::make_unique<HeuristicStylusPalmDetectionFilter>(
24 shared_palm_state.get(), hold_sample_count, hold_time,
25 suppress_time);
26 touches_.resize(kNumTouchEvdevSlots);
27 test_start_time_ = base::TimeTicks::Now();
28 }
29
30 protected:
31 const int hold_sample_count = 5;
32 const base::TimeDelta hold_time = base::TimeDelta::FromSecondsD(1.0);
33 const base::TimeDelta suppress_time = base::TimeDelta::FromSecondsD(0.4);
34
35 const base::TimeDelta sample_interval =
36 base::TimeDelta::FromMillisecondsD(7.5);
37
38 std::unique_ptr<SharedPalmDetectionFilterState> shared_palm_state;
39 std::unique_ptr<PalmDetectionFilter> palm_detection_filter_;
40 std::vector<InProgressTouchEvdev> touches_;
41 base::TimeTicks test_start_time_;
42
43 DISALLOW_COPY_AND_ASSIGN(HeuristicStylusPalmDetectionFilterTest);
44 };
45
46 class HeuristicStylusPalmDetectionFilterDeathTest
47 : public HeuristicStylusPalmDetectionFilterTest {};
48
TEST_F(HeuristicStylusPalmDetectionFilterDeathTest,TestDCheck)49 TEST_F(HeuristicStylusPalmDetectionFilterDeathTest, TestDCheck) {
50 // We run with a time where hold_time < suppress_time, which should DCHECK.
51 EXPECT_DCHECK_DEATH(
52 palm_detection_filter_ =
53 std::make_unique<HeuristicStylusPalmDetectionFilter>(
54 shared_palm_state.get(), hold_sample_count, hold_time,
55 hold_time + base::TimeDelta::FromMillisecondsD(0.1)));
56 }
57
TEST_F(HeuristicStylusPalmDetectionFilterTest,TestSetsToZero)58 TEST_F(HeuristicStylusPalmDetectionFilterTest, TestSetsToZero) {
59 std::bitset<kNumTouchEvdevSlots> suppress, hold;
60 suppress.set(kNumTouchEvdevSlots - 1, 1);
61 hold.set(0, 1);
62 palm_detection_filter_->Filter(touches_, test_start_time_, &hold, &suppress);
63 EXPECT_TRUE(hold.none());
64 EXPECT_TRUE(suppress.none());
65 }
66
TEST_F(HeuristicStylusPalmDetectionFilterTest,TestCancelAfterStylus)67 TEST_F(HeuristicStylusPalmDetectionFilterTest, TestCancelAfterStylus) {
68 touches_[0].touching = true;
69 touches_[0].tool_code = BTN_TOOL_PEN;
70 std::bitset<kNumTouchEvdevSlots> suppress, hold;
71 // Set Palm as test_start_time_;
72 palm_detection_filter_->Filter(touches_, test_start_time_, &hold, &suppress);
73 EXPECT_TRUE(hold.none());
74 EXPECT_TRUE(suppress.none());
75
76 // Now, lets start two touches 7.5ms afterwards.
77 touches_[0].tool_code = 0;
78 touches_[1].touching = true;
79 base::TimeTicks start_time = test_start_time_ + sample_interval;
80 palm_detection_filter_->Filter(touches_, start_time, &hold, &suppress);
81 // expect none held, 0 and 1 cancelled, and others untouched.
82 EXPECT_TRUE(hold.none());
83 EXPECT_TRUE(suppress.test(0));
84 EXPECT_TRUE(suppress.test(1));
85 suppress.reset(0);
86 suppress.reset(1);
87 EXPECT_TRUE(suppress.none());
88
89 // Now, what if we keep going with these strokes for a long time.
90 for (;
91 start_time < test_start_time_ + base::TimeDelta::FromMillisecondsD(1000);
92 start_time += sample_interval) {
93 palm_detection_filter_->Filter(touches_, start_time, &hold, &suppress);
94 EXPECT_TRUE(hold.none());
95 EXPECT_TRUE(suppress.test(0));
96 EXPECT_TRUE(suppress.test(1));
97 suppress.reset(0);
98 suppress.reset(1);
99 EXPECT_TRUE(suppress.none());
100 }
101 }
102
TEST_F(HeuristicStylusPalmDetectionFilterTest,TestHoldAfterStylus)103 TEST_F(HeuristicStylusPalmDetectionFilterTest, TestHoldAfterStylus) {
104 touches_[0].touching = true;
105 touches_[0].tool_code = BTN_TOOL_PEN;
106 std::bitset<kNumTouchEvdevSlots> suppress, hold;
107 // Set Palm as test_start_time_;
108 palm_detection_filter_->Filter(touches_, test_start_time_, &hold, &suppress);
109 EXPECT_TRUE(hold.none());
110 EXPECT_TRUE(suppress.none());
111 EXPECT_EQ(0u, shared_palm_state->active_finger_touches);
112
113 // Now, lets start two touches a little before end of hold time.
114 touches_[0].tool_code = 0;
115 touches_[1].touching = true;
116 base::TimeTicks start_time =
117 test_start_time_ + hold_time - (hold_sample_count - 2) * sample_interval;
118 palm_detection_filter_->Filter(touches_, start_time, &hold, &suppress);
119 EXPECT_TRUE(suppress.none());
120 EXPECT_TRUE(hold.test(0));
121 EXPECT_TRUE(hold.test(1));
122 hold.reset(0);
123 hold.reset(1);
124 EXPECT_TRUE(hold.none());
125 for (int i = 0; i < 10; ++i) {
126 start_time += sample_interval;
127 palm_detection_filter_->Filter(touches_, start_time, &hold, &suppress);
128 EXPECT_TRUE(suppress.none());
129 // We've already held one item, so we expect 1 - the sample count to get
130 // held. Note that 1 of these falls _after_ the overall hold time, but we
131 // hold it since we depend on touch start.
132 if (i < hold_sample_count - 1) {
133 EXPECT_TRUE(hold.test(0)) << "Failed at i = " << i;
134 EXPECT_TRUE(hold.test(1)) << "Failed at i = " << i;
135 hold.reset(0);
136 hold.reset(1);
137 EXPECT_TRUE(hold.none());
138 ASSERT_EQ(0u, shared_palm_state->active_finger_touches)
139 << " Failed at i = " << i;
140 } else {
141 ASSERT_EQ(2u, shared_palm_state->active_finger_touches)
142 << " Failed at i = " << i;
143 EXPECT_TRUE(hold.none());
144 }
145 }
146 }
147
TEST_F(HeuristicStylusPalmDetectionFilterTest,TestNothingLongAfterStylus)148 TEST_F(HeuristicStylusPalmDetectionFilterTest, TestNothingLongAfterStylus) {
149 touches_[0].touching = true;
150 touches_[0].tool_code = BTN_TOOL_PEN;
151 std::bitset<kNumTouchEvdevSlots> suppress, hold;
152 // Set Palm as test_start_time_;
153 palm_detection_filter_->Filter(touches_, test_start_time_, &hold, &suppress);
154 EXPECT_TRUE(hold.none());
155 EXPECT_TRUE(suppress.none());
156 touches_[0].tool_code = 0;
157 touches_[1].touching = true;
158 base::TimeTicks start_time =
159 test_start_time_ + hold_time + base::TimeDelta::FromMillisecondsD(1e-2);
160 palm_detection_filter_->Filter(touches_, start_time, &hold, &suppress);
161 EXPECT_EQ(2u, shared_palm_state->active_finger_touches);
162 EXPECT_TRUE(hold.none());
163 EXPECT_TRUE(suppress.none());
164 }
165
TEST_F(HeuristicStylusPalmDetectionFilterTest,TestHover)166 TEST_F(HeuristicStylusPalmDetectionFilterTest, TestHover) {
167 touches_[0].touching = false;
168 touches_[0].tool_code = BTN_TOOL_PEN;
169 std::bitset<kNumTouchEvdevSlots> suppress, hold;
170 // Set Palm as test_start_time_;
171 palm_detection_filter_->Filter(touches_, test_start_time_, &hold, &suppress);
172 EXPECT_TRUE(hold.none());
173 EXPECT_TRUE(suppress.none());
174
175 // Now, do we filter a finger?
176 touches_[0].tool_code = 0;
177 touches_[0].touching = true;
178 base::TimeTicks start_time =
179 test_start_time_ + hold_time - base::TimeDelta::FromMillisecondsD(1e-2);
180 palm_detection_filter_->Filter(touches_, start_time, &hold, &suppress);
181 EXPECT_TRUE(hold.test(0));
182 EXPECT_TRUE(suppress.none());
183 hold.reset(0);
184 EXPECT_TRUE(hold.none());
185 }
186
187 } // namespace ui
188