chromium/ios/web/web_state/user_interaction_state.mm

// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#import "ios/web/web_state/user_interaction_state.h"

#import "base/time/time.h"

namespace {
// The duration of the period following a screen touch during which the user is
// still considered to be interacting with the page.
constexpr base::TimeDelta kMaximumDelayForUserInteraction = base::Seconds(2);
}

namespace web {

UserInteractionState::UserInteractionState()
    : user_interaction_registered_since_page_loaded_(false),
      user_interaction_registered_since_last_url_change_(false),
      user_interaction_registered_since_web_view_created_(false),
      tap_in_progress_(false),
      last_user_interaction_(nullptr) {}

UserInteractionState::~UserInteractionState() {}

bool UserInteractionState::UserInteractionRegisteredSincePageLoaded() const {
  return user_interaction_registered_since_page_loaded_;
}

void UserInteractionState::SetUserInteractionRegisteredSincePageLoaded(
    bool user_interaction_registered_since_page_loaded) {
  user_interaction_registered_since_page_loaded_ =
      user_interaction_registered_since_page_loaded;
  if (user_interaction_registered_since_page_loaded) {
    user_interaction_registered_since_last_url_change_ = true;
    user_interaction_registered_since_web_view_created_ = true;
  }
}

bool UserInteractionState::UserInteractionRegisteredSinceLastUrlChange() const {
  return user_interaction_registered_since_last_url_change_;
}

void UserInteractionState::SetUserInteractionRegisteredSinceLastUrlChange(
    bool user_interaction_registered_since_last_url_change) {
  user_interaction_registered_since_last_url_change_ =
      user_interaction_registered_since_last_url_change;
  if (user_interaction_registered_since_last_url_change) {
    user_interaction_registered_since_web_view_created_ = true;
  }
}

bool UserInteractionState::UserInteractionRegisteredSinceWebViewCreated()
    const {
  return user_interaction_registered_since_web_view_created_;
}

void UserInteractionState::SetTapInProgress(bool tap_in_progress) {
  tap_in_progress_ = tap_in_progress;
}

void UserInteractionState::ResetLastTransferTime() {
  last_transfer_time_ = base::TimeTicks::Now();
}

web::UserInteractionEvent* UserInteractionState::LastUserInteraction() const {
  return last_user_interaction_.get();
}

void UserInteractionState::SetLastUserInteraction(
    std::unique_ptr<web::UserInteractionEvent> last_user_interaction) {
  last_user_interaction_ = std::move(last_user_interaction);
}

bool UserInteractionState::HasUserTappedRecently(WKWebView* web_view) const {
  // Scrolling generates a pair of touch on/off event which causes
  // last_user_interaction_ to register that there was user interaction. Checks
  // for scrolling first to override time-based tap heuristics.
  if (web_view.scrollView.dragging || web_view.scrollView.decelerating)
    return NO;
  if (!last_user_interaction_)
    return NO;
  if (tap_in_progress_)
    return YES;
  return (base::TimeTicks::Now() - last_user_interaction_->time) <
         kMaximumDelayForUserInteraction;
}

bool UserInteractionState::IsUserInteracting(WKWebView* web_view) const {
  // If page transfer started after last tap, user is deemed to be no longer
  // interacting.
  if (!last_user_interaction_ ||
      last_transfer_time_ > last_user_interaction_->time) {
    return NO;
  }
  return HasUserTappedRecently(web_view);
}

}  // namespace web