Fix long press caps lock handling (DO NOT MERGE)

This is cherry-pick of I3850f283.

Bug: 5627467
Change-Id: If46dcbe5bac42b975bd001fefb9f11520a0abb70
diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java
index a57b9d1..4578507 100644
--- a/java/src/com/android/inputmethod/keyboard/Keyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java
@@ -170,6 +170,10 @@
         return mShiftState.isShiftLocked();
     }
 
+    public boolean isShiftLockShifted() {
+        return mShiftState.isShiftLockShifted();
+    }
+
     public boolean setShifted(boolean newShiftState) {
         for (final Key key : mShiftKeys) {
             if (!newShiftState && !mShiftState.isShiftLocked()) {
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index 83871a6..ac718fc 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -386,6 +386,13 @@
         return false;
     }
 
+    private boolean isShiftLockShifted() {
+        LatinKeyboard latinKeyboard = getLatinKeyboard();
+        if (latinKeyboard != null)
+            return latinKeyboard.isShiftLockShifted();
+        return false;
+    }
+
     public boolean isAutomaticTemporaryUpperCase() {
         LatinKeyboard latinKeyboard = getLatinKeyboard();
         if (latinKeyboard != null)
@@ -559,6 +566,9 @@
             if (shiftKeyState.isMomentary()) {
                 // After chording input while normal state.
                 toggleShift();
+            } else if (isShiftLocked() && !isShiftLockShifted() && shiftKeyState.isPressing()
+                    && !withSliding) {
+                // Shift has been long pressed, ignore this release.
             } else if (isShiftLocked() && !shiftKeyState.isIgnoring() && !withSliding) {
                 // Shift has been pressed without chording while caps lock state.
                 toggleCapsLock();
diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
index aab52e1..6ce3876 100644
--- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
@@ -351,7 +351,7 @@
         // calling setAlreadyProcessed() nor remove the tracker from mPointerQueue.
         final int primaryCode = ignore ? Keyboard.CODE_HAPTIC_AND_AUDIO_FEEDBACK_ONLY
                 : Keyboard.CODE_CAPSLOCK;
-        mKeyboardActionListener.onCodeInput(primaryCode, null, 0, 0);
+        invokeCodeInput(primaryCode);
     }
 
     // This default implementation returns a more keys panel.
@@ -399,18 +399,22 @@
             if (primaryCode == Keyboard.CODE_DIGIT0 && latinKeyboard.isPhoneKeyboard()) {
                 tracker.onLongPressed();
                 // Long pressing on 0 in phone number keypad gives you a '+'.
-                return invokeOnKey(Keyboard.CODE_PLUS);
+                invokeCodeInput(Keyboard.CODE_PLUS);
+                invokeReleaseKey(primaryCode);
+                return true;
             }
             if (primaryCode == Keyboard.CODE_SHIFT && latinKeyboard.isAlphaKeyboard()) {
                 tracker.onLongPressed();
-                return invokeOnKey(Keyboard.CODE_CAPSLOCK);
+                invokeCodeInput(Keyboard.CODE_CAPSLOCK);
+                invokeReleaseKey(primaryCode);
+                return true;
             }
         }
         if (primaryCode == Keyboard.CODE_SETTINGS || primaryCode == Keyboard.CODE_SPACE) {
             // Both long pressing settings key and space key invoke IME switcher dialog.
-            if (getKeyboardActionListener().onCustomRequest(
-                    LatinIME.CODE_SHOW_INPUT_METHOD_PICKER)) {
+            if (invokeCustomRequest(LatinIME.CODE_SHOW_INPUT_METHOD_PICKER)) {
                 tracker.onLongPressed();
+                invokeReleaseKey(primaryCode);
                 return true;
             } else {
                 return openMoreKeysPanel(parentKey, tracker);
@@ -420,11 +424,18 @@
         }
     }
 
-    private boolean invokeOnKey(int primaryCode) {
+    private boolean invokeCustomRequest(int code) {
+        return getKeyboardActionListener().onCustomRequest(code);
+    }
+
+    private void invokeCodeInput(int primaryCode) {
         getKeyboardActionListener().onCodeInput(primaryCode, null,
                 KeyboardActionListener.NOT_A_TOUCH_COORDINATE,
                 KeyboardActionListener.NOT_A_TOUCH_COORDINATE);
-        return true;
+    }
+
+    private void invokeReleaseKey(int primaryCode) {
+        getKeyboardActionListener().onRelease(primaryCode, false);
     }
 
     private boolean openMoreKeysPanel(Key parentKey, PointerTracker tracker) {
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardShiftState.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardShiftState.java
index fd98456..28a53ce 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardShiftState.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardShiftState.java
@@ -103,6 +103,10 @@
         return mState == SHIFT_LOCKED || mState == SHIFT_LOCK_SHIFTED;
     }
 
+    public boolean isShiftLockShifted() {
+        return mState == SHIFT_LOCK_SHIFTED;
+    }
+
     public boolean isAutomaticTemporaryUpperCase() {
         return mState == AUTO_SHIFTED;
     }