blob: 1c770ae83950d72d937d0bbee47570a8b2f98ad5 [file] [log] [blame]
// Copyright 2018 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 "chromecast/graphics/triple_tap_detector.h"
#include "base/run_loop.h"
#include "base/test/simple_test_tick_clock.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "ui/aura/client/screen_position_client.h"
#include "ui/aura/test/aura_test_base.h"
#include "ui/aura/window.h"
#include "ui/events/event_utils.h"
#include "ui/events/gesture_detection/gesture_configuration.h"
#include "ui/events/test/event_generator.h"
#include "ui/events/test/events_test_utils.h"
#include "ui/wm/core/default_screen_position_client.h"
using testing::_;
using testing::Eq;
namespace chromecast {
namespace {
constexpr gfx::Point kTestTapLocation(50, 50);
constexpr int kTapLengthMs = 50;
} // namespace
class MockTripleTapDetectorDelegate : public TripleTapDetectorDelegate {
public:
~MockTripleTapDetectorDelegate() override = default;
MOCK_METHOD1(OnTripleTap, void(const gfx::Point&));
};
class TripleTapDetectorTest : public aura::test::AuraTestBase {
public:
~TripleTapDetectorTest() override = default;
void SetUp() override {
aura::test::AuraTestBase::SetUp();
screen_position_client_.reset(new wm::DefaultScreenPositionClient());
aura::client::SetScreenPositionClient(root_window(),
screen_position_client_.get());
triple_tap_delegate_ = std::make_unique<MockTripleTapDetectorDelegate>();
triple_tap_detector_ = std::make_unique<TripleTapDetector>(
root_window(), triple_tap_delegate_.get());
generator_.reset(new ui::test::EventGenerator(root_window()));
// Tests fail if time is ever 0.
simulated_clock_.Advance(base::TimeDelta::FromMilliseconds(10));
// ui takes ownership of the tick clock.
ui::SetEventTickClockForTesting(&simulated_clock_);
}
void TearDown() override {
triple_tap_detector_.reset();
aura::test::AuraTestBase::TearDown();
}
// Pause the minimum amount of tap to trigger a double tap.
void DoubleTapPause() {
simulated_clock_.Advance(gesture_detector_config_.double_tap_min_time);
}
// Pause just past the maximum amount of time to trigger a double tap.
void TooLongPause() {
simulated_clock_.Advance(gesture_detector_config_.double_tap_timeout);
simulated_clock_.Advance(base::TimeDelta::FromMilliseconds(1));
triple_tap_detector_->triple_tap_timer_.Stop();
triple_tap_detector_->OnTripleTapIntervalTimerFired();
}
// Simulate a tap event.
void Tap(const gfx::Point& tap_point) {
ui::TouchEvent press(
ui::ET_TOUCH_PRESSED, tap_point, simulated_clock_.NowTicks(),
ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH,
ui::PointerDetails::kUnknownPointerId));
generator_->Dispatch(&press);
simulated_clock_.Advance(base::TimeDelta::FromMilliseconds(kTapLengthMs));
ui::TouchEvent release(
ui::ET_TOUCH_RELEASED, tap_point, simulated_clock_.NowTicks(),
ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH,
ui::PointerDetails::kUnknownPointerId));
generator_->Dispatch(&release);
}
void Tap() { Tap(kTestTapLocation); }
TripleTapDetector& detector() { return *triple_tap_detector_; }
MockTripleTapDetectorDelegate& delegate() { return *triple_tap_delegate_; }
private:
ui::GestureDetector::Config gesture_detector_config_;
std::unique_ptr<aura::client::ScreenPositionClient> screen_position_client_;
std::unique_ptr<TripleTapDetector> triple_tap_detector_;
std::unique_ptr<MockTripleTapDetectorDelegate> triple_tap_delegate_;
base::SimpleTestTickClock simulated_clock_;
std::unique_ptr<ui::test::EventGenerator> generator_;
};
// Verify that a simple correct triple tap triggers the delegate.
TEST_F(TripleTapDetectorTest, TripleTap) {
EXPECT_CALL(delegate(), OnTripleTap(Eq(kTestTapLocation)));
detector().set_enabled(true);
Tap();
DoubleTapPause();
Tap();
DoubleTapPause();
Tap();
base::RunLoop run_loop;
run_loop.RunUntilIdle();
}
// Verify that no triple taps are detected when the detector is not enabled.
TEST_F(TripleTapDetectorTest, InactiveNoTriple) {
EXPECT_CALL(delegate(), OnTripleTap(Eq(kTestTapLocation))).Times(0);
Tap();
DoubleTapPause();
Tap();
DoubleTapPause();
Tap();
base::RunLoop run_loop;
run_loop.RunUntilIdle();
}
// Verify it's not a triple tap if the pause from the first tap to the second
// tap is too long.
TEST_F(TripleTapDetectorTest, FirstTapTooLong) {
EXPECT_CALL(delegate(), OnTripleTap(Eq(kTestTapLocation))).Times(0);
detector().set_enabled(true);
Tap();
TooLongPause();
Tap();
DoubleTapPause();
Tap();
base::RunLoop run_loop;
run_loop.RunUntilIdle();
}
// Verify it's not a triple tap if the pause from the second tap to the last tap
// is too long.
TEST_F(TripleTapDetectorTest, LastTapTooLong) {
EXPECT_CALL(delegate(), OnTripleTap(Eq(kTestTapLocation))).Times(0);
detector().set_enabled(true);
Tap();
DoubleTapPause();
Tap();
TooLongPause();
Tap();
base::RunLoop run_loop;
run_loop.RunUntilIdle();
}
} // namespace chromecast