Merge "Refactor SuggestionsStripLayoutHelper class"
diff --git a/java/src/com/android/inputmethod/compat/ViewCompatUtils.java b/java/src/com/android/inputmethod/compat/ViewCompatUtils.java
new file mode 100644
index 0000000..dec739d
--- /dev/null
+++ b/java/src/com/android/inputmethod/compat/ViewCompatUtils.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.compat;
+
+import android.view.View;
+
+import java.lang.reflect.Method;
+
+// TODO: Use {@link android.support.v4.view.ViewCompat} instead of this utility class.
+// Currently {@link #getPaddingEnd(View)} and {@link #setPaddingRelative(View,int,int,int,int)}
+// are missing from android-support-v4 static library in KitKat SDK.
+public final class ViewCompatUtils {
+    // Note that View.LAYOUT_DIRECTION_LTR and View.LAYOUT_DIRECTION_RTL have been introduced in
+    // API level 17 (Build.VERSION_CODE.JELLY_BEAN_MR1).
+    public static final int LAYOUT_DIRECTION_LTR = (Integer)CompatUtils.getFieldValue(null, 0x0,
+            CompatUtils.getField(View.class, "LAYOUT_DIRECTION_LTR"));
+    public static final int LAYOUT_DIRECTION_RTL = (Integer)CompatUtils.getFieldValue(null, 0x1,
+            CompatUtils.getField(View.class, "LAYOUT_DIRECTION_RTL"));
+
+    // Note that View.getPaddingEnd(), View.setPaddingRelative(int,int,int,int), and
+    // View.getLayoutDirection() have been introduced in API level 17
+    // (Build.VERSION_CODE.JELLY_BEAN_MR1).
+    private static final Method METHOD_getPaddingEnd = CompatUtils.getMethod(
+            View.class, "getPaddingEnd");
+    private static final Method METHOD_setPaddingRelative = CompatUtils.getMethod(
+            View.class, "setPaddingRelative",
+            Integer.TYPE, Integer.TYPE, Integer.TYPE, Integer.TYPE);
+    private static final Method METHOD_getLayoutDirection = CompatUtils.getMethod(
+            View.class, "getLayoutDirection");
+
+    private ViewCompatUtils() {
+        // This utility class is not publicly instantiable.
+    }
+
+    public static int getPaddingEnd(final View view) {
+        if (METHOD_getPaddingEnd == null) {
+            return view.getPaddingRight();
+        }
+        return (Integer)CompatUtils.invoke(view, 0, METHOD_getPaddingEnd);
+    }
+
+    public static void setPaddingRelative(final View view, final int start, final int top,
+            final int end, final int bottom) {
+        if (METHOD_setPaddingRelative == null) {
+            view.setPadding(start, top, end, bottom);
+            return;
+        }
+        CompatUtils.invoke(view, null, METHOD_setPaddingRelative, start, top, end, bottom);
+    }
+
+    public static int getLayoutDirection(final View view) {
+        if (METHOD_getLayoutDirection == null) {
+            return LAYOUT_DIRECTION_LTR;
+        }
+        return (Integer)CompatUtils.invoke(view, 0, METHOD_getLayoutDirection);
+    }
+}
diff --git a/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java b/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java
index 8dea908..5bde668 100644
--- a/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java
+++ b/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java
@@ -23,12 +23,13 @@
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
+import android.graphics.Color;
 import android.graphics.Rect;
 import android.os.Build;
+import android.os.CountDownTimer;
 import android.preference.PreferenceManager;
 import android.support.v4.view.PagerAdapter;
 import android.support.v4.view.ViewPager;
-import android.text.format.DateUtils;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.Pair;
@@ -58,6 +59,7 @@
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
 
 /**
  * View class to implement Emoji palettes.
@@ -752,9 +754,8 @@
         }
     }
 
-    // TODO: Do the same things done in PointerTracker
     private static class DeleteKeyOnTouchListener implements OnTouchListener {
-        private static final long MAX_REPEAT_COUNT_TIME = 30 * DateUtils.SECOND_IN_MILLIS;
+        private static final long MAX_REPEAT_COUNT_TIME = TimeUnit.SECONDS.toMillis(30);
         private final int mDeleteKeyPressedBackgroundColor;
         private final long mKeyRepeatStartTimeout;
         private final long mKeyRepeatInterval;
@@ -765,61 +766,36 @@
                     res.getColor(R.color.emoji_key_pressed_background_color);
             mKeyRepeatStartTimeout = res.getInteger(R.integer.config_key_repeat_start_timeout);
             mKeyRepeatInterval = res.getInteger(R.integer.config_key_repeat_interval);
+            mTimer = new CountDownTimer(MAX_REPEAT_COUNT_TIME, mKeyRepeatInterval) {
+                @Override
+                public void onTick(long millisUntilFinished) {
+                    final long elapsed = MAX_REPEAT_COUNT_TIME - millisUntilFinished;
+                    if (elapsed < mKeyRepeatStartTimeout) {
+                        return;
+                    }
+                    onKeyRepeat();
+                }
+                @Override
+                public void onFinish() {
+                    onKeyRepeat();
+                }
+            };
         }
 
+        /** Key-repeat state. */
+        private static final int KEY_REPEAT_STATE_INITIALIZED = 0;
+        // The key is touched but auto key-repeat is not started yet.
+        private static final int KEY_REPEAT_STATE_KEY_DOWN = 1;
+        // At least one key-repeat event has already been triggered and the key is not released.
+        private static final int KEY_REPEAT_STATE_KEY_REPEAT = 2;
+
         private KeyboardActionListener mKeyboardActionListener =
                 KeyboardActionListener.EMPTY_LISTENER;
-        private DummyRepeatKeyRepeatTimer mTimer;
 
-        private synchronized void startRepeat() {
-            if (mTimer != null) {
-                abortRepeat();
-            }
-            mTimer = new DummyRepeatKeyRepeatTimer();
-            mTimer.start();
-        }
-
-        private synchronized void abortRepeat() {
-            mTimer.abort();
-            mTimer = null;
-        }
-
-        // TODO: Remove
-        // This function is mimicking the repeat code in PointerTracker.
-        // Specifically referring to PointerTracker#startRepeatKey and PointerTracker#onKeyRepeat.
-        private class DummyRepeatKeyRepeatTimer extends Thread {
-            public boolean mAborted = false;
-
-            @Override
-            public void run() {
-                int repeatCount = 1;
-                int timeCount = 0;
-                while (timeCount < MAX_REPEAT_COUNT_TIME && !mAborted) {
-                    if (timeCount > mKeyRepeatStartTimeout) {
-                        pressDelete(repeatCount);
-                    }
-                    timeCount += mKeyRepeatInterval;
-                    ++repeatCount;
-                    try {
-                        Thread.sleep(mKeyRepeatInterval);
-                    } catch (InterruptedException e) {
-                    }
-                }
-            }
-
-            public void abort() {
-                mAborted = true;
-            }
-        }
-
-        public void pressDelete(final int repeatCount) {
-            mKeyboardActionListener.onPressKey(
-                    Constants.CODE_DELETE, repeatCount, true /* isSinglePointer */);
-            mKeyboardActionListener.onCodeInput(
-                    Constants.CODE_DELETE, NOT_A_COORDINATE, NOT_A_COORDINATE);
-            mKeyboardActionListener.onReleaseKey(
-                    Constants.CODE_DELETE, false /* withSliding */);
-        }
+        // TODO: Do the same things done in PointerTracker
+        private final CountDownTimer mTimer;
+        private int mState = KEY_REPEAT_STATE_INITIALIZED;
+        private int mRepeatCount = 0;
 
         public void setKeyboardActionListener(final KeyboardActionListener listener) {
             mKeyboardActionListener = listener;
@@ -827,18 +803,80 @@
 
         @Override
         public boolean onTouch(final View v, final MotionEvent event) {
-            switch(event.getAction()) {
+            switch (event.getActionMasked()) {
             case MotionEvent.ACTION_DOWN:
-                v.setBackgroundColor(mDeleteKeyPressedBackgroundColor);
-                pressDelete(0 /* repeatCount */);
-                startRepeat();
+                onTouchDown(v);
                 return true;
+            case MotionEvent.ACTION_MOVE:
+                final float x = event.getX();
+                final float y = event.getY();
+                if (x < 0.0f || v.getWidth() < x || y < 0.0f || v.getHeight() < y) {
+                    // Stop generating key events once the finger moves away from the view area.
+                    onTouchCanceled(v);
+                }
+                return true;
+            case MotionEvent.ACTION_CANCEL:
             case MotionEvent.ACTION_UP:
-                v.setBackgroundColor(0);
-                abortRepeat();
+                onTouchUp(v);
                 return true;
             }
             return false;
         }
+
+        private void handleKeyDown() {
+            mKeyboardActionListener.onPressKey(
+                    Constants.CODE_DELETE, mRepeatCount, true /* isSinglePointer */);
+        }
+
+        private void handleKeyUp() {
+            mKeyboardActionListener.onCodeInput(
+                    Constants.CODE_DELETE, NOT_A_COORDINATE, NOT_A_COORDINATE);
+            mKeyboardActionListener.onReleaseKey(
+                    Constants.CODE_DELETE, false /* withSliding */);
+            ++mRepeatCount;
+        }
+
+        private void onTouchDown(final View v) {
+            mTimer.cancel();
+            mRepeatCount = 0;
+            handleKeyDown();
+            v.setBackgroundColor(mDeleteKeyPressedBackgroundColor);
+            mState = KEY_REPEAT_STATE_KEY_DOWN;
+            mTimer.start();
+        }
+
+        private void onTouchUp(final View v) {
+            mTimer.cancel();
+            if (mState == KEY_REPEAT_STATE_KEY_DOWN) {
+                handleKeyUp();
+            }
+            v.setBackgroundColor(Color.TRANSPARENT);
+            mState = KEY_REPEAT_STATE_INITIALIZED;
+        }
+
+        private void onTouchCanceled(final View v) {
+            mTimer.cancel();
+            v.setBackgroundColor(Color.TRANSPARENT);
+            mState = KEY_REPEAT_STATE_INITIALIZED;
+        }
+
+        // Called by {@link #mTimer} in the UI thread as an auto key-repeat signal.
+        private void onKeyRepeat() {
+            switch (mState) {
+            case KEY_REPEAT_STATE_INITIALIZED:
+                // Basically this should not happen.
+                break;
+            case KEY_REPEAT_STATE_KEY_DOWN:
+                // Do not call {@link #handleKeyDown} here because it has already been called
+                // in {@link #onTouchDown}.
+                handleKeyUp();
+                mState = KEY_REPEAT_STATE_KEY_REPEAT;
+                break;
+            case KEY_REPEAT_STATE_KEY_REPEAT:
+                handleKeyDown();
+                handleKeyUp();
+                break;
+            }
+        }
     }
 }
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index bba9bd5..82d824b 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -888,10 +888,7 @@
         mInputLogic.finishInput();
         // Notify ResearchLogger
         if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
-            ResearchLogger.latinIME_onFinishInputViewInternal(finishingInput,
-                    // TODO[IL]: mInputLogic.mConnection should be private
-                    mInputLogic.mConnection.getExpectedSelectionStart(),
-                    mInputLogic.mConnection.getExpectedSelectionEnd(), getCurrentInputConnection());
+            ResearchLogger.latinIME_onFinishInputViewInternal(finishingInput);
         }
     }
 
@@ -1186,7 +1183,7 @@
     // the right layout.
     // TODO[IL]: Remove this, pass the input logic to the keyboard switcher instead?
     public int getCurrentAutoCapsState() {
-        return mInputLogic.getCurrentAutoCapsState(null /* optionalSettingsValues */);
+        return mInputLogic.getCurrentAutoCapsState(Settings.getInstance().getCurrent());
     }
 
     // Called from the KeyboardSwitcher which needs to know recaps state to display
@@ -1288,8 +1285,12 @@
         } else {
             codeToSend = codePoint;
         }
-        mInputLogic.onCodeInput(codeToSend, keyX, keyY, mHandler, mKeyboardSwitcher,
-                mSubtypeSwitcher);
+        if (Constants.CODE_SHORTCUT == codePoint) {
+            mSubtypeSwitcher.switchToShortcutIME(this);
+            // Still call the *#onCodeInput methods for readability.
+        }
+        mInputLogic.onCodeInput(codeToSend, keyX, keyY, Settings.getInstance().getCurrent(),
+                mHandler, mKeyboardSwitcher);
         mKeyboardSwitcher.onCodeInput(codePoint);
     }
 
diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
index 6e9bdc3..6e35432 100644
--- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
+++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
@@ -36,14 +36,12 @@
 import com.android.inputmethod.latin.LatinIME;
 import com.android.inputmethod.latin.LatinImeLogger;
 import com.android.inputmethod.latin.RichInputConnection;
-import com.android.inputmethod.latin.SubtypeSwitcher;
 import com.android.inputmethod.latin.Suggest;
 import com.android.inputmethod.latin.Suggest.OnGetSuggestedWordsCallback;
 import com.android.inputmethod.latin.SuggestedWords;
 import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
 import com.android.inputmethod.latin.WordComposer;
 import com.android.inputmethod.latin.define.ProductionFlag;
-import com.android.inputmethod.latin.settings.Settings;
 import com.android.inputmethod.latin.settings.SettingsValues;
 import com.android.inputmethod.latin.settings.SpacingAndPunctuations;
 import com.android.inputmethod.latin.utils.AsyncResultHolder;
@@ -192,13 +190,12 @@
      * @param y the y-coordinate where the user pressed the key, or NOT_A_COORDINATE.
      */
     public void onCodeInput(final int code, final int x, final int y,
-            // TODO: remove these three arguments
-            final LatinIME.UIHandler handler,
-            final KeyboardSwitcher keyboardSwitcher, final SubtypeSwitcher subtypeSwitcher) {
+            final SettingsValues settingsValues,
+            // TODO: remove these two arguments
+            final LatinIME.UIHandler handler, final KeyboardSwitcher keyboardSwitcher) {
         if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
             ResearchLogger.latinIME_onCodeInput(code, x, y);
         }
-        final SettingsValues settingsValues = Settings.getInstance().getCurrent();
         final long when = SystemClock.uptimeMillis();
         if (code != Constants.CODE_DELETE
                 || when > mLastKeyTime + Constants.LONG_PRESS_MILLISECONDS) {
@@ -247,7 +244,8 @@
             onSettingsKeyPressed();
             break;
         case Constants.CODE_SHORTCUT:
-            subtypeSwitcher.switchToShortcutIME(mLatinIME);
+            // We need to switch to the shortcut IME. This is handled by LatinIME since the
+            // input logic has no business with IME switching.
             break;
         case Constants.CODE_ACTION_NEXT:
             performEditorAction(EditorInfo.IME_ACTION_NEXT);
@@ -1256,15 +1254,10 @@
      * This is called from the KeyboardSwitcher (through a trampoline in LatinIME) because it
      * needs to know auto caps state to display the right layout.
      *
-     * @param optionalSettingsValues settings values, or null if we should just get the current ones
-     *   from the singleton.
+     * @param settingsValues the relevant settings values
      * @return a caps mode from TextUtils.CAP_MODE_* or Constants.TextUtils.CAP_MODE_OFF.
      */
-    public int getCurrentAutoCapsState(final SettingsValues optionalSettingsValues) {
-        // If we are in a batch edit, we need to use the same settings values as the outside
-        // code, that will pass it to us. Otherwise, we can just take the current values.
-        final SettingsValues settingsValues = null != optionalSettingsValues
-                ? optionalSettingsValues : Settings.getInstance().getCurrent();
+    public int getCurrentAutoCapsState(final SettingsValues settingsValues) {
         if (!settingsValues.mAutoCap) return Constants.TextUtils.CAP_MODE_OFF;
 
         final EditorInfo ei = getCurrentInputEditorInfo();
diff --git a/java/src/com/android/inputmethod/latin/setup/SetupStartIndicatorView.java b/java/src/com/android/inputmethod/latin/setup/SetupStartIndicatorView.java
index 73d25f6..974dfdd 100644
--- a/java/src/com/android/inputmethod/latin/setup/SetupStartIndicatorView.java
+++ b/java/src/com/android/inputmethod/latin/setup/SetupStartIndicatorView.java
@@ -21,13 +21,13 @@
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.graphics.Path;
-import android.support.v4.view.ViewCompat;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
+import com.android.inputmethod.compat.ViewCompatUtils;
 import com.android.inputmethod.latin.R;
 
 public final class SetupStartIndicatorView extends LinearLayout {
@@ -96,13 +96,13 @@
         @Override
         protected void onDraw(final Canvas canvas) {
             super.onDraw(canvas);
-            final int layoutDirection = ViewCompat.getLayoutDirection(this);
+            final int layoutDirection = ViewCompatUtils.getLayoutDirection(this);
             final int width = getWidth();
             final int height = getHeight();
             final float halfHeight = height / 2.0f;
             final Path path = mIndicatorPath;
             path.rewind();
-            if (layoutDirection == ViewCompat.LAYOUT_DIRECTION_RTL) {
+            if (layoutDirection == ViewCompatUtils.LAYOUT_DIRECTION_RTL) {
                 // Left arrow
                 path.moveTo(width, 0.0f);
                 path.lineTo(0.0f, halfHeight);
diff --git a/java/src/com/android/inputmethod/latin/setup/SetupStepIndicatorView.java b/java/src/com/android/inputmethod/latin/setup/SetupStepIndicatorView.java
index 6734e61..c909507 100644
--- a/java/src/com/android/inputmethod/latin/setup/SetupStepIndicatorView.java
+++ b/java/src/com/android/inputmethod/latin/setup/SetupStepIndicatorView.java
@@ -20,10 +20,10 @@
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.graphics.Path;
-import android.support.v4.view.ViewCompat;
 import android.util.AttributeSet;
 import android.view.View;
 
+import com.android.inputmethod.compat.ViewCompatUtils;
 import com.android.inputmethod.latin.R;
 
 public final class SetupStepIndicatorView extends View {
@@ -38,12 +38,12 @@
     }
 
     public void setIndicatorPosition(final int stepPos, final int totalStepNum) {
-        final int layoutDirection = ViewCompat.getLayoutDirection(this);
+        final int layoutDirection = ViewCompatUtils.getLayoutDirection(this);
         // The indicator position is the center of the partition that is equally divided into
         // the total step number.
         final float partionWidth = 1.0f / totalStepNum;
         final float pos = stepPos * partionWidth + partionWidth / 2.0f;
-        mXRatio = (layoutDirection == ViewCompat.LAYOUT_DIRECTION_RTL) ? 1.0f - pos : pos;
+        mXRatio = (layoutDirection == ViewCompatUtils.LAYOUT_DIRECTION_RTL) ? 1.0f - pos : pos;
         invalidate();
     }
 
diff --git a/java/src/com/android/inputmethod/latin/setup/SetupWizardActivity.java b/java/src/com/android/inputmethod/latin/setup/SetupWizardActivity.java
index baff57a..5072fab 100644
--- a/java/src/com/android/inputmethod/latin/setup/SetupWizardActivity.java
+++ b/java/src/com/android/inputmethod/latin/setup/SetupWizardActivity.java
@@ -25,7 +25,6 @@
 import android.os.Bundle;
 import android.os.Message;
 import android.provider.Settings;
-import android.support.v4.view.ViewCompat;
 import android.util.Log;
 import android.view.View;
 import android.view.inputmethod.InputMethodInfo;
@@ -35,6 +34,7 @@
 import android.widget.VideoView;
 
 import com.android.inputmethod.compat.TextViewCompatUtils;
+import com.android.inputmethod.compat.ViewCompatUtils;
 import com.android.inputmethod.latin.R;
 import com.android.inputmethod.latin.settings.SettingsActivity;
 import com.android.inputmethod.latin.utils.CollectionUtils;
@@ -449,8 +449,8 @@
             mActionLabel = (TextView)mStepView.findViewById(R.id.setup_step_action_label);
             mActionLabel.setText(res.getString(actionLabel));
             if (actionIcon == 0) {
-                final int paddingEnd = ViewCompat.getPaddingEnd(mActionLabel);
-                ViewCompat.setPaddingRelative(mActionLabel, paddingEnd, 0, paddingEnd, 0);
+                final int paddingEnd = ViewCompatUtils.getPaddingEnd(mActionLabel);
+                ViewCompatUtils.setPaddingRelative(mActionLabel, paddingEnd, 0, paddingEnd, 0);
             } else {
                 TextViewCompatUtils.setCompoundDrawablesRelativeWithIntrinsicBounds(
                         mActionLabel, res.getDrawable(actionIcon), null, null, null);
diff --git a/java/src/com/android/inputmethod/research/ResearchLogger.java b/java/src/com/android/inputmethod/research/ResearchLogger.java
index 2a8148d..b1f54c0 100644
--- a/java/src/com/android/inputmethod/research/ResearchLogger.java
+++ b/java/src/com/android/inputmethod/research/ResearchLogger.java
@@ -1117,14 +1117,13 @@
     private static final LogStatement LOGSTATEMENT_LATINIME_ONFINISHINPUTVIEWINTERNAL =
             new LogStatement("LatinIMEOnFinishInputViewInternal", false, false, "isTextTruncated",
                     "text");
-    public static void latinIME_onFinishInputViewInternal(final boolean finishingInput,
-            final int savedSelectionStart, final int savedSelectionEnd, final InputConnection ic) {
+    public static void latinIME_onFinishInputViewInternal(final boolean finishingInput) {
         // The finishingInput flag is set in InputMethodService.  It is true if called from
         // doFinishInput(), which can be called as part of doStartInput().  This can happen at times
         // when the IME is not closing, such as when powering up.  The finishinInput flag is false
         // if called from finishViews(), which is called from hideWindow() and onDestroy().  These
         // are the situations in which we want to finish up the researchLog.
-        if (ic != null && !finishingInput) {
+        if (!finishingInput) {
             final ResearchLogger researchLogger = getInstance();
             // Assume that OUTPUT_ENTIRE_BUFFER is only true when we don't care about privacy (e.g.
             // during a live user test), so the normal isPotentiallyPrivate and
diff --git a/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java
index ccdd567..939dedb 100644
--- a/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java
+++ b/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java
@@ -20,9 +20,9 @@
 import android.content.res.Resources;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
+import android.view.inputmethod.InputMethodInfo;
 import android.view.inputmethod.InputMethodSubtype;
 
-import com.android.inputmethod.latin.R;
 import com.android.inputmethod.latin.RichInputMethodManager;
 
 import java.util.ArrayList;
@@ -30,7 +30,7 @@
 
 @SmallTest
 public class SubtypeLocaleUtilsTests extends AndroidTestCase {
-    // Locale to subtypes list.
+    // All input method subtypes of LatinIME.
     private final ArrayList<InputMethodSubtype> mSubtypesList = CollectionUtils.newArrayList();
 
     private RichInputMethodManager mRichImm;
@@ -62,6 +62,13 @@
         mRes = context.getResources();
         SubtypeLocaleUtils.init(context);
 
+        final InputMethodInfo imi = mRichImm.getInputMethodInfoOfThisIme();
+        final int subtypeCount = imi.getSubtypeCount();
+        for (int index = 0; index < subtypeCount; index++) {
+            final InputMethodSubtype subtype = imi.getSubtypeAt(index);
+            mSubtypesList.add(subtype);
+        }
+
         EN_US = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
                 Locale.US.toString(), "qwerty");
         EN_GB = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
@@ -99,14 +106,15 @@
 
     public void testAllFullDisplayName() {
         for (final InputMethodSubtype subtype : mSubtypesList) {
-            final String subtypeName =
-                    SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(subtype);
+            final String subtypeName = SubtypeLocaleUtils
+                    .getSubtypeDisplayNameInSystemLocale(subtype);
             if (SubtypeLocaleUtils.isNoLanguage(subtype)) {
-                final String noLanguage = mRes.getString(R.string.subtype_no_language);
-                assertTrue(subtypeName, subtypeName.contains(noLanguage));
+                final String layoutName = SubtypeLocaleUtils
+                        .getKeyboardLayoutSetDisplayName(subtype);
+                assertTrue(subtypeName, subtypeName.contains(layoutName));
             } else {
-                final String languageName =
-                        SubtypeLocaleUtils.getSubtypeLocaleDisplayName(subtype.getLocale());
+                final String languageName = SubtypeLocaleUtils
+                        .getSubtypeLocaleDisplayNameInSystemLocale(subtype.getLocale());
                 assertTrue(subtypeName, subtypeName.contains(languageName));
             }
         }
@@ -266,11 +274,11 @@
 
     public void testAllFullDisplayNameForSpacebar() {
         for (final InputMethodSubtype subtype : mSubtypesList) {
-            final String subtypeName =
-                    SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(subtype);
+            final String subtypeName = SubtypeLocaleUtils
+                    .getSubtypeDisplayNameInSystemLocale(subtype);
             final String spacebarText = SubtypeLocaleUtils.getFullDisplayName(subtype);
-            final String languageName =
-                    SubtypeLocaleUtils.getSubtypeLocaleDisplayName(subtype.getLocale());
+            final String languageName = SubtypeLocaleUtils
+                    .getSubtypeLocaleDisplayName(subtype.getLocale());
             if (SubtypeLocaleUtils.isNoLanguage(subtype)) {
                 assertFalse(subtypeName, spacebarText.contains(languageName));
             } else {
@@ -281,15 +289,16 @@
 
    public void testAllMiddleDisplayNameForSpacebar() {
         for (final InputMethodSubtype subtype : mSubtypesList) {
-            final String subtypeName =
-                    SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(subtype);
+            final String subtypeName = SubtypeLocaleUtils
+                    .getSubtypeDisplayNameInSystemLocale(subtype);
             final String spacebarText = SubtypeLocaleUtils.getMiddleDisplayName(subtype);
             if (SubtypeLocaleUtils.isNoLanguage(subtype)) {
                 assertEquals(subtypeName,
-                        SubtypeLocaleUtils.getKeyboardLayoutSetName(subtype), spacebarText);
+                        SubtypeLocaleUtils.getKeyboardLayoutSetDisplayName(subtype), spacebarText);
             } else {
+                final Locale locale = SubtypeLocaleUtils.getSubtypeLocale(subtype);
                 assertEquals(subtypeName,
-                        SubtypeLocaleUtils.getSubtypeLocaleDisplayName(subtype.getLocale()),
+                        SubtypeLocaleUtils.getSubtypeLocaleDisplayName(locale.getLanguage()),
                         spacebarText);
             }
         }
@@ -297,8 +306,8 @@
 
     public void testAllShortDisplayNameForSpacebar() {
         for (final InputMethodSubtype subtype : mSubtypesList) {
-            final String subtypeName =
-                    SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(subtype);
+            final String subtypeName = SubtypeLocaleUtils
+                    .getSubtypeDisplayNameInSystemLocale(subtype);
             final Locale locale = SubtypeLocaleUtils.getSubtypeLocale(subtype);
             final String spacebarText = SubtypeLocaleUtils.getShortDisplayName(subtype);
             final String languageCode = StringUtils.capitalizeFirstCodePoint(