Commit 57366e25 authored by Ryan Daum's avatar Ryan Daum Committed by Commit Bot

[chromecast] Make triple tap detector detect doubles, too.

A single detector for both multiple and triple tap events on cast, as
part of the effort so that the triple tap for the magnification
gesture and the double tap inside the TouchExplorationController do
not conflict.

Bug: internal b/112634029
Test: manual and unit test

Change-Id: Ifd23bbc40eb9cfd710acce7ca387eaae137c7ba1
Reviewed-on: https://chromium-review.googlesource.com/1178640Reviewed-by: default avatarAlex Sakhartchouk <alexst@chromium.org>
Commit-Queue: Ryan Daum <rdaum@chromium.org>
Cr-Commit-Position: refs/heads/master@{#584080}
parent 5b0fc0fb
...@@ -30,7 +30,8 @@ AccessibilityManager::AccessibilityManager( ...@@ -30,7 +30,8 @@ AccessibilityManager::AccessibilityManager(
root_window, activation_client, root_window, activation_client,
accessibility_focus_ring_controller_.get(), &accessibility_sound_proxy_, accessibility_focus_ring_controller_.get(), &accessibility_sound_proxy_,
window_manager->GetGestureHandler()); window_manager->GetGestureHandler());
triple_tap_detector_ = std::make_unique<TripleTapDetector>(root_window, this); magnify_gesture_detector_ =
std::make_unique<MultipleTapDetector>(root_window, this);
magnification_controller_ = magnification_controller_ =
std::make_unique<FullscreenMagnificationController>( std::make_unique<FullscreenMagnificationController>(
root_window, window_manager->GetGestureHandler()); root_window, window_manager->GetGestureHandler());
...@@ -99,7 +100,7 @@ aura::WindowTreeHost* AccessibilityManager::window_tree_host() const { ...@@ -99,7 +100,7 @@ aura::WindowTreeHost* AccessibilityManager::window_tree_host() const {
void AccessibilityManager::SetMagnificationGestureEnabled( void AccessibilityManager::SetMagnificationGestureEnabled(
bool gesture_enabled) { bool gesture_enabled) {
triple_tap_detector_->set_enabled(gesture_enabled); magnify_gesture_detector_->set_enabled(gesture_enabled);
// If the gesture is not enabled, make sure that magnification is turned off, // If the gesture is not enabled, make sure that magnification is turned off,
// in case we're already in magnification. Otherwise the user will be stuck in // in case we're already in magnification. Otherwise the user will be stuck in
...@@ -110,7 +111,7 @@ void AccessibilityManager::SetMagnificationGestureEnabled( ...@@ -110,7 +111,7 @@ void AccessibilityManager::SetMagnificationGestureEnabled(
} }
bool AccessibilityManager::IsMagnificationGestureEnabled() const { bool AccessibilityManager::IsMagnificationGestureEnabled() const {
return triple_tap_detector_->enabled(); return magnify_gesture_detector_->enabled();
} }
void AccessibilityManager::OnTripleTap(const gfx::Point& tap_location) { void AccessibilityManager::OnTripleTap(const gfx::Point& tap_location) {
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
#include "chromecast/browser/accessibility/accessibility_sound_proxy.h" #include "chromecast/browser/accessibility/accessibility_sound_proxy.h"
#include "chromecast/browser/accessibility/touch_exploration_manager.h" #include "chromecast/browser/accessibility/touch_exploration_manager.h"
#include "chromecast/graphics/accessibility/accessibility_focus_ring_controller.h" #include "chromecast/graphics/accessibility/accessibility_focus_ring_controller.h"
#include "chromecast/graphics/gestures/triple_tap_detector.h" #include "chromecast/graphics/gestures/multiple_tap_detector.h"
namespace aura { namespace aura {
class WindowTreeHost; class WindowTreeHost;
...@@ -27,7 +27,7 @@ namespace shell { ...@@ -27,7 +27,7 @@ namespace shell {
// Responsible for delegating chromecast browser process accessibility functions // Responsible for delegating chromecast browser process accessibility functions
// to the responsible party. // to the responsible party.
class AccessibilityManager : public TripleTapDetectorDelegate { class AccessibilityManager : public MultipleTapDetectorDelegate {
public: public:
explicit AccessibilityManager(CastWindowManagerAura* window_manager); explicit AccessibilityManager(CastWindowManagerAura* window_manager);
~AccessibilityManager() override; ~AccessibilityManager() override;
...@@ -73,7 +73,7 @@ class AccessibilityManager : public TripleTapDetectorDelegate { ...@@ -73,7 +73,7 @@ class AccessibilityManager : public TripleTapDetectorDelegate {
// Returns whether the magnification gesture is currently enabled. // Returns whether the magnification gesture is currently enabled.
bool IsMagnificationGestureEnabled() const; bool IsMagnificationGestureEnabled() const;
// TripleTapDetectorDelegate implementation // MultipleTapDetectorDelegate implementation
void OnTripleTap(const gfx::Point& tap_location) override; void OnTripleTap(const gfx::Point& tap_location) override;
// Sets the player for earcons. // Sets the player for earcons.
...@@ -87,7 +87,7 @@ class AccessibilityManager : public TripleTapDetectorDelegate { ...@@ -87,7 +87,7 @@ class AccessibilityManager : public TripleTapDetectorDelegate {
std::unique_ptr<AccessibilityFocusRingController> std::unique_ptr<AccessibilityFocusRingController>
accessibility_focus_ring_controller_; accessibility_focus_ring_controller_;
std::unique_ptr<TouchExplorationManager> touch_exploration_manager_; std::unique_ptr<TouchExplorationManager> touch_exploration_manager_;
std::unique_ptr<TripleTapDetector> triple_tap_detector_; std::unique_ptr<MultipleTapDetector> magnify_gesture_detector_;
std::unique_ptr<MagnificationController> magnification_controller_; std::unique_ptr<MagnificationController> magnification_controller_;
AccessibilitySoundProxy accessibility_sound_proxy_; AccessibilitySoundProxy accessibility_sound_proxy_;
......
...@@ -50,10 +50,10 @@ cast_source_set("graphics") { ...@@ -50,10 +50,10 @@ cast_source_set("graphics") {
"gestures/cast_system_gesture_dispatcher.h", "gestures/cast_system_gesture_dispatcher.h",
"gestures/cast_system_gesture_event_handler.cc", "gestures/cast_system_gesture_event_handler.cc",
"gestures/cast_system_gesture_event_handler.h", "gestures/cast_system_gesture_event_handler.h",
"gestures/multiple_tap_detector.cc",
"gestures/multiple_tap_detector.h",
"gestures/side_swipe_detector.cc", "gestures/side_swipe_detector.cc",
"gestures/side_swipe_detector.h", "gestures/side_swipe_detector.h",
"gestures/triple_tap_detector.cc",
"gestures/triple_tap_detector.h",
] ]
deps += [ deps += [
...@@ -116,8 +116,8 @@ if (use_aura && !is_cast_audio_only) { ...@@ -116,8 +116,8 @@ if (use_aura && !is_cast_audio_only) {
"cast_focus_client_aura_test.cc", "cast_focus_client_aura_test.cc",
"cast_views_test.cc", "cast_views_test.cc",
"cast_window_manager_aura_test.cc", "cast_window_manager_aura_test.cc",
"gestures/multiple_tap_detector_test.cc",
"gestures/side_swipe_detector_test.cc", "gestures/side_swipe_detector_test.cc",
"gestures/triple_tap_detector_test.cc",
"run_all_unittests.cc", "run_all_unittests.cc",
] ]
deps = [ deps = [
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "chromecast/graphics/gestures/triple_tap_detector.h" #include "chromecast/graphics/gestures/multiple_tap_detector.h"
#include "base/auto_reset.h" #include "base/auto_reset.h"
#include "base/logging.h" #include "base/logging.h"
...@@ -15,21 +15,39 @@ ...@@ -15,21 +15,39 @@
namespace chromecast { namespace chromecast {
TripleTapDetector::TripleTapDetector(aura::Window* root_window, namespace {
TripleTapDetectorDelegate* delegate)
std::unique_ptr<ui::TouchEvent> MakeCancelEvent(
const base::TimeTicks& time_stamp,
const ui::TouchEvent& stashed_press) {
std::unique_ptr<ui::TouchEvent> rewritten_touch_event =
std::make_unique<ui::TouchEvent>(ui::ET_TOUCH_CANCELLED, gfx::Point(),
time_stamp,
stashed_press.pointer_details());
rewritten_touch_event->set_location_f(stashed_press.location_f());
rewritten_touch_event->set_root_location_f(stashed_press.root_location_f());
rewritten_touch_event->set_flags(stashed_press.flags());
return rewritten_touch_event;
}
} // namespace
MultipleTapDetector::MultipleTapDetector(aura::Window* root_window,
MultipleTapDetectorDelegate* delegate)
: root_window_(root_window), : root_window_(root_window),
delegate_(delegate), delegate_(delegate),
enabled_(false), enabled_(false),
triple_tap_state_(TripleTapState::NONE), tap_state_(MultiTapState::NONE),
tap_count_(0) { tap_count_(0) {
root_window->GetHost()->GetEventSource()->AddEventRewriter(this); root_window->GetHost()->GetEventSource()->AddEventRewriter(this);
} }
TripleTapDetector::~TripleTapDetector() { MultipleTapDetector::~MultipleTapDetector() {
root_window_->GetHost()->GetEventSource()->RemoveEventRewriter(this); root_window_->GetHost()->GetEventSource()->RemoveEventRewriter(this);
} }
ui::EventRewriteStatus TripleTapDetector::RewriteEvent( ui::EventRewriteStatus MultipleTapDetector::RewriteEvent(
const ui::Event& event, const ui::Event& event,
std::unique_ptr<ui::Event>* rewritten_event) { std::unique_ptr<ui::Event>* rewritten_event) {
if (!enabled_ || !delegate_ || !event.IsTouchEvent()) { if (!enabled_ || !delegate_ || !event.IsTouchEvent()) {
...@@ -39,35 +57,35 @@ ui::EventRewriteStatus TripleTapDetector::RewriteEvent( ...@@ -39,35 +57,35 @@ ui::EventRewriteStatus TripleTapDetector::RewriteEvent(
const ui::TouchEvent& touch_event = static_cast<const ui::TouchEvent&>(event); const ui::TouchEvent& touch_event = static_cast<const ui::TouchEvent&>(event);
if (event.type() == ui::ET_TOUCH_PRESSED) { if (event.type() == ui::ET_TOUCH_PRESSED) {
// If a press happened again before the minimum inter-tap interval, cancel // If a press happened again before the minimum inter-tap interval, cancel
// the triple tap. // the detection.
if (triple_tap_state_ == TripleTapState::INTERVAL_WAIT && if (tap_state_ == MultiTapState::INTERVAL_WAIT &&
(event.time_stamp() - stashed_events_.back().time_stamp()) < (event.time_stamp() - stashed_events_.back().time_stamp()) <
gesture_detector_config_.double_tap_min_time) { gesture_detector_config_.double_tap_min_time) {
stashed_events_.clear(); stashed_events_.clear();
TripleTapReset(); TapDetectorStateReset();
return ui::EVENT_REWRITE_CONTINUE; return ui::EVENT_REWRITE_CONTINUE;
} }
// If the user moved too far from the last tap position, it's not a triple // If the user moved too far from the last tap position, it's not a multi
// tap. // tap.
if (tap_count_) { if (tap_count_) {
float distance = (touch_event.location() - last_tap_location_).Length(); float distance = (touch_event.location() - last_tap_location_).Length();
if (distance > gesture_detector_config_.double_tap_slop) { if (distance > gesture_detector_config_.double_tap_slop) {
TripleTapReset(); TapDetectorStateReset();
stashed_events_.clear(); stashed_events_.clear();
return ui::EVENT_REWRITE_CONTINUE; return ui::EVENT_REWRITE_CONTINUE;
} }
} }
// Otherwise transition into a touched state. // Otherwise transition into a touched state.
triple_tap_state_ = TripleTapState::TOUCH; tap_state_ = MultiTapState::TOUCH;
last_tap_location_ = touch_event.location(); last_tap_location_ = touch_event.location();
// If this is pressed too long, it should be treated as a long-press, and // If this is pressed too long, it should be treated as a long-press, and
// not part of a triple-tap, so set a timer to detect that. // not part of a triple-tap, so set a timer to detect that.
triple_tap_timer_.Start(FROM_HERE, triple_tap_timer_.Start(
gesture_detector_config_.longpress_timeout, this, FROM_HERE, gesture_detector_config_.longpress_timeout, this,
&TripleTapDetector::OnLongPressIntervalTimerFired); &MultipleTapDetector::OnLongPressIntervalTimerFired);
// If we've already gotten one tap, discard this event, only the original // If we've already gotten one tap, discard this event, only the original
// tap needs to get through. // tap needs to get through.
...@@ -76,7 +94,7 @@ ui::EventRewriteStatus TripleTapDetector::RewriteEvent( ...@@ -76,7 +94,7 @@ ui::EventRewriteStatus TripleTapDetector::RewriteEvent(
} }
// Copy the event so we can issue a cancel for it later if this turns out to // Copy the event so we can issue a cancel for it later if this turns out to
// be a triple-tap. // be a multi-tap.
stashed_events_.push_back(touch_event); stashed_events_.push_back(touch_event);
return ui::EVENT_REWRITE_CONTINUE; return ui::EVENT_REWRITE_CONTINUE;
...@@ -84,29 +102,21 @@ ui::EventRewriteStatus TripleTapDetector::RewriteEvent( ...@@ -84,29 +102,21 @@ ui::EventRewriteStatus TripleTapDetector::RewriteEvent(
// Finger was released while we were waiting for one, count it as a tap. // Finger was released while we were waiting for one, count it as a tap.
if (touch_event.type() == ui::ET_TOUCH_RELEASED && if (touch_event.type() == ui::ET_TOUCH_RELEASED &&
triple_tap_state_ == TripleTapState::TOUCH) { tap_state_ == MultiTapState::TOUCH) {
triple_tap_state_ = TripleTapState::INTERVAL_WAIT; tap_state_ = MultiTapState::INTERVAL_WAIT;
triple_tap_timer_.Start(FROM_HERE, triple_tap_timer_.Start(FROM_HERE,
gesture_detector_config_.double_tap_timeout, this, gesture_detector_config_.double_tap_timeout, this,
&TripleTapDetector::OnTripleTapIntervalTimerFired); &MultipleTapDetector::OnTapIntervalTimerFired);
tap_count_++; tap_count_++;
if (tap_count_ == 3) { if (tap_count_ == 3) {
TripleTapReset(); TapDetectorStateReset();
delegate_->OnTripleTap(touch_event.location()); delegate_->OnTripleTap(touch_event.location());
// Start issuing cancel events for old presses. // Start issuing cancel events for old presses.
DCHECK(!stashed_events_.empty()); DCHECK(!stashed_events_.empty());
const auto& stashed_press = stashed_events_.front(); *rewritten_event =
std::unique_ptr<ui::TouchEvent> rewritten_touch_event = MakeCancelEvent(touch_event.time_stamp(), stashed_events_.front());
std::make_unique<ui::TouchEvent>(ui::ET_TOUCH_CANCELLED, gfx::Point(),
touch_event.time_stamp(),
stashed_press.pointer_details());
rewritten_touch_event->set_location_f(stashed_press.location_f());
rewritten_touch_event->set_root_location_f(
stashed_press.root_location_f());
rewritten_touch_event->set_flags(stashed_press.flags());
*rewritten_event = std::move(rewritten_touch_event);
stashed_events_.pop_front(); stashed_events_.pop_front();
if (!stashed_events_.empty()) if (!stashed_events_.empty())
...@@ -121,18 +131,11 @@ ui::EventRewriteStatus TripleTapDetector::RewriteEvent( ...@@ -121,18 +131,11 @@ ui::EventRewriteStatus TripleTapDetector::RewriteEvent(
return ui::EVENT_REWRITE_CONTINUE; return ui::EVENT_REWRITE_CONTINUE;
} }
ui::EventRewriteStatus TripleTapDetector::NextDispatchEvent( ui::EventRewriteStatus MultipleTapDetector::NextDispatchEvent(
const ui::Event& last_event, const ui::Event& last_event,
std::unique_ptr<ui::Event>* new_event) { std::unique_ptr<ui::Event>* new_event) {
const auto& stashed_press = stashed_events_.front(); *new_event =
std::unique_ptr<ui::TouchEvent> rewritten_touch_event = MakeCancelEvent(last_event.time_stamp(), stashed_events_.front());
std::make_unique<ui::TouchEvent>(ui::ET_TOUCH_CANCELLED, gfx::Point(),
last_event.time_stamp(),
stashed_press.pointer_details());
rewritten_touch_event->set_location_f(stashed_press.location_f());
rewritten_touch_event->set_root_location_f(stashed_press.root_location_f());
rewritten_touch_event->set_flags(stashed_press.flags());
*new_event = std::move(rewritten_touch_event);
stashed_events_.pop_front(); stashed_events_.pop_front();
if (!stashed_events_.empty()) if (!stashed_events_.empty())
...@@ -141,20 +144,43 @@ ui::EventRewriteStatus TripleTapDetector::NextDispatchEvent( ...@@ -141,20 +144,43 @@ ui::EventRewriteStatus TripleTapDetector::NextDispatchEvent(
return ui::EVENT_REWRITE_DISCARD; return ui::EVENT_REWRITE_DISCARD;
} }
void TripleTapDetector::OnTripleTapIntervalTimerFired() { void MultipleTapDetector::OnTapIntervalTimerFired() {
TripleTapReset(); // We didn't quite reach a third tap, but a second was reached.
// So call out the double-tap.
if (tap_count_ == 2) {
delegate_->OnDoubleTap(last_tap_location_);
// Unfortunately we cannot NextDispatchEvent to issue a cancel on the second
// tap, so we have to manually DispatchEvent to the EventSource.
// Subsequent EventRewriters in the chain will not see the event.
if (!stashed_events_.empty()) {
std::unique_ptr<ui::TouchEvent> cancel_event =
MakeCancelEvent(base::TimeTicks::Now(), stashed_events_.front());
DispatchEvent(cancel_event.get());
}
}
TapDetectorStateReset();
stashed_events_.clear(); stashed_events_.clear();
} }
void TripleTapDetector::OnLongPressIntervalTimerFired() { void MultipleTapDetector::OnLongPressIntervalTimerFired() {
TripleTapReset(); TapDetectorStateReset();
stashed_events_.clear(); stashed_events_.clear();
} }
void TripleTapDetector::TripleTapReset() { void MultipleTapDetector::TapDetectorStateReset() {
triple_tap_state_ = TripleTapState::NONE; tap_state_ = MultiTapState::NONE;
tap_count_ = 0; tap_count_ = 0;
triple_tap_timer_.Stop(); triple_tap_timer_.Stop();
} }
void MultipleTapDetector::DispatchEvent(ui::TouchEvent* event) {
// Turn off triple-tap before re-dispatching to avoid infinite recursion into
// this detector.
base::AutoReset<bool> toggle_enable(&enabled_, false);
DCHECK(!root_window_->GetHost()
->dispatcher()
->OnEventFromSource(event)
.dispatcher_destroyed);
}
} // namespace chromecast } // namespace chromecast
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#ifndef CHROMECAST_GRAPHICS_GESTURES_TRIPLE_TAP_DETECTOR_H_ #ifndef CHROMECAST_GRAPHICS_GESTURES_MULTIPLE_TAP_DETECTOR_H_
#define CHROMECAST_GRAPHICS_GESTURES_TRIPLE_TAP_DETECTOR_H_ #define CHROMECAST_GRAPHICS_GESTURES_MULTIPLE_TAP_DETECTOR_H_
#include <deque> #include <deque>
...@@ -28,25 +28,26 @@ class TouchEvent; ...@@ -28,25 +28,26 @@ class TouchEvent;
namespace chromecast { namespace chromecast {
class TripleTapDetectorDelegate { class MultipleTapDetectorDelegate {
public: public:
virtual ~TripleTapDetectorDelegate() = default; virtual ~MultipleTapDetectorDelegate() = default;
virtual void OnTripleTap(const gfx::Point& touch_location) = 0; virtual void OnTripleTap(const gfx::Point& touch_location) = 0;
virtual void OnDoubleTap(const gfx::Point& touch_location) {}
}; };
enum class TripleTapState { enum class MultiTapState {
NONE, NONE,
TOUCH, TOUCH,
INTERVAL_WAIT, INTERVAL_WAIT,
}; };
// An event rewriter responsible for detecting triple-tap events on the root // An event rewriter responsible for detecting triple-tap or double-tap events
// window. // on the root window.
class TripleTapDetector : public ui::EventRewriter { class MultipleTapDetector : public ui::EventRewriter {
public: public:
TripleTapDetector(aura::Window* root_window, MultipleTapDetector(aura::Window* root_window,
TripleTapDetectorDelegate* delegate); MultipleTapDetectorDelegate* delegate);
~TripleTapDetector() override; ~MultipleTapDetector() override;
void set_enabled(bool enabled) { enabled_ = enabled; } void set_enabled(bool enabled) { enabled_ = enabled; }
bool enabled() const { return enabled_; } bool enabled() const { return enabled_; }
...@@ -60,33 +61,34 @@ class TripleTapDetector : public ui::EventRewriter { ...@@ -60,33 +61,34 @@ class TripleTapDetector : public ui::EventRewriter {
std::unique_ptr<ui::Event>* new_event) override; std::unique_ptr<ui::Event>* new_event) override;
private: private:
friend class TripleTapDetectorTest; friend class MultipleTapDetectorTest;
// Expiration event for maximum time between taps in a triple tap. // Expiration event for maximum time between taps in a tap.
void OnTripleTapIntervalTimerFired(); void OnTapIntervalTimerFired();
// Expiration event for a finger that is pressed too long during a triple tap. // Expiration event for a finger that is pressed too long during a multi tap.
void OnLongPressIntervalTimerFired(); void OnLongPressIntervalTimerFired();
void TapDetectorStateReset();
void TripleTapReset(); void DispatchEvent(ui::TouchEvent* event);
// A default gesture detector config, so we can share the same // A default gesture detector config, so we can share the same
// timeout and pixel slop constants. // timeout and pixel slop constants.
ui::GestureDetector::Config gesture_detector_config_; ui::GestureDetector::Config gesture_detector_config_;
aura::Window* root_window_; aura::Window* root_window_;
TripleTapDetectorDelegate* delegate_; MultipleTapDetectorDelegate* delegate_;
bool enabled_; bool enabled_;
TripleTapState triple_tap_state_; MultiTapState tap_state_;
int tap_count_; int tap_count_;
gfx::Point last_tap_location_; gfx::Point last_tap_location_;
base::OneShotTimer triple_tap_timer_; base::OneShotTimer triple_tap_timer_;
std::deque<ui::TouchEvent> stashed_events_; std::deque<ui::TouchEvent> stashed_events_;
DISALLOW_COPY_AND_ASSIGN(TripleTapDetector); DISALLOW_COPY_AND_ASSIGN(MultipleTapDetector);
}; };
} // namespace chromecast } // namespace chromecast
#endif // CHROMECAST_GRAPHICS_GESTURES_TRIPLE_TAP_DETECTOR_H_ #endif // CHROMECAST_GRAPHICS_GESTURES_MULTIPLE_TAP_DETECTOR_H_
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "chromecast/graphics/gestures/triple_tap_detector.h" #include "chromecast/graphics/gestures/multiple_tap_detector.h"
#include "base/run_loop.h" #include "base/run_loop.h"
#include "base/test/simple_test_tick_clock.h" #include "base/test/simple_test_tick_clock.h"
...@@ -26,15 +26,16 @@ constexpr gfx::Point kTestTapLocation(50, 50); ...@@ -26,15 +26,16 @@ constexpr gfx::Point kTestTapLocation(50, 50);
constexpr int kTapLengthMs = 50; constexpr int kTapLengthMs = 50;
} // namespace } // namespace
class MockTripleTapDetectorDelegate : public TripleTapDetectorDelegate { class MockMultipleTapDetectorDelegate : public MultipleTapDetectorDelegate {
public: public:
~MockTripleTapDetectorDelegate() override = default; ~MockMultipleTapDetectorDelegate() override = default;
MOCK_METHOD1(OnTripleTap, void(const gfx::Point&)); MOCK_METHOD1(OnTripleTap, void(const gfx::Point&));
MOCK_METHOD1(OnDoubleTap, void(const gfx::Point&));
}; };
class TripleTapDetectorTest : public aura::test::AuraTestBase { class MultipleTapDetectorTest : public aura::test::AuraTestBase {
public: public:
~TripleTapDetectorTest() override = default; ~MultipleTapDetectorTest() override = default;
void SetUp() override { void SetUp() override {
aura::test::AuraTestBase::SetUp(); aura::test::AuraTestBase::SetUp();
...@@ -43,8 +44,8 @@ class TripleTapDetectorTest : public aura::test::AuraTestBase { ...@@ -43,8 +44,8 @@ class TripleTapDetectorTest : public aura::test::AuraTestBase {
aura::client::SetScreenPositionClient(root_window(), aura::client::SetScreenPositionClient(root_window(),
screen_position_client_.get()); screen_position_client_.get());
triple_tap_delegate_ = std::make_unique<MockTripleTapDetectorDelegate>(); triple_tap_delegate_ = std::make_unique<MockMultipleTapDetectorDelegate>();
triple_tap_detector_ = std::make_unique<TripleTapDetector>( triple_tap_detector_ = std::make_unique<MultipleTapDetector>(
root_window(), triple_tap_delegate_.get()); root_window(), triple_tap_delegate_.get());
generator_.reset(new ui::test::EventGenerator(root_window())); generator_.reset(new ui::test::EventGenerator(root_window()));
...@@ -70,7 +71,7 @@ class TripleTapDetectorTest : public aura::test::AuraTestBase { ...@@ -70,7 +71,7 @@ class TripleTapDetectorTest : public aura::test::AuraTestBase {
simulated_clock_.Advance(gesture_detector_config_.double_tap_timeout); simulated_clock_.Advance(gesture_detector_config_.double_tap_timeout);
simulated_clock_.Advance(base::TimeDelta::FromMilliseconds(1)); simulated_clock_.Advance(base::TimeDelta::FromMilliseconds(1));
triple_tap_detector_->triple_tap_timer_.Stop(); triple_tap_detector_->triple_tap_timer_.Stop();
triple_tap_detector_->OnTripleTapIntervalTimerFired(); triple_tap_detector_->OnTapIntervalTimerFired();
} }
// Simulate a tap event. // Simulate a tap event.
...@@ -90,23 +91,25 @@ class TripleTapDetectorTest : public aura::test::AuraTestBase { ...@@ -90,23 +91,25 @@ class TripleTapDetectorTest : public aura::test::AuraTestBase {
void Tap() { Tap(kTestTapLocation); } void Tap() { Tap(kTestTapLocation); }
TripleTapDetector& detector() { return *triple_tap_detector_; } MultipleTapDetector& detector() { return *triple_tap_detector_; }
MockTripleTapDetectorDelegate& delegate() { return *triple_tap_delegate_; } MockMultipleTapDetectorDelegate& delegate() { return *triple_tap_delegate_; }
private: private:
ui::GestureDetector::Config gesture_detector_config_; ui::GestureDetector::Config gesture_detector_config_;
std::unique_ptr<aura::client::ScreenPositionClient> screen_position_client_; std::unique_ptr<aura::client::ScreenPositionClient> screen_position_client_;
std::unique_ptr<TripleTapDetector> triple_tap_detector_; std::unique_ptr<MultipleTapDetector> triple_tap_detector_;
std::unique_ptr<MockTripleTapDetectorDelegate> triple_tap_delegate_; std::unique_ptr<MockMultipleTapDetectorDelegate> triple_tap_delegate_;
base::SimpleTestTickClock simulated_clock_; base::SimpleTestTickClock simulated_clock_;
std::unique_ptr<ui::test::EventGenerator> generator_; std::unique_ptr<ui::test::EventGenerator> generator_;
}; };
// Verify that a simple correct triple tap triggers the delegate. // Verify that a simple correct triple tap triggers the delegate.
TEST_F(TripleTapDetectorTest, TripleTap) { TEST_F(MultipleTapDetectorTest, TripleTap) {
EXPECT_CALL(delegate(), OnTripleTap(Eq(kTestTapLocation))); EXPECT_CALL(delegate(), OnTripleTap(Eq(kTestTapLocation))).Times(1);
;
EXPECT_CALL(delegate(), OnDoubleTap(Eq(kTestTapLocation))).Times(0);
detector().set_enabled(true); detector().set_enabled(true);
...@@ -120,10 +123,27 @@ TEST_F(TripleTapDetectorTest, TripleTap) { ...@@ -120,10 +123,27 @@ TEST_F(TripleTapDetectorTest, TripleTap) {
run_loop.RunUntilIdle(); run_loop.RunUntilIdle();
} }
// Verify that no triple taps are detected when the detector is not enabled. // Verify double tap when there's two taps then a pause past our double tap
TEST_F(TripleTapDetectorTest, InactiveNoTriple) { // interval.
TEST_F(MultipleTapDetectorTest, DoubleTap) {
EXPECT_CALL(delegate(), OnTripleTap(Eq(kTestTapLocation))).Times(0); EXPECT_CALL(delegate(), OnTripleTap(Eq(kTestTapLocation))).Times(0);
EXPECT_CALL(delegate(), OnDoubleTap(Eq(kTestTapLocation))).Times(1);
detector().set_enabled(true);
Tap();
DoubleTapPause();
Tap();
TooLongPause();
base::RunLoop run_loop;
run_loop.RunUntilIdle();
}
// Verify that no multi taps are detected when the detector is not enabled.
TEST_F(MultipleTapDetectorTest, Inactive) {
EXPECT_CALL(delegate(), OnTripleTap(Eq(kTestTapLocation))).Times(0);
EXPECT_CALL(delegate(), OnDoubleTap(Eq(kTestTapLocation))).Times(0);
Tap(); Tap();
DoubleTapPause(); DoubleTapPause();
Tap(); Tap();
...@@ -134,10 +154,11 @@ TEST_F(TripleTapDetectorTest, InactiveNoTriple) { ...@@ -134,10 +154,11 @@ TEST_F(TripleTapDetectorTest, InactiveNoTriple) {
run_loop.RunUntilIdle(); run_loop.RunUntilIdle();
} }
// Verify it's not a triple tap if the pause from the first tap to the second // Verify it's not a multi tap of any kind if the pause from the first tap to
// tap is too long. // the second tap is too long.
TEST_F(TripleTapDetectorTest, FirstTapTooLong) { TEST_F(MultipleTapDetectorTest, FirstTapTooLong) {
EXPECT_CALL(delegate(), OnTripleTap(Eq(kTestTapLocation))).Times(0); EXPECT_CALL(delegate(), OnTripleTap(Eq(kTestTapLocation))).Times(0);
EXPECT_CALL(delegate(), OnDoubleTap(Eq(kTestTapLocation))).Times(0);
detector().set_enabled(true); detector().set_enabled(true);
...@@ -151,10 +172,11 @@ TEST_F(TripleTapDetectorTest, FirstTapTooLong) { ...@@ -151,10 +172,11 @@ TEST_F(TripleTapDetectorTest, FirstTapTooLong) {
run_loop.RunUntilIdle(); run_loop.RunUntilIdle();
} }
// Verify it's not a triple tap if the pause from the second tap to the last tap // Verify it's not a triple tap but instead a doubletap if the pause from the
// is too long. // second tap to the last tap is too long.
TEST_F(TripleTapDetectorTest, LastTapTooLong) { TEST_F(MultipleTapDetectorTest, LastTapTooLongIsDoubleTap) {
EXPECT_CALL(delegate(), OnTripleTap(Eq(kTestTapLocation))).Times(0); EXPECT_CALL(delegate(), OnTripleTap(Eq(kTestTapLocation))).Times(0);
EXPECT_CALL(delegate(), OnDoubleTap(Eq(kTestTapLocation))).Times(1);
detector().set_enabled(true); detector().set_enabled(true);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment