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