1558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// Copyright 2013 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch#include "content/browser/renderer_host/input/tap_suppression_controller.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/debug/trace_event.h"
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h"
9558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch#include "content/browser/renderer_host/input/tap_suppression_controller_client.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace content {
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)TapSuppressionController::Config::Config()
14010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    : enabled(false),
15010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      max_cancel_to_down_time(base::TimeDelta::FromMilliseconds(180)),
16010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      max_tap_gap_time(base::TimeDelta::FromMilliseconds(500)) {
17010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
18010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TapSuppressionController::TapSuppressionController(
20010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    TapSuppressionControllerClient* client,
21010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    const Config& config)
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : client_(client),
23010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      state_(config.enabled ? NOTHING : DISABLED),
24010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      max_cancel_to_down_time_(config.max_cancel_to_down_time),
25010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      max_tap_gap_time_(config.max_tap_gap_time) {
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TapSuppressionController::~TapSuppressionController() {}
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TapSuppressionController::GestureFlingCancel() {
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  switch (state_) {
32010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    case DISABLED:
33010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      break;
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case NOTHING:
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case GFC_IN_PROGRESS:
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case LAST_CANCEL_STOPPED_FLING:
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      state_ = GFC_IN_PROGRESS;
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case TAP_DOWN_STASHED:
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TapSuppressionController::GestureFlingCancelAck(bool processed) {
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::TimeTicks event_time = Now();
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  switch (state_) {
47010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    case DISABLED:
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case NOTHING:
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case GFC_IN_PROGRESS:
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (processed)
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        fling_cancel_time_ = event_time;
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      state_ = LAST_CANCEL_STOPPED_FLING;
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case TAP_DOWN_STASHED:
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (!processed) {
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        TRACE_EVENT0("browser",
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                     "TapSuppressionController::GestureFlingCancelAck");
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        StopTapDownTimer();
601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        client_->ForwardStashedTapDown();
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        state_ = NOTHING;
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }  // Else waiting for the timer to release the stashed tap down.
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case LAST_CANCEL_STOPPED_FLING:
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool TapSuppressionController::ShouldDeferTapDown() {
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::TimeTicks event_time = Now();
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  switch (state_) {
72010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    case DISABLED:
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case NOTHING:
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case GFC_IN_PROGRESS:
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      state_ = TAP_DOWN_STASHED;
77010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      StartTapDownTimer(max_tap_gap_time_);
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return true;
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case TAP_DOWN_STASHED:
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      NOTREACHED() << "TapDown on TAP_DOWN_STASHED state";
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      state_ = NOTHING;
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case LAST_CANCEL_STOPPED_FLING:
84010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      if ((event_time - fling_cancel_time_) < max_cancel_to_down_time_) {
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        state_ = TAP_DOWN_STASHED;
86010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        StartTapDownTimer(max_tap_gap_time_);
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return true;
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      } else {
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        state_ = NOTHING;
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return false;
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  NOTREACHED() << "Invalid state";
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return false;
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
97f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool TapSuppressionController::ShouldSuppressTapEnd() {
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  switch (state_) {
99010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    case DISABLED:
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case NOTHING:
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case GFC_IN_PROGRESS:
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case TAP_DOWN_STASHED:
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      state_ = NOTHING;
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      StopTapDownTimer();
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      client_->DropStashedTapDown();
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return true;
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case LAST_CANCEL_STOPPED_FLING:
109f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      NOTREACHED() << "Invalid tap end on LAST_CANCEL_STOPPED_FLING state";
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::TimeTicks TapSuppressionController::Now() {
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return base::TimeTicks::Now();
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TapSuppressionController::StartTapDownTimer(const base::TimeDelta& delay) {
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  tap_down_timer_.Start(FROM_HERE, delay, this,
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        &TapSuppressionController::TapDownTimerExpired);
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TapSuppressionController::StopTapDownTimer() {
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  tap_down_timer_.Stop();
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TapSuppressionController::TapDownTimerExpired() {
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  switch (state_) {
129010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    case DISABLED:
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case NOTHING:
131010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      NOTREACHED() << "Timer fired on invalid state.";
132010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      break;
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case GFC_IN_PROGRESS:
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case LAST_CANCEL_STOPPED_FLING:
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      NOTREACHED() << "Timer fired on invalid state.";
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      state_ = NOTHING;
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case TAP_DOWN_STASHED:
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      TRACE_EVENT0("browser",
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   "TapSuppressionController::TapDownTimerExpired");
1411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      client_->ForwardStashedTapDown();
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      state_ = NOTHING;
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace content
148