Merge "Make it easy to open several dictionaries from tests"
diff --git a/java/res/values/attrs.xml b/java/res/values/attrs.xml
index 478a5c0..80bf704 100644
--- a/java/res/values/attrs.xml
+++ b/java/res/values/attrs.xml
@@ -161,7 +161,7 @@
 
     <declare-styleable name="SuggestionStripView">
         <attr name="suggestionStripOption" format="integer">
-            <!-- This should be aligned with SuggestionStripViewParams.AUTO_CORRECT_* and etc. -->
+            <!-- This should be aligned with SuggestionStripLayoutHelper.AUTO_CORRECT_* and etc. -->
             <flag name="autoCorrectBold" value="0x01" />
             <flag name="autoCorrectUnderline" value="0x02" />
             <flag name="validTypedWordBold" value="0x04" />
diff --git a/java/res/values/keypress-vibration-durations.xml b/java/res/values/keypress-vibration-durations.xml
index ad6bead..0474b1c 100644
--- a/java/res/values/keypress-vibration-durations.xml
+++ b/java/res/values/keypress-vibration-durations.xml
@@ -39,10 +39,19 @@
         <item>MODEL=(SAMSUNG-)?SCH-(J021|R530|I535|I939):MANUFACTURER=samsung,8</item>
         <item>MODEL=(SAMSUNG-)?(SCL21|SC-06D|SC-03E):MANUFACTURER=samsung,8</item>
         <item>MODEL=(SAMSUNG-)?(SHV-210[KLS]?|SPH-L710):MANUFACTURER=samsung,8</item>
+        <!-- Samsung Galaxy S4 -->
+        <item>MODEL=(SAMSUNG-)?GT-I(950[0258][G]?):MANUFACTURER=samsung,7</item>
+        <item>MODEL=(SAMSUNG-)?SGH-(I337|M919|N045):MANUFACTURER=samsung,7</item>
+        <item>MODEL=(SAMSUNG-)?SCH-(I545|I959|R970):MANUFACTURER=samsung,7</item>
+        <item>MODEL=(SAMSUNG-)?SPH-(L720):MANUFACTURER=samsung,7</item>
+        <item>MODEL=(SAMSUNG-)?(SC-04E):MANUFACTURER=samsung,7</item>
+        <item>MODEL=(SAMSUNG-)?(SHV-E300[KLS]?):MANUFACTURER=samsung,7</item>
         <!-- LG Optimus G -->
         <item>MODEL=LG-E97[013]|LS970|L-01E:MANUFACTURER=LGE,15</item>
         <!-- HTC One X -->
         <item>MODEL=HTC One X:MANUFACTURER=HTC,20</item>
+        <!-- HTC One -->
+        <item>MODEL=HTC One:MANUFACTURER=HTC,15</item>
         <!-- Motorola Razor M -->
         <item>MODEL=XT907:MANUFACTURER=motorola,30</item>
         <!-- Sony Xperia Z -->
diff --git a/java/src/com/android/inputmethod/latin/SuggestedWords.java b/java/src/com/android/inputmethod/latin/SuggestedWords.java
index 1f45327..7a16595 100644
--- a/java/src/com/android/inputmethod/latin/SuggestedWords.java
+++ b/java/src/com/android/inputmethod/latin/SuggestedWords.java
@@ -24,6 +24,9 @@
 import java.util.HashSet;
 
 public final class SuggestedWords {
+    public static final int INDEX_OF_TYPED_WORD = 0;
+    public static final int INDEX_OF_AUTO_CORRECTION = 1;
+
     private static final ArrayList<SuggestedWordInfo> EMPTY_WORD_INFO_LIST =
             CollectionUtils.newArrayList(0);
     public static final SuggestedWords EMPTY = new SuggestedWords(
@@ -61,12 +64,12 @@
         return mSuggestedWordInfoList.size();
     }
 
-    public String getWord(int pos) {
-        return mSuggestedWordInfoList.get(pos).mWord;
+    public String getWord(final int index) {
+        return mSuggestedWordInfoList.get(index).mWord;
     }
 
-    public SuggestedWordInfo getInfo(int pos) {
-        return mSuggestedWordInfoList.get(pos);
+    public SuggestedWordInfo getInfo(final int index) {
+        return mSuggestedWordInfoList.get(index);
     }
 
     public boolean willAutoCorrect() {
@@ -108,8 +111,8 @@
                 SuggestedWordInfo.KIND_TYPED, Dictionary.TYPE_USER_TYPED));
         alreadySeen.add(typedWord.toString());
         final int previousSize = previousSuggestions.size();
-        for (int pos = 1; pos < previousSize; pos++) {
-            final SuggestedWordInfo prevWordInfo = previousSuggestions.getInfo(pos);
+        for (int index = 1; index < previousSize; index++) {
+            final SuggestedWordInfo prevWordInfo = previousSuggestions.getInfo(index);
             final String prevWord = prevWordInfo.mWord;
             // Filter out duplicate suggestion.
             if (!alreadySeen.contains(prevWord)) {
diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java
index 0f96c54..949720f 100644
--- a/java/src/com/android/inputmethod/latin/Utils.java
+++ b/java/src/com/android/inputmethod/latin/Utils.java
@@ -64,7 +64,8 @@
      *        task should be interrupted; otherwise, in-progress tasks are allowed
      *        to complete.
      */
-    public static void cancelTask(AsyncTask<?, ?, ?> task, boolean mayInterruptIfRunning) {
+    public static void cancelTask(final AsyncTask<?, ?, ?> task,
+            final boolean mayInterruptIfRunning) {
         if (task != null && task.getStatus() != AsyncTask.Status.FINISHED) {
             task.cancel(mayInterruptIfRunning);
         }
@@ -86,26 +87,34 @@
         private RingCharBuffer() {
             // Intentional empty constructor for singleton.
         }
+
         @UsedForTesting
         public static RingCharBuffer getInstance() {
             return sRingCharBuffer;
         }
-        public static RingCharBuffer init(InputMethodService context, boolean enabled,
-                boolean usabilityStudy) {
-            if (!(enabled || usabilityStudy)) return null;
+
+        public static RingCharBuffer init(final InputMethodService context, final boolean enabled,
+                final boolean usabilityStudy) {
+            if (!(enabled || usabilityStudy)) {
+                return null;
+            }
             sRingCharBuffer.mContext = context;
             sRingCharBuffer.mEnabled = true;
             UsabilityStudyLogUtils.getInstance().init(context);
             return sRingCharBuffer;
         }
-        private static int normalize(int in) {
+
+        private static int normalize(final int in) {
             int ret = in % BUFSIZE;
             return ret < 0 ? ret + BUFSIZE : ret;
         }
+
         // TODO: accept code points
         @UsedForTesting
-        public void push(char c, int x, int y) {
-            if (!mEnabled) return;
+        public void push(final char c, final int x, final int y) {
+            if (!mEnabled) {
+                return;
+            }
             mCharBuf[mEnd] = c;
             mXBuf[mEnd] = x;
             mYBuf[mEnd] = y;
@@ -114,52 +123,54 @@
                 ++mLength;
             }
         }
+
         public char pop() {
             if (mLength < 1) {
                 return PLACEHOLDER_DELIMITER_CHAR;
-            } else {
-                mEnd = normalize(mEnd - 1);
-                --mLength;
-                return mCharBuf[mEnd];
             }
+            mEnd = normalize(mEnd - 1);
+            --mLength;
+            return mCharBuf[mEnd];
         }
-        public char getBackwardNthChar(int n) {
+
+        public char getBackwardNthChar(final int n) {
             if (mLength <= n || n < 0) {
                 return PLACEHOLDER_DELIMITER_CHAR;
-            } else {
-                return mCharBuf[normalize(mEnd - n - 1)];
             }
+            return mCharBuf[normalize(mEnd - n - 1)];
         }
-        public int getPreviousX(char c, int back) {
+
+        public int getPreviousX(final char c, final int back) {
+            final int index = normalize(mEnd - 2 - back);
+            if (mLength <= back
+                    || Character.toLowerCase(c) != Character.toLowerCase(mCharBuf[index])) {
+                return INVALID_COORDINATE;
+            }
+            return mXBuf[index];
+        }
+
+        public int getPreviousY(final char c, final int back) {
             int index = normalize(mEnd - 2 - back);
             if (mLength <= back
                     || Character.toLowerCase(c) != Character.toLowerCase(mCharBuf[index])) {
                 return INVALID_COORDINATE;
-            } else {
-                return mXBuf[index];
             }
+            return mYBuf[index];
         }
-        public int getPreviousY(char c, int back) {
-            int index = normalize(mEnd - 2 - back);
-            if (mLength <= back
-                    || Character.toLowerCase(c) != Character.toLowerCase(mCharBuf[index])) {
-                return INVALID_COORDINATE;
-            } else {
-                return mYBuf[index];
-            }
-        }
-        public String getLastWord(int ignoreCharCount) {
-            StringBuilder sb = new StringBuilder();
+
+        public String getLastWord(final int ignoreCharCount) {
+            final StringBuilder sb = new StringBuilder();
+            final LatinIME latinIme = (LatinIME)mContext;
             int i = ignoreCharCount;
             for (; i < mLength; ++i) {
-                char c = mCharBuf[normalize(mEnd - 1 - i)];
-                if (!((LatinIME)mContext).isWordSeparator(c)) {
+                final char c = mCharBuf[normalize(mEnd - 1 - i)];
+                if (!latinIme.isWordSeparator(c)) {
                     break;
                 }
             }
             for (; i < mLength; ++i) {
                 char c = mCharBuf[normalize(mEnd - 1 - i)];
-                if (!((LatinIME)mContext).isWordSeparator(c)) {
+                if (!latinIme.isWordSeparator(c)) {
                     sb.append(c);
                 } else {
                     break;
@@ -167,6 +178,7 @@
             }
             return sb.reverse().toString();
         }
+
         public void reset() {
             mLength = 0;
         }
@@ -174,11 +186,11 @@
 
     // Get the current stack trace
     public static String getStackTrace(final int limit) {
-        StringBuilder sb = new StringBuilder();
+        final StringBuilder sb = new StringBuilder();
         try {
             throw new RuntimeException();
-        } catch (RuntimeException e) {
-            StackTraceElement[] frames = e.getStackTrace();
+        } catch (final RuntimeException e) {
+            final StackTraceElement[] frames = e.getStackTrace();
             // Start at 1 because the first frame is here and we don't care about it
             for (int j = 1; j < frames.length && j < limit + 1; ++j) {
                 sb.append(frames[j].toString() + "\n");
@@ -222,7 +234,7 @@
             return OnDemandInitializationHolder.sInstance;
         }
 
-        public void init(InputMethodService ims) {
+        public void init(final InputMethodService ims) {
             mIms = ims;
             mDirectory = ims.getFilesDir();
         }
@@ -232,17 +244,17 @@
                     && (mDirectory != null && mDirectory.exists())) {
                 try {
                     mWriter = getPrintWriter(mDirectory, FILENAME, false);
-                } catch (IOException e) {
+                } catch (final IOException e) {
                     Log.e(USABILITY_TAG, "Can't create log file.");
                 }
             }
         }
 
-        public static void writeBackSpace(int x, int y) {
+        public static void writeBackSpace(final int x, final int y) {
             UsabilityStudyLogUtils.getInstance().write("<backspace>\t" + x + "\t" + y);
         }
 
-        public void writeChar(char c, int x, int y) {
+        public static void writeChar(final char c, final int x, final int y) {
             String inputChar = String.valueOf(c);
             switch (c) {
                 case '\n':
@@ -279,15 +291,15 @@
 
         private synchronized String getBufferedLogs() {
             mWriter.flush();
-            StringBuilder sb = new StringBuilder();
-            BufferedReader br = getBufferedReader();
+            final StringBuilder sb = new StringBuilder();
+            final BufferedReader br = getBufferedReader();
             String line;
             try {
                 while ((line = br.readLine()) != null) {
                     sb.append('\n');
                     sb.append(line);
                 }
-            } catch (IOException e) {
+            } catch (final IOException e) {
                 Log.e(USABILITY_TAG, "Can't read log file.");
             } finally {
                 if (LatinImeLogger.sDBG) {
@@ -295,7 +307,7 @@
                 }
                 try {
                     br.close();
-                } catch (IOException e) {
+                } catch (final IOException e) {
                     // ignore.
                 }
             }
@@ -334,10 +346,10 @@
                         srcStream.close();
                         dest.close();
                         destStream.close();
-                    } catch (FileNotFoundException e1) {
+                    } catch (final FileNotFoundException e1) {
                         Log.w(USABILITY_TAG, e1);
                         return;
-                    } catch (IOException e2) {
+                    } catch (final IOException e2) {
                         Log.w(USABILITY_TAG, e2);
                         return;
                     }
@@ -387,13 +399,13 @@
             createLogFileIfNotExist();
             try {
                 return new BufferedReader(new FileReader(mFile));
-            } catch (FileNotFoundException e) {
+            } catch (final FileNotFoundException e) {
                 return null;
             }
         }
 
-        private PrintWriter getPrintWriter(
-                File dir, String filename, boolean renew) throws IOException {
+        private PrintWriter getPrintWriter(final File dir, final String filename,
+                final boolean renew) throws IOException {
             mFile = new File(dir, filename);
             if (mFile.exists()) {
                 if (renew) {
@@ -405,8 +417,7 @@
     }
 
     public static final class Stats {
-        public static void onNonSeparator(final char code, final int x,
-                final int y) {
+        public static void onNonSeparator(final char code, final int x, final int y) {
             RingCharBuffer.getInstance().push(code, x, y);
             LatinImeLogger.logOnInputChar();
         }
@@ -430,7 +441,9 @@
         public static void onAutoCorrection(final String typedWord, final String correctedWord,
                 final String separatorString, final WordComposer wordComposer) {
             final boolean isBatchMode = wordComposer.isBatchMode();
-            if (!isBatchMode && TextUtils.isEmpty(typedWord)) return;
+            if (!isBatchMode && TextUtils.isEmpty(typedWord)) {
+                return;
+            }
             // TODO: this fails when the separator is more than 1 code point long, but
             // the backend can't handle it yet. The only case when this happens is with
             // smileys and other multi-character keys.
@@ -454,36 +467,43 @@
     }
 
     public static String getDebugInfo(final SuggestedWords suggestions, final int pos) {
-        if (!LatinImeLogger.sDBG) return null;
+        if (!LatinImeLogger.sDBG) {
+            return null;
+        }
         final SuggestedWordInfo wordInfo = suggestions.getInfo(pos);
-        if (wordInfo == null) return null;
+        if (wordInfo == null) {
+            return null;
+        }
         final String info = wordInfo.getDebugString();
-        if (TextUtils.isEmpty(info)) return null;
+        if (TextUtils.isEmpty(info)) {
+            return null;
+        }
         return info;
     }
 
-    public static int getAcitivityTitleResId(Context context, Class<? extends Activity> cls) {
+    public static int getAcitivityTitleResId(final Context context,
+            final Class<? extends Activity> cls) {
         final ComponentName cn = new ComponentName(context, cls);
         try {
             final ActivityInfo ai = context.getPackageManager().getActivityInfo(cn, 0);
             if (ai != null) {
                 return ai.labelRes;
             }
-        } catch (NameNotFoundException e) {
+        } catch (final NameNotFoundException e) {
             Log.e(TAG, "Failed to get settings activity title res id.", e);
         }
         return 0;
     }
 
-    public static String getVersionName(Context context) {
+    public static String getVersionName(final Context context) {
         try {
             if (context == null) {
                 return "";
             }
             final String packageName = context.getPackageName();
-            PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);
+            final PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);
             return info.versionName;
-        } catch (NameNotFoundException e) {
+        } catch (final NameNotFoundException e) {
             Log.e(TAG, "Could not find version info.", e);
         }
         return "";
diff --git a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java
index 09f81d4..322ae5b 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java
@@ -61,7 +61,7 @@
             super();
         }
 
-        public int layout(final SuggestedWords suggestedWords, final int fromPos,
+        public int layout(final SuggestedWords suggestedWords, final int fromIndex,
                 final int maxWidth, final int minWidth, final int maxRow, final Paint paint,
                 final Resources res) {
             clearKeys();
@@ -70,53 +70,54 @@
             final float padding = res.getDimension(R.dimen.more_suggestions_key_horizontal_padding);
 
             int row = 0;
-            int pos = fromPos, rowStartPos = fromPos;
+            int index = fromIndex;
+            int rowStartIndex = fromIndex;
             final int size = Math.min(suggestedWords.size(), SuggestionStripView.MAX_SUGGESTIONS);
-            while (pos < size) {
-                final String word = suggestedWords.getWord(pos);
+            while (index < size) {
+                final String word = suggestedWords.getWord(index);
                 // TODO: Should take care of text x-scaling.
-                mWidths[pos] = (int)(TypefaceUtils.getLabelWidth(word, paint) + padding);
-                final int numColumn = pos - rowStartPos + 1;
+                mWidths[index] = (int)(TypefaceUtils.getLabelWidth(word, paint) + padding);
+                final int numColumn = index - rowStartIndex + 1;
                 final int columnWidth =
                         (maxWidth - mDividerWidth * (numColumn - 1)) / numColumn;
                 if (numColumn > MAX_COLUMNS_IN_ROW
-                        || !fitInWidth(rowStartPos, pos + 1, columnWidth)) {
+                        || !fitInWidth(rowStartIndex, index + 1, columnWidth)) {
                     if ((row + 1) >= maxRow) {
                         break;
                     }
-                    mNumColumnsInRow[row] = pos - rowStartPos;
-                    rowStartPos = pos;
+                    mNumColumnsInRow[row] = index - rowStartIndex;
+                    rowStartIndex = index;
                     row++;
                 }
-                mColumnOrders[pos] = pos - rowStartPos;
-                mRowNumbers[pos] = row;
-                pos++;
+                mColumnOrders[index] = index - rowStartIndex;
+                mRowNumbers[index] = row;
+                index++;
             }
-            mNumColumnsInRow[row] = pos - rowStartPos;
+            mNumColumnsInRow[row] = index - rowStartIndex;
             mNumRows = row + 1;
             mBaseWidth = mOccupiedWidth = Math.max(
-                    minWidth, calcurateMaxRowWidth(fromPos, pos));
+                    minWidth, calcurateMaxRowWidth(fromIndex, index));
             mBaseHeight = mOccupiedHeight = mNumRows * mDefaultRowHeight + mVerticalGap;
-            return pos - fromPos;
+            return index - fromIndex;
         }
 
-        private boolean fitInWidth(final int startPos, final int endPos, final int width) {
-            for (int pos = startPos; pos < endPos; pos++) {
-                if (mWidths[pos] > width)
+        private boolean fitInWidth(final int startIndex, final int endIndex, final int width) {
+            for (int index = startIndex; index < endIndex; index++) {
+                if (mWidths[index] > width)
                     return false;
             }
             return true;
         }
 
-        private int calcurateMaxRowWidth(final int startPos, final int endPos) {
+        private int calcurateMaxRowWidth(final int startIndex, final int endIndex) {
             int maxRowWidth = 0;
-            int pos = startPos;
+            int index = startIndex;
             for (int row = 0; row < mNumRows; row++) {
                 final int numColumnInRow = mNumColumnsInRow[row];
                 int maxKeyWidth = 0;
-                while (pos < endPos && mRowNumbers[pos] == row) {
-                    maxKeyWidth = Math.max(maxKeyWidth, mWidths[pos]);
-                    pos++;
+                while (index < endIndex && mRowNumbers[index] == row) {
+                    maxKeyWidth = Math.max(maxKeyWidth, mWidths[index]);
+                    index++;
                 }
                 maxRowWidth = Math.max(maxRowWidth,
                         maxKeyWidth * numColumnInRow + mDividerWidth * (numColumnInRow - 1));
@@ -130,40 +131,40 @@
             { 2, 0, 1},
         };
 
-        public int getNumColumnInRow(final int pos) {
-            return mNumColumnsInRow[mRowNumbers[pos]];
+        public int getNumColumnInRow(final int index) {
+            return mNumColumnsInRow[mRowNumbers[index]];
         }
 
-        public int getColumnNumber(final int pos) {
-            final int columnOrder = mColumnOrders[pos];
-            final int numColumn = getNumColumnInRow(pos);
+        public int getColumnNumber(final int index) {
+            final int columnOrder = mColumnOrders[index];
+            final int numColumn = getNumColumnInRow(index);
             return COLUMN_ORDER_TO_NUMBER[numColumn - 1][columnOrder];
         }
 
-        public int getX(final int pos) {
-            final int columnNumber = getColumnNumber(pos);
-            return columnNumber * (getWidth(pos) + mDividerWidth);
+        public int getX(final int index) {
+            final int columnNumber = getColumnNumber(index);
+            return columnNumber * (getWidth(index) + mDividerWidth);
         }
 
-        public int getY(final int pos) {
-            final int row = mRowNumbers[pos];
+        public int getY(final int index) {
+            final int row = mRowNumbers[index];
             return (mNumRows -1 - row) * mDefaultRowHeight + mTopPadding;
         }
 
-        public int getWidth(final int pos) {
-            final int numColumnInRow = getNumColumnInRow(pos);
+        public int getWidth(final int index) {
+            final int numColumnInRow = getNumColumnInRow(index);
             return (mOccupiedWidth - mDividerWidth * (numColumnInRow - 1)) / numColumnInRow;
         }
 
-        public void markAsEdgeKey(final Key key, final int pos) {
-            final int row = mRowNumbers[pos];
+        public void markAsEdgeKey(final Key key, final int index) {
+            final int row = mRowNumbers[index];
             if (row == 0)
                 key.markAsBottomEdge(this);
             if (row == mNumRows - 1)
                 key.markAsTopEdge(this);
 
             final int numColumnInRow = mNumColumnsInRow[row];
-            final int column = getColumnNumber(pos);
+            final int column = getColumnNumber(index);
             if (column == 0)
                 key.markAsLeftEdge(this);
             if (column == numColumnInRow - 1)
@@ -174,15 +175,15 @@
     public static final class Builder extends KeyboardBuilder<MoreSuggestionsParam> {
         private final MoreSuggestionsView mPaneView;
         private SuggestedWords mSuggestedWords;
-        private int mFromPos;
-        private int mToPos;
+        private int mFromIndex;
+        private int mToIndex;
 
         public Builder(final Context context, final MoreSuggestionsView paneView) {
             super(context, new MoreSuggestionsParam());
             mPaneView = paneView;
         }
 
-        public Builder layout(final SuggestedWords suggestedWords, final int fromPos,
+        public Builder layout(final SuggestedWords suggestedWords, final int fromIndex,
                 final int maxWidth, final int minWidth, final int maxRow,
                 final Keyboard parentKeyboard) {
             final int xmlId = R.xml.kbd_suggestions_pane_template;
@@ -190,10 +191,10 @@
             mParams.mVerticalGap = mParams.mTopPadding = parentKeyboard.mVerticalGap / 2;
 
             mPaneView.updateKeyboardGeometry(mParams.mDefaultRowHeight);
-            final int count = mParams.layout(suggestedWords, fromPos, maxWidth, minWidth, maxRow,
+            final int count = mParams.layout(suggestedWords, fromIndex, maxWidth, minWidth, maxRow,
                     mPaneView.newLabelPaint(null /* key */), mResources);
-            mFromPos = fromPos;
-            mToPos = fromPos + count;
+            mFromIndex = fromIndex;
+            mToIndex = fromIndex + count;
             mSuggestedWords = suggestedWords;
             return this;
         }
@@ -201,20 +202,20 @@
         @Override
         public MoreSuggestions build() {
             final MoreSuggestionsParam params = mParams;
-            for (int pos = mFromPos; pos < mToPos; pos++) {
-                final int x = params.getX(pos);
-                final int y = params.getY(pos);
-                final int width = params.getWidth(pos);
-                final String word = mSuggestedWords.getWord(pos);
-                final String info = Utils.getDebugInfo(mSuggestedWords, pos);
-                final int index = pos + SUGGESTION_CODE_BASE;
+            for (int index = mFromIndex; index < mToIndex; index++) {
+                final int x = params.getX(index);
+                final int y = params.getY(index);
+                final int width = params.getWidth(index);
+                final String word = mSuggestedWords.getWord(index);
+                final String info = Utils.getDebugInfo(mSuggestedWords, index);
+                final int indexInMoreSuggestions = index + SUGGESTION_CODE_BASE;
                 final Key key = new Key(
-                        params, word, info, KeyboardIconsSet.ICON_UNDEFINED, index, null, x, y,
-                        width, params.mDefaultRowHeight, 0);
-                params.markAsEdgeKey(key, pos);
+                        params, word, info, KeyboardIconsSet.ICON_UNDEFINED, indexInMoreSuggestions,
+                        null, x, y, width, params.mDefaultRowHeight, 0);
+                params.markAsEdgeKey(key, index);
                 params.onAddKey(key);
-                final int columnNumber = params.getColumnNumber(pos);
-                final int numColumnInRow = params.getNumColumnInRow(pos);
+                final int columnNumber = params.getColumnNumber(index);
+                final int numColumnInRow = params.getNumColumnInRow(index);
                 if (columnNumber < numColumnInRow - 1) {
                     final Divider divider = new Divider(params, params.mDivider, x + width, y,
                             params.mDividerWidth, params.mDefaultRowHeight);
diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java
index d9bb3ea..2f2ec35 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java
@@ -23,9 +23,9 @@
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Paint;
+import android.graphics.Paint.Align;
 import android.graphics.Rect;
 import android.graphics.Typeface;
-import android.graphics.Paint.Align;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.text.Spannable;
@@ -40,14 +40,13 @@
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
-import android.view.ViewGroup;
 import android.view.View.OnClickListener;
+import android.view.ViewGroup;
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
 import com.android.inputmethod.keyboard.ViewLayoutUtils;
 import com.android.inputmethod.latin.AutoCorrection;
-import com.android.inputmethod.latin.CollectionUtils;
 import com.android.inputmethod.latin.LatinImeLogger;
 import com.android.inputmethod.latin.R;
 import com.android.inputmethod.latin.ResourceUtils;
@@ -71,7 +70,11 @@
     private int mMaxMoreSuggestionsRow;
     public final float mMinMoreSuggestionsWidth;
     public final int mMoreSuggestionsBottomGap;
+    public boolean mMoreSuggestionsAvailable;
 
+    // The index of these {@link ArrayList} is the position in the suggestion strip. The indices
+    // increase towards the right for LTR scripts and the left for RTL scripts, starting with 0.
+    // The position of the most important suggestion is in {@link #mCenterPositionInStrip}
     private final ArrayList<TextView> mWordViews;
     private final ArrayList<View> mDividerViews;
     private final ArrayList<TextView> mDebugInfoViews;
@@ -89,16 +92,14 @@
 
     private static final CharacterStyle BOLD_SPAN = new StyleSpan(Typeface.BOLD);
     private static final CharacterStyle UNDERLINE_SPAN = new UnderlineSpan();
+
+    private final int mSuggestionStripOption;
+    // These constants are the flag values of
+    // {@link R.styleable#SuggestionStripView_suggestionStripOption} attribute.
     private static final int AUTO_CORRECT_BOLD = 0x01;
     private static final int AUTO_CORRECT_UNDERLINE = 0x02;
     private static final int VALID_TYPED_WORD_BOLD = 0x04;
 
-    private final int mSuggestionStripOption;
-
-    private final ArrayList<CharSequence> mWords = CollectionUtils.newArrayList();
-
-    public boolean mMoreSuggestionsAvailable;
-
     private final TextView mWordToSaveView;
     private final TextView mLeftwardsArrowView;
     private final TextView mHintToSaveView;
@@ -205,7 +206,7 @@
         return new BitmapDrawable(res, buffer);
     }
 
-    private CharSequence getStyledSuggestionWord(final SuggestedWords suggestedWords,
+    private CharSequence getStyledSuggestedWord(final SuggestedWords suggestedWords,
             final int indexInSuggestedWords) {
         final String word = suggestedWords.getWord(indexInSuggestedWords);
         final boolean isAutoCorrect = indexInSuggestedWords == 1
@@ -233,7 +234,8 @@
             final SuggestedWords suggestedWords) {
         // TODO: This works for 3 suggestions. Revisit this algorithm when there are 5 or more
         // suggestions.
-        final int mostImportantIndexInSuggestedWords = suggestedWords.willAutoCorrect() ? 1 : 0;
+        final int mostImportantIndexInSuggestedWords = suggestedWords.willAutoCorrect()
+                ? SuggestedWords.INDEX_OF_AUTO_CORRECTION : SuggestedWords.INDEX_OF_TYPED_WORD;
         if (positionInStrip == mCenterPositionInStrip) {
             return mostImportantIndexInSuggestedWords;
         }
@@ -245,10 +247,9 @@
 
     private int getSuggestionTextColor(final int positionInStrip,
             final SuggestedWords suggestedWords) {
-        final int indexInSuggestedWords = getIndexInSuggestedWords(
-                positionInStrip, suggestedWords);
+        final int indexInSuggestedWords = getIndexInSuggestedWords(positionInStrip, suggestedWords);
         // TODO: Need to revisit this logic with bigram suggestions
-        final boolean isSuggested = (indexInSuggestedWords != 0);
+        final boolean isSuggested = (indexInSuggestedWords != SuggestedWords.INDEX_OF_TYPED_WORD);
 
         final int color;
         if (positionInStrip == mCenterPositionInStrip && suggestedWords.willAutoCorrect()) {
@@ -265,7 +266,8 @@
             // is in slot 1.
             if (positionInStrip == mCenterPositionInStrip
                     && AutoCorrection.shouldBlockAutoCorrectionBySafetyNet(
-                            suggestedWords.getWord(1), suggestedWords.getWord(0))) {
+                            suggestedWords.getWord(SuggestedWords.INDEX_OF_AUTO_CORRECTION),
+                            suggestedWords.getWord(SuggestedWords.INDEX_OF_TYPED_WORD))) {
                 return 0xFFFF0000;
             }
         }
@@ -296,7 +298,7 @@
         }
 
         final int countInStrip = mSuggestionsCountInStrip;
-        setupWords(suggestedWords, countInStrip);
+        setupWordViewsTextAndColor(suggestedWords, countInStrip);
         mMoreSuggestionsAvailable = (suggestedWords.size() > countInStrip);
         int x = 0;
         for (int positionInStrip = 0; positionInStrip < countInStrip; positionInStrip++) {
@@ -308,41 +310,37 @@
             }
 
             final int width = getSuggestionWidth(positionInStrip, placerView.getWidth());
-            final TextView wordView = layoutWord(suggestedWords, positionInStrip, width);
+            final TextView wordView = layoutWord(positionInStrip, width);
             stripView.addView(wordView);
             setLayoutWeight(wordView, getSuggestionWeight(positionInStrip),
                     ViewGroup.LayoutParams.MATCH_PARENT);
             x += wordView.getMeasuredWidth();
 
             if (SuggestionStripView.DBG) {
-                layoutDebugInfo(suggestedWords, positionInStrip, placerView, x);
+                layoutDebugInfo(positionInStrip, placerView, x);
             }
         }
     }
 
     /**
-     * Format appropriately the suggested word indirectly specified by
-     * <code>positionInStrip</code> as text in a corresponding {@link TextView}. When the
-     * suggested word doesn't exist, the corresponding {@link TextView} will be disabled
-     * and never respond to user interaction. The suggested word may be shrunk or ellipsized to
-     * fit in the specified width.
+     * Format appropriately the suggested word in {@link #mWordViews} specified by
+     * <code>positionInStrip</code>. When the suggested word doesn't exist, the corresponding
+     * {@link TextView} will be disabled and never respond to user interaction. The suggested word
+     * may be shrunk or ellipsized to fit in the specified width.
      *
      * The <code>positionInStrip</code> argument is the index in the suggestion strip. The indices
      * increase towards the right for LTR scripts and the left for RTL scripts, starting with 0.
-     * The index of the most important suggestion is in {@link #mCenterPositionInStrip}. This
+     * The position of the most important suggestion is in {@link #mCenterPositionInStrip}. This
      * usually doesn't match the index in <code>suggedtedWords</code> -- see
      * {@link #getIndexInSuggestedWords(int,SuggestedWords)}.
      *
-     * @param suggestedWords the list of suggestions.
-     * @param positionInStrip the in the suggestion strip.
+     * @param positionInStrip the position in the suggestion strip.
      * @param width the maximum width for layout in pixels.
      * @return the {@link TextView} containing the suggested word appropriately formatted.
      */
-    private TextView layoutWord(final SuggestedWords suggestedWords, final int positionInStrip,
-            final int width) {
-        final int indexInSuggestedWords = getIndexInSuggestedWords(positionInStrip, suggestedWords);
-        final CharSequence word = mWords.get(indexInSuggestedWords);
-        final TextView wordView = mWordViews.get(indexInSuggestedWords);
+    private TextView layoutWord(final int positionInStrip, final int width) {
+        final TextView wordView = mWordViews.get(positionInStrip);
+        final CharSequence word = wordView.getText();
         if (positionInStrip == mCenterPositionInStrip && mMoreSuggestionsAvailable) {
             // TODO: This "more suggestions hint" should have a nicely designed icon.
             wordView.setCompoundDrawablesWithIntrinsicBounds(
@@ -355,7 +353,6 @@
 
         // Disable this suggestion if the suggestion is null or empty.
         wordView.setEnabled(!TextUtils.isEmpty(word));
-        wordView.setTextColor(getSuggestionTextColor(positionInStrip, suggestedWords));
         final CharSequence text = getEllipsizedText(word, width, wordView.getPaint());
         final float scaleX = wordView.getTextScaleX();
         wordView.setText(text); // TextView.setText() resets text scale x to 1.0.
@@ -363,18 +360,13 @@
         return wordView;
     }
 
-    private void layoutDebugInfo(final SuggestedWords suggestedWords, final int positionInStrip,
-            final ViewGroup placerView, final int x) {
-        final int indexInSuggestedWords = getIndexInSuggestedWords(positionInStrip, suggestedWords);
-        if (indexInSuggestedWords >= suggestedWords.size()) {
-            return;
-        }
-        final String debugInfo = Utils.getDebugInfo(suggestedWords, indexInSuggestedWords);
+    private void layoutDebugInfo(final int positionInStrip, final ViewGroup placerView,
+            final int x) {
+        final TextView debugInfoView = mDebugInfoViews.get(positionInStrip);
+        final CharSequence debugInfo = debugInfoView.getText();
         if (debugInfo == null) {
             return;
         }
-        final TextView debugInfoView = mDebugInfoViews.get(indexInSuggestedWords);
-        debugInfoView.setText(debugInfo);
         placerView.addView(debugInfoView);
         debugInfoView.measure(
                 ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
@@ -399,39 +391,52 @@
         return (1.0f - mCenterSuggestionWeight) / (mSuggestionsCountInStrip - 1);
     }
 
-    private void setupWords(final SuggestedWords suggestedWords, final int countInStrip) {
-        mWords.clear();
+    private void setupWordViewsTextAndColor(final SuggestedWords suggestedWords,
+            final int countInStrip) {
         final int count = Math.min(suggestedWords.size(), countInStrip);
-        for (int pos = 0; pos < count; pos++) {
-            final CharSequence styled = getStyledSuggestionWord(suggestedWords, pos);
-            mWords.add(styled);
+        for (int positionInStrip = 0; positionInStrip < count; positionInStrip++) {
+            final int indexInSuggestedWords =
+                    getIndexInSuggestedWords(positionInStrip, suggestedWords);
+            final TextView wordView = mWordViews.get(positionInStrip);
+            // {@link TextView#getTag()} is used to get the index in suggestedWords at
+            // {@link SuggestionStripView#onClick(View)}.
+            wordView.setTag(indexInSuggestedWords);
+            wordView.setText(getStyledSuggestedWord(suggestedWords, indexInSuggestedWords));
+            wordView.setTextColor(getSuggestionTextColor(positionInStrip, suggestedWords));
+            if (SuggestionStripView.DBG) {
+                mDebugInfoViews.get(positionInStrip).setText(
+                        Utils.getDebugInfo(suggestedWords, indexInSuggestedWords));
+            }
         }
-        for (int pos = count; pos < countInStrip; pos++) {
-            // Make this inactive for touches in layout().
-            mWords.add(null);
+        for (int positionInStrip = count; positionInStrip < countInStrip; positionInStrip++) {
+            mWordViews.get(positionInStrip).setText(null);
+            // Make this inactive for touches in {@link #layoutWord(int,int)}.
+            if (SuggestionStripView.DBG) {
+                mDebugInfoViews.get(positionInStrip).setText(null);
+            }
         }
     }
 
     private void layoutPunctuationSuggestions(final SuggestedWords suggestedWords,
             final ViewGroup stripView) {
         final int countInStrip = Math.min(suggestedWords.size(), PUNCTUATIONS_IN_STRIP);
-        for (int indexInStrip = 0; indexInStrip < countInStrip; indexInStrip++) {
-            if (indexInStrip != 0) {
+        for (int positionInStrip = 0; positionInStrip < countInStrip; positionInStrip++) {
+            if (positionInStrip != 0) {
                 // Add divider if this isn't the left most suggestion in suggestions strip.
-                addDivider(stripView, mDividerViews.get(indexInStrip));
+                addDivider(stripView, mDividerViews.get(positionInStrip));
             }
 
-            final TextView word = mWordViews.get(indexInStrip);
-            word.setEnabled(true);
-            word.setTextColor(mColorAutoCorrect);
-            final String text = suggestedWords.getWord(indexInStrip);
-            word.setText(text);
-            word.setTextScaleX(1.0f);
-            word.setCompoundDrawables(null, null, null, null);
-            stripView.addView(word);
-            setLayoutWeight(word, 1.0f, mSuggestionsStripHeight);
+            final TextView wordView = mWordViews.get(positionInStrip);
+            wordView.setEnabled(true);
+            wordView.setTextColor(mColorAutoCorrect);
+            final String punctuation = suggestedWords.getWord(positionInStrip);
+            wordView.setText(punctuation);
+            wordView.setTextScaleX(1.0f);
+            wordView.setCompoundDrawables(null, null, null, null);
+            stripView.addView(wordView);
+            setLayoutWeight(wordView, 1.0f, mSuggestionsStripHeight);
         }
-        mMoreSuggestionsAvailable = false;
+        mMoreSuggestionsAvailable = (suggestedWords.size() > countInStrip);
     }
 
     public void layoutAddToDictionaryHint(final String word, final ViewGroup stripView,
diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
index 226bf87..b2b9427 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
@@ -93,12 +93,10 @@
         mSuggestionsStrip = (ViewGroup)findViewById(R.id.suggestions_strip);
         for (int pos = 0; pos < MAX_SUGGESTIONS; pos++) {
             final TextView word = (TextView)inflater.inflate(R.layout.suggestion_word, null);
-            word.setTag(pos);
             word.setOnClickListener(this);
             word.setOnLongClickListener(this);
             mWordViews.add(word);
             final View divider = inflater.inflate(R.layout.suggestion_divider, null);
-            divider.setTag(pos);
             divider.setOnClickListener(this);
             mDividerViews.add(divider);
             mDebugInfoViews.add((TextView)inflater.inflate(R.layout.suggestion_info, null));
diff --git a/native/jni/src/suggest/core/layout/proximity_info.cpp b/native/jni/src/suggest/core/layout/proximity_info.cpp
index 995e104..6dd8805 100644
--- a/native/jni/src/suggest/core/layout/proximity_info.cpp
+++ b/native/jni/src/suggest/core/layout/proximity_info.cpp
@@ -14,13 +14,13 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "LatinIME: proximity_info.cpp"
+
 #include "suggest/core/layout/proximity_info.h"
 
 #include <cstring>
 #include <cmath>
 
-#define LOG_TAG "LatinIME: proximity_info.cpp"
-
 #include "char_utils.h"
 #include "defines.h"
 #include "jni.h"
diff --git a/native/jni/src/suggest/core/layout/proximity_info_state.cpp b/native/jni/src/suggest/core/layout/proximity_info_state.cpp
index fb57174..2bd3ceb 100644
--- a/native/jni/src/suggest/core/layout/proximity_info_state.cpp
+++ b/native/jni/src/suggest/core/layout/proximity_info_state.cpp
@@ -14,14 +14,14 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "LatinIME: proximity_info_state.cpp"
+
 #include "suggest/core/layout/proximity_info_state.h"
 
 #include <cstring> // for memset() and memcpy()
 #include <sstream> // for debug prints
 #include <vector>
 
-#define LOG_TAG "LatinIME: proximity_info_state.cpp"
-
 #include "defines.h"
 #include "suggest/core/layout/geometry_utils.h"
 #include "suggest/core/layout/proximity_info.h"