Commit 43dc4556 authored by jdduke@chromium.org's avatar jdduke@chromium.org

[Android] Perform haptic feedback after long press when appropriate

Tentatively trigger haptic feedback when ContentViewCore is directed to show the
the paste popup. While there are no guarantees that such a commend was triggered
by a long press gesture, it should still be a usability improvement. Also
trigger feedback when the selection is updated via a repeated long press gesture.

BUG=150151,399619

Review URL: https://codereview.chromium.org/467303002

Cr-Commit-Position: refs/heads/master@{#290107}
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@290107 0039d316-1c4b-4281-b951-d872f2087c98
parent 672631c8
......@@ -620,7 +620,7 @@ void ContentViewCoreImpl::ShowPastePopup(int x_dip, int y_dip) {
ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
if (obj.is_null())
return;
Java_ContentViewCore_showPastePopup(env, obj.obj(),
Java_ContentViewCore_showPastePopupWithFeedback(env, obj.obj(),
static_cast<jint>(x_dip),
static_cast<jint>(y_dip));
}
......
......@@ -4,6 +4,7 @@
#include "content/browser/renderer_host/input/touch_selection_controller.h"
#include "base/auto_reset.h"
#include "base/logging.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
......@@ -12,7 +13,7 @@ namespace content {
TouchSelectionController::TouchSelectionController(
TouchSelectionControllerClient* client)
: client_(client),
last_input_event_type_(INPUT_EVENT_TYPE_NONE),
response_pending_input_event_(INPUT_EVENT_TYPE_NONE),
start_orientation_(TOUCH_HANDLE_ORIENTATION_UNDEFINED),
start_visible_(false),
end_orientation_(TOUCH_HANDLE_ORIENTATION_UNDEFINED),
......@@ -38,8 +39,11 @@ void TouchSelectionController::OnSelectionBoundsChanged(
const gfx::RectF& end_rect,
TouchHandleOrientation end_orientation,
bool end_visible) {
if (!activate_selection_automatically_ && !activate_insertion_automatically_)
if (!activate_selection_automatically_ &&
!activate_insertion_automatically_) {
DCHECK_EQ(INPUT_EVENT_TYPE_NONE, response_pending_input_event_);
return;
}
if (start_rect_ == start_rect && end_rect_ == end_rect &&
start_orientation_ == start_orientation &&
......@@ -54,6 +58,14 @@ void TouchSelectionController::OnSelectionBoundsChanged(
end_orientation_ = end_orientation;
end_visible_ = end_visible;
// Ensure that |response_pending_input_event_| is cleared after the method
// completes, while also making its current value available for the duration
// of the call.
InputEventType causal_input_event = response_pending_input_event_;
response_pending_input_event_ = INPUT_EVENT_TYPE_NONE;
base::AutoReset<InputEventType> auto_reset_response_pending_input_event(
&response_pending_input_event_, causal_input_event);
const bool is_selection_dragging =
is_selection_active_ && (start_selection_handle_->is_dragging() ||
end_selection_handle_->is_dragging());
......@@ -117,14 +129,14 @@ bool TouchSelectionController::WillHandleTouchEvent(
}
void TouchSelectionController::OnLongPressEvent() {
last_input_event_type_ = LONG_PRESS;
response_pending_input_event_ = LONG_PRESS;
ShowSelectionHandlesAutomatically();
ShowInsertionHandleAutomatically();
ResetCachedValuesIfInactive();
}
void TouchSelectionController::OnTapEvent() {
last_input_event_type_ = TAP;
response_pending_input_event_ = TAP;
activate_selection_automatically_ = false;
DeactivateSelection();
ShowInsertionHandleAutomatically();
......@@ -132,7 +144,7 @@ void TouchSelectionController::OnTapEvent() {
}
void TouchSelectionController::HideAndDisallowShowingAutomatically() {
last_input_event_type_ = INPUT_EVENT_TYPE_NONE;
response_pending_input_event_ = INPUT_EVENT_TYPE_NONE;
DeactivateInsertion();
DeactivateSelection();
activate_insertion_automatically_ = false;
......@@ -248,7 +260,7 @@ void TouchSelectionController::ShowSelectionHandlesAutomatically() {
void TouchSelectionController::OnInsertionChanged() {
DeactivateSelection();
if (last_input_event_type_ == TAP && selection_empty_) {
if (response_pending_input_event_ == TAP && selection_empty_) {
HideAndDisallowShowingAutomatically();
return;
}
......@@ -324,8 +336,12 @@ void TouchSelectionController::ActivateSelection() {
end_selection_handle_->SetOrientation(end_orientation_);
}
if (!is_selection_active_) {
// As a long press received while a selection is already active may trigger
// an entirely new selection, notify the client but avoid sending an
// intervening SELECTION_CLEARED update to avoid unnecessary state changes.
if (!is_selection_active_ || response_pending_input_event_ == LONG_PRESS) {
is_selection_active_ = true;
response_pending_input_event_ = INPUT_EVENT_TYPE_NONE;
client_->OnSelectionEvent(SELECTION_SHOWN, GetStartPosition());
}
}
......
......@@ -117,7 +117,7 @@ class CONTENT_EXPORT TouchSelectionController : public TouchHandleClient {
TouchSelectionControllerClient* const client_;
InputEventType last_input_event_type_;
InputEventType response_pending_input_event_;
gfx::RectF start_rect_;
TouchHandleOrientation start_orientation_;
......
......@@ -478,6 +478,25 @@ TEST_F(TouchSelectionControllerTest, SelectionBasic) {
EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
}
TEST_F(TouchSelectionControllerTest, SelectionRepeatedLongPress) {
gfx::RectF start_rect(5, 5, 0, 10);
gfx::RectF end_rect(50, 5, 0, 10);
bool visible = true;
controller().OnLongPressEvent();
ChangeSelection(start_rect, visible, end_rect, visible);
EXPECT_EQ(SELECTION_SHOWN, GetLastEventType());
EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
// A long press triggering a new selection should re-send the SELECTION_SHOWN
// event notification.
start_rect.Offset(10, 10);
controller().OnLongPressEvent();
ChangeSelection(start_rect, visible, end_rect, visible);
EXPECT_EQ(SELECTION_SHOWN, GetLastEventType());
EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
}
TEST_F(TouchSelectionControllerTest, SelectionDragged) {
base::TimeTicks event_time = base::TimeTicks::Now();
controller().OnLongPressEvent();
......
......@@ -2406,12 +2406,21 @@ public class ContentViewCore
@SuppressWarnings("unused")
@CalledByNative
private void showPastePopup(int xDip, int yDip) {
if (!mHasInsertion || !canPaste()) return;
private void showPastePopupWithFeedback(int xDip, int yDip) {
// TODO(jdduke): Remove this when there is a better signal that long press caused
// showing of the paste popup. See http://crbug.com/150151.
if (showPastePopup(xDip, yDip)) {
mContainerView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
}
}
private boolean showPastePopup(int xDip, int yDip) {
if (!mHasInsertion || !canPaste()) return false;
final float contentOffsetYPix = mRenderCoordinates.getContentOffsetYPix();
getPastePopup().showAt(
(int) mRenderCoordinates.fromDipToPix(xDip),
(int) (mRenderCoordinates.fromDipToPix(yDip) + contentOffsetYPix));
return true;
}
private PastePopupMenu getPastePopup() {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment