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

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

Issue 335943002: [Android] Composited selection handle rendering (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@input_native_handles_final
Patch Set: Clean up paste popup interaction Created 6 years, 5 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/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);
}
}

Powered by Google App Engine
This is Rietveld 408576698