1// Copyright 2013 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 "content/browser/renderer_host/input/tap_suppression_controller.h" 6 7#include "base/debug/trace_event.h" 8#include "base/logging.h" 9#include "content/browser/renderer_host/input/tap_suppression_controller_client.h" 10 11namespace content { 12 13TapSuppressionController::Config::Config() 14 : enabled(false), 15 max_cancel_to_down_time(base::TimeDelta::FromMilliseconds(180)), 16 max_tap_gap_time(base::TimeDelta::FromMilliseconds(500)) { 17} 18 19TapSuppressionController::TapSuppressionController( 20 TapSuppressionControllerClient* client, 21 const Config& config) 22 : client_(client), 23 state_(config.enabled ? NOTHING : DISABLED), 24 max_cancel_to_down_time_(config.max_cancel_to_down_time), 25 max_tap_gap_time_(config.max_tap_gap_time) { 26} 27 28TapSuppressionController::~TapSuppressionController() {} 29 30void TapSuppressionController::GestureFlingCancel() { 31 switch (state_) { 32 case DISABLED: 33 break; 34 case NOTHING: 35 case GFC_IN_PROGRESS: 36 case LAST_CANCEL_STOPPED_FLING: 37 state_ = GFC_IN_PROGRESS; 38 break; 39 case TAP_DOWN_STASHED: 40 break; 41 } 42} 43 44void TapSuppressionController::GestureFlingCancelAck(bool processed) { 45 base::TimeTicks event_time = Now(); 46 switch (state_) { 47 case DISABLED: 48 case NOTHING: 49 break; 50 case GFC_IN_PROGRESS: 51 if (processed) 52 fling_cancel_time_ = event_time; 53 state_ = LAST_CANCEL_STOPPED_FLING; 54 break; 55 case TAP_DOWN_STASHED: 56 if (!processed) { 57 TRACE_EVENT0("browser", 58 "TapSuppressionController::GestureFlingCancelAck"); 59 StopTapDownTimer(); 60 client_->ForwardStashedTapDown(); 61 state_ = NOTHING; 62 } // Else waiting for the timer to release the stashed tap down. 63 break; 64 case LAST_CANCEL_STOPPED_FLING: 65 break; 66 } 67} 68 69bool TapSuppressionController::ShouldDeferTapDown() { 70 base::TimeTicks event_time = Now(); 71 switch (state_) { 72 case DISABLED: 73 case NOTHING: 74 return false; 75 case GFC_IN_PROGRESS: 76 state_ = TAP_DOWN_STASHED; 77 StartTapDownTimer(max_tap_gap_time_); 78 return true; 79 case TAP_DOWN_STASHED: 80 NOTREACHED() << "TapDown on TAP_DOWN_STASHED state"; 81 state_ = NOTHING; 82 return false; 83 case LAST_CANCEL_STOPPED_FLING: 84 if ((event_time - fling_cancel_time_) < max_cancel_to_down_time_) { 85 state_ = TAP_DOWN_STASHED; 86 StartTapDownTimer(max_tap_gap_time_); 87 return true; 88 } else { 89 state_ = NOTHING; 90 return false; 91 } 92 } 93 NOTREACHED() << "Invalid state"; 94 return false; 95} 96 97bool TapSuppressionController::ShouldSuppressTapEnd() { 98 switch (state_) { 99 case DISABLED: 100 case NOTHING: 101 case GFC_IN_PROGRESS: 102 return false; 103 case TAP_DOWN_STASHED: 104 state_ = NOTHING; 105 StopTapDownTimer(); 106 client_->DropStashedTapDown(); 107 return true; 108 case LAST_CANCEL_STOPPED_FLING: 109 NOTREACHED() << "Invalid tap end on LAST_CANCEL_STOPPED_FLING state"; 110 } 111 return false; 112} 113 114base::TimeTicks TapSuppressionController::Now() { 115 return base::TimeTicks::Now(); 116} 117 118void TapSuppressionController::StartTapDownTimer(const base::TimeDelta& delay) { 119 tap_down_timer_.Start(FROM_HERE, delay, this, 120 &TapSuppressionController::TapDownTimerExpired); 121} 122 123void TapSuppressionController::StopTapDownTimer() { 124 tap_down_timer_.Stop(); 125} 126 127void TapSuppressionController::TapDownTimerExpired() { 128 switch (state_) { 129 case DISABLED: 130 case NOTHING: 131 NOTREACHED() << "Timer fired on invalid state."; 132 break; 133 case GFC_IN_PROGRESS: 134 case LAST_CANCEL_STOPPED_FLING: 135 NOTREACHED() << "Timer fired on invalid state."; 136 state_ = NOTHING; 137 break; 138 case TAP_DOWN_STASHED: 139 TRACE_EVENT0("browser", 140 "TapSuppressionController::TapDownTimerExpired"); 141 client_->ForwardStashedTapDown(); 142 state_ = NOTHING; 143 break; 144 } 145} 146 147} // namespace content 148