Ignore the Emoji key when not connected.

When the LatinIME does not have an active InputConnection, it will not try
to toggle the Emoji keyboard.

Bug 19513415.

Change-Id: I31f928cd7db1cddd771c548cd3dc42f8af64d0e2
diff --git a/java/src/com/android/inputmethod/latin/EmojiAltPhysicalKeyDetector.java b/java/src/com/android/inputmethod/latin/EmojiAltPhysicalKeyDetector.java
index 8116a49..9b27111 100644
--- a/java/src/com/android/inputmethod/latin/EmojiAltPhysicalKeyDetector.java
+++ b/java/src/com/android/inputmethod/latin/EmojiAltPhysicalKeyDetector.java
@@ -16,6 +16,7 @@
 
 package com.android.inputmethod.latin;
 
+import android.util.Log;
 import android.view.KeyEvent;
 
 import com.android.inputmethod.keyboard.KeyboardSwitcher;
@@ -25,10 +26,18 @@
  * A class for detecting Emoji-Alt physical key.
  */
 final class EmojiAltPhysicalKeyDetector {
+    private static final String TAG = "EmojiAltPhysicalKeyDetector";
+
+    private final RichInputConnection mRichInputConnection;
+
     // True if the Alt key has been used as a modifier. In this case the Alt key up isn't
     // recognized as an emoji key.
     private boolean mAltHasBeenUsedAsAModifier;
 
+    public EmojiAltPhysicalKeyDetector(final RichInputConnection richInputConnection) {
+        mRichInputConnection = richInputConnection;
+    }
+
     /**
      * Record a down key event.
      * @param keyEvent a down key event.
@@ -62,9 +71,14 @@
         if (!Settings.getInstance().getCurrent().mEnableEmojiAltPhysicalKey) {
             return;
         }
-        if (!mAltHasBeenUsedAsAModifier) {
-            onEmojiAltKeyDetected();
+        if (mAltHasBeenUsedAsAModifier) {
+            return;
         }
+        if (!mRichInputConnection.isConnected()) {
+            Log.w(TAG, "onKeyUp() : No connection to text view");
+            return;
+        }
+        onEmojiAltKeyDetected();
     }
 
     private static void onEmojiAltKeyDetected() {
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index c5c7d2d..76d4a4a 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -143,7 +143,7 @@
     @UsedForTesting final KeyboardSwitcher mKeyboardSwitcher;
     private final SubtypeState mSubtypeState = new SubtypeState();
     private final EmojiAltPhysicalKeyDetector mEmojiAltPhysicalKeyDetector =
-            new EmojiAltPhysicalKeyDetector();
+            new EmojiAltPhysicalKeyDetector(mInputLogic.mConnection);
     private StatsUtilsManager mStatsUtilsManager;
     // Working variable for {@link #startShowingInputView()} and
     // {@link #onEvaluateInputViewShown()}.
diff --git a/java/src/com/android/inputmethod/latin/RichInputConnection.java b/java/src/com/android/inputmethod/latin/RichInputConnection.java
index 0210d7e..08e8fe3 100644
--- a/java/src/com/android/inputmethod/latin/RichInputConnection.java
+++ b/java/src/com/android/inputmethod/latin/RichInputConnection.java
@@ -101,12 +101,17 @@
     private final InputMethodService mParent;
     InputConnection mIC;
     int mNestLevel;
+
     public RichInputConnection(final InputMethodService parent) {
         mParent = parent;
         mIC = null;
         mNestLevel = 0;
     }
 
+    public boolean isConnected() {
+        return mIC != null;
+    }
+
     private void checkConsistencyForDebug() {
         final ExtractedTextRequest r = new ExtractedTextRequest();
         r.hintMaxChars = 0;
@@ -142,7 +147,7 @@
     public void beginBatchEdit() {
         if (++mNestLevel == 1) {
             mIC = mParent.getCurrentInputConnection();
-            if (null != mIC) {
+            if (isConnected()) {
                 mIC.beginBatchEdit();
             }
         } else {
@@ -157,7 +162,7 @@
 
     public void endBatchEdit() {
         if (mNestLevel <= 0) Log.e(TAG, "Batch edit not in progress!"); // TODO: exception instead
-        if (--mNestLevel == 0 && null != mIC) {
+        if (--mNestLevel == 0 && isConnected()) {
             mIC.endBatchEdit();
         }
         if (DEBUG_PREVIOUS_TEXT) checkConsistencyForDebug();
@@ -189,7 +194,7 @@
             Log.d(TAG, "Will try to retrieve text later.");
             return false;
         }
-        if (null != mIC && shouldFinishComposition) {
+        if (isConnected() && shouldFinishComposition) {
             mIC.finishComposingText();
         }
         return true;
@@ -205,8 +210,9 @@
         mIC = mParent.getCurrentInputConnection();
         // Call upon the inputconnection directly since our own method is using the cache, and
         // we want to refresh it.
-        final CharSequence textBeforeCursor = null == mIC ? null :
-                mIC.getTextBeforeCursor(Constants.EDITOR_CONTENTS_CACHE_SIZE, 0);
+        final CharSequence textBeforeCursor = isConnected()
+                ? mIC.getTextBeforeCursor(Constants.EDITOR_CONTENTS_CACHE_SIZE, 0)
+                : null;
         if (null == textBeforeCursor) {
             // For some reason the app thinks we are not connected to it. This looks like a
             // framework bug... Fall back to ground state and return false.
@@ -235,7 +241,7 @@
         // it works, but it's wrong and should be fixed.
         mCommittedTextBeforeComposingText.append(mComposingText);
         mComposingText.setLength(0);
-        if (null != mIC) {
+        if (isConnected()) {
             mIC.finishComposingText();
         }
     }
@@ -256,7 +262,7 @@
         mExpectedSelStart += text.length() - mComposingText.length();
         mExpectedSelEnd = mExpectedSelStart;
         mComposingText.setLength(0);
-        if (null != mIC) {
+        if (isConnected()) {
             mTempObjectForCommitText.clear();
             mTempObjectForCommitText.append(text);
             final CharacterStyle[] spans = mTempObjectForCommitText.getSpans(
@@ -283,7 +289,7 @@
     }
 
     public CharSequence getSelectedText(final int flags) {
-        return (null == mIC) ? null : mIC.getSelectedText(flags);
+        return isConnected() ?  mIC.getSelectedText(flags) : null;
     }
 
     public boolean canDeleteCharacters() {
@@ -308,7 +314,9 @@
     public int getCursorCapsMode(final int inputType,
             final SpacingAndPunctuations spacingAndPunctuations, final boolean hasSpaceBefore) {
         mIC = mParent.getCurrentInputConnection();
-        if (null == mIC) return Constants.TextUtils.CAP_MODE_OFF;
+        if (!isConnected()) {
+            return Constants.TextUtils.CAP_MODE_OFF;
+        }
         if (!TextUtils.isEmpty(mComposingText)) {
             if (hasSpaceBefore) {
                 // If we have some composing text and a space before, then we should have
@@ -368,12 +376,12 @@
             return s;
         }
         mIC = mParent.getCurrentInputConnection();
-        return (null == mIC) ? null : mIC.getTextBeforeCursor(n, flags);
+        return isConnected() ? mIC.getTextBeforeCursor(n, flags) : null;
     }
 
     public CharSequence getTextAfterCursor(final int n, final int flags) {
         mIC = mParent.getCurrentInputConnection();
-        return (null == mIC) ? null : mIC.getTextAfterCursor(n, flags);
+        return isConnected() ? mIC.getTextAfterCursor(n, flags) : null;
     }
 
     public void deleteSurroundingText(final int beforeLength, final int afterLength) {
@@ -400,7 +408,7 @@
             mExpectedSelEnd -= mExpectedSelStart;
             mExpectedSelStart = 0;
         }
-        if (null != mIC) {
+        if (isConnected()) {
             mIC.deleteSurroundingText(beforeLength, afterLength);
         }
         if (DEBUG_PREVIOUS_TEXT) checkConsistencyForDebug();
@@ -408,7 +416,7 @@
 
     public void performEditorAction(final int actionId) {
         mIC = mParent.getCurrentInputConnection();
-        if (null != mIC) {
+        if (isConnected()) {
             mIC.performEditorAction(actionId);
         }
     }
@@ -460,7 +468,7 @@
                 break;
             }
         }
-        if (null != mIC) {
+        if (isConnected()) {
             mIC.sendKeyEvent(keyEvent);
         }
     }
@@ -483,7 +491,7 @@
             mCommittedTextBeforeComposingText.append(
                     textBeforeCursor.subSequence(0, indexOfStartOfComposingText));
         }
-        if (null != mIC) {
+        if (isConnected()) {
             mIC.setComposingRegion(start, end);
         }
     }
@@ -497,7 +505,7 @@
         mComposingText.append(text);
         // TODO: support values of newCursorPosition != 1. At this time, this is never called with
         // newCursorPosition != 1.
-        if (null != mIC) {
+        if (isConnected()) {
             mIC.setComposingText(text, newCursorPosition);
         }
         if (DEBUG_PREVIOUS_TEXT) checkConsistencyForDebug();
@@ -522,7 +530,7 @@
         }
         mExpectedSelStart = start;
         mExpectedSelEnd = end;
-        if (null != mIC) {
+        if (isConnected()) {
             final boolean isIcValid = mIC.setSelection(start, end);
             if (!isIcValid) {
                 return false;
@@ -536,7 +544,7 @@
         if (DEBUG_PREVIOUS_TEXT) checkConsistencyForDebug();
         // This has no effect on the text field and does not change its content. It only makes
         // TextView flash the text for a second based on indices contained in the argument.
-        if (null != mIC) {
+        if (isConnected()) {
             mIC.commitCorrection(correctionInfo);
         }
         if (DEBUG_PREVIOUS_TEXT) checkConsistencyForDebug();
@@ -552,7 +560,7 @@
         mExpectedSelStart += text.length() - mComposingText.length();
         mExpectedSelEnd = mExpectedSelStart;
         mComposingText.setLength(0);
-        if (null != mIC) {
+        if (isConnected()) {
             mIC.commitCompletion(completionInfo);
         }
         if (DEBUG_PREVIOUS_TEXT) checkConsistencyForDebug();
@@ -563,7 +571,7 @@
     public NgramContext getNgramContextFromNthPreviousWord(
             final SpacingAndPunctuations spacingAndPunctuations, final int n) {
         mIC = mParent.getCurrentInputConnection();
-        if (null == mIC) {
+        if (!isConnected()) {
             return NgramContext.EMPTY_PREV_WORDS_INFO;
         }
         final CharSequence prev = getTextBeforeCursor(LOOKBACK_CHARACTER_NUM, 0);
@@ -608,7 +616,7 @@
     public TextRange getWordRangeAtCursor(final SpacingAndPunctuations spacingAndPunctuations,
             final int scriptId) {
         mIC = mParent.getCurrentInputConnection();
-        if (mIC == null) {
+        if (!isConnected()) {
             return null;
         }
         final CharSequence before = mIC.getTextBeforeCursor(Constants.EDITOR_CONTENTS_CACHE_SIZE,
@@ -824,7 +832,7 @@
         mIC = mParent.getCurrentInputConnection();
         final CharSequence textBeforeCursor = getTextBeforeCursor(
                 Constants.EDITOR_CONTENTS_CACHE_SIZE, 0);
-        final CharSequence selectedText = null == mIC ? null : mIC.getSelectedText(0 /* flags */);
+        final CharSequence selectedText = isConnected() ? mIC.getSelectedText(0 /* flags */) : null;
         if (null == textBeforeCursor ||
                 (!TextUtils.isEmpty(selectedText) && mExpectedSelEnd == mExpectedSelStart)) {
             // If textBeforeCursor is null, we have no idea what kind of text field we have or if
@@ -863,7 +871,7 @@
     @Override
     public boolean performPrivateCommand(final String action, final Bundle data) {
         mIC = mParent.getCurrentInputConnection();
-        if (mIC == null) {
+        if (!isConnected()) {
             return false;
         }
         return mIC.performPrivateCommand(action, data);
@@ -923,7 +931,7 @@
     public boolean requestCursorUpdates(final boolean enableMonitor,
             final boolean requestImmediateCallback) {
         mIC = mParent.getCurrentInputConnection();
-        if (mIC == null) {
+        if (!isConnected()) {
             return false;
         }
         return InputConnectionCompatUtils.requestCursorUpdates(