Index: ui/events/ozone/evdev/touch_noise/single_position_touch_noise_filter.cc |
diff --git a/ui/events/ozone/evdev/touch_noise/single_position_touch_noise_filter.cc b/ui/events/ozone/evdev/touch_noise/single_position_touch_noise_filter.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..b5e14823e98ceff1eb9ef240e9485608e81bebd9 |
--- /dev/null |
+++ b/ui/events/ozone/evdev/touch_noise/single_position_touch_noise_filter.cc |
@@ -0,0 +1,144 @@ |
+// Copyright 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "ui/events/ozone/evdev/touch_noise/single_position_touch_noise_filter.h" |
+ |
+#include "base/logging.h" |
+#include "base/strings/stringprintf.h" |
+ |
+namespace ui { |
+ |
+namespace { |
+ |
+// Max squared distance between fingers for the fingers to be considered in the |
+// same position. |
+const int kSamePositionMaxDistance2 = 2 * 2; |
+ |
+// Max squared movement of a finger before it's no longer considered noise. |
+const int kNoiseMaxMovement2 = 2 * 2; |
+ |
+// Min duration in milliseconds after which touches in the same position are |
+// considered noise. |
+const int kMinDurationMs = 2000; |
+ |
+// Max duration in milliseconds to check for common positions with previous |
+// touches. |
+const int kMaxDurationMs = 4000; |
+ |
+// Returns the squared distance between |p1| and |p2|. |
+int Distance2(const gfx::PointF& p1, const gfx::PointF& p2) { |
+ gfx::Vector2dF offset = p2 - p1; |
+ return offset.x() * offset.x() + offset.y() * offset.y(); |
+} |
+ |
+} // namespace |
+ |
+SinglePositionTouchNoiseFilter::SinglePositionTouchNoiseFilter() |
+ : touches_start_(0), touches_end_(0) { |
+ for (size_t i = 0; i < kNumSlots; i++) |
+ tracked_slots_[i] = kNumTrackedTouches; |
+} |
+ |
+void SinglePositionTouchNoiseFilter::FilterFrame(Frame* previous, |
+ Frame* current) { |
+ // Forget old touches which will no longer be considered for overlap. |
+ base::TimeDelta touch_cutoff = |
+ current->timestamp - base::TimeDelta::FromMilliseconds(kMaxDurationMs); |
+ for (size_t i = touches_start_; i != touches_end_; |
+ i = (i + 1) % kNumTrackedTouches) { |
+ if (!tracked_touches_[i].valid) |
+ continue; |
+ if (tracked_touches_[i].end < touch_cutoff) |
+ StopTrackingTouch(i); |
+ } |
+ |
+ for (size_t slot = 0; slot < kNumSlots; ++slot) { |
+ Finger* cur = ¤t->fingers[slot]; |
+ Finger* prev = &previous->fingers[slot]; |
+ |
+ bool arrived = prev->tracking_id == -1 && cur->tracking_id >= 0; |
+ bool departed = prev->tracking_id >= 0 && cur->tracking_id == -1; |
+ if (departed) |
+ tracked_slots_[slot] = kNumTrackedTouches; |
+ if (cur->tracking_id == -1) |
+ continue; |
+ |
+ // Track all new touches until they move too far. |
+ if (arrived) |
+ TrackTouch(slot, current); |
+ |
+ size_t t_ind = tracked_slots_[slot]; |
+ if (t_ind != kNumTrackedTouches) { |
+ tracked_touches_[t_ind].end = current->timestamp; |
+ // Stop tracking if touch moves more than sqrt(kNoiseMaxMovement2). |
+ if (Distance2(cur->location, tracked_touches_[t_ind].location) > |
+ kNoiseMaxMovement2) { |
+ StopTrackingTouch(t_ind); |
+ } else { |
+ // Determine duration over which touches have been occuring in this |
+ // position. |
+ base::TimeDelta max_duration; |
+ for (size_t i = touches_start_; i != touches_end_; |
+ i = (i + 1) % kNumTrackedTouches) { |
+ Touch* touch = &tracked_touches_[i]; |
+ if (!touch->valid) |
+ continue; |
+ if (Distance2(cur->location, touch->location) <= |
+ kSamePositionMaxDistance2) { |
+ base::TimeDelta duration = current->timestamp - touch->begin; |
+ if (duration > max_duration) |
+ max_duration = duration; |
+ } |
+ } |
+ |
+ if (max_duration.InMilliseconds() > kMinDurationMs) { |
+ VLOG(2) << base::StringPrintf( |
+ "Cancel tracking id %d, in position occurring for %ldms", |
+ cur->tracking_id, max_duration.InMilliseconds()); |
+ cur->canceled = true; |
+ } |
+ } |
+ } |
+ } |
+} |
+ |
+void SinglePositionTouchNoiseFilter::StopTrackingTouch(size_t index) { |
+ size_t slot = tracked_touches_[index].slot; |
+ if (tracked_slots_[slot] == index) |
+ tracked_slots_[slot] = kNumTrackedTouches; |
+ tracked_touches_[index].valid = false; |
+ |
+ // If first touch is canceled, remove all dead touches. |
+ if (index == touches_start_) { |
+ while (!tracked_touches_[touches_start_].valid && |
+ touches_start_ != touches_end_) { |
+ touches_start_ = (touches_start_ + 1) % kNumTrackedTouches; |
+ } |
+ } |
+} |
+ |
+void SinglePositionTouchNoiseFilter::TrackTouch(size_t slot, Frame* frame) { |
+ size_t index = (touches_end_ + 1) % kNumTrackedTouches; |
+ // If we would reach the start touch index, we cannot track any more touches. |
+ if (index == touches_start_) |
+ return; |
+ |
+ touches_end_ = index; |
+ tracked_touches_[index].valid = true; |
+ tracked_touches_[index].location = frame->fingers[slot].location; |
+ tracked_touches_[index].begin = frame->timestamp; |
+ tracked_touches_[index].end = frame->timestamp; |
+ tracked_touches_[index].slot = slot; |
+ tracked_slots_[slot] = index; |
+} |
+ |
+SinglePositionTouchNoiseFilter::SinglePositionTouchNoiseFilter::Touch::Touch() |
+ : valid(false), slot(0) { |
+} |
+ |
+SinglePositionTouchNoiseFilter::SinglePositionTouchNoiseFilter::Touch:: |
+ ~Touch() { |
+} |
+ |
+} // namespace ui |