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