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
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
index db16917..bece719 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
@@ -1031,7 +1031,6 @@
         return (mMoreKeysPanel != null);
     }
 
-    @Override
     public boolean dismissMoreKeysPanel() {
         if (isShowingMoreKeysPanel()) {
             return mMoreKeysPanel.dismissMoreKeysPanel();
diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
index 7d7eedb..767297a 100644
--- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
@@ -135,7 +135,6 @@
     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 @@
             }
             mMoreKeysPanelCache.put(parentKey, moreKeysPanel);
         }
-        mMoreKeysPanelPointerTrackerId = tracker.mPointerId;
 
         final int[] lastCoords = CoordinateUtils.newInstance();
         tracker.getLastCoordinates(lastCoords);
@@ -732,14 +730,9 @@
         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 @@
                 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 @@
 
     @Override
     public boolean onDismissMoreKeysPanel() {
-        mMoreKeysPanelPointerTrackerId = -1;
         dimEntireKeyboard(false /* dimmed */);
         return super.onDismissMoreKeysPanel();
     }
diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java
index 16606a1..ce2a8ad 100644
--- a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java
@@ -19,76 +19,28 @@
 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);
@@ -124,26 +76,6 @@
     }
 
     @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
         // delay of 0. The delay does not matter actually since the popup is not shown anyway.
@@ -156,10 +88,8 @@
         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 @@
         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;
@@ -192,6 +189,35 @@
     }
 
     @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();
     }
diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysPanel.java b/java/src/com/android/inputmethod/keyboard/MoreKeysPanel.java
index 8bcddcc..8f43c9c 100644
--- a/java/src/com/android/inputmethod/keyboard/MoreKeysPanel.java
+++ b/java/src/com/android/inputmethod/keyboard/MoreKeysPanel.java
@@ -18,7 +18,7 @@
 
 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 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();
     }
@@ -55,6 +55,36 @@
     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}.
      *
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
index a44f3ed..7d91aed 100644
--- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java
+++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
@@ -84,7 +84,6 @@
         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 @@
     // 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 @@
         if (DEBUG_EVENT) {
             printTouchEvent("onDownEvent:", x, y, eventTime);
         }
-
         mDrawingProxy = handler.getDrawingProxy();
         mTimerProxy = handler.getTimerProxy();
         setKeyboardActionListener(handler.getKeyboardActionListener());
@@ -848,7 +846,7 @@
         }
         // 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 @@
         }
     }
 
+    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 @@
             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 @@
                         false /* isMajorEvent */, null);
             }
         }
-
         onMoveEventInternal(x, y, eventTime);
     }
 
@@ -964,7 +972,7 @@
         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 @@
                     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 @@
                 sPointerTrackerQueue.releaseAllPointersOlderThan(this, eventTime);
             }
         }
-        onUpEventInternal(eventTime);
+        onUpEventInternal(x, y, eventTime);
         sPointerTrackerQueue.remove(this);
     }
 
@@ -1111,11 +1119,14 @@
         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 @@
         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 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 @@
         mTimerProxy.cancelKeyTimers();
         setReleasedKeyGraphics(mCurrentKey);
         resetSlidingKeyInput();
-        if (mIsShowingMoreKeysPanel) {
-            mDrawingProxy.dismissMoreKeysPanel();
-            mIsShowingMoreKeysPanel = false;
-        }
+        mMoreKeysPanel.dismissMoreKeysPanel();
+        mMoreKeysPanel = null;
     }
 
     private void startRepeatKey(final Key key) {
diff --git a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java
index f0017c0..26a304e 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java
@@ -17,66 +17,17 @@
 package com.android.inputmethod.latin.suggestions;
 
 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.KeyDetector;
 import com.android.inputmethod.keyboard.Keyboard;
-import com.android.inputmethod.keyboard.KeyboardActionListener;
-import com.android.inputmethod.keyboard.KeyboardView;
-import com.android.inputmethod.keyboard.MoreKeysDetector;
-import com.android.inputmethod.keyboard.MoreKeysPanel;
-import com.android.inputmethod.keyboard.PointerTracker;
-import com.android.inputmethod.keyboard.PointerTracker.DrawingProxy;
-import com.android.inputmethod.keyboard.PointerTracker.KeyEventHandler;
-import com.android.inputmethod.keyboard.PointerTracker.TimerProxy;
-import com.android.inputmethod.latin.CoordinateUtils;
+import com.android.inputmethod.keyboard.MoreKeysKeyboardView;
 import com.android.inputmethod.latin.R;
 
 /**
  * A view that renders a virtual {@link MoreSuggestions}. It handles rendering of keys and detecting
  * key presses and touch movements.
  */
-public final class MoreSuggestionsView extends KeyboardView implements MoreKeysPanel {
-    private final int[] mCoordinates = CoordinateUtils.newInstance();
-
-    final KeyDetector mModalPanelKeyDetector;
-    private final KeyDetector mSlidingPanelKeyDetector;
-
-    private Controller mController;
-    KeyboardActionListener mListener;
-    private int mOriginX;
-    private int mOriginY;
-
-    static final TimerProxy EMPTY_TIMER_PROXY = new TimerProxy.Adapter();
-
-    final KeyboardActionListener mSuggestionsPaneListener =
-            new KeyboardActionListener.Adapter() {
-        @Override
-        public void onPressKey(final int primaryCode) {
-            mListener.onPressKey(primaryCode);
-        }
-
-        @Override
-        public void onReleaseKey(final int primaryCode, final boolean withSliding) {
-            mListener.onReleaseKey(primaryCode, withSliding);
-        }
-
-        @Override
-        public void onCodeInput(final int primaryCode, final int x, final int y) {
-            final int index = primaryCode - MoreSuggestions.SUGGESTION_CODE_BASE;
-            if (index >= 0 && index < SuggestionStripView.MAX_SUGGESTIONS) {
-                mListener.onCustomRequest(index);
-            }
-        }
-
-        @Override
-        public void onCancelInput() {
-            mListener.onCancelInput();
-        }
-    };
+public final class MoreSuggestionsView extends MoreKeysKeyboardView {
 
     public MoreSuggestionsView(final Context context, final AttributeSet attrs) {
         this(context, attrs, R.attr.moreSuggestionsViewStyle);
@@ -85,12 +36,12 @@
     public MoreSuggestionsView(final Context context, final AttributeSet attrs,
             final int defStyle) {
         super(context, attrs, defStyle);
+    }
 
-        final Resources res = context.getResources();
-        mModalPanelKeyDetector = new KeyDetector(/* keyHysteresisDistance */ 0);
-        mSlidingPanelKeyDetector = new MoreKeysDetector(
-                res.getDimension(R.dimen.more_suggestions_slide_allowance));
-        setKeyPreviewPopupEnabled(false, 0);
+    @Override
+    protected int getDefaultCoordX() {
+        final MoreSuggestions pane = (MoreSuggestions)getKeyboard();
+        return pane.mOccupiedWidth / 2;
     }
 
     @Override
@@ -110,119 +61,11 @@
     }
 
     @Override
-    public void setKeyboard(final Keyboard keyboard) {
-        super.setKeyboard(keyboard);
-        mModalPanelKeyDetector.setKeyboard(keyboard, -getPaddingLeft(), -getPaddingTop());
-        mSlidingPanelKeyDetector.setKeyboard(keyboard, -getPaddingLeft(),
-                -getPaddingTop() + mVerticalCorrection);
-    }
-
-    @Override
-    public KeyDetector getKeyDetector() {
-        return mSlidingPanelKeyDetector;
-    }
-
-    @Override
-    public KeyboardActionListener getKeyboardActionListener() {
-        return mSuggestionsPaneListener;
-    }
-
-    @Override
-    public DrawingProxy getDrawingProxy() {
-        return this;
-    }
-
-    @Override
-    public TimerProxy getTimerProxy() {
-        return EMPTY_TIMER_PROXY;
-    }
-
-    @Override
-    public void setKeyPreviewPopupEnabled(final boolean previewEnabled, final int delay) {
-        // Suggestions pane needs no pop-up key preview displayed, so we pass always false with a
-        // delay of 0. The delay does not matter actually since the popup is not shown anyway.
-        super.setKeyPreviewPopupEnabled(false, 0);
-    }
-
-    @Override
-    public void showMoreKeysPanel(final View parentView, final Controller controller,
-            final int pointX, final int pointY, final KeyboardActionListener listener) {
-        mController = controller;
-        mListener = listener;
-        final View container = getContainerView();
-        final MoreSuggestions pane = (MoreSuggestions)getKeyboard();
-        final int defaultCoordX = pane.mOccupiedWidth / 2;
-        // The coordinates of panel's left-top corner in parentView's coordinate system.
-        final int x = pointX - defaultCoordX - container.getPaddingLeft();
-        final int y = pointY - container.getMeasuredHeight() + container.getPaddingBottom();
-
-        parentView.getLocationInWindow(mCoordinates);
-        // Ensure the horizontal position of the panel does not extend past the screen edges.
-        final int maxX = parentView.getMeasuredWidth() - container.getMeasuredWidth();
-        final int panelX = Math.max(0, Math.min(maxX, x + CoordinateUtils.x(mCoordinates)));
-        final int panelY = y + CoordinateUtils.y(mCoordinates);
-        container.setX(panelX);
-        container.setY(panelY);
-
-        mOriginX = x + container.getPaddingLeft();
-        mOriginY = y + container.getPaddingTop();
-        controller.onShowMoreKeysPanel(this);
-    }
-
-    @Override
-    public boolean dismissMoreKeysPanel() {
-        if (mController == null) return false;
-        return mController.onDismissMoreKeysPanel();
-    }
-
-    @Override
-    public int translateX(final int x) {
-        return x - mOriginX;
-    }
-
-    @Override
-    public int translateY(final int y) {
-        return y - mOriginY;
-    }
-
-    private final KeyEventHandler mModalPanelKeyEventHandler = new KeyEventHandler() {
-        @Override
-        public KeyDetector getKeyDetector() {
-            return mModalPanelKeyDetector;
+    public void onCodeInput(final int primaryCode, final int x, final int y) {
+        final int index = primaryCode - MoreSuggestions.SUGGESTION_CODE_BASE;
+        if (index >= 0 && index < SuggestionStripView.MAX_SUGGESTIONS) {
+            mListener.onCustomRequest(index);
         }
-
-        @Override
-        public KeyboardActionListener getKeyboardActionListener() {
-            return mSuggestionsPaneListener;
-        }
-
-        @Override
-        public DrawingProxy getDrawingProxy() {
-            return MoreSuggestionsView.this;
-        }
-
-        @Override
-        public TimerProxy getTimerProxy() {
-            return EMPTY_TIMER_PROXY;
-        }
-    };
-
-    @Override
-    public boolean onTouchEvent(final MotionEvent me) {
-        final int action = me.getAction();
-        final long eventTime = me.getEventTime();
-        final int index = me.getActionIndex();
-        final int id = me.getPointerId(index);
-        final PointerTracker tracker = PointerTracker.getPointerTracker(id, this);
-        final int x = (int)me.getX(index);
-        final int y = (int)me.getY(index);
-        tracker.processMotionEvent(action, x, y, eventTime, mModalPanelKeyEventHandler);
-        return true;
-    }
-
-    @Override
-    public View getContainerView() {
-        return (View)getParent();
     }
 
     @Override
diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
index e27fc2a..1888912 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
@@ -54,7 +54,6 @@
 import com.android.inputmethod.keyboard.KeyboardSwitcher;
 import com.android.inputmethod.keyboard.KeyboardView;
 import com.android.inputmethod.keyboard.MoreKeysPanel;
-import com.android.inputmethod.keyboard.PointerTracker;
 import com.android.inputmethod.keyboard.ViewLayoutUtils;
 import com.android.inputmethod.latin.AutoCorrection;
 import com.android.inputmethod.latin.CollectionUtils;
@@ -771,7 +770,6 @@
         final long eventTime = me.getEventTime();
         final int index = me.getActionIndex();
         final int id = me.getPointerId(index);
-        final PointerTracker tracker = PointerTracker.getPointerTracker(id, moreKeysPanel);
         final int x = (int)me.getX(index);
         final int y = (int)me.getY(index);
         final int translatedX = moreKeysPanel.translateX(x);
@@ -783,7 +781,6 @@
                 // Decided to be in the sliding input mode only when the touch point has been moved
                 // upward.
                 mMoreSuggestionsMode = MORE_SUGGESTIONS_IN_SLIDING_MODE;
-                tracker.onShowMoreKeysPanel(translatedX, translatedY, moreKeysPanel);
             } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_POINTER_UP) {
                 // Decided to be in the modal input mode
                 mMoreSuggestionsMode = MORE_SUGGESTIONS_IN_MODAL_MODE;
@@ -792,7 +789,7 @@
         }
 
         // MORE_SUGGESTIONS_IN_SLIDING_MODE
-        tracker.processMotionEvent(action, translatedX, translatedY, eventTime, moreKeysPanel);
+        mMoreSuggestionsView.processMotionEvent(action, translatedX, translatedY, id, eventTime);
         return true;
     }