Index: content/public/android/java/src/org/chromium/content/browser/input/PopupTouchHandleDrawable.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/PopupTouchHandleDrawable.java |
similarity index 51% |
rename from content/public/android/java/src/org/chromium/content/browser/input/HandleView.java |
rename to content/public/android/java/src/org/chromium/content/browser/input/PopupTouchHandleDrawable.java |
index 2b50079a25361af7172df81a839228ec63f7fdb4..42ae084e46125e2987527e0ca22157a77b69fdb3 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/PopupTouchHandleDrawable.java |
@@ -5,19 +5,17 @@ |
package org.chromium.content.browser.input; |
import android.content.Context; |
-import android.content.res.TypedArray; |
import android.graphics.Canvas; |
import android.graphics.Rect; |
import android.graphics.drawable.Drawable; |
-import android.os.SystemClock; |
-import android.util.TypedValue; |
import android.view.MotionEvent; |
import android.view.View; |
-import android.view.ViewConfiguration; |
import android.view.ViewParent; |
import android.view.animation.AnimationUtils; |
import android.widget.PopupWindow; |
+import org.chromium.base.CalledByNative; |
+import org.chromium.base.JNINamespace; |
import org.chromium.content.browser.PositionObserver; |
/** |
@@ -27,10 +25,12 @@ import org.chromium.content.browser.PositionObserver; |
* hierarchy. |
* |
*/ |
-public class HandleView extends View { |
+@JNINamespace("content") |
+public class PopupTouchHandleDrawable extends View { |
private static final float FADE_DURATION = 200.f; |
private Drawable mDrawable; |
+ private final PopupTouchHandleDrawableDelegate mDelegate; |
private final PopupWindow mContainer; |
// The position of the handle relative to the parent view. |
@@ -45,12 +45,10 @@ public class HandleView extends View { |
private float mHotspotX; |
private float mHotspotY; |
- private final CursorController mController; |
private boolean mIsDragging; |
private float mTouchToWindowOffsetX; |
private float mTouchToWindowOffsetY; |
- private final int mLineOffsetY; |
private float mDownPositionX, mDownPositionY; |
private long mTouchTimer; |
cjhopman
2014/07/09 22:29:12
Tap is now detected by native, so touchtimer isn't
jdduke (slow)
2014/07/10 02:08:40
Done.
|
private boolean mIsInsertionHandle = false; |
cjhopman
2014/07/09 22:29:12
This seems unused.
jdduke (slow)
2014/07/10 02:08:40
Done.
|
@@ -58,49 +56,39 @@ public class HandleView extends View { |
private long mFadeStartTime; |
private final View mParent; |
- private InsertionHandleController.PastePopupMenu mPastePopupWindow; |
private final Rect mTempRect = new Rect(); |
+ private final int[] mTempScreenCoords = new int[2]; |
static final int LEFT = 0; |
static final int CENTER = 1; |
static final int RIGHT = 2; |
private int mOrientation = -1; |
- /** Defer re-orientation while dragging to prevent confusing handle re-positioning. */ |
- private int mDeferredOrientation = -1; |
- |
private final PositionObserver mParentPositionObserver; |
private final PositionObserver.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. |
- private static final float LINE_OFFSET_Y_DIP = 5.0f; |
- |
- private static final int[] TEXT_VIEW_HANDLE_ATTRS = { |
- android.R.attr.textSelectHandleLeft, |
- android.R.attr.textSelectHandle, |
- android.R.attr.textSelectHandleRight, |
- }; |
+ /** |
+ * Provides additional interaction behaviors necessary for handle |
+ * manipulation and interaction. |
+ */ |
+ public interface PopupTouchHandleDrawableDelegate { |
+ /** |
+ * Should route MotionEvents to the appropriate logic layer for |
+ * performing handle manipulation. |
+ */ |
+ boolean onTouchHandleEvent(MotionEvent ev); |
+ } |
- HandleView(CursorController controller, int orientation, View parent, |
+ public PopupTouchHandleDrawable(PopupTouchHandleDrawableDelegate delegate, View parent, |
PositionObserver parentPositionObserver) { |
super(parent.getContext()); |
+ mDelegate = delegate; |
mParent = parent; |
Context context = mParent.getContext(); |
- mController = controller; |
mContainer = new PopupWindow(context, null, android.R.attr.textSelectHandleWindowStyle); |
- mContainer.setSplitTouchEnabled(true); |
+ mContainer.setSplitTouchEnabled(false); |
mContainer.setClippingEnabled(false); |
- mContainer.setAnimationStyle(0); |
- |
- setOrientation(orientation); |
- |
- // Convert line offset dips to pixels. |
- mLineOffsetY = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, |
- LINE_OFFSET_Y_DIP, context.getResources().getDisplayMetrics()); |
- |
mAlpha = 1.f; |
mParentPositionListener = new PositionObserver.Listener() { |
@@ -112,45 +100,50 @@ public class HandleView extends View { |
mParentPositionObserver = parentPositionObserver; |
} |
- void setOrientation(int orientation) { |
- assert orientation >= LEFT && orientation <= RIGHT; |
- |
- if (mIsDragging) { |
- mDeferredOrientation = orientation; |
- return; |
- } |
+ @Override |
+ public boolean onTouchEvent(MotionEvent event) { |
+ // Convert from PopupWindow local coordinates to |
+ // parent view local coordinates prior to forwarding. |
+ mParent.getLocationOnScreen(mTempScreenCoords); |
+ final float offsetX = event.getRawX() - event.getX() - mTempScreenCoords[0]; |
+ final float offsetY = event.getRawY() - event.getY() - mTempScreenCoords[1]; |
+ final MotionEvent offsetEvent = MotionEvent.obtainNoHistory(event); |
+ offsetEvent.offsetLocation(offsetX, offsetY); |
+ final boolean handled = mDelegate.onTouchHandleEvent(offsetEvent); |
+ offsetEvent.recycle(); |
+ return handled; |
+ } |
+ private void setOrientation(int orientation) { |
+ assert orientation >= LEFT && orientation <= RIGHT; |
if (mOrientation == orientation) return; |
final boolean hadValidOrientation = mOrientation != -1; |
mOrientation = orientation; |
- mDeferredOrientation = -1; |
- |
- Context context = mParent.getContext(); |
- TypedArray a = context.getTheme().obtainStyledAttributes(TEXT_VIEW_HANDLE_ATTRS); |
- mDrawable = a.getDrawable(orientation); |
- a.recycle(); |
mIsInsertionHandle = (orientation == CENTER); |
final int oldAdjustedPositionX = getAdjustedPositionX(); |
final int oldAdjustedPositionY = getAdjustedPositionY(); |
- int handleWidth = mDrawable.getIntrinsicWidth(); |
+ Context context = mParent.getContext(); |
switch (orientation) { |
case LEFT: { |
- mHotspotX = (handleWidth * 3) / 4f; |
+ mDrawable = HandleViewResources.getLeftHandleDrawable(context); |
+ mHotspotX = (mDrawable.getIntrinsicWidth() * 3) / 4f; |
break; |
} |
case RIGHT: { |
- mHotspotX = handleWidth / 4f; |
+ mDrawable = HandleViewResources.getRightHandleDrawable(context); |
+ mHotspotX = mDrawable.getIntrinsicWidth() / 4f; |
break; |
} |
case CENTER: |
default: { |
- mHotspotX = handleWidth / 2f; |
+ mDrawable = HandleViewResources.getCenterHandleDrawable(context); |
+ mHotspotX = mDrawable.getIntrinsicWidth() / 2f; |
break; |
} |
} |
@@ -162,16 +155,7 @@ public class HandleView extends View { |
invalidate(); |
} |
- @Override |
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { |
- setMeasuredDimension(mDrawable.getIntrinsicWidth(), |
- mDrawable.getIntrinsicHeight()); |
- } |
- |
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; |
@@ -188,18 +172,11 @@ public class HandleView extends View { |
} |
private void onPositionChanged() { |
- // Deferring View invalidation while the handles are hidden prevents |
- // scheduling conflicts with the compositor. |
- if (getVisibility() != VISIBLE) return; |
mContainer.update(getContainerPositionX(), getContainerPositionY(), |
getRight() - getLeft(), getBottom() - getTop()); |
} |
- private void showContainer() { |
- mContainer.showAtLocation(mParent, 0, getContainerPositionX(), getContainerPositionY()); |
- } |
- |
- void show() { |
+ private void show() { |
// While hidden, the parent position may have become stale. It must be updated before |
// checking isPositionVisible(). |
updateParentPosition(mParentPositionObserver.getPositionX(), |
@@ -210,25 +187,16 @@ public class HandleView extends View { |
} |
mParentPositionObserver.addListener(mParentPositionListener); |
mContainer.setContentView(this); |
- showContainer(); |
- |
- // Hide paste view when handle is moved on screen. |
- if (mPastePopupWindow != null) { |
- mPastePopupWindow.hide(); |
- } |
+ mContainer.showAtLocation(mParent, 0, getContainerPositionX(), getContainerPositionY()); |
} |
- void hide() { |
+ private void hide() { |
mIsDragging = false; |
- mDeferredOrientation = -1; |
mContainer.dismiss(); |
mParentPositionObserver.removeListener(mParentPositionListener); |
- if (mPastePopupWindow != null) { |
- mPastePopupWindow.hide(); |
- } |
} |
- boolean isShowing() { |
+ private boolean isShowing() { |
return mContainer.isShowing(); |
} |
@@ -257,7 +225,7 @@ public class HandleView extends View { |
} |
// x and y are in physical pixels. |
- void moveTo(int x, int y) { |
+ private void moveTo(int x, int y) { |
int previousPositionX = mPositionX; |
int previousPositionY = mPositionY; |
@@ -266,146 +234,48 @@ public class HandleView extends View { |
if (isPositionVisible()) { |
if (mContainer.isShowing()) { |
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) { |
- // Hide paste popup window as soon as the handle is dragged. |
- if (mPastePopupWindow != null) { |
- mPastePopupWindow.hide(); |
- } |
- } |
} else { |
hide(); |
} |
} |
@Override |
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { |
+ if (mDrawable == null) return; |
+ setMeasuredDimension(mDrawable.getIntrinsicWidth(), |
+ mDrawable.getIntrinsicHeight()); |
+ } |
+ |
+ @Override |
protected void onDraw(Canvas c) { |
+ if (mDrawable == null) return; |
updateAlpha(); |
mDrawable.setBounds(0, 0, getRight() - getLeft(), getBottom() - getTop()); |
mDrawable.draw(c); |
} |
- @Override |
- public boolean onTouchEvent(MotionEvent ev) { |
- switch (ev.getActionMasked()) { |
- case MotionEvent.ACTION_DOWN: { |
- mDownPositionX = ev.getRawX(); |
- mDownPositionY = ev.getRawY(); |
- mTouchToWindowOffsetX = mDownPositionX - mPositionX; |
- mTouchToWindowOffsetY = mDownPositionY - mPositionY; |
- mIsDragging = true; |
- mController.beforeStartUpdatingPosition(this); |
- mTouchTimer = SystemClock.uptimeMillis(); |
- break; |
- } |
- |
- case MotionEvent.ACTION_MOVE: { |
- updatePosition(ev.getRawX(), ev.getRawY()); |
- break; |
- } |
- |
- case MotionEvent.ACTION_UP: |
- if (mIsInsertionHandle) { |
- long delay = SystemClock.uptimeMillis() - mTouchTimer; |
- if (delay < ViewConfiguration.getTapTimeout()) { |
- if (mPastePopupWindow != null && mPastePopupWindow.isShowing()) { |
- // Tapping on the handle dismisses the displayed paste view, |
- mPastePopupWindow.hide(); |
- } else { |
- showPastePopupWindow(); |
- } |
- } |
- } |
- mIsDragging = false; |
- if (mDeferredOrientation != -1) setOrientation(mDeferredOrientation); |
- break; |
- |
- case MotionEvent.ACTION_CANCEL: |
- mIsDragging = false; |
- if (mDeferredOrientation != -1) setOrientation(mDeferredOrientation); |
- break; |
- |
- default: |
- return false; |
- } |
- return true; |
- } |
- |
- boolean isDragging() { |
- return mIsDragging; |
- } |
- |
- /** |
- * @return Returns the x position of the handle |
- */ |
- int getPositionX() { |
- return mPositionX; |
- } |
- |
- /** |
- * @return Returns the y position of the handle |
- */ |
- int getPositionY() { |
- return mPositionY; |
- } |
- |
- private void updatePosition(float rawX, float rawY) { |
- final float newPosX = rawX - mTouchToWindowOffsetX + mHotspotX; |
- final float newPosY = rawY - mTouchToWindowOffsetY + mHotspotY - mLineOffsetY; |
- |
- mController.updatePosition(this, Math.round(newPosX), Math.round(newPosY)); |
- } |
- |
// x and y are in physical pixels. |
- void positionAt(int x, int y) { |
+ private void positionAt(int x, int y) { |
moveTo(x - Math.round(mHotspotX), y - Math.round(mHotspotY)); |
} |
// Returns the x coordinate of the position that the handle appears to be pointing to relative |
// to the handles "parent" view. |
- int getAdjustedPositionX() { |
+ private int getAdjustedPositionX() { |
return mPositionX + Math.round(mHotspotX); |
} |
// Returns the y coordinate of the position that the handle appears to be pointing to relative |
// to the handles "parent" view. |
- int getAdjustedPositionY() { |
+ private int getAdjustedPositionY() { |
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. |
- // As the handle points to a position on the base of the line of text, this method |
- // returns a coordinate a small number of pixels higher (i.e. a slightly smaller number) |
- // than getAdjustedPositionY. |
- int getLineAdjustedPositionY() { |
- return (int) (mPositionY + mHotspotY - mLineOffsetY); |
- } |
- |
- Drawable getDrawable() { |
- return mDrawable; |
- } |
- |
private void updateAlpha() { |
+ if (mDrawable == null) return; |
if (mAlpha == 1.f) return; |
mAlpha = Math.min(1.f, |
(AnimationUtils.currentAnimationTimeMillis() - mFadeStartTime) / FADE_DURATION); |
@@ -413,26 +283,52 @@ public class HandleView extends View { |
invalidate(); |
} |
- /** |
- * If the handle is not visible, sets its visibility to View.VISIBLE and begins fading it in. |
- */ |
- void beginFadeIn() { |
+ // If the handle is not visible, sets its visibility to View.VISIBLE and begins fading it in. |
+ private void beginFadeIn() { |
if (getVisibility() == VISIBLE) return; |
mAlpha = 0.f; |
mFadeStartTime = AnimationUtils.currentAnimationTimeMillis(); |
setVisibility(VISIBLE); |
- // Position updates may have been deferred while the handle was hidden. |
- onPositionChanged(); |
+ // Force a position update as such updates may have gone suppressed while invisible. |
+ if (isShowing()) onPositionChanged(); |
} |
- void showPastePopupWindow() { |
- InsertionHandleController ihc = (InsertionHandleController) mController; |
- if (mIsInsertionHandle && ihc.canPaste()) { |
- if (mPastePopupWindow == null) { |
- // Lazy initialization: create when actually shown only. |
- mPastePopupWindow = ihc.new PastePopupMenu(); |
- } |
- mPastePopupWindow.show(); |
- } |
+ @CalledByNative |
+ private void setRightOrientation() { |
+ setOrientation(RIGHT); |
+ } |
+ |
+ @CalledByNative |
+ private void setLeftOrientation() { |
+ setOrientation(LEFT); |
+ } |
+ |
+ @CalledByNative |
+ private void setCenterOrientation() { |
+ setOrientation(CENTER); |
+ } |
+ |
+ @CalledByNative |
+ private void setOpacity(float alpha) { |
+ mAlpha = alpha; |
+ } |
+ |
+ @CalledByNative |
+ private void setFocus(float x, float y) { |
+ positionAt((int) x, (int) y); |
+ } |
+ |
+ @CalledByNative |
+ private void setVisible(boolean visible) { |
+ setVisibility(visible ? VISIBLE : INVISIBLE); |
+ } |
+ |
+ @CalledByNative |
+ private boolean containsPoint(float x, float y) { |
+ if (mDrawable == null) return false; |
+ final int width = mDrawable.getIntrinsicWidth(); |
+ final int height = mDrawable.getIntrinsicHeight(); |
+ return x > mPositionX && x < (mPositionX + width) |
+ && y > mPositionY && y < (mPositionY + height); |
} |
} |