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