Merge "Remove mPreviousKey in PointerTracker"
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
index 3cef002..42305a1 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
@@ -881,7 +881,7 @@
     // TODO: clean up this method.
     private void dismissKeyPreview() {
         for (PointerTracker tracker : mPointerTrackers)
-            tracker.releaseKey();
+            tracker.setReleasedKeyGraphics();
         showPreview(KeyDetector.NOT_A_KEY, null);
     }
 
@@ -1034,16 +1034,13 @@
         if (result) {
             dismissKeyPreview();
             mMiniKeyboardTrackerId = tracker.mPointerId;
-            // Mark this tracker "already processed" and remove it from the pointer queue
-            tracker.setAlreadyProcessed();
-            mPointerQueue.remove(tracker);
+            tracker.onLongPressed(mPointerQueue);
         }
         return result;
     }
 
     private void onLongPressShiftKey(PointerTracker tracker) {
-        tracker.setAlreadyProcessed();
-        mPointerQueue.remove(tracker);
+        tracker.onLongPressed(mPointerQueue);
         mKeyboardActionListener.onCodeInput(Keyboard.CODE_CAPSLOCK, null, 0, 0);
     }
 
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
index 5d137b9..800174c 100644
--- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java
+++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
@@ -91,9 +91,6 @@
     // ignore modifier key if true
     private boolean mIgnoreModifierKey;
 
-    // pressed key
-    private int mPreviousKey = NOT_A_KEY;
-
     // Empty {@link KeyboardActionListener}
     private static final KeyboardActionListener EMPTY_LISTENER = new KeyboardActionListener() {
         @Override
@@ -250,29 +247,24 @@
         return key != null && key.mCode == Keyboard.CODE_SPACE;
     }
 
-    public void releaseKey() {
-        updateKeyGraphics(NOT_A_KEY);
+    public void setReleasedKeyGraphics() {
+        setReleasedKeyGraphics(mKeyState.getKeyIndex());
     }
 
-    private void updateKeyGraphics(int keyIndex) {
-        int oldKeyIndex = mPreviousKey;
-        mPreviousKey = keyIndex;
-        if (keyIndex != oldKeyIndex) {
-            if (isValidKeyIndex(oldKeyIndex)) {
-                final Key oldKey = mKeys.get(oldKeyIndex);
-                oldKey.onReleased();
-                mProxy.invalidateKey(oldKey);
-            }
-            if (isValidKeyIndex(keyIndex)) {
-                final Key newKey = mKeys.get(keyIndex);
-                newKey.onPressed();
-                mProxy.invalidateKey(newKey);
-            }
+    private void setReleasedKeyGraphics(int keyIndex) {
+        final Key key = getKey(keyIndex);
+        if (key != null) {
+            key.onReleased();
+            mProxy.invalidateKey(key);
         }
     }
 
-    public void setAlreadyProcessed() {
-        mKeyAlreadyProcessed = true;
+    private void setPressedKeyGraphics(int keyIndex) {
+        final Key key = getKey(keyIndex);
+        if (key != null && key.mEnabled) {
+            key.onPressed();
+            mProxy.invalidateKey(key);
+        }
     }
 
     private void checkAssertion(PointerTrackerQueue queue) {
@@ -318,7 +310,7 @@
                 if (DEBUG_MODE)
                     Log.w(TAG, "onDownEvent: ignore potential noise: time=" + deltaT
                             + " distance=" + distanceSquared);
-                setAlreadyProcessed();
+                mKeyAlreadyProcessed = true;
                 return;
             }
         }
@@ -346,24 +338,25 @@
         mIsRepeatableKey = false;
         mIsInSlidingKeyInput = false;
         mIgnoreModifierKey = false;
-        final Key key = getKey(keyIndex);
-        if (key != null) {
+        if (isValidKeyIndex(keyIndex)) {
             // This onPress call may have changed keyboard layout. Those cases are detected at
             // {@link #setKeyboard}. In those cases, we should update keyIndex according to the new
             // keyboard layout.
-            if (callListenerOnPressAndCheckKeyboardLayoutChange(key, false))
+            if (callListenerOnPressAndCheckKeyboardLayoutChange(getKey(keyIndex), false))
                 keyIndex = mKeyState.onDownKey(x, y, eventTime);
 
             // Accessibility disables key repeat because users may need to pause on a key to hear
             // its spoken description.
-            if (key.mRepeatable && !mIsAccessibilityEnabled) {
+            final Key key = getKey(keyIndex);
+            if (key != null && key.mRepeatable && !mIsAccessibilityEnabled) {
                 repeatKey(keyIndex);
                 mHandler.startKeyRepeatTimer(mDelayBeforeKeyRepeatStart, keyIndex, this);
                 mIsRepeatableKey = true;
             }
             startLongPressTimer(keyIndex);
+            showKeyPreview(keyIndex);
+            setPressedKeyGraphics(keyIndex);
         }
-        showKeyPreviewAndUpdateKeyGraphics(keyIndex);
     }
 
     private void startSlidingKeyInput(Key key) {
@@ -382,8 +375,9 @@
 
         final int lastX = keyState.getLastX();
         final int lastY = keyState.getLastY();
+        final int oldKeyIndex = keyState.getKeyIndex();
+        final Key oldKey = getKey(oldKeyIndex);
         int keyIndex = keyState.onMoveKey(x, y);
-        final Key oldKey = getKey(keyState.getKeyIndex());
         if (isValidKeyIndex(keyIndex)) {
             if (oldKey == null) {
                 // The pointer has been slid in to the new key, but the finger was not on any keys.
@@ -395,10 +389,13 @@
                     keyIndex = keyState.onMoveKey(x, y);
                 keyState.onMoveToNewKey(keyIndex, x, y);
                 startLongPressTimer(keyIndex);
+                showKeyPreview(keyIndex);
+                setPressedKeyGraphics(keyIndex);
             } else if (!isMinorMoveBounce(x, y, keyIndex)) {
                 // The pointer has been slid in to the new key from the previous key, we must call
                 // onRelease() first to notify that the previous key has been released, then call
                 // onPress() to notify that the new key is being pressed.
+                setReleasedKeyGraphics(oldKeyIndex);
                 callListenerOnRelease(oldKey, oldKey.mCode, true);
                 startSlidingKeyInput(oldKey);
                 mHandler.cancelLongPressTimers();
@@ -410,6 +407,8 @@
                         keyIndex = keyState.onMoveKey(x, y);
                     keyState.onMoveToNewKey(keyIndex, x, y);
                     startLongPressTimer(keyIndex);
+                    setPressedKeyGraphics(keyIndex);
+                    showKeyPreview(keyIndex);
                 } else {
                     // HACK: On some devices, quick successive touches may be translated to sudden
                     // move by touch panel firmware. This hack detects the case and translates the
@@ -424,8 +423,9 @@
                         onUpEventInternal(lastX, lastY, eventTime);
                         onDownEventInternal(x, y, eventTime);
                     } else {
-                        setAlreadyProcessed();
-                        showKeyPreviewAndUpdateKeyGraphics(NOT_A_KEY);
+                        mKeyAlreadyProcessed = true;
+                        showKeyPreview(NOT_A_KEY);
+                        setReleasedKeyGraphics(oldKeyIndex);
                     }
                     return;
                 }
@@ -434,19 +434,19 @@
             if (oldKey != null && !isMinorMoveBounce(x, y, keyIndex)) {
                 // The pointer has been slid out from the previous key, we must call onRelease() to
                 // notify that the previous key has been released.
+                setReleasedKeyGraphics(oldKeyIndex);
                 callListenerOnRelease(oldKey, oldKey.mCode, true);
                 startSlidingKeyInput(oldKey);
                 mHandler.cancelLongPressTimers();
                 if (mIsAllowedSlidingKeyInput) {
-                    keyState.onMoveToNewKey(keyIndex, x ,y);
+                    keyState.onMoveToNewKey(keyIndex, x, y);
                 } else {
-                    setAlreadyProcessed();
-                    showKeyPreviewAndUpdateKeyGraphics(NOT_A_KEY);
+                    mKeyAlreadyProcessed = true;
+                    showKeyPreview(NOT_A_KEY);
                     return;
                 }
             }
         }
-        showKeyPreviewAndUpdateKeyGraphics(keyState.getKeyIndex());
     }
 
     public void onUpEvent(int x, int y, long eventTime, PointerTrackerQueue queue) {
@@ -469,30 +469,38 @@
 
     public void onUpEventForRelease(int x, int y, long eventTime) {
         onUpEventInternal(x, y, eventTime);
+        mKeyAlreadyProcessed = true;
     }
 
-    private void onUpEventInternal(int pointX, int pointY, long eventTime) {
-        int x = pointX;
-        int y = pointY;
+    private void onUpEventInternal(int x, int y, long eventTime) {
         mHandler.cancelKeyTimers();
         mHandler.cancelPopupPreview();
-        showKeyPreviewAndUpdateKeyGraphics(NOT_A_KEY);
         mIsInSlidingKeyInput = false;
+        final PointerTrackerKeyState keyState = mKeyState;
+        final int keyX, keyY;
+        if (!isMinorMoveBounce(x, y, keyState.onMoveKey(x, y))) {
+            keyX = x;
+            keyY = y;
+        } else {
+            // Use previous fixed key coordinates.
+            keyX = keyState.getKeyX();
+            keyY = keyState.getKeyY();
+        }
+        final int keyIndex = keyState.onUpKey(keyX, keyY, eventTime);
+        showKeyPreview(NOT_A_KEY);
+        setReleasedKeyGraphics(keyIndex);
         if (mKeyAlreadyProcessed)
             return;
-        final PointerTrackerKeyState keyState = mKeyState;
-        int keyIndex = keyState.onUpKey(x, y, eventTime);
-        if (isMinorMoveBounce(x, y, keyIndex)) {
-            // Use previous fixed key index and coordinates.
-            keyIndex = keyState.getKeyIndex();
-            x = keyState.getKeyX();
-            y = keyState.getKeyY();
-        }
         if (!mIsRepeatableKey) {
-            detectAndSendKey(keyIndex, x, y);
+            detectAndSendKey(keyIndex, keyX, keyY);
         }
     }
 
+    public void onLongPressed(PointerTrackerQueue queue) {
+        mKeyAlreadyProcessed = true;
+        queue.remove(this);
+    }
+
     public void onCancelEvent(int x, int y, long eventTime, PointerTrackerQueue queue) {
         if (ENABLE_ASSERTION) checkAssertion(queue);
         if (DEBUG_EVENT)
@@ -506,7 +514,8 @@
     private void onCancelEventInternal() {
         mHandler.cancelKeyTimers();
         mHandler.cancelPopupPreview();
-        showKeyPreviewAndUpdateKeyGraphics(NOT_A_KEY);
+        showKeyPreview(NOT_A_KEY);
+        setReleasedKeyGraphics(mKeyState.getKeyIndex());
         mIsInSlidingKeyInput = false;
     }
 
@@ -542,7 +551,7 @@
         }
     }
 
-    private void showKeyPreviewAndUpdateKeyGraphics(int keyIndex) {
+    private void showKeyPreview(int keyIndex) {
         final Key key = getKey(keyIndex);
         if (key != null && !key.mEnabled)
             return;
@@ -555,7 +564,6 @@
         } else {
             mProxy.showPreview(keyIndex, this);
         }
-        updateKeyGraphics(keyIndex);
     }
 
     private void startLongPressTimer(int keyIndex) {
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTrackerKeyState.java b/java/src/com/android/inputmethod/keyboard/PointerTrackerKeyState.java
index a62ed96..b3ed1e2 100644
--- a/java/src/com/android/inputmethod/keyboard/PointerTrackerKeyState.java
+++ b/java/src/com/android/inputmethod/keyboard/PointerTrackerKeyState.java
@@ -92,6 +92,7 @@
 
     public int onUpKey(int x, int y, long eventTime) {
         mUpTime = eventTime;
+        mKeyIndex = KeyDetector.NOT_A_KEY;
         return onMoveKeyInternal(x, y);
     }
 }
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTrackerQueue.java b/java/src/com/android/inputmethod/keyboard/PointerTrackerQueue.java
index 928f3cd..b1e3576 100644
--- a/java/src/com/android/inputmethod/keyboard/PointerTrackerQueue.java
+++ b/java/src/com/android/inputmethod/keyboard/PointerTrackerQueue.java
@@ -29,14 +29,13 @@
         if (mQueue.lastIndexOf(tracker) < 0) {
             return;
         }
-        LinkedList<PointerTracker> queue = mQueue;
+        final LinkedList<PointerTracker> queue = mQueue;
         int oldestPos = 0;
         for (PointerTracker t = queue.get(oldestPos); t != tracker; t = queue.get(oldestPos)) {
             if (t.isModifier()) {
                 oldestPos++;
             } else {
                 t.onUpEventForRelease(t.getLastX(), t.getLastY(), eventTime);
-                t.setAlreadyProcessed();
                 queue.remove(oldestPos);
             }
         }
@@ -51,7 +50,6 @@
             if (t == tracker)
                 continue;
             t.onUpEventForRelease(t.getLastX(), t.getLastY(), eventTime);
-            t.setAlreadyProcessed();
         }
         mQueue.clear();
         if (tracker != null)