Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 464fb74e authored by Jeff Brown's avatar Jeff Brown Committed by Android Git Automerger
Browse files

am 9785bf0f: am 14a288da: Merge "Add suuport for splitting touch events across...

am 9785bf0f: am 14a288da: Merge "Add suuport for splitting touch events across windows." into gingerbread

Merge commit '9785bf0f'

* commit '9785bf0f':
  Add suuport for splitting touch events across windows.
parents 6d3ed72b 9785bf0f
Loading
Loading
Loading
Loading
+0 −61
Original line number Diff line number Diff line
@@ -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));
@@ -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);
@@ -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;
    }
+13 −0
Original line number Diff line number Diff line
@@ -591,6 +591,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.
+34 −0
Original line number Diff line number Diff line
@@ -87,6 +87,7 @@ public class PopupWindow {
    private boolean mTouchable = true;
    private boolean mOutsideTouchable = false;
    private boolean mClippingEnabled = true;
    private boolean mSplitTouchEnabled;

    private OnTouchListener mTouchInterceptor;
    
@@ -575,6 +576,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
@@ -900,6 +931,9 @@ public class PopupWindow {
        if (!mClippingEnabled) {
            curFlags |= WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
        }
        if (mSplitTouchEnabled) {
            curFlags |= WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
        }
        return curFlags;
    }
    
+11 −48
Original line number Diff line number Diff line
@@ -7688,16 +7688,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()}.
@@ -7718,22 +7712,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.
@@ -7757,6 +7739,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
@@ -7855,7 +7838,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:
@@ -7889,13 +7872,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() {
@@ -7928,7 +7909,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);

@@ -7952,24 +7933,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
@@ -8003,15 +7974,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;
@@ -8108,14 +8079,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.
         */
+8 −0
Original line number Diff line number Diff line
@@ -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