Move sliding language switch code to PointerTracker

This change is hack and temporal.

Big: 4328445
Change-Id: I0b8851e9f05390db20ddaa10f35cff1cc9f016da
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index a58ad23..f97d128 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -146,11 +146,6 @@
         // Update the settings key state because number of enabled IMEs could have been changed
         mSettingsKeyEnabledInSettings = getSettingsKeyMode(mPrefs, mInputMethodService);
         final KeyboardId id = getKeyboardId(attribute, isSymbols);
-
-        final Keyboard oldKeyboard = mInputView.getKeyboard();
-        if (oldKeyboard != null && oldKeyboard.mId.equals(id))
-            return;
-
         makeSymbolsKeyboardIds(id.mMode, attribute);
         mCurrentId = id;
         mInputView.setKeyPreviewEnabled(mInputMethodService.getPopupOn());
@@ -296,12 +291,6 @@
         return null;
     }
 
-    public void keyReleased() {
-        LatinKeyboard latinKeyboard = getLatinKeyboard();
-        if (latinKeyboard != null)
-            latinKeyboard.keyReleased();
-    }
-
     public boolean isShiftedOrShiftLocked() {
         LatinKeyboard latinKeyboard = getLatinKeyboard();
         if (latinKeyboard != null)
diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java
index b8bcee6..5854db6 100644
--- a/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java
@@ -56,17 +56,15 @@
     private final Key mSpaceKey;
     private final Drawable mSpaceIcon;
     private final Drawable mSpacePreviewIcon;
-    private final int[] mSpaceKeyIndexArray;
+    private final int mSpaceKeyIndex;
     private final Drawable mSpaceAutoCorrectionIndicator;
     private final Drawable mButtonArrowLeftIcon;
     private final Drawable mButtonArrowRightIcon;
     private final int mSpacebarTextColor;
     private final int mSpacebarTextShadowColor;
-    private final int mSpacebarVerticalCorrection;
     private float mSpacebarTextFadeFactor = 0.0f;
-    private int mSpaceDragStartX;
-    private int mSpaceDragLastDiff;
-    private boolean mCurrentlyInSpace;
+    private final int mSpacebarLanguageSwitchThreshold;
+    private int mSpacebarLanguageSwitchDiff;
     private SlidingLocaleDrawable mSlidingLocaleIcon;
     private final HashMap<Integer, SoftReference<BitmapDrawable>> mSpaceDrawableCache =
             new HashMap<Integer, SoftReference<BitmapDrawable>>();
@@ -115,7 +113,7 @@
         mSpaceKey = (spaceKeyIndex >= 0) ? keys.get(spaceKeyIndex) : null;
         mSpaceIcon = (mSpaceKey != null) ? mSpaceKey.getIcon() : null;
         mSpacePreviewIcon = (mSpaceKey != null) ? mSpaceKey.getPreviewIcon() : null;
-        mSpaceKeyIndexArray = new int[] { spaceKeyIndex };
+        mSpaceKeyIndex = spaceKeyIndex;
 
         mShortcutKey = (shortcutKeyIndex >= 0) ? keys.get(shortcutKeyIndex) : null;
         mEnabledShortcutIcon = (mShortcutKey != null) ? mShortcutKey.getIcon() : null;
@@ -133,8 +131,8 @@
         mSpaceAutoCorrectionIndicator = res.getDrawable(R.drawable.sym_keyboard_space_led);
         mButtonArrowLeftIcon = res.getDrawable(R.drawable.sym_keyboard_language_arrows_left);
         mButtonArrowRightIcon = res.getDrawable(R.drawable.sym_keyboard_language_arrows_right);
-        mSpacebarVerticalCorrection = res.getDimensionPixelOffset(
-                R.dimen.spacebar_vertical_correction);
+        // The threshold is "key width" x 1.5
+        mSpacebarLanguageSwitchThreshold = (getMostCommonKeyWidth() * 3) / 2;
     }
 
     public void setSpacebarTextFadeFactor(float fadeFactor, LatinKeyboardView view) {
@@ -325,7 +323,10 @@
         return buffer;
     }
 
-    private void updateLocaleDrag(int diff) {
+    public void updateSpacebarPreviewIcon(int diff) {
+        if (mSpacebarLanguageSwitchDiff == diff)
+            return;
+        mSpacebarLanguageSwitchDiff = diff;
         if (mSlidingLocaleIcon == null) {
             final int width = Math.max(mSpaceKey.mWidth,
                     (int)(getMinWidth() * SPACEBAR_POPUP_MIN_RATIO));
@@ -333,7 +334,6 @@
             mSlidingLocaleIcon =
                     new SlidingLocaleDrawable(mContext, mSpacePreviewIcon, width, height);
             mSlidingLocaleIcon.setBounds(0, 0, width, height);
-            mSpaceKey.setPreviewIcon(mSlidingLocaleIcon);
         }
         mSlidingLocaleIcon.setDiff(diff);
         if (Math.abs(diff) == Integer.MAX_VALUE) {
@@ -344,85 +344,44 @@
         mSpaceKey.getPreviewIcon().invalidateSelf();
     }
 
-    // This method is called when "popup on keypress" is off.
+    public boolean shouldTriggerSpacebarSlidingLanguageSwitch(int diff) {
+        return Math.abs(diff) > mSpacebarLanguageSwitchThreshold;
+    }
+
+    /**
+     * Return true if spacebar needs showing preview even when "popup on keypress" is off.
+     * @param keyIndex index of the pressing key
+     * @return true if spacebar needs showing preview
+     */
     @Override
     public boolean needSpacebarPreview(int keyIndex) {
+        // This method is called when "popup on keypress" is off.
         if (!mSubtypeSwitcher.useSpacebarLanguageSwitcher())
             return false;
         // Dismiss key preview.
         if (keyIndex == KeyDetector.NOT_A_KEY)
             return true;
         // Key is not a spacebar.
-        if (keyIndex != mSpaceKeyIndexArray[0])
+        if (keyIndex != mSpaceKeyIndex)
             return false;
         // The language switcher will be displayed only when the dragging distance is greater
-        // than average key width of this keyboard.
-        return Math.abs(mSpaceDragLastDiff) > getMostCommonKeyWidth();
+        // than the threshold.
+        return shouldTriggerSpacebarSlidingLanguageSwitch(mSpacebarLanguageSwitchDiff);
     }
 
     public int getLanguageChangeDirection() {
-        if (mSpaceKey == null || SubtypeSwitcher.getInstance().getEnabledKeyboardLocaleCount() <= 1
-                || Math.abs(mSpaceDragLastDiff) < getMostCommonKeyWidth() * SPACEBAR_DRAG_WIDTH) {
+        if (mSpaceKey == null || mSubtypeSwitcher.getEnabledKeyboardLocaleCount() <= 1 || Math.abs(
+                mSpacebarLanguageSwitchDiff) < getMostCommonKeyWidth() * SPACEBAR_DRAG_WIDTH) {
             return 0; // No change
         }
-        return mSpaceDragLastDiff > 0 ? 1 : -1;
-    }
-
-    public void keyReleased() {
-        mCurrentlyInSpace = false;
-        mSpaceDragLastDiff = 0;
-        if (mSpaceKey != null) {
-            updateLocaleDrag(Integer.MAX_VALUE);
-        }
-    }
-
-    /**
-     * Does the magic of locking the touch gesture into the spacebar when
-     * switching input languages.
-     */
-    @Override
-    public boolean isInside(Key key, int pointX, int pointY) {
-        int x = pointX;
-        int y = pointY;
-        final int code = key.mCode;
-        if (code == CODE_SPACE) {
-            y += mSpacebarVerticalCorrection;
-            if (SubtypeSwitcher.getInstance().useSpacebarLanguageSwitcher()
-                    && SubtypeSwitcher.getInstance().getEnabledKeyboardLocaleCount() > 1) {
-                if (mCurrentlyInSpace) {
-                    int diff = x - mSpaceDragStartX;
-                    if (Math.abs(diff - mSpaceDragLastDiff) > 0) {
-                        updateLocaleDrag(diff);
-                    }
-                    mSpaceDragLastDiff = diff;
-                    return true;
-                } else {
-                    boolean isOnSpace = key.isOnKey(x, y);
-                    if (isOnSpace) {
-                        mCurrentlyInSpace = true;
-                        mSpaceDragStartX = x;
-                        updateLocaleDrag(0);
-                    }
-                    return isOnSpace;
-                }
-            }
-        }
-
-        // Lock into the spacebar
-        if (mCurrentlyInSpace) return false;
-
-        return key.isOnKey(x, y);
+        return mSpacebarLanguageSwitchDiff > 0 ? 1 : -1;
     }
 
     @Override
     public int[] getNearestKeys(int x, int y) {
-        if (mCurrentlyInSpace) {
-            return mSpaceKeyIndexArray;
-        } else {
-            // Avoid dead pixels at edges of the keyboard
-            return super.getNearestKeys(Math.max(0, Math.min(x, getMinWidth() - 1)),
-                    Math.max(0, Math.min(y, getHeight() - 1)));
-        }
+        // Avoid dead pixels at edges of the keyboard
+        return super.getNearestKeys(Math.max(0, Math.min(x, getMinWidth() - 1)),
+                Math.max(0, Math.min(y, getHeight() - 1)));
     }
 
     private static int getTextSizeFromTheme(Theme theme, int style, int defValue) {
diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
index a64a9e6..efc446a 100644
--- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
@@ -68,11 +68,6 @@
 
     @Override
     public void setKeyboard(Keyboard newKeyboard) {
-        final LatinKeyboard oldKeyboard = getLatinKeyboard();
-        if (oldKeyboard != null) {
-            // Reset old keyboard state before switching to new keyboard.
-            oldKeyboard.keyReleased();
-        }
         super.setKeyboard(newKeyboard);
         // One-seventh of the keyboard width seems like a reasonable threshold
         mJumpThresholdSquare = newKeyboard.getMinWidth() / 7;
@@ -216,8 +211,7 @@
 
     @Override
     public boolean onTouchEvent(MotionEvent me) {
-        LatinKeyboard keyboard = getLatinKeyboard();
-        if (keyboard == null) return true;
+        if (getLatinKeyboard() == null) return true;
 
         // If there was a sudden jump, return without processing the actual motion event.
         if (handleSuddenJump(me)) {
@@ -226,24 +220,6 @@
             return true;
         }
 
-        // Reset any bounding box controls in the keyboard
-        if (me.getAction() == MotionEvent.ACTION_DOWN) {
-            keyboard.keyReleased();
-        }
-
-        if (me.getAction() == MotionEvent.ACTION_UP) {
-            int languageDirection = keyboard.getLanguageChangeDirection();
-            if (languageDirection != 0) {
-                getOnKeyboardActionListener().onCodeInput(
-                        languageDirection == 1
-                        ? LatinKeyboard.CODE_NEXT_LANGUAGE : LatinKeyboard.CODE_PREV_LANGUAGE,
-                        null, mLastX, mLastY);
-                me.setAction(MotionEvent.ACTION_CANCEL);
-                keyboard.keyReleased();
-                return super.onTouchEvent(me);
-            }
-        }
-
         return super.onTouchEvent(me);
     }
 
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
index 1b1aa49..29867c3 100644
--- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java
+++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
@@ -19,6 +19,7 @@
 import com.android.inputmethod.keyboard.KeyboardView.UIHandler;
 import com.android.inputmethod.latin.LatinImeLogger;
 import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.SubtypeSwitcher;
 
 import android.content.res.Resources;
 import android.util.Log;
@@ -90,6 +91,12 @@
     // ignore modifier key if true
     private boolean mIgnoreModifierKey;
 
+    // TODO: Remove these hacking variables
+    // true if this pointer is in sliding language switch
+    private boolean mIsInSlidingLanguageSwitch;
+    private int mSpaceKeyIndex;
+    private final SubtypeSwitcher mSubtypeSwitcher;
+
     // Empty {@link KeyboardActionListener}
     private static final KeyboardActionListener EMPTY_LISTENER = new KeyboardActionListener() {
         @Override
@@ -129,6 +136,7 @@
                 R.dimen.config_touch_noise_threshold_distance);
         mTouchNoiseThresholdDistanceSquared = (int)(
                 touchNoiseThresholdDistance * touchNoiseThresholdDistance);
+        mSubtypeSwitcher = SubtypeSwitcher.getInstance();
     }
 
     public void setOnKeyboardActionListener(KeyboardActionListener listener) {
@@ -338,6 +346,7 @@
         mKeyAlreadyProcessed = false;
         mIsRepeatableKey = false;
         mIsInSlidingKeyInput = false;
+        mIsInSlidingLanguageSwitch = false;
         mIgnoreModifierKey = false;
         if (isValidKeyIndex(keyIndex)) {
             // This onPress call may have changed keyboard layout. Those cases are detected at
@@ -374,6 +383,12 @@
             return;
         final PointerTrackerKeyState keyState = mKeyState;
 
+        // TODO: Remove this hacking code
+        if (mIsInSlidingLanguageSwitch) {
+            ((LatinKeyboard)mKeyboard).updateSpacebarPreviewIcon(x - keyState.getKeyX());
+            showKeyPreview(mSpaceKeyIndex);
+            return;
+        }
         final int lastX = keyState.getLastX();
         final int lastY = keyState.getLastY();
         final int oldKeyIndex = keyState.getKeyIndex();
@@ -428,11 +443,25 @@
                         dismissKeyPreview();
                         setReleasedKeyGraphics(oldKeyIndex);
                     }
-                    return;
                 }
-            } else if (mKeyboard.needSpacebarPreview(keyIndex)) {
-                // Display spacebar slide language switcher.
-                showKeyPreview(keyIndex);
+            }
+            // TODO: Remove this hack code
+            else if (isSpaceKey(keyIndex) && !mIsInSlidingLanguageSwitch
+                    && mKeyboard instanceof LatinKeyboard) {
+                final LatinKeyboard keyboard = ((LatinKeyboard)mKeyboard);
+                if (mSubtypeSwitcher.useSpacebarLanguageSwitcher()
+                        && mSubtypeSwitcher.getEnabledKeyboardLocaleCount() > 1) {
+                    final int diff = x - keyState.getKeyX();
+                    if (keyboard.shouldTriggerSpacebarSlidingLanguageSwitch(diff)) {
+                        // Detect start sliding language switch.
+                        mIsInSlidingLanguageSwitch = true;
+                        mSpaceKeyIndex = keyIndex;
+                        keyboard.updateSpacebarPreviewIcon(diff);
+                        // Display spacebar slide language switcher.
+                        showKeyPreview(keyIndex);
+                        queue.releaseAllPointersExcept(this, eventTime, true);
+                    }
+                }
             }
         } else {
             if (oldKey != null && isMajorEnoughMoveToBeOnNewKey(x, y, keyIndex)) {
@@ -447,7 +476,6 @@
                 } else {
                     mKeyAlreadyProcessed = true;
                     dismissKeyPreview();
-                    return;
                 }
             }
         }
@@ -462,7 +490,7 @@
             if (isModifier()) {
                 // Before processing an up event of modifier key, all pointers already being
                 // tracked should be released.
-                queue.releaseAllPointersExcept(this, eventTime);
+                queue.releaseAllPointersExcept(this, eventTime, true);
             } else {
                 queue.releaseAllPointersOlderThan(this, eventTime);
             }
@@ -474,8 +502,10 @@
     // Let this pointer tracker know that one of newer-than-this pointer trackers got an up event.
     // This pointer tracker needs to keep the key top graphics "pressed", but needs to get a
     // "virtual" up event.
-    public void onPhantomUpEvent(int x, int y, long eventTime) {
-        onUpEventInternal(x, y, eventTime, false);
+    public void onPhantomUpEvent(int x, int y, long eventTime, boolean updateReleasedKeyGraphics) {
+        if (DEBUG_EVENT)
+            printTouchEvent("onPhntEvent:", x, y, eventTime);
+        onUpEventInternal(x, y, eventTime, updateReleasedKeyGraphics);
         mKeyAlreadyProcessed = true;
     }
 
@@ -500,6 +530,20 @@
             setReleasedKeyGraphics(keyIndex);
         if (mKeyAlreadyProcessed)
             return;
+        // TODO: Remove this hacking code
+        if (mIsInSlidingLanguageSwitch) {
+            setReleasedKeyGraphics(mSpaceKeyIndex);
+            final int languageDir = ((LatinKeyboard)mKeyboard).getLanguageChangeDirection();
+            if (languageDir != 0) {
+                final int code = (languageDir == 1)
+                        ? LatinKeyboard.CODE_NEXT_LANGUAGE : LatinKeyboard.CODE_PREV_LANGUAGE;
+                // This will change keyboard layout.
+                mListener.onCodeInput(code, new int[] {code}, keyX, keyY);
+            }
+            ((LatinKeyboard)mKeyboard).updateSpacebarPreviewIcon(0);
+            mIsInSlidingLanguageSwitch = false;
+            return;
+        }
         if (!mIsRepeatableKey) {
             detectAndSendKey(keyIndex, keyX, keyY);
         }
@@ -515,8 +559,10 @@
         if (DEBUG_EVENT)
             printTouchEvent("onCancelEvt:", x, y, eventTime);
 
-        if (queue != null)
+        if (queue != null) {
+            queue.releaseAllPointersExcept(this, eventTime, true);
             queue.remove(this);
+        }
         onCancelEventInternal();
     }
 
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTrackerQueue.java b/java/src/com/android/inputmethod/keyboard/PointerTrackerQueue.java
index 0a94100..42089d5 100644
--- a/java/src/com/android/inputmethod/keyboard/PointerTrackerQueue.java
+++ b/java/src/com/android/inputmethod/keyboard/PointerTrackerQueue.java
@@ -35,21 +35,22 @@
             if (t.isModifier()) {
                 oldestPos++;
             } else {
-                t.onPhantomUpEvent(t.getLastX(), t.getLastY(), eventTime);
+                t.onPhantomUpEvent(t.getLastX(), t.getLastY(), eventTime, false);
                 queue.remove(oldestPos);
             }
         }
     }
 
     public void releaseAllPointers(long eventTime) {
-        releaseAllPointersExcept(null, eventTime);
+        releaseAllPointersExcept(null, eventTime, true);
     }
 
-    public void releaseAllPointersExcept(PointerTracker tracker, long eventTime) {
+    public void releaseAllPointersExcept(PointerTracker tracker, long eventTime,
+            boolean updateReleasedKeyGraphics) {
         for (PointerTracker t : mQueue) {
             if (t == tracker)
                 continue;
-            t.onPhantomUpEvent(t.getLastX(), t.getLastY(), eventTime);
+            t.onPhantomUpEvent(t.getLastX(), t.getLastY(), eventTime, updateReleasedKeyGraphics);
         }
         mQueue.clear();
         if (tracker != null)
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index f9bcfc6..28fd6aa 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -359,11 +359,14 @@
             final LatinKeyboardView inputView = mKeyboardSwitcher.getInputView();
             if (inputView != null) {
                 final LatinKeyboard keyboard = mKeyboardSwitcher.getLatinKeyboard();
+                // The language is always displayed when the delay is negative.
+                final boolean needsToDisplayLanguage = localeChanged
+                        || mConfigDelayBeforeFadeoutLanguageOnSpacebar < 0;
                 // The language is never displayed when the delay is zero.
                 if (mConfigDelayBeforeFadeoutLanguageOnSpacebar != 0)
-                    inputView.setSpacebarTextFadeFactor(localeChanged ? 1.0f
+                    inputView.setSpacebarTextFadeFactor(needsToDisplayLanguage ? 1.0f
                             : mConfigFinalFadeoutFactorOfLanguageOnSpacebar, keyboard);
-                // The language is always displayed when the delay is negative.
+                // The fadeout animation will start when the delay is positive.
                 if (localeChanged && mConfigDelayBeforeFadeoutLanguageOnSpacebar > 0) {
                     sendMessageDelayed(obtainMessage(MSG_FADEOUT_LANGUAGE_ON_SPACEBAR, keyboard),
                             mConfigDelayBeforeFadeoutLanguageOnSpacebar);
@@ -2058,7 +2061,6 @@
     public void onRelease(int primaryCode, boolean withSliding) {
         KeyboardSwitcher switcher = mKeyboardSwitcher;
         // Reset any drag flags in the keyboard
-        switcher.keyReleased();
         final boolean distinctMultiTouch = switcher.hasDistinctMultitouch();
         if (distinctMultiTouch && primaryCode == Keyboard.CODE_SHIFT) {
             switcher.onReleaseShift(withSliding);