Merge "Fix test fails caused by I8bede13c87"
diff --git a/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java b/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java
index 5bde668..36ebbb5 100644
--- a/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java
+++ b/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java
@@ -73,7 +73,7 @@
  * Because of the above reasons, this class doesn't extend {@link KeyboardView}.
  */
 public final class EmojiPalettesView extends LinearLayout implements OnTabChangeListener,
-        ViewPager.OnPageChangeListener, View.OnTouchListener,
+        ViewPager.OnPageChangeListener, View.OnClickListener, View.OnTouchListener,
         EmojiPageKeyboardView.OnKeyEventListener {
     static final String TAG = EmojiPalettesView.class.getSimpleName();
     private static final boolean DEBUG_PAGER = false;
@@ -482,22 +482,35 @@
         final LinearLayout actionBar = (LinearLayout)findViewById(R.id.emoji_action_bar);
         mEmojiLayoutParams.setActionBarProperties(actionBar);
 
+        // deleteKey depends only on OnTouchListener.
         final ImageView deleteKey = (ImageView)findViewById(R.id.emoji_keyboard_delete);
         deleteKey.setTag(Constants.CODE_DELETE);
         deleteKey.setOnTouchListener(mDeleteKeyOnTouchListener);
+
+        // alphabetKey depends only on OnTouchListener as it does everything in key-press in
+        // ACTION_DOWN.
         final ImageView alphabetKey = (ImageView)findViewById(R.id.emoji_keyboard_alphabet);
         alphabetKey.setBackgroundResource(mEmojiFunctionalKeyBackgroundId);
         alphabetKey.setTag(Constants.CODE_SWITCH_ALPHA_SYMBOL);
         alphabetKey.setOnTouchListener(this);
-        final ImageView spaceKey = (ImageView)findViewById(R.id.emoji_keyboard_space);
-        spaceKey.setBackgroundResource(mKeyBackgroundId);
-        spaceKey.setTag(Constants.CODE_SPACE);
-        spaceKey.setOnTouchListener(this);
-        mEmojiLayoutParams.setKeyProperties(spaceKey);
+
+        // alphabetKey2 depends only on OnTouchListener as it does everything in key-press in
+        // ACTION_DOWN.
         final ImageView alphabetKey2 = (ImageView)findViewById(R.id.emoji_keyboard_alphabet2);
         alphabetKey2.setBackgroundResource(mEmojiFunctionalKeyBackgroundId);
         alphabetKey2.setTag(Constants.CODE_SWITCH_ALPHA_SYMBOL);
         alphabetKey2.setOnTouchListener(this);
+
+        // spaceKey depends on {@link View.OnClickListener} as well as {@link View.OnTouchListener}.
+        // {@link View.OnTouchListener} is used as the trigger of key-press while
+        // {@link View.OnClickListener} is used as the trigger of key-release which may not occur
+        // if the event is canceled by moving off the finger from the view.
+        final ImageView spaceKey = (ImageView)findViewById(R.id.emoji_keyboard_space);
+        spaceKey.setBackgroundResource(mKeyBackgroundId);
+        spaceKey.setTag(Constants.CODE_SPACE);
+        spaceKey.setOnTouchListener(this);
+        spaceKey.setOnClickListener(this);
+        mEmojiLayoutParams.setKeyProperties(spaceKey);
     }
 
     @Override
@@ -507,7 +520,6 @@
         updateEmojiCategoryPageIdView();
     }
 
-
     @Override
     public void onPageSelected(final int position) {
         final Pair<Integer, Integer> newPos =
@@ -545,40 +557,62 @@
         }
     }
 
-    // Called from {@link EmojiPageKeyboardView} through {@link View.OnTouchListener} interface to
-    // handle touch events from View-based elements such as the space bar.
+    /**
+     * Called from {@link EmojiPageKeyboardView} through {@link android.view.View.OnTouchListener}
+     * interface to handle touch events from View-based elements such as the space bar.
+     * Note that this method is used only for observing {@link MotionEvent#ACTION_DOWN} to trigger
+     * {@link KeyboardActionListener#onPressKey}. {@link KeyboardActionListener#onReleaseKey} will
+     * be covered by {@link #onClick} as long as the event is not canceled.
+     */
     @Override
     public boolean onTouch(final View v, final MotionEvent event) {
+        if (event.getActionMasked() != MotionEvent.ACTION_DOWN) {
+            return false;
+        }
         final Object tag = v.getTag();
         if (!(tag instanceof Integer)) {
             return false;
         }
         final int code = (Integer) tag;
-        switch (event.getAction()) {
-            case MotionEvent.ACTION_DOWN:
-                mKeyboardActionListener.onPressKey(
-                        code, 0 /* repeatCount */, true /* isSinglePointer */);
-                break;
-            case MotionEvent.ACTION_UP:
-                mKeyboardActionListener.onCodeInput(code, NOT_A_COORDINATE, NOT_A_COORDINATE);
-                mKeyboardActionListener.onReleaseKey(code, false /* withSliding */);
-                break;
-        }
+        mKeyboardActionListener.onPressKey(
+                code, 0 /* repeatCount */, true /* isSinglePointer */);
+        // It's important to return false here. Otherwise, {@link #onClick} and touch-down visual
+        // feedback stop working.
         return false;
     }
 
-    // Called from {@link EmojiPageKeyboardView} through
-    // {@link EmojiPageKeyboardView.OnKeyEventListener} interface to handle touch events from
-    // non-View-based elements like typical Emoji characters.
+    /**
+     * Called from {@link EmojiPageKeyboardView} through {@link android.view.View.OnClickListener}
+     * interface to handle non-canceled touch-up events from View-based elements such as the space
+     * bar.
+     */
+    @Override
+    public void onClick(View v) {
+        final Object tag = v.getTag();
+        if (!(tag instanceof Integer)) {
+            return;
+        }
+        final int code = (Integer) tag;
+        mKeyboardActionListener.onCodeInput(code, NOT_A_COORDINATE, NOT_A_COORDINATE);
+        mKeyboardActionListener.onReleaseKey(code, false /* withSliding */);
+    }
+
+    /**
+     * Called from {@link EmojiPageKeyboardView} through
+     * {@link com.android.inputmethod.keyboard.internal.EmojiPageKeyboardView.OnKeyEventListener}
+     * interface to handle touch events from non-View-based elements such as Emoji buttons.
+     */
     @Override
     public void onPressKey(final Key key) {
         final int code = key.getCode();
         mKeyboardActionListener.onPressKey(code, 0 /* repeatCount */, true /* isSinglePointer */);
     }
 
-    // Called from {@link EmojiPageKeyboardView} through
-    // {@link EmojiPageKeyboardView.OnKeyEventListener} interface to handle touch events from
-    // non-View-based elements like typical Emoji characters.
+    /**
+     * Called from {@link EmojiPageKeyboardView} through
+     * {@link com.android.inputmethod.keyboard.internal.EmojiPageKeyboardView.OnKeyEventListener}
+     * interface to handle touch events from non-View-based elements such as Emoji buttons.
+     */
     @Override
     public void onReleaseKey(final Key key) {
         mEmojiPalettesAdapter.addRecentKey(key);
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index ba7503d..efc14fc 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -1011,7 +1011,6 @@
                 false /* isPrediction */);
         // When in fullscreen mode, show completions generated by the application
         setSuggestedWords(suggestedWords);
-        setAutoCorrectionIndicator(false);
         setSuggestionStripShown(true);
         if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
             ResearchLogger.latinIME_onDisplayCompletions(applicationSpecifiedCompletions);
@@ -1331,14 +1330,12 @@
 
     // TODO[IL]: Define a clear interface for this
     public void setSuggestedWords(final SuggestedWords words) {
-        mInputLogic.mSuggestedWords = words;
         if (mSuggestionStripView != null) {
             mSuggestionStripView.setSuggestions(words);
             mKeyboardSwitcher.onAutoCorrectionStateChanged(words.mWillAutoCorrect);
         }
-    }
-
-    private void setAutoCorrectionIndicator(final boolean newAutoCorrectionIndicator) {
+        mInputLogic.mSuggestedWords = words;
+        final boolean newAutoCorrectionIndicator = words.mWillAutoCorrect;
         // Put a blue underline to a word in TextView which will be auto-corrected.
         if (mInputLogic.mIsAutoCorrectionIndicatorOn != newAutoCorrectionIndicator
                 && mInputLogic.mWordComposer.isComposingWord()) {
@@ -1426,16 +1423,8 @@
 
     private void showSuggestionStripWithTypedWord(final SuggestedWords sourceSuggestedWords,
             final String typedWord) {
-        // TODO: refactor this
         final SuggestedWords suggestedWords =
                 sourceSuggestedWords.isEmpty() ? SuggestedWords.EMPTY : sourceSuggestedWords;
-        if (suggestedWords.isEmpty()) {
-            // No auto-correction is available, clear the cached values.
-            AccessibilityUtils.getInstance().setAutoCorrection(suggestedWords, typedWord);
-            setSuggestedWords(suggestedWords);
-            setAutoCorrectionIndicator(false);
-            return;
-        }
         final String autoCorrection;
         if (suggestedWords.mWillAutoCorrect) {
             autoCorrection = suggestedWords.getWord(SuggestedWords.INDEX_OF_AUTO_CORRECTION);
@@ -1444,12 +1433,13 @@
             // because it may differ from mWordComposer.mTypedWord.
             autoCorrection = typedWord;
         }
-        mInputLogic.mWordComposer.setAutoCorrection(autoCorrection);
+        if (SuggestedWords.EMPTY != suggestedWords) {
+            mInputLogic.mWordComposer.setAutoCorrection(autoCorrection);
+        }
         setSuggestedWords(suggestedWords);
-        setAutoCorrectionIndicator(suggestedWords.mWillAutoCorrect);
         setSuggestionStripShown(isSuggestionsStripVisible());
-        // An auto-correction is available, cache it in accessibility code so
-        // we can be speak it if the user touches a key that will insert it.
+        // Cache the auto-correction in accessibility code so we can speak it if the user
+        // touches a key that will insert it.
         AccessibilityUtils.getInstance().setAutoCorrection(suggestedWords, typedWord);
     }
 
@@ -1564,7 +1554,6 @@
         } else {
             setSuggestedWords(currentSettings.mSpacingAndPunctuations.mSuggestPuncList);
         }
-        setAutoCorrectionIndicator(false);
         setSuggestionStripShown(isSuggestionsStripVisible());
     }