// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.contextualsearch;
import androidx.annotation.Nullable;
/**
* Implements a {@link ContextualSearchHeuristic} that a Tap relatively far away from an existing
* Contextual Search selection should just dismiss our UX. When a Tap is close by, we assume the
* user must have missed the original intended target so we reselect based on the new Tap location.
*/
class TapFarFromPreviousSuppression extends ContextualSearchHeuristic {
private static final double RETAP_DISTANCE_SQUARED_DP = Math.pow(75, 2);
private final ContextualSearchTapState mPreviousTapState;
private final float mPxToDp;
private final boolean mShouldHandleTap;
/**
* Constructs a heuristic to determine if the current Tap should be suppressed because it is
* far from the previous tap.
* @param controller The {@link ContextualSearchSelectionController}.
* @param previousTapState The state of the previous tap gesture, or {@code null}.
* @param x The x coordinate of the tap gesture.
* @param y The y coordinate of the tap gesture.
* @param wasSelectionEmptyBeforeTap Whether the selection was empty just before this tap.
*/
TapFarFromPreviousSuppression(
ContextualSearchSelectionController controller,
@Nullable ContextualSearchTapState previousTapState,
int x,
int y,
boolean wasSelectionEmptyBeforeTap) {
mPxToDp = controller.getPxToDp();
mPreviousTapState = previousTapState;
mShouldHandleTap = shouldHandleTap(x, y, wasSelectionEmptyBeforeTap);
}
@Override
protected boolean isConditionSatisfiedAndEnabled() {
return !mShouldHandleTap;
}
/**
* Determines whether the tap should be handled based on whether it's near a previous tap and
* whether the selection was visible just before that tap. Uses the previous tap state.
* @param x The x coordinate of the current tap.
* @param y The y coordinate of the current tap.
* @param wasSelectionEmptyBeforeTap Whether the selection was empty before the current tap.
* @return whether a tap at the given coordinates should be handled or not.
*/
private boolean shouldHandleTap(int x, int y, boolean wasSelectionEmptyBeforeTap) {
if (mPreviousTapState == null || wasSelectionEmptyBeforeTap) return true;
return wasTapCloseToPreviousTap(x, y);
}
/**
* @return Whether a tap at the given coordinates is considered "close" to the previous tap.
*/
private boolean wasTapCloseToPreviousTap(int x, int y) {
float deltaXDp = (mPreviousTapState.getX() - x) * mPxToDp;
float deltaYDp = (mPreviousTapState.getY() - y) * mPxToDp;
float distanceSquaredDp = deltaXDp * deltaXDp + deltaYDp * deltaYDp;
return distanceSquaredDp <= RETAP_DISTANCE_SQUARED_DP;
}
}