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

Commit 35580bad authored by Tom Ouyang's avatar Tom Ouyang
Browse files

Refactor more keys menu framework (part 2)

- Integrate pointer tracking between more keys menu, more suggestions menu, and main keyboard.
- Adds multi-touch support for more keys menus. Long press with one finger and select keys with another finger.

Bug: 7508007

Change-Id: I394f28cd79e342d6bcfea573af72aa33b9def00f
parent 082507e1
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -1031,7 +1031,6 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy,
        return (mMoreKeysPanel != null);
    }

    @Override
    public boolean dismissMoreKeysPanel() {
        if (isShowingMoreKeysPanel()) {
            return mMoreKeysPanel.dismissMoreKeysPanel();
+6 −24
Original line number Diff line number Diff line
@@ -135,7 +135,6 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
    private int mAltCodeKeyWhileTypingAnimAlpha = Constants.Color.ALPHA_OPAQUE;

    // More keys keyboard
    private int mMoreKeysPanelPointerTrackerId;
    private final WeakHashMap<Key, MoreKeysPanel> mMoreKeysPanelCache =
            new WeakHashMap<Key, MoreKeysPanel>();
    private final boolean mConfigShowMoreKeysKeyboardAtTouchedPoint;
@@ -662,7 +661,6 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
            }
            mMoreKeysPanelCache.put(parentKey, moreKeysPanel);
        }
        mMoreKeysPanelPointerTrackerId = tracker.mPointerId;

        final int[] lastCoords = CoordinateUtils.newInstance();
        tracker.getLastCoordinates(lastCoords);
@@ -732,14 +730,9 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
        final long eventTime = me.getEventTime();
        final int index = me.getActionIndex();
        final int id = me.getPointerId(index);
        final int x, y;
        if (mMoreKeysPanel != null && id == mMoreKeysPanelPointerTrackerId) {
            x = mMoreKeysPanel.translateX((int)me.getX(index));
            y = mMoreKeysPanel.translateY((int)me.getY(index));
        } else {
            x = (int)me.getX(index);
            y = (int)me.getY(index);
        }
        final int x = (int)me.getX(index);
        final int y = (int)me.getY(index);

        // TODO: This might be moved to the tracker.processMotionEvent() call below.
        if (ENABLE_USABILITY_STUDY_LOG && action != MotionEvent.ACTION_MOVE) {
            writeUsabilityStudyLog(me, action, eventTime, index, id, x, y);
@@ -800,19 +793,9 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
                final int pointerId = me.getPointerId(i);
                final PointerTracker tracker = PointerTracker.getPointerTracker(
                        pointerId, this);
                final int px, py;
                final MotionEvent motionEvent;
                if (mMoreKeysPanel != null
                        && tracker.mPointerId == mMoreKeysPanelPointerTrackerId) {
                    px = mMoreKeysPanel.translateX((int)me.getX(i));
                    py = mMoreKeysPanel.translateY((int)me.getY(i));
                    motionEvent = null;
                } else {
                    px = (int)me.getX(i);
                    py = (int)me.getY(i);
                    motionEvent = me;
                }
                tracker.onMoveEvent(px, py, eventTime, motionEvent);
                final int px = (int)me.getX(i);
                final int py = (int)me.getY(i);
                tracker.onMoveEvent(px, py, eventTime, me);
                if (ENABLE_USABILITY_STUDY_LOG) {
                    writeUsabilityStudyLog(me, action, eventTime, i, pointerId, px, py);
                }
@@ -867,7 +850,6 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack

    @Override
    public boolean onDismissMoreKeysPanel() {
        mMoreKeysPanelPointerTrackerId = -1;
        dimEntireKeyboard(false /* dimmed */);
        return super.onDismissMoreKeysPanel();
    }
+102 −76
Original line number Diff line number Diff line
@@ -19,76 +19,28 @@ package com.android.inputmethod.keyboard;
import android.content.Context;
import android.content.res.Resources;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import com.android.inputmethod.keyboard.PointerTracker.DrawingProxy;
import com.android.inputmethod.keyboard.PointerTracker.TimerProxy;
import com.android.inputmethod.latin.Constants;
import com.android.inputmethod.latin.CoordinateUtils;
import com.android.inputmethod.latin.InputPointers;
import com.android.inputmethod.latin.R;

/**
 * A view that renders a virtual {@link MoreKeysKeyboard}. It handles rendering of keys and
 * detecting key presses and touch movements.
 */
public final class MoreKeysKeyboardView extends KeyboardView implements MoreKeysPanel {
public class MoreKeysKeyboardView extends KeyboardView implements MoreKeysPanel {
    private final int[] mCoordinates = CoordinateUtils.newInstance();

    private final KeyDetector mKeyDetector;

    private Controller mController;
    private KeyboardActionListener mListener;
    protected KeyboardActionListener mListener;
    private int mOriginX;
    private int mOriginY;
    private Key mCurrentKey;

    private static final TimerProxy EMPTY_TIMER_PROXY = new TimerProxy.Adapter();

    private final KeyboardActionListener mMoreKeysKeyboardListener =
            new KeyboardActionListener.Adapter() {
        @Override
        public void onCodeInput(final int primaryCode, final int x, final int y) {
            // Because a more keys keyboard doesn't need proximity characters correction, we don't
            // send touch event coordinates.
            mListener.onCodeInput(
                    primaryCode, Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE);
        }

        @Override
        public void onTextInput(final String text) {
            mListener.onTextInput(text);
        }

        @Override
        public void onStartBatchInput() {
            mListener.onStartBatchInput();
        }

        @Override
        public void onUpdateBatchInput(final InputPointers batchPointers) {
            mListener.onUpdateBatchInput(batchPointers);
        }

        @Override
        public void onEndBatchInput(final InputPointers batchPointers) {
            mListener.onEndBatchInput(batchPointers);
        }

        @Override
        public void onCancelInput() {
            mListener.onCancelInput();
        }

        @Override
        public void onPressKey(final int primaryCode) {
            mListener.onPressKey(primaryCode);
        }

        @Override
        public void onReleaseKey(final int primaryCode, final boolean withSliding) {
            mListener.onReleaseKey(primaryCode, withSliding);
        }
    };
    private int mActivePointerId;

    public MoreKeysKeyboardView(final Context context, final AttributeSet attrs) {
        this(context, attrs, R.attr.moreKeysKeyboardViewStyle);
@@ -123,26 +75,6 @@ public final class MoreKeysKeyboardView extends KeyboardView implements MoreKeys
                -getPaddingTop() + mVerticalCorrection);
    }

    @Override
    public KeyDetector getKeyDetector() {
        return mKeyDetector;
    }

    @Override
    public KeyboardActionListener getKeyboardActionListener() {
        return mMoreKeysKeyboardListener;
    }

    @Override
    public DrawingProxy getDrawingProxy() {
        return this;
    }

    @Override
    public TimerProxy getTimerProxy() {
        return EMPTY_TIMER_PROXY;
    }

    @Override
    public void setKeyPreviewPopupEnabled(final boolean previewEnabled, final int delay) {
        // More keys keyboard needs no pop-up key preview displayed, so we pass always false with a
@@ -156,10 +88,8 @@ public final class MoreKeysKeyboardView extends KeyboardView implements MoreKeys
        mController = controller;
        mListener = listener;
        final View container = getContainerView();
        final MoreKeysKeyboard pane = (MoreKeysKeyboard)getKeyboard();
        final int defaultCoordX = pane.getDefaultCoordX();
        // The coordinates of panel's left-top corner in parentView's coordinate system.
        final int x = pointX - defaultCoordX - container.getPaddingLeft();
        final int x = pointX - getDefaultCoordX() - container.getPaddingLeft();
        final int y = pointY - container.getMeasuredHeight() + container.getPaddingBottom();

        parentView.getLocationInWindow(mCoordinates);
@@ -175,6 +105,73 @@ public final class MoreKeysKeyboardView extends KeyboardView implements MoreKeys
        controller.onShowMoreKeysPanel(this);
    }

    /**
     * Returns the default x coordinate for showing this panel.
     */
    protected int getDefaultCoordX() {
        return ((MoreKeysKeyboard)getKeyboard()).getDefaultCoordX();
    }

    @Override
    public void onDownEvent(final int x, final int y, final int pointerId, final long eventTime) {
        mActivePointerId = pointerId;
        onMoveKeyInternal(x, y, pointerId);
    }

    @Override
    public void onMoveEvent(int x, int y, final int pointerId, long eventTime) {
        onMoveKeyInternal(x, y, pointerId);
    }

    @Override
    public void onUpEvent(final int x, final int y, final int pointerId, final long eventTime) {
        if (mCurrentKey != null && mActivePointerId == pointerId) {
            updateReleaseKeyGraphics(mCurrentKey);
            onCodeInput(mCurrentKey.mCode, x, y);
            mCurrentKey = null;
        }
    }

    /**
     * Performs the specific action for this panel when the user presses a key on the panel.
     */
    protected void onCodeInput(final int code, final int x, final int y) {
        if (code == Constants.CODE_OUTPUT_TEXT) {
            mListener.onTextInput(mCurrentKey.getOutputText());
        } else if (code != Constants.CODE_UNSPECIFIED) {
            mListener.onCodeInput(code, x, y);
        }
    }

    private void onMoveKeyInternal(int x, int y, int pointerId) {
        if (mActivePointerId != pointerId) {
            // Ignore old pointers when newer pointer is active.
            return;
        }
        final Key oldKey = mCurrentKey;
        final Key newKey = mKeyDetector.detectHitKey(x, y);
        if (newKey != oldKey) {
            mCurrentKey = newKey;
            invalidateKey(mCurrentKey);
            if (oldKey != null) {
                updateReleaseKeyGraphics(oldKey);
            }
            if (newKey != null) {
                updatePressKeyGraphics(newKey);
            }
        }
    }

    private void updateReleaseKeyGraphics(final Key key) {
        key.onReleased();
        invalidateKey(key);
    }

    private void updatePressKeyGraphics(final Key key) {
        key.onPressed();
        invalidateKey(key);
    }

    @Override
    public boolean dismissMoreKeysPanel() {
        if (mController == null) return false;
@@ -191,6 +188,35 @@ public final class MoreKeysKeyboardView extends KeyboardView implements MoreKeys
        return y - mOriginY;
    }

    @Override
    public boolean onTouchEvent(final MotionEvent me) {
        final int action = me.getActionMasked();
        final long eventTime = me.getEventTime();
        final int index = me.getActionIndex();
        final int x = (int)me.getX(index);
        final int y = (int)me.getY(index);
        final int pointerId = me.getPointerId(index);
        processMotionEvent(action, x, y, pointerId, eventTime);
        return true;
    }

    public void processMotionEvent(final int action, final int x, final int y,
            final int pointerId, final long eventTime) {
        switch (action) {
        case MotionEvent.ACTION_DOWN:
        case MotionEvent.ACTION_POINTER_DOWN:
            onDownEvent(x, y, pointerId, eventTime);
            break;
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_POINTER_UP:
            onUpEvent(x, y, pointerId, eventTime);
            break;
        case MotionEvent.ACTION_MOVE:
            onMoveEvent(x, y, pointerId, eventTime);
            break;
        }
    }

    @Override
    public View getContainerView() {
        return (View)getParent();
+32 −2
Original line number Diff line number Diff line
@@ -18,7 +18,7 @@ package com.android.inputmethod.keyboard;

import android.view.View;

public interface MoreKeysPanel extends PointerTracker.KeyEventHandler {
public interface MoreKeysPanel {
    public interface Controller {
        /**
         * Add the {@link MoreKeysPanel} to the target view.
@@ -27,7 +27,7 @@ public interface MoreKeysPanel extends PointerTracker.KeyEventHandler {
        public void onShowMoreKeysPanel(final MoreKeysPanel panel);

        /**
         * Remove the current {@link MoreKeysPanel} to the target view.
         * Remove the current {@link MoreKeysPanel} from the target view.
         */
        public boolean onDismissMoreKeysPanel();
    }
@@ -54,6 +54,36 @@ public interface MoreKeysPanel extends PointerTracker.KeyEventHandler {
     */
    public boolean dismissMoreKeysPanel();

    /**
     * Process a move event on the more keys panel.
     *
     * @param x translated x coordinate of the touch point
     * @param y translated y coordinate of the touch point
     * @param pointerId pointer id touch point
     * @param eventTime timestamp of touch point
     */
    public void onMoveEvent(final int x, final int y, final int pointerId, final long eventTime);

    /**
     * Process a down event on the more keys panel.
     *
     * @param x translated x coordinate of the touch point
     * @param y translated y coordinate of the touch point
     * @param pointerId pointer id touch point
     * @param eventTime timestamp of touch point
     */
    public void onDownEvent(final int x, final int y, final int pointerId, final long eventTime);

    /**
     * Process an up event on the more keys panel.
     *
     * @param x translated x coordinate of the touch point
     * @param y translated y coordinate of the touch point
     * @param pointerId pointer id touch point
     * @param eventTime timestamp of touch point
     */
    public void onUpEvent(final int x, final int y, final int pointerId, final long eventTime);

    /**
     * Translate X-coordinate of touch event to the local X-coordinate of this
     * {@link MoreKeysPanel}.
+40 −22
Original line number Diff line number Diff line
@@ -84,7 +84,6 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
        public void showSlidingKeyInputPreview(PointerTracker tracker);
        public void dismissSlidingKeyInputPreview();
        public void showGesturePreviewTrail(PointerTracker tracker, boolean isOldestTracker);
        public boolean dismissMoreKeysPanel();
    }

    public interface TimerProxy {
@@ -319,8 +318,8 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
    // true if this pointer is no longer tracking touch event.
    private boolean mIsTrackingCanceled;

    // true if this pointer has been long-pressed and is showing a more keys panel.
    private boolean mIsShowingMoreKeysPanel;
    // the more keys panel currently being shown. equals null if no panel is active.
    private MoreKeysPanel mMoreKeysPanel;

    // true if this pointer is in a sliding key input.
    boolean mIsInSlidingKeyInput;
@@ -812,7 +811,6 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
        if (DEBUG_EVENT) {
            printTouchEvent("onDownEvent:", x, y, eventTime);
        }

        mDrawingProxy = handler.getDrawingProxy();
        mTimerProxy = handler.getTimerProxy();
        setKeyboardActionListener(handler.getKeyboardActionListener());
@@ -848,7 +846,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
        }
        // A gesture should start only from a non-modifier key.
        mIsDetectingGesture = (mKeyboard != null) && mKeyboard.mId.isAlphabetKeyboard()
                && !mIsShowingMoreKeysPanel && key != null && !key.isModifier();
                && !isShowingMoreKeysPanel() && key != null && !key.isModifier();
        if (mIsDetectingGesture) {
            if (getActivePointerTrackerCount() == 1) {
                sGestureFirstDownTime = eventTime;
@@ -858,6 +856,10 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
        }
    }

    private boolean isShowingMoreKeysPanel() {
        return (mMoreKeysPanel != null);
    }

    private void onDownEventInternal(final int x, final int y, final long eventTime) {
        Key key = onDownKey(x, y, eventTime);
        // Sliding key is allowed when 1) enabled by configuration, 2) this pointer starts sliding
@@ -920,6 +922,13 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
            return;
        }

        if (isShowingMoreKeysPanel()) {
            final int translatedX = mMoreKeysPanel.translateX(x);
            final int translatedY = mMoreKeysPanel.translateY(y);
            mMoreKeysPanel.onMoveEvent(translatedX, translatedY, mPointerId, eventTime);
            return;
        }

        if (sShouldHandleGesture && me != null) {
            // Add historical points to gesture path.
            final int pointerIndex = me.findPointerIndex(mPointerId);
@@ -932,7 +941,6 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
                        false /* isMajorEvent */, null);
            }
        }

        onMoveEventInternal(x, y, eventTime);
    }

@@ -964,7 +972,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
        if (ProductionFlag.IS_EXPERIMENTAL) {
            ResearchLogger.pointerTracker_onMoveEvent(x, y, lastX, lastY);
        }
        onUpEventInternal(eventTime);
        onUpEventInternal(x, y, eventTime);
        onDownEventInternal(x, y, eventTime);
    }

@@ -983,7 +991,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
                    lastX, lastY, Constants.printableCode(oldKey.mCode),
                    x, y, Constants.printableCode(key.mCode)));
        }
        onUpEventInternal(eventTime);
        onUpEventInternal(x, y, eventTime);
        onDownEventInternal(x, y, eventTime);
    }

@@ -1099,7 +1107,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
                sPointerTrackerQueue.releaseAllPointersOlderThan(this, eventTime);
            }
        }
        onUpEventInternal(eventTime);
        onUpEventInternal(x, y, eventTime);
        sPointerTrackerQueue.remove(this);
    }

@@ -1111,11 +1119,14 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
        if (DEBUG_EVENT) {
            printTouchEvent("onPhntEvent:", mLastX, mLastY, eventTime);
        }
        onUpEventInternal(eventTime);
        if (isShowingMoreKeysPanel()) {
            return;
        }
        onUpEventInternal(mLastX, mLastY, eventTime);
        cancelTracking();
    }

    private void onUpEventInternal(final long eventTime) {
    private void onUpEventInternal(final int x, final int y, final long eventTime) {
        mTimerProxy.cancelKeyTimers();
        resetSlidingKeyInput();
        mIsDetectingGesture = false;
@@ -1123,9 +1134,16 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
        mCurrentKey = null;
        // Release the last pressed key.
        setReleasedKeyGraphics(currentKey);
        if (mIsShowingMoreKeysPanel) {
            mDrawingProxy.dismissMoreKeysPanel();
            mIsShowingMoreKeysPanel = false;

        if (isShowingMoreKeysPanel()) {
            if (!mIsTrackingCanceled) {
                final int translatedX = mMoreKeysPanel.translateX(x);
                final int translatedY = mMoreKeysPanel.translateY(y);
                mMoreKeysPanel.onUpEvent(translatedX, translatedY, mPointerId, eventTime);
            }
            mMoreKeysPanel.dismissMoreKeysPanel();
            mMoreKeysPanel = null;
            return;
        }

        if (sInGesture) {
@@ -1144,10 +1162,12 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
        }
    }

    public void onShowMoreKeysPanel(final int x, final int y, final KeyEventHandler handler) {
        onLongPressed();
        mIsShowingMoreKeysPanel = true;
        onDownEvent(x, y, SystemClock.uptimeMillis(), handler);
    public void onShowMoreKeysPanel(final int translatedX, final int translatedY,
                final MoreKeysPanel panel) {
        setReleasedKeyGraphics(mCurrentKey);
        final long eventTime = SystemClock.uptimeMillis();
        mMoreKeysPanel = panel;
        mMoreKeysPanel.onDownEvent(translatedX, translatedY, mPointerId, eventTime);
    }

    @Override
@@ -1179,10 +1199,8 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
        mTimerProxy.cancelKeyTimers();
        setReleasedKeyGraphics(mCurrentKey);
        resetSlidingKeyInput();
        if (mIsShowingMoreKeysPanel) {
            mDrawingProxy.dismissMoreKeysPanel();
            mIsShowingMoreKeysPanel = false;
        }
        mMoreKeysPanel.dismissMoreKeysPanel();
        mMoreKeysPanel = null;
    }

    private void startRepeatKey(final Key key) {
Loading