Loading core/java/android/text/method/ArrowKeyMovementMethod.java +0 −61 Original line number Diff line number Diff line Loading @@ -23,19 +23,12 @@ import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; import android.widget.TextView; import android.widget.TextView.CursorController; // XXX this doesn't extend MetaKeyKeyListener because the signatures // don't match. Need to figure that out. Meanwhile the meta keys // won't work in fields that don't take input. public class ArrowKeyMovementMethod implements MovementMethod { /** * An optional controller for the cursor. * Use {@link #setCursorController(CursorController)} to set this field. */ private CursorController mCursorController; private boolean isCap(Spannable buffer) { return ((MetaKeyKeyListener.getMetaState(buffer, KeyEvent.META_SHIFT_ON) == 1) || (MetaKeyKeyListener.getMetaState(buffer, MetaKeyKeyListener.META_SELECTING) != 0)); Loading Loading @@ -192,21 +185,10 @@ public class ArrowKeyMovementMethod implements MovementMethod { } public boolean onTrackballEvent(TextView widget, Spannable text, MotionEvent event) { if (mCursorController != null) { mCursorController.hide(); } return false; } public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) { if (mCursorController != null) { return onTouchEventCursor(widget, buffer, event); } else { return onTouchEventStandard(widget, buffer, event); } } private boolean onTouchEventStandard(TextView widget, Spannable buffer, MotionEvent event) { int initialScrollX = -1, initialScrollY = -1; if (event.getAction() == MotionEvent.ACTION_UP) { initialScrollX = Touch.getInitialScrollX(widget, buffer); Loading Loading @@ -278,49 +260,6 @@ public class ArrowKeyMovementMethod implements MovementMethod { return handled; } private boolean onTouchEventCursor(TextView widget, Spannable buffer, MotionEvent event) { if (widget.isFocused() && !widget.didTouchFocusSelect()) { switch (event.getActionMasked()) { case MotionEvent.ACTION_MOVE: widget.cancelLongPress(); // Offset the current touch position (from controller to cursor) final float x = event.getX() + mCursorController.getOffsetX(); final float y = event.getY() + mCursorController.getOffsetY(); mCursorController.updatePosition((int) x, (int) y); return true; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: mCursorController = null; return true; } } return false; } /** * Defines the cursor controller. * * When set, this object can be used to handle touch events, that can be translated into cursor * updates. * * {@link MotionEvent#ACTION_MOVE} events will call back the * {@link CursorController#updatePosition(int, int)} controller's method, passing the current * finger coordinates (offset by {@link CursorController#getOffsetX()} and * {@link CursorController#getOffsetY()}) as parameters. * * When the gesture is finished (on a {@link MotionEvent#ACTION_UP} or * {@link MotionEvent#ACTION_CANCEL} event), the controller is reset to null. * * @param cursorController A cursor controller implementation * * @hide */ public void setCursorController(CursorController cursorController) { mCursorController = cursorController; } public boolean canSelectArbitrarily() { return true; } Loading core/java/android/view/WindowManager.java +13 −0 Original line number Diff line number Diff line Loading @@ -584,6 +584,19 @@ public interface WindowManager extends ViewManager { */ public static final int FLAG_DISMISS_KEYGUARD = 0x00400000; /** Window flag: when set the window will accept for touch events * outside of its bounds to be sent to other windows that also * support split touch. When this flag is not set, the first pointer * that goes down determines the window to which all subsequent touches * go until all pointers go up. When this flag is set, each pointer * (not necessarily the first) that goes down determines the window * to which all subsequent touches of that pointer will go until that * pointer goes up thereby enabling touches with multiple pointers * to be split across multiple windows. * * {@hide} */ public static final int FLAG_SPLIT_TOUCH = 0x00800000; /** Window flag: *sigh* The lock screen wants to continue running its * animation while it is fading. A kind-of hack to allow this. Maybe * in the future we just make this the default behavior. Loading core/java/android/widget/PopupWindow.java +34 −0 Original line number Diff line number Diff line Loading @@ -85,6 +85,7 @@ public class PopupWindow { private boolean mTouchable = true; private boolean mOutsideTouchable = false; private boolean mClippingEnabled = true; private boolean mSplitTouchEnabled; private OnTouchListener mTouchInterceptor; Loading Loading @@ -564,6 +565,36 @@ public class PopupWindow { mClippingEnabled = enabled; } /** * <p>Indicates whether the popup window supports splitting touches.</p> * * @return true if the touch splitting is enabled, false otherwise * * @see #setSplitTouchEnabled(boolean) * @hide */ public boolean isSplitTouchEnabled() { return mSplitTouchEnabled; } /** * <p>Allows the popup window to split touches across other windows that also * support split touch. When this flag is not set, the first pointer * that goes down determines the window to which all subsequent touches * go until all pointers go up. When this flag is set, each pointer * (not necessarily the first) that goes down determines the window * to which all subsequent touches of that pointer will go until that * pointer goes up thereby enabling touches with multiple pointers * to be split across multiple windows.</p> * * @param enabled true if the split touches should be enabled, false otherwise * @see #isSplitTouchEnabled() * @hide */ public void setSplitTouchEnabled(boolean enabled) { mSplitTouchEnabled = enabled; } /** * <p>Change the width and height measure specs that are given to the * window manager by the popup. By default these are 0, meaning that Loading Loading @@ -889,6 +920,9 @@ public class PopupWindow { if (!mClippingEnabled) { curFlags |= WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; } if (mSplitTouchEnabled) { curFlags |= WindowManager.LayoutParams.FLAG_SPLIT_TOUCH; } return curFlags; } Loading core/java/android/widget/TextView.java +11 −48 Original line number Diff line number Diff line Loading @@ -7601,16 +7601,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener /** * A CursorController instance can be used to control a cursor in the text. * * It can be passed to an {@link ArrowKeyMovementMethod} which can intercepts events * and send them to this object instead of the cursor. * * It is not used outside of {@link TextView}. * @hide */ public interface CursorController { /* Cursor fade-out animation duration, in milliseconds. */ static final int FADE_OUT_DURATION = 400; private interface CursorController { /** * Makes the cursor controller visible on screen. Will be drawn by {@link #draw(Canvas)}. * See also {@link #hide()}. Loading @@ -7631,22 +7625,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener /** * Update the controller's position. */ public void updatePosition(int x, int y); public void updatePosition(HandleView handle, int x, int y); public void updatePosition(); /** * The controller and the cursor's positions can be link by a fixed offset, * computed when the controller is touched, and then maintained as it moves * @return Horizontal offset between the controller and the cursor. */ public float getOffsetX(); /** * @return Vertical offset between the controller and the cursor. */ public float getOffsetY(); /** * This method is called by {@link #onTouchEvent(MotionEvent)} and gives the controller * a chance to become active and/or visible. Loading @@ -7670,6 +7652,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mDrawable = handle; mContainer = new PopupWindow(TextView.this.mContext, null, com.android.internal.R.attr.textSelectHandleWindowStyle); mContainer.setSplitTouchEnabled(true); } @Override Loading Loading @@ -7768,7 +7751,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener TextView.this.getLocationOnScreen(coords); final int x = (int) (rawX - coords[0] + 0.5f); final int y = (int) (rawY - coords[1] + 0.5f); mController.updatePosition(x, y); mController.updatePosition(this, x, y); break; case MotionEvent.ACTION_UP: Loading Loading @@ -7802,13 +7785,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } class InsertionPointCursorController implements CursorController { private class InsertionPointCursorController implements CursorController { private static final int DELAY_BEFORE_FADE_OUT = 4100; // The cursor controller image private final HandleView mHandle; // Offset between finger hot point on cursor controller and actual cursor private float mOffsetX, mOffsetY; private final Runnable mHider = new Runnable() { public void run() { Loading Loading @@ -7841,7 +7822,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return mHandle.isShowing(); } public void updatePosition(int x, int y) { public void updatePosition(HandleView handle, int x, int y) { final int previousOffset = getSelectionStart(); int offset = getHysteresisOffset(x, y, previousOffset); Loading @@ -7865,24 +7846,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mHandle.positionAtCursor(offset, true); } public float getOffsetX() { return mOffsetX; } public float getOffsetY() { return mOffsetY; } public boolean onTouchEvent(MotionEvent ev) { return false; } } class SelectionModifierCursorController implements CursorController { private class SelectionModifierCursorController implements CursorController { // The cursor controller images private HandleView mStartHandle, mEndHandle; // Offset between finger hot point on active cursor controller and actual cursor private float mOffsetX, mOffsetY; // The offsets of that last touch down event. Remembered to start selection there. private int mMinTouchOffset, mMaxTouchOffset; // Whether selection anchors are active Loading Loading @@ -7916,15 +7887,15 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener hide(); } public void updatePosition(int x, int y) { public void updatePosition(HandleView handle, int x, int y) { int selectionStart = getSelectionStart(); int selectionEnd = getSelectionEnd(); final int previousOffset = mStartHandle.isDragging() ? selectionStart : selectionEnd; final int previousOffset = handle == mStartHandle ? selectionStart : selectionEnd; int offset = getHysteresisOffset(x, y, previousOffset); // Handle the case where start and end are swapped, making sure start <= end if (mStartHandle.isDragging()) { if (handle == mStartHandle) { if (offset <= selectionEnd) { if (selectionStart == offset) { return; // no change, no need to redraw; Loading Loading @@ -8021,14 +7992,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return mMaxTouchOffset; } public float getOffsetX() { return mOffsetX; } public float getOffsetY() { return mOffsetY; } /** * @return true iff this controller is currently used to move the selection start. */ Loading include/ui/Input.h +8 −0 Original line number Diff line number Diff line Loading @@ -40,9 +40,17 @@ enum { /* * Maximum number of pointers supported per motion event. * Smallest number of pointers is 1. */ #define MAX_POINTERS 10 /* * Maximum pointer id value supported in a motion event. * Smallest pointer id is 0. * (This is limited by our use of BitSet32 to track pointer assignments.) */ #define MAX_POINTER_ID 31 /* * Declare a concrete type for the NDK's input event forward declaration. */ Loading Loading
core/java/android/text/method/ArrowKeyMovementMethod.java +0 −61 Original line number Diff line number Diff line Loading @@ -23,19 +23,12 @@ import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; import android.widget.TextView; import android.widget.TextView.CursorController; // XXX this doesn't extend MetaKeyKeyListener because the signatures // don't match. Need to figure that out. Meanwhile the meta keys // won't work in fields that don't take input. public class ArrowKeyMovementMethod implements MovementMethod { /** * An optional controller for the cursor. * Use {@link #setCursorController(CursorController)} to set this field. */ private CursorController mCursorController; private boolean isCap(Spannable buffer) { return ((MetaKeyKeyListener.getMetaState(buffer, KeyEvent.META_SHIFT_ON) == 1) || (MetaKeyKeyListener.getMetaState(buffer, MetaKeyKeyListener.META_SELECTING) != 0)); Loading Loading @@ -192,21 +185,10 @@ public class ArrowKeyMovementMethod implements MovementMethod { } public boolean onTrackballEvent(TextView widget, Spannable text, MotionEvent event) { if (mCursorController != null) { mCursorController.hide(); } return false; } public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) { if (mCursorController != null) { return onTouchEventCursor(widget, buffer, event); } else { return onTouchEventStandard(widget, buffer, event); } } private boolean onTouchEventStandard(TextView widget, Spannable buffer, MotionEvent event) { int initialScrollX = -1, initialScrollY = -1; if (event.getAction() == MotionEvent.ACTION_UP) { initialScrollX = Touch.getInitialScrollX(widget, buffer); Loading Loading @@ -278,49 +260,6 @@ public class ArrowKeyMovementMethod implements MovementMethod { return handled; } private boolean onTouchEventCursor(TextView widget, Spannable buffer, MotionEvent event) { if (widget.isFocused() && !widget.didTouchFocusSelect()) { switch (event.getActionMasked()) { case MotionEvent.ACTION_MOVE: widget.cancelLongPress(); // Offset the current touch position (from controller to cursor) final float x = event.getX() + mCursorController.getOffsetX(); final float y = event.getY() + mCursorController.getOffsetY(); mCursorController.updatePosition((int) x, (int) y); return true; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: mCursorController = null; return true; } } return false; } /** * Defines the cursor controller. * * When set, this object can be used to handle touch events, that can be translated into cursor * updates. * * {@link MotionEvent#ACTION_MOVE} events will call back the * {@link CursorController#updatePosition(int, int)} controller's method, passing the current * finger coordinates (offset by {@link CursorController#getOffsetX()} and * {@link CursorController#getOffsetY()}) as parameters. * * When the gesture is finished (on a {@link MotionEvent#ACTION_UP} or * {@link MotionEvent#ACTION_CANCEL} event), the controller is reset to null. * * @param cursorController A cursor controller implementation * * @hide */ public void setCursorController(CursorController cursorController) { mCursorController = cursorController; } public boolean canSelectArbitrarily() { return true; } Loading
core/java/android/view/WindowManager.java +13 −0 Original line number Diff line number Diff line Loading @@ -584,6 +584,19 @@ public interface WindowManager extends ViewManager { */ public static final int FLAG_DISMISS_KEYGUARD = 0x00400000; /** Window flag: when set the window will accept for touch events * outside of its bounds to be sent to other windows that also * support split touch. When this flag is not set, the first pointer * that goes down determines the window to which all subsequent touches * go until all pointers go up. When this flag is set, each pointer * (not necessarily the first) that goes down determines the window * to which all subsequent touches of that pointer will go until that * pointer goes up thereby enabling touches with multiple pointers * to be split across multiple windows. * * {@hide} */ public static final int FLAG_SPLIT_TOUCH = 0x00800000; /** Window flag: *sigh* The lock screen wants to continue running its * animation while it is fading. A kind-of hack to allow this. Maybe * in the future we just make this the default behavior. Loading
core/java/android/widget/PopupWindow.java +34 −0 Original line number Diff line number Diff line Loading @@ -85,6 +85,7 @@ public class PopupWindow { private boolean mTouchable = true; private boolean mOutsideTouchable = false; private boolean mClippingEnabled = true; private boolean mSplitTouchEnabled; private OnTouchListener mTouchInterceptor; Loading Loading @@ -564,6 +565,36 @@ public class PopupWindow { mClippingEnabled = enabled; } /** * <p>Indicates whether the popup window supports splitting touches.</p> * * @return true if the touch splitting is enabled, false otherwise * * @see #setSplitTouchEnabled(boolean) * @hide */ public boolean isSplitTouchEnabled() { return mSplitTouchEnabled; } /** * <p>Allows the popup window to split touches across other windows that also * support split touch. When this flag is not set, the first pointer * that goes down determines the window to which all subsequent touches * go until all pointers go up. When this flag is set, each pointer * (not necessarily the first) that goes down determines the window * to which all subsequent touches of that pointer will go until that * pointer goes up thereby enabling touches with multiple pointers * to be split across multiple windows.</p> * * @param enabled true if the split touches should be enabled, false otherwise * @see #isSplitTouchEnabled() * @hide */ public void setSplitTouchEnabled(boolean enabled) { mSplitTouchEnabled = enabled; } /** * <p>Change the width and height measure specs that are given to the * window manager by the popup. By default these are 0, meaning that Loading Loading @@ -889,6 +920,9 @@ public class PopupWindow { if (!mClippingEnabled) { curFlags |= WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; } if (mSplitTouchEnabled) { curFlags |= WindowManager.LayoutParams.FLAG_SPLIT_TOUCH; } return curFlags; } Loading
core/java/android/widget/TextView.java +11 −48 Original line number Diff line number Diff line Loading @@ -7601,16 +7601,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener /** * A CursorController instance can be used to control a cursor in the text. * * It can be passed to an {@link ArrowKeyMovementMethod} which can intercepts events * and send them to this object instead of the cursor. * * It is not used outside of {@link TextView}. * @hide */ public interface CursorController { /* Cursor fade-out animation duration, in milliseconds. */ static final int FADE_OUT_DURATION = 400; private interface CursorController { /** * Makes the cursor controller visible on screen. Will be drawn by {@link #draw(Canvas)}. * See also {@link #hide()}. Loading @@ -7631,22 +7625,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener /** * Update the controller's position. */ public void updatePosition(int x, int y); public void updatePosition(HandleView handle, int x, int y); public void updatePosition(); /** * The controller and the cursor's positions can be link by a fixed offset, * computed when the controller is touched, and then maintained as it moves * @return Horizontal offset between the controller and the cursor. */ public float getOffsetX(); /** * @return Vertical offset between the controller and the cursor. */ public float getOffsetY(); /** * This method is called by {@link #onTouchEvent(MotionEvent)} and gives the controller * a chance to become active and/or visible. Loading @@ -7670,6 +7652,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mDrawable = handle; mContainer = new PopupWindow(TextView.this.mContext, null, com.android.internal.R.attr.textSelectHandleWindowStyle); mContainer.setSplitTouchEnabled(true); } @Override Loading Loading @@ -7768,7 +7751,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener TextView.this.getLocationOnScreen(coords); final int x = (int) (rawX - coords[0] + 0.5f); final int y = (int) (rawY - coords[1] + 0.5f); mController.updatePosition(x, y); mController.updatePosition(this, x, y); break; case MotionEvent.ACTION_UP: Loading Loading @@ -7802,13 +7785,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } class InsertionPointCursorController implements CursorController { private class InsertionPointCursorController implements CursorController { private static final int DELAY_BEFORE_FADE_OUT = 4100; // The cursor controller image private final HandleView mHandle; // Offset between finger hot point on cursor controller and actual cursor private float mOffsetX, mOffsetY; private final Runnable mHider = new Runnable() { public void run() { Loading Loading @@ -7841,7 +7822,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return mHandle.isShowing(); } public void updatePosition(int x, int y) { public void updatePosition(HandleView handle, int x, int y) { final int previousOffset = getSelectionStart(); int offset = getHysteresisOffset(x, y, previousOffset); Loading @@ -7865,24 +7846,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mHandle.positionAtCursor(offset, true); } public float getOffsetX() { return mOffsetX; } public float getOffsetY() { return mOffsetY; } public boolean onTouchEvent(MotionEvent ev) { return false; } } class SelectionModifierCursorController implements CursorController { private class SelectionModifierCursorController implements CursorController { // The cursor controller images private HandleView mStartHandle, mEndHandle; // Offset between finger hot point on active cursor controller and actual cursor private float mOffsetX, mOffsetY; // The offsets of that last touch down event. Remembered to start selection there. private int mMinTouchOffset, mMaxTouchOffset; // Whether selection anchors are active Loading Loading @@ -7916,15 +7887,15 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener hide(); } public void updatePosition(int x, int y) { public void updatePosition(HandleView handle, int x, int y) { int selectionStart = getSelectionStart(); int selectionEnd = getSelectionEnd(); final int previousOffset = mStartHandle.isDragging() ? selectionStart : selectionEnd; final int previousOffset = handle == mStartHandle ? selectionStart : selectionEnd; int offset = getHysteresisOffset(x, y, previousOffset); // Handle the case where start and end are swapped, making sure start <= end if (mStartHandle.isDragging()) { if (handle == mStartHandle) { if (offset <= selectionEnd) { if (selectionStart == offset) { return; // no change, no need to redraw; Loading Loading @@ -8021,14 +7992,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return mMaxTouchOffset; } public float getOffsetX() { return mOffsetX; } public float getOffsetY() { return mOffsetY; } /** * @return true iff this controller is currently used to move the selection start. */ Loading
include/ui/Input.h +8 −0 Original line number Diff line number Diff line Loading @@ -40,9 +40,17 @@ enum { /* * Maximum number of pointers supported per motion event. * Smallest number of pointers is 1. */ #define MAX_POINTERS 10 /* * Maximum pointer id value supported in a motion event. * Smallest pointer id is 0. * (This is limited by our use of BitSet32 to track pointer assignments.) */ #define MAX_POINTER_ID 31 /* * Declare a concrete type for the NDK's input event forward declaration. */ Loading