Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1242)

Unified Diff: content/public/android/java/src/org/chromium/content/browser/input/HandleView.java

Issue 24449007: [Android] Allow text handles to observe position of "parent" view (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Address comments Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: content/public/android/java/src/org/chromium/content/browser/input/HandleView.java
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/HandleView.java b/content/public/android/java/src/org/chromium/content/browser/input/HandleView.java
index 88a6deaefea4fe0c835e75c433730ccf3a24636d..32075668b5166bdef76d43d18a79330d9ff4ad40 100644
--- a/content/public/android/java/src/org/chromium/content/browser/input/HandleView.java
+++ b/content/public/android/java/src/org/chromium/content/browser/input/HandleView.java
@@ -24,33 +24,44 @@ import android.view.ViewGroup.LayoutParams;
import android.widget.PopupWindow;
import android.widget.TextView;
+import org.chromium.content.browser.PositionObserverInterface;
+
/**
* View that displays a selection or insertion handle for text editing.
+ *
+ * While a HandleView is logically a child of some other view, it does not exist in that View's
+ * hierarchy.
+ *
*/
public class HandleView extends View {
private static final float FADE_DURATION = 200.f;
private Drawable mDrawable;
- private final PopupWindow mContainer;
+
+ // The position of the handle relative to the parent view.
private int mPositionX;
private int mPositionY;
+
+ // The position of the parent relative to the application's root view.
+ private int mParentPositionX;
+ private int mParentPositionY;
+
+ // The offset from this handles position to the "tip" of the handle.
+ private float mHotspotX;
+ private float mHotspotY;
+
private final CursorController mController;
private boolean mIsDragging;
private float mTouchToWindowOffsetX;
private float mTouchToWindowOffsetY;
- private float mHotspotX;
- private float mHotspotY;
+
private int mLineOffsetY;
- private int mLastParentX;
- private int mLastParentY;
private float mDownPositionX, mDownPositionY;
- private int mContainerPositionX, mContainerPositionY;
private long mTouchTimer;
private boolean mIsInsertionHandle = false;
private float mAlpha;
private long mFadeStartTime;
- private View mParent;
private InsertionHandleController.PastePopupMenu mPastePopupWindow;
private final int mTextSelectHandleLeftRes;
@@ -61,13 +72,14 @@ public class HandleView extends View {
private Drawable mSelectHandleRight;
private Drawable mSelectHandleCenter;
- private final int[] mTempCoords = new int[2];
- private final Rect mTempRect = new Rect();
-
static final int LEFT = 0;
static final int CENTER = 1;
static final int RIGHT = 2;
+ private Delegate mParent;
+ private PositionObserverInterface mParentPositionObserver;
+ private PositionObserverInterface.Listener mParentPositionListener;
+
// Number of dips to subtract from the handle's y position to give a suitable
// y coordinate for the corresponding text position. This is to compensate for the fact
// that the handle position is at the base of the line of text.
@@ -79,16 +91,104 @@ public class HandleView extends View {
android.R.attr.textSelectHandleRight,
};
- HandleView(CursorController controller, int pos, View parent) {
+ public interface Delegate {
+ /**
+ * @return The application context.
+ */
+ public Context getContext();
+
+ /**
+ * @return Whether this position (relative to the root view) is visible in the handle's
+ * parent.
+ */
+ public boolean isPositionVisible(int x, int y);
+
+ /**
+ * Dismiss the container containing the handle.
+ */
+ public void dismissContainer();
+
+ /**
+ * @return Whether the container is showing.
+ */
+ public boolean isContainerShowing();
+
+ /**
+ * Show the container for this handle.
+ *
+ * @param view The view to show in the container.
+ * @param x The x position (relative to the root view) to show the container at.
+ * @param y The y position (relative to the root view) to show the container at.
+ */
+ public void showContainerAtPosition(View view, int x, int y);
+
+ /**
+ * Set the position and size of the container.
+ */
+ public void updateContainerPosition(int x, int y, int width, int height);
+ }
+
+ /**
+ * A delegate for displaying a HandleView in a PopupWindow.
+ */
+ public static class ViewDelegate implements Delegate {
+ private final View mView;
+ private final PopupWindow mContainer;
+ private final Rect mTempRect = new Rect();
+
+ public ViewDelegate(View view) {
+ mView = view;
+ mContainer = new PopupWindow(getContext(), null,
+ android.R.attr.textSelectHandleWindowStyle);
+ mContainer.setSplitTouchEnabled(true);
+ mContainer.setClippingEnabled(false);
+ }
+
+ public Context getContext() {
+ return mView.getContext();
+ }
+
+ public boolean isPositionVisible(int x, int y) {
+ final Rect clip = mTempRect;
+ clip.left = 0;
+ clip.top = 0;
+ clip.right = mView.getWidth();
+ clip.bottom = mView.getHeight();
+
+ final ViewParent parent = mView.getParent();
+ if (parent == null || !parent.getChildVisibleRect(mView, clip, null)) {
+ return false;
+ }
+
+ return x >= clip.left && x <= clip.right &&
+ y >= clip.top && y <= clip.bottom;
+ }
+
+ public void dismissContainer() {
+ mContainer.dismiss();
+ }
+
+ public boolean isContainerShowing() {
+ return mContainer.isShowing();
+ }
+
+ public void showContainerAtPosition(View view, int x, int y) {
+ mContainer.setContentView(view);
+ mContainer.showAtLocation(mView, 0, x, y);
+ }
+
+ public void updateContainerPosition(int x, int y, int width, int height) {
+ mContainer.update(x, y, width, height);
+ }
+ }
+
+ HandleView(CursorController controller, int pos, Delegate parent,
+ PositionObserverInterface parentPositionObserver) {
super(parent.getContext());
- Context context = parent.getContext();
mParent = parent;
mController = controller;
- mContainer = new PopupWindow(context, null, android.R.attr.textSelectHandleWindowStyle);
- mContainer.setSplitTouchEnabled(true);
- mContainer.setClippingEnabled(false);
- TypedArray a = context.obtainStyledAttributes(TEXT_VIEW_HANDLE_ATTRS);
+ TypedArray a = mParent.getContext().obtainStyledAttributes(TEXT_VIEW_HANDLE_ATTRS);
mTextSelectHandleLeftRes = a.getResourceId(a.getIndex(LEFT), 0);
mTextSelectHandleRes = a.getResourceId(a.getIndex(CENTER), 0);
mTextSelectHandleRightRes = a.getResourceId(a.getIndex(RIGHT), 0);
@@ -98,9 +198,17 @@ public class HandleView extends View {
// Convert line offset dips to pixels.
mLineOffsetY = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
- LINE_OFFSET_Y_DIP, context.getResources().getDisplayMetrics());
+ LINE_OFFSET_Y_DIP, mParent.getContext().getResources().getDisplayMetrics());
mAlpha = 1.f;
+
+ mParentPositionListener = new PositionObserverInterface.Listener() {
+ @Override
+ public void onPositionChanged(int x, int y) {
+ updateParentPosition(x, y);
+ }
+ };
+ mParentPositionObserver = parentPositionObserver;
}
void setOrientation(int pos) {
@@ -152,21 +260,47 @@ public class HandleView extends View {
mDrawable.getIntrinsicHeight());
}
- private void updateContainerPosition() {
- final int[] coords = mTempCoords;
- mParent.getLocationInWindow(coords);
- mContainerPositionX = coords[0] + mPositionX;
- mContainerPositionY = coords[1] + mPositionY;
+ private void updateParentPosition(int parentPositionX, int parentPositionY) {
+ // Hide paste popup window as soon as a scroll occurs.
+ if (mPastePopupWindow != null) {
+ mPastePopupWindow.hide();
+ }
+
+ mTouchToWindowOffsetX += parentPositionX - mParentPositionX;
+ mTouchToWindowOffsetY += parentPositionY - mParentPositionY;
+ mParentPositionX = parentPositionX;
+ mParentPositionY = parentPositionY;
+ onPositionChanged();
+ }
+
+ private int getContainerPositionX() {
+ return mParentPositionX + mPositionX;
+ }
+
+ private int getContainerPositionY() {
+ return mParentPositionY + mPositionY;
+ }
+
+ private void onPositionChanged() {
+ mParent.updateContainerPosition(getContainerPositionX(), getContainerPositionY(),
+ getRight() - getLeft(), getBottom() - getTop());
+ }
+
+ private void showContainer() {
+ mParent.showContainerAtPosition(this, getContainerPositionX(), getContainerPositionY());
}
void show() {
+ // While hidden, the parent position may have become stale. It must be updated before
+ // checking isPositionVisible().
+ updateParentPosition(mParentPositionObserver.getPositionX(),
+ mParentPositionObserver.getPositionY());
if (!isPositionVisible()) {
hide();
return;
}
- mContainer.setContentView(this);
- updateContainerPosition();
- mContainer.showAtLocation(mParent, 0, mContainerPositionX, mContainerPositionY);
+ mParentPositionObserver.addListener(mParentPositionListener);
+ showContainer();
// Hide paste view when handle is moved on screen.
if (mPastePopupWindow != null) {
@@ -176,14 +310,15 @@ public class HandleView extends View {
void hide() {
mIsDragging = false;
- mContainer.dismiss();
+ mParent.dismissContainer();
+ mParentPositionObserver.removeListener(mParentPositionListener);
if (mPastePopupWindow != null) {
mPastePopupWindow.hide();
}
}
boolean isShowing() {
- return mContainer.isShowing();
+ return mParent.isContainerShowing();
}
private boolean isPositionVisible() {
@@ -192,66 +327,32 @@ public class HandleView extends View {
return true;
}
- final Rect clip = mTempRect;
- clip.left = 0;
- clip.top = 0;
- clip.right = mParent.getWidth();
- clip.bottom = mParent.getHeight();
-
- final ViewParent parent = mParent.getParent();
- if (parent == null || !parent.getChildVisibleRect(mParent, clip, null)) {
- return false;
- }
-
- final int[] coords = mTempCoords;
- mParent.getLocationInWindow(coords);
- final int posX = coords[0] + mPositionX + (int) mHotspotX;
- final int posY = coords[1] + mPositionY + (int) mHotspotY;
+ final int posX = getRootViewRelativePositionX();
+ final int posY = getRootViewRelativePositionY();
- return posX >= clip.left && posX <= clip.right &&
- posY >= clip.top && posY <= clip.bottom;
+ return mParent.isPositionVisible(posX, posY);
}
// x and y are in physical pixels.
void moveTo(int x, int y) {
+ int previousPositionX = mPositionX;
+ int previousPositionY = mPositionY;
+
mPositionX = x;
mPositionY = y;
if (isPositionVisible()) {
- int[] coords = null;
- if (mContainer.isShowing()) {
- coords = mTempCoords;
- mParent.getLocationInWindow(coords);
- final int containerPositionX = coords[0] + mPositionX;
- final int containerPositionY = coords[1] + mPositionY;
-
- if (containerPositionX != mContainerPositionX ||
- containerPositionY != mContainerPositionY) {
- mContainerPositionX = containerPositionX;
- mContainerPositionY = containerPositionY;
-
- mContainer.update(mContainerPositionX, mContainerPositionY,
- getRight() - getLeft(), getBottom() - getTop());
-
- // Hide paste popup window as soon as a scroll occurs.
- if (mPastePopupWindow != null) {
- mPastePopupWindow.hide();
- }
+ if (mParent.isContainerShowing()) {
+ onPositionChanged();
+ // Hide paste popup window as soon as the handle is dragged.
+ if (mPastePopupWindow != null &&
+ (previousPositionX != mPositionX || previousPositionY != mPositionY)) {
+ mPastePopupWindow.hide();
}
} else {
show();
}
if (mIsDragging) {
- if (coords == null) {
- coords = mTempCoords;
- mParent.getLocationInWindow(coords);
- }
- if (coords[0] != mLastParentX || coords[1] != mLastParentY) {
- mTouchToWindowOffsetX += coords[0] - mLastParentX;
- mTouchToWindowOffsetY += coords[1] - mLastParentY;
- mLastParentX = coords[0];
- mLastParentY = coords[1];
- }
// Hide paste popup window as soon as the handle is dragged.
if (mPastePopupWindow != null) {
mPastePopupWindow.hide();
@@ -265,9 +366,6 @@ public class HandleView extends View {
@Override
protected void onDraw(Canvas c) {
updateAlpha();
- updateContainerPosition();
- mContainer.update(mContainerPositionX, mContainerPositionY,
- getRight() - getLeft(), getBottom() - getTop());
mDrawable.setBounds(0, 0, getRight() - getLeft(), getBottom() - getTop());
mDrawable.draw(c);
}
@@ -280,10 +378,6 @@ public class HandleView extends View {
mDownPositionY = ev.getRawY();
mTouchToWindowOffsetX = mDownPositionX - mPositionX;
mTouchToWindowOffsetY = mDownPositionY - mPositionY;
- final int[] coords = mTempCoords;
- mParent.getLocationInWindow(coords);
- mLastParentX = coords[0];
- mLastParentY = coords[1];
mIsDragging = true;
mController.beforeStartUpdatingPosition(this);
mTouchTimer = SystemClock.uptimeMillis();
@@ -347,17 +441,31 @@ public class HandleView extends View {
// x and y are in physical pixels.
void positionAt(int x, int y) {
- moveTo((int)(x - mHotspotX), (int)(y - mHotspotY));
+ moveTo(x - Math.round(mHotspotX), y - Math.round(mHotspotY));
}
- // Returns the x coordinate of the position that the handle appears to be pointing to.
+ // Returns the x coordinate of the position that the handle appears to be pointing to relative
+ // to the handles "parent" view.
int getAdjustedPositionX() {
- return (int) (mPositionX + mHotspotX);
+ return mPositionX + Math.round(mHotspotX);
}
- // Returns the y coordinate of the position that the handle appears to be pointing to.
+ // Returns the y coordinate of the position that the handle appears to be pointing to relative
+ // to the handles "parent" view.
int getAdjustedPositionY() {
- return (int) (mPositionY + mHotspotY);
+ return mPositionY + Math.round(mHotspotY);
+ }
+
+ // Returns the x coordinate of the postion that the handle appears to be pointing to relative to
+ // the root view of the application.
+ int getRootViewRelativePositionX() {
+ return getContainerPositionX() + Math.round(mHotspotX);
+ }
+
+ // Returns the y coordinate of the postion that the handle appears to be pointing to relative to
+ // the root view of the application.
+ int getRootViewRelativePositionY() {
+ return getContainerPositionY() + Math.round(mHotspotY);
}
// Returns a suitable y coordinate for the text position corresponding to the handle.

Powered by Google App Engine
This is Rietveld 408576698