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,9 +620,9 @@ void ContentViewCoreImpl::ShowPastePopup(int x_dip, int y_dip) { ...@@ -620,9 +620,9 @@ void ContentViewCoreImpl::ShowPastePopup(int x_dip, int y_dip) {
ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
if (obj.is_null()) if (obj.is_null())
return; return;
Java_ContentViewCore_showPastePopup(env, obj.obj(), Java_ContentViewCore_showPastePopupWithFeedback(env, obj.obj(),
static_cast<jint>(x_dip), static_cast<jint>(x_dip),
static_cast<jint>(y_dip)); static_cast<jint>(y_dip));
} }
void ContentViewCoreImpl::GetScaledContentBitmap( void ContentViewCoreImpl::GetScaledContentBitmap(
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "content/browser/renderer_host/input/touch_selection_controller.h" #include "content/browser/renderer_host/input/touch_selection_controller.h"
#include "base/auto_reset.h"
#include "base/logging.h" #include "base/logging.h"
#include "third_party/WebKit/public/web/WebInputEvent.h" #include "third_party/WebKit/public/web/WebInputEvent.h"
...@@ -12,7 +13,7 @@ namespace content { ...@@ -12,7 +13,7 @@ namespace content {
TouchSelectionController::TouchSelectionController( TouchSelectionController::TouchSelectionController(
TouchSelectionControllerClient* client) TouchSelectionControllerClient* client)
: client_(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_orientation_(TOUCH_HANDLE_ORIENTATION_UNDEFINED),
start_visible_(false), start_visible_(false),
end_orientation_(TOUCH_HANDLE_ORIENTATION_UNDEFINED), end_orientation_(TOUCH_HANDLE_ORIENTATION_UNDEFINED),
...@@ -38,8 +39,11 @@ void TouchSelectionController::OnSelectionBoundsChanged( ...@@ -38,8 +39,11 @@ void TouchSelectionController::OnSelectionBoundsChanged(
const gfx::RectF& end_rect, const gfx::RectF& end_rect,
TouchHandleOrientation end_orientation, TouchHandleOrientation end_orientation,
bool end_visible) { 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; return;
}
if (start_rect_ == start_rect && end_rect_ == end_rect && if (start_rect_ == start_rect && end_rect_ == end_rect &&
start_orientation_ == start_orientation && start_orientation_ == start_orientation &&
...@@ -54,6 +58,14 @@ void TouchSelectionController::OnSelectionBoundsChanged( ...@@ -54,6 +58,14 @@ void TouchSelectionController::OnSelectionBoundsChanged(
end_orientation_ = end_orientation; end_orientation_ = end_orientation;
end_visible_ = end_visible; 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 = const bool is_selection_dragging =
is_selection_active_ && (start_selection_handle_->is_dragging() || is_selection_active_ && (start_selection_handle_->is_dragging() ||
end_selection_handle_->is_dragging()); end_selection_handle_->is_dragging());
...@@ -117,14 +129,14 @@ bool TouchSelectionController::WillHandleTouchEvent( ...@@ -117,14 +129,14 @@ bool TouchSelectionController::WillHandleTouchEvent(
} }
void TouchSelectionController::OnLongPressEvent() { void TouchSelectionController::OnLongPressEvent() {
last_input_event_type_ = LONG_PRESS; response_pending_input_event_ = LONG_PRESS;
ShowSelectionHandlesAutomatically(); ShowSelectionHandlesAutomatically();
ShowInsertionHandleAutomatically(); ShowInsertionHandleAutomatically();
ResetCachedValuesIfInactive(); ResetCachedValuesIfInactive();
} }
void TouchSelectionController::OnTapEvent() { void TouchSelectionController::OnTapEvent() {
last_input_event_type_ = TAP; response_pending_input_event_ = TAP;
activate_selection_automatically_ = false; activate_selection_automatically_ = false;
DeactivateSelection(); DeactivateSelection();
ShowInsertionHandleAutomatically(); ShowInsertionHandleAutomatically();
...@@ -132,7 +144,7 @@ void TouchSelectionController::OnTapEvent() { ...@@ -132,7 +144,7 @@ void TouchSelectionController::OnTapEvent() {
} }
void TouchSelectionController::HideAndDisallowShowingAutomatically() { void TouchSelectionController::HideAndDisallowShowingAutomatically() {
last_input_event_type_ = INPUT_EVENT_TYPE_NONE; response_pending_input_event_ = INPUT_EVENT_TYPE_NONE;
DeactivateInsertion(); DeactivateInsertion();
DeactivateSelection(); DeactivateSelection();
activate_insertion_automatically_ = false; activate_insertion_automatically_ = false;
...@@ -248,7 +260,7 @@ void TouchSelectionController::ShowSelectionHandlesAutomatically() { ...@@ -248,7 +260,7 @@ void TouchSelectionController::ShowSelectionHandlesAutomatically() {
void TouchSelectionController::OnInsertionChanged() { void TouchSelectionController::OnInsertionChanged() {
DeactivateSelection(); DeactivateSelection();
if (last_input_event_type_ == TAP && selection_empty_) { if (response_pending_input_event_ == TAP && selection_empty_) {
HideAndDisallowShowingAutomatically(); HideAndDisallowShowingAutomatically();
return; return;
} }
...@@ -324,8 +336,12 @@ void TouchSelectionController::ActivateSelection() { ...@@ -324,8 +336,12 @@ void TouchSelectionController::ActivateSelection() {
end_selection_handle_->SetOrientation(end_orientation_); 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; is_selection_active_ = true;
response_pending_input_event_ = INPUT_EVENT_TYPE_NONE;
client_->OnSelectionEvent(SELECTION_SHOWN, GetStartPosition()); client_->OnSelectionEvent(SELECTION_SHOWN, GetStartPosition());
} }
} }
......
...@@ -117,7 +117,7 @@ class CONTENT_EXPORT TouchSelectionController : public TouchHandleClient { ...@@ -117,7 +117,7 @@ class CONTENT_EXPORT TouchSelectionController : public TouchHandleClient {
TouchSelectionControllerClient* const client_; TouchSelectionControllerClient* const client_;
InputEventType last_input_event_type_; InputEventType response_pending_input_event_;
gfx::RectF start_rect_; gfx::RectF start_rect_;
TouchHandleOrientation start_orientation_; TouchHandleOrientation start_orientation_;
......
...@@ -478,6 +478,25 @@ TEST_F(TouchSelectionControllerTest, SelectionBasic) { ...@@ -478,6 +478,25 @@ TEST_F(TouchSelectionControllerTest, SelectionBasic) {
EXPECT_EQ(gfx::PointF(), GetLastEventAnchor()); 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) { TEST_F(TouchSelectionControllerTest, SelectionDragged) {
base::TimeTicks event_time = base::TimeTicks::Now(); base::TimeTicks event_time = base::TimeTicks::Now();
controller().OnLongPressEvent(); controller().OnLongPressEvent();
......
...@@ -2406,12 +2406,21 @@ public class ContentViewCore ...@@ -2406,12 +2406,21 @@ public class ContentViewCore
@SuppressWarnings("unused") @SuppressWarnings("unused")
@CalledByNative @CalledByNative
private void showPastePopup(int xDip, int yDip) { private void showPastePopupWithFeedback(int xDip, int yDip) {
if (!mHasInsertion || !canPaste()) return; // 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(); final float contentOffsetYPix = mRenderCoordinates.getContentOffsetYPix();
getPastePopup().showAt( getPastePopup().showAt(
(int) mRenderCoordinates.fromDipToPix(xDip), (int) mRenderCoordinates.fromDipToPix(xDip),
(int) (mRenderCoordinates.fromDipToPix(yDip) + contentOffsetYPix)); (int) (mRenderCoordinates.fromDipToPix(yDip) + contentOffsetYPix));
return true;
} }
private PastePopupMenu getPastePopup() { 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