1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 package org.chromium.content.browser.input;
7 import android.view.View;
9 import com.google.common.annotations.VisibleForTesting;
11 import org.chromium.content.browser.PositionObserver;
14 * CursorController for selecting a range of text.
16 public abstract class SelectionHandleController implements CursorController {
18 // The following constants match the ones in
19 // third_party/WebKit/public/web/WebTextDirection.h
20 private static final int TEXT_DIRECTION_DEFAULT = 0;
21 private static final int TEXT_DIRECTION_LTR = 1;
22 private static final int TEXT_DIRECTION_RTL = 2;
24 /** The cursor controller images, lazily created when shown. */
25 private HandleView mStartHandle, mEndHandle;
27 /** Whether handles should show automatically when text is selected. */
28 private boolean mAllowAutomaticShowing = true;
30 /** Whether selection anchors are active. */
31 private boolean mIsShowing;
35 private int mFixedHandleX;
36 private int mFixedHandleY;
38 private PositionObserver mPositionObserver;
40 public SelectionHandleController(View parent, PositionObserver positionObserver) {
42 mPositionObserver = positionObserver;
45 /** Automatically show selection anchors when text is selected. */
46 public void allowAutomaticShowing() {
47 mAllowAutomaticShowing = true;
50 /** Hide selection anchors, and don't automatically show them. */
51 public void hideAndDisallowAutomaticShowing() {
53 mAllowAutomaticShowing = false;
57 public boolean isShowing() {
64 if (mStartHandle != null) mStartHandle.hide();
65 if (mEndHandle != null) mEndHandle.hide();
70 void cancelFadeOutAnimation() {
75 * Updates the selection for a movement of the given handle (which
76 * should be the start handle or end handle) to coordinates x,y.
77 * Note that this will not actually result in the handle moving to (x,y):
78 * selectBetweenCoordinates(x1,y1,x2,y2) will trigger the selection and set the
79 * actual coordinates later via set[Start|End]HandlePosition.
82 public void updatePosition(HandleView handle, int x, int y) {
83 selectBetweenCoordinates(mFixedHandleX, mFixedHandleY, x, y);
87 public void beforeStartUpdatingPosition(HandleView handle) {
88 HandleView fixedHandle = (handle == mStartHandle) ? mEndHandle : mStartHandle;
89 mFixedHandleX = fixedHandle.getAdjustedPositionX();
90 mFixedHandleY = fixedHandle.getLineAdjustedPositionY();
94 * The concrete implementation must trigger a selection between the given
95 * coordinates and (possibly asynchronously) set the actual handle positions
96 * after the selection is made via set[Start|End]HandlePosition.
98 protected abstract void selectBetweenCoordinates(int x1, int y1, int x2, int y2);
101 * @return true iff this controller is being used to move the selection start.
103 boolean isSelectionStartDragged() {
104 return mStartHandle != null && mStartHandle.isDragging();
108 * @return true iff this controller is being used to drag either the selection start or end.
110 public boolean isDragging() {
111 return (mStartHandle != null && mStartHandle.isDragging()) ||
112 (mEndHandle != null && mEndHandle.isDragging());
116 public void onTouchModeChanged(boolean isInTouchMode) {
117 if (!isInTouchMode) {
123 public void onDetached() {}
126 * Moves the start handle so that it points at the given coordinates.
127 * @param x The start handle position X in physical pixels.
128 * @param y The start handle position Y in physical pixels.
130 public void setStartHandlePosition(float x, float y) {
131 mStartHandle.positionAt((int) x, (int) y);
135 * Moves the end handle so that it points at the given coordinates.
136 * @param x The end handle position X in physical pixels.
137 * @param y The end handle position Y in physical pixels.
139 public void setEndHandlePosition(float x, float y) {
140 mEndHandle.positionAt((int) x, (int) y);
144 * If the handles are not visible, sets their visibility to View.VISIBLE and begins fading them
147 public void beginHandleFadeIn() {
148 mStartHandle.beginFadeIn();
149 mEndHandle.beginFadeIn();
153 * Sets the start and end handles to the given visibility.
155 public void setHandleVisibility(int visibility) {
156 mStartHandle.setVisibility(visibility);
157 mEndHandle.setVisibility(visibility);
161 * Shows the handles if allowed.
163 * @param startDir Direction (left/right) of start handle.
164 * @param endDir Direction (left/right) of end handle.
166 public void onSelectionChanged(int startDir, int endDir) {
167 if (mAllowAutomaticShowing) {
168 showHandles(startDir, endDir);
173 * Sets both start and end position and show the handles.
174 * Note: this method does not trigger a selection, see
175 * selectBetweenCoordinates()
177 * @param startDir Direction (left/right) of start handle.
178 * @param endDir Direction (left/right) of end handle.
180 public void showHandles(int startDir, int endDir) {
181 createHandlesIfNeeded(startDir, endDir);
182 showHandlesIfNeeded();
186 public HandleView getStartHandleViewForTest() {
191 public HandleView getEndHandleViewForTest() {
195 private void createHandlesIfNeeded(int startDir, int endDir) {
196 if (mStartHandle == null) {
197 mStartHandle = new HandleView(this,
198 startDir == TEXT_DIRECTION_RTL ? HandleView.RIGHT : HandleView.LEFT, mParent,
201 if (mEndHandle == null) {
202 mEndHandle = new HandleView(this,
203 endDir == TEXT_DIRECTION_RTL ? HandleView.LEFT : HandleView.RIGHT, mParent,
208 private void showHandlesIfNeeded() {
213 setHandleVisibility(HandleView.VISIBLE);