Symbol key acts as modifier key

On a device that has distinct multi-touch panel, pressing '123?' key
will change keyboard layout to symbol mode.  While pressing '123?'
key, you can press other symbol key to input.  Then releasing '123?'
key will change keyboard layout back to alphabet mode.

Bug: 2973383
Change-Id: I3b069fb19141820def8060db4766a08c7c0a6ff0
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index ddfcaa9..f85206e 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -229,8 +229,9 @@
     private int mDeleteCount;
     private long mLastKeyTime;
 
-    // Shift modifier key state
+    // Modifier keys state
     private ModifierKeyState mShiftKeyState = new ModifierKeyState();
+    private ModifierKeyState mSymbolKeyState = new ModifierKeyState();
 
     private Tutorial mTutorial;
 
@@ -1133,6 +1134,7 @@
             mDeleteCount = 0;
         }
         mLastKeyTime = when;
+        final boolean distinctMultiTouch = mKeyboardSwitcher.hasDistinctMultitouch();
         switch (primaryCode) {
             case Keyboard.KEYCODE_DELETE:
                 handleBackspace();
@@ -1141,9 +1143,14 @@
                 break;
             case Keyboard.KEYCODE_SHIFT:
                 // Shift key is handled in onPress() when device has distinct multi-touch panel.
-                if (!mKeyboardSwitcher.hasDistinctMultitouch())
+                if (!distinctMultiTouch)
                     handleShift();
                 break;
+            case Keyboard.KEYCODE_MODE_CHANGE:
+                // Symbol key is handled in onPress() when device has distinct multi-touch panel.
+                if (!distinctMultiTouch)
+                    changeKeyboardMode();
+                break;
             case Keyboard.KEYCODE_CANCEL:
                 if (!isShowingOptionDialog()) {
                     handleClose();
@@ -1161,10 +1168,6 @@
             case LatinKeyboardView.KEYCODE_PREV_LANGUAGE:
                 toggleLanguage(false, false);
                 break;
-            case Keyboard.KEYCODE_MODE_CHANGE:
-                // TODO: Mode change (symbol key) should be handled in onPress().
-                changeKeyboardMode();
-                break;
             case LatinKeyboardView.KEYCODE_VOICE:
                 if (VOICE_INSTALLED) {
                     startListening(false /* was a button press, was not a swipe */);
@@ -2210,13 +2213,16 @@
     public void onPress(int primaryCode) {
         vibrate();
         playKeyClick(primaryCode);
-        if (mKeyboardSwitcher.hasDistinctMultitouch() && primaryCode == Keyboard.KEYCODE_SHIFT) {
+        final boolean distinctMultiTouch = mKeyboardSwitcher.hasDistinctMultitouch();
+        if (distinctMultiTouch && primaryCode == Keyboard.KEYCODE_SHIFT) {
             mShiftKeyState.onPress();
             handleShift();
-        } else if (primaryCode == Keyboard.KEYCODE_MODE_CHANGE) {
-            // TODO: We should handle KEYCODE_MODE_CHANGE (symbol) here as well.
+        } else if (distinctMultiTouch && primaryCode == Keyboard.KEYCODE_MODE_CHANGE) {
+            mSymbolKeyState.onPress();
+            changeKeyboardMode();
         } else {
             mShiftKeyState.onOtherKeyPressed();
+            mSymbolKeyState.onOtherKeyPressed();
         }
     }
 
@@ -2224,12 +2230,15 @@
         // Reset any drag flags in the keyboard
         ((LatinKeyboard) mKeyboardSwitcher.getInputView().getKeyboard()).keyReleased();
         //vibrate();
-        if (mKeyboardSwitcher.hasDistinctMultitouch() && primaryCode == Keyboard.KEYCODE_SHIFT) {
+        final boolean distinctMultiTouch = mKeyboardSwitcher.hasDistinctMultitouch();
+        if (distinctMultiTouch && primaryCode == Keyboard.KEYCODE_SHIFT) {
             if (mShiftKeyState.isMomentary())
                 resetShift();
             mShiftKeyState.onRelease();
-        } else if (primaryCode == Keyboard.KEYCODE_MODE_CHANGE) {
-            // TODO: We should handle KEYCODE_MODE_CHANGE (symbol) here as well.
+        } else if (distinctMultiTouch && primaryCode == Keyboard.KEYCODE_MODE_CHANGE) {
+            if (mSymbolKeyState.isMomentary())
+                changeKeyboardMode();
+            mSymbolKeyState.onRelease();
         }
     }
 
diff --git a/java/src/com/android/inputmethod/latin/LatinKeyboardView.java b/java/src/com/android/inputmethod/latin/LatinKeyboardView.java
index 8f20a22..c17d7c5 100644
--- a/java/src/com/android/inputmethod/latin/LatinKeyboardView.java
+++ b/java/src/com/android/inputmethod/latin/LatinKeyboardView.java
@@ -52,9 +52,6 @@
     /** The y coordinate of the last row */
     private int mLastRowY;
 
-    // This is local working variable for onLongPress().
-    private int[] mKeyCodes = new int[1];
-
     public LatinKeyboardView(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
diff --git a/java/src/com/android/inputmethod/latin/PointerTracker.java b/java/src/com/android/inputmethod/latin/PointerTracker.java
index 8b1f019..e10c9b8 100644
--- a/java/src/com/android/inputmethod/latin/PointerTracker.java
+++ b/java/src/com/android/inputmethod/latin/PointerTracker.java
@@ -111,6 +111,8 @@
             throw new IllegalArgumentException();
         mKeys = keys;
         mKeyDebounceThresholdSquared = (int)(hysteresisPixel * hysteresisPixel);
+        // Update current key index because keyboard layout has been changed.
+        mCurrentKey = mKeyDetector.getKeyIndexAndNearbyCodes(mStartX, mStartY, null);
     }
 
     private boolean isValidKeyIndex(int keyIndex) {
@@ -126,8 +128,8 @@
         if (key == null)
             return false;
         int primaryCode = key.codes[0];
-        // TODO: KEYCODE_MODE_CHANGE (symbol) will be also a modifier key
-        return primaryCode == Keyboard.KEYCODE_SHIFT;
+        return primaryCode == Keyboard.KEYCODE_SHIFT
+                || primaryCode == Keyboard.KEYCODE_MODE_CHANGE;
     }
 
     public void updateKey(int keyIndex) {
@@ -173,6 +175,8 @@
     }
 
     public void onDownEvent(int x, int y, long eventTime) {
+        if (DEBUG)
+            debugLog("onDownEvent:", x, y);
         int keyIndex = mKeyDetector.getKeyIndexAndNearbyCodes(x, y, null);
         mCurrentKey = keyIndex;
         mStartX = x;
@@ -186,6 +190,8 @@
         if (mListener != null) {
             int primaryCode = isValidKeyIndex(keyIndex) ? mKeys[keyIndex].codes[0] : 0;
             mListener.onPress(primaryCode);
+            // This onPress call may have changed keyboard layout and have updated mCurrentKey
+            keyIndex = mCurrentKey;
         }
         if (isValidKeyIndex(keyIndex)) {
             if (mKeys[keyIndex].repeatable) {
@@ -197,11 +203,11 @@
         }
         showKeyPreviewAndUpdateKey(keyIndex);
         updateMoveDebouncing(x, y);
-        if (DEBUG)
-            debugLog("onDownEvent:", x, y);
     }
 
     public void onMoveEvent(int x, int y, long eventTime) {
+        if (DEBUG_MOVE)
+            debugLog("onMoveEvent:", x, y);
         if (mKeyAlreadyProcessed)
             return;
         int keyIndex = mKeyDetector.getKeyIndexAndNearbyCodes(x, y, null);
@@ -242,15 +248,13 @@
          */
         showKeyPreviewAndUpdateKey(isMinorTimeBounce() ? mLastKey : mCurrentKey);
         updateMoveDebouncing(x, y);
-        if (DEBUG_MOVE)
-            debugLog("onMoveEvent:", x, y);
     }
 
     public void onUpEvent(int x, int y, long eventTime) {
-        if (mKeyAlreadyProcessed)
-            return;
         if (DEBUG)
             debugLog("onUpEvent  :", x, y);
+        if (mKeyAlreadyProcessed)
+            return;
         mHandler.cancelKeyTimers();
         mHandler.cancelPopupPreview();
         int keyIndex = mKeyDetector.getKeyIndexAndNearbyCodes(x, y, null);
@@ -384,8 +388,11 @@
         // The modifier key, such as shift key, should not be shown as preview when multi-touch is
         // supported. On thge other hand, if multi-touch is not supported, the modifier key should
         // be shown as preview.
-        if (!isModifier() || !mHasDistinctMultitouch)
+        if (mHasDistinctMultitouch && isModifier()) {
+            mProxy.showPreview(NOT_A_KEY, this);
+        } else {
             mProxy.showPreview(keyIndex, this);
+        }
     }
 
     private void detectAndSendKey(int index, int x, int y, long eventTime) {
@@ -478,7 +485,7 @@
     }
 
     private void debugLog(String title, int x, int y) {
-        Key key = getKey(mCurrentKey);
+        Key key = getKey(mKeyDetector.getKeyIndexAndNearbyCodes(x, y, null));
         final String code;
         if (key == null) {
             code = "----";