Merge "Import revised translations."
diff --git a/java/src/com/android/inputmethod/keyboard/KeyStyles.java b/java/src/com/android/inputmethod/keyboard/KeyStyles.java
index daa9c86..e3b1071 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyStyles.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyStyles.java
@@ -47,6 +47,7 @@
 
     public static class EmptyKeyStyle implements KeyStyle {
         private EmptyKeyStyle() {
+            // Nothing to do.
         }
 
         @Override
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardParser.java b/java/src/com/android/inputmethod/keyboard/KeyboardParser.java
index 213eac5..8a7d674 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardParser.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardParser.java
@@ -18,6 +18,7 @@
 
 import com.android.inputmethod.latin.R;
 
+import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
 import android.content.res.Resources;
@@ -142,8 +143,8 @@
     public void parseKeyboard(XmlResourceParser parser)
             throws XmlPullParserException, IOException {
         int event;
-        while ((event = parser.next()) != XmlResourceParser.END_DOCUMENT) {
-            if (event == XmlResourceParser.START_TAG) {
+        while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) {
+            if (event == XmlPullParser.START_TAG) {
                 final String tag = parser.getName();
                 if (DEBUG_TAG) debugStartTag("parseKeyboard", tag, false);
                 if (TAG_KEYBOARD.equals(tag)) {
@@ -186,8 +187,8 @@
     private void parseKeyboardContent(XmlResourceParser parser, List<Key> keys)
             throws XmlPullParserException, IOException {
         int event;
-        while ((event = parser.next()) != XmlResourceParser.END_DOCUMENT) {
-            if (event == XmlResourceParser.START_TAG) {
+        while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) {
+            if (event == XmlPullParser.START_TAG) {
                 final String tag = parser.getName();
                 if (DEBUG_TAG) debugStartTag("parseKeyboardContent", tag, keys == null);
                 if (TAG_ROW.equals(tag)) {
@@ -204,7 +205,7 @@
                 } else {
                     throw new IllegalStartTag(parser, TAG_ROW);
                 }
-            } else if (event == XmlResourceParser.END_TAG) {
+            } else if (event == XmlPullParser.END_TAG) {
                 final String tag = parser.getName();
                 if (DEBUG_TAG) debugEndTag("parseKeyboardContent", tag, keys == null);
                 if (TAG_KEYBOARD.equals(tag)) {
@@ -226,8 +227,8 @@
     private void parseRowContent(XmlResourceParser parser, Row row, List<Key> keys)
             throws XmlPullParserException, IOException {
         int event;
-        while ((event = parser.next()) != XmlResourceParser.END_DOCUMENT) {
-            if (event == XmlResourceParser.START_TAG) {
+        while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) {
+            if (event == XmlPullParser.START_TAG) {
                 final String tag = parser.getName();
                 if (DEBUG_TAG) debugStartTag("parseRowContent", tag, keys == null);
                 if (TAG_KEY.equals(tag)) {
@@ -243,7 +244,7 @@
                 } else {
                     throw new IllegalStartTag(parser, TAG_KEY);
                 }
-            } else if (event == XmlResourceParser.END_TAG) {
+            } else if (event == XmlPullParser.END_TAG) {
                 final String tag = parser.getName();
                 if (DEBUG_TAG) debugEndTag("parseRowContent", tag, keys == null);
                 if (TAG_ROW.equals(tag)) {
@@ -327,8 +328,8 @@
     private void parseMerge(XmlResourceParser parser, Row row, List<Key> keys)
             throws XmlPullParserException, IOException {
         int event;
-        while ((event = parser.next()) != XmlResourceParser.END_DOCUMENT) {
-            if (event == XmlResourceParser.START_TAG) {
+        while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) {
+            if (event == XmlPullParser.START_TAG) {
                 final String tag = parser.getName();
                 if (DEBUG_TAG) debugStartTag("parseMerge", tag, keys == null);
                 if (TAG_MERGE.equals(tag)) {
@@ -361,8 +362,8 @@
         boolean selected = false;
         int event;
         if (DEBUG_TAG) Log.d(TAG, "parseSwitchInternal: id=" + mKeyboard.mId);
-        while ((event = parser.next()) != XmlResourceParser.END_DOCUMENT) {
-            if (event == XmlResourceParser.START_TAG) {
+        while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) {
+            if (event == XmlPullParser.START_TAG) {
                 final String tag = parser.getName();
                 if (DEBUG_TAG) debugStartTag("parseSwitchInternal", tag, keys == null);
                 if (TAG_CASE.equals(tag)) {
@@ -372,7 +373,7 @@
                 } else {
                     throw new IllegalStartTag(parser, TAG_KEY);
                 }
-            } else if (event == XmlResourceParser.END_TAG) {
+            } else if (event == XmlPullParser.END_TAG) {
                 final String tag = parser.getName();
                 if (DEBUG_TAG) debugEndTag("parseRowContent", tag, keys == null);
                 if (TAG_SWITCH.equals(tag)) {
@@ -469,8 +470,7 @@
         return true;
     }
 
-    private void parseKeyStyle(XmlResourceParser parser, List<Key> keys)
-            throws XmlPullParserException, IOException {
+    private void parseKeyStyle(XmlResourceParser parser, List<Key> keys) {
         TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser),
                 R.styleable.Keyboard_KeyStyle);
         TypedArray keyAttrs = mResources.obtainAttributes(Xml.asAttributeSet(parser),
@@ -489,7 +489,7 @@
 
     private static void checkEndTag(String tag, XmlResourceParser parser)
             throws XmlPullParserException, IOException {
-        if (parser.next() == XmlResourceParser.END_TAG && tag.equals(parser.getName()))
+        if (parser.next() == XmlPullParser.END_TAG && tag.equals(parser.getName()))
             return;
         throw new NonEmptyTag(tag, parser);
     }
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index 88e7ad5..51e878c 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -100,6 +100,7 @@
     }
 
     private KeyboardSwitcher() {
+        // Intentional empty constructor for singleton.
     }
 
     public static void init(LatinIME ims, SharedPreferences prefs) {
@@ -554,12 +555,13 @@
     }
 
     private void createInputViewInternal(int newLayout, boolean forceReset) {
-        if (mLayoutId != newLayout || mInputView == null || forceReset) {
+        int layoutId = newLayout;
+        if (mLayoutId != layoutId || mInputView == null || forceReset) {
             if (mInputView != null) {
                 mInputView.closing();
             }
-            if (THEMES.length <= newLayout) {
-                newLayout = Integer.valueOf(DEFAULT_LAYOUT_ID);
+            if (THEMES.length <= layoutId) {
+                layoutId = Integer.valueOf(DEFAULT_LAYOUT_ID);
             }
 
             Utils.GCUtils.getInstance().reset();
@@ -567,20 +569,20 @@
             for (int i = 0; i < Utils.GCUtils.GC_TRY_LOOP_MAX && tryGC; ++i) {
                 try {
                     mInputView = (LatinKeyboardView) mInputMethodService.getLayoutInflater(
-                            ).inflate(THEMES[newLayout], null);
+                            ).inflate(THEMES[layoutId], null);
                     tryGC = false;
                 } catch (OutOfMemoryError e) {
                     Log.w(TAG, "load keyboard failed: " + e);
                     tryGC = Utils.GCUtils.getInstance().tryGCOrWait(
-                            mLayoutId + "," + newLayout, e);
+                            mLayoutId + "," + layoutId, e);
                 } catch (InflateException e) {
                     Log.w(TAG, "load keyboard failed: " + e);
                     tryGC = Utils.GCUtils.getInstance().tryGCOrWait(
-                            mLayoutId + "," + newLayout, e);
+                            mLayoutId + "," + layoutId, e);
                 }
             }
             mInputView.setOnKeyboardActionListener(mInputMethodService);
-            mLayoutId = newLayout;
+            mLayoutId = layoutId;
         }
     }
 
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
index 9842686..70267a7 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
@@ -289,7 +289,7 @@
             cancelPopupPreview();
             cancelDismissPreview();
         }
-    };
+    }
 
     public KeyboardView(Context context, AttributeSet attrs) {
         this(context, attrs, R.attr.keyboardViewStyle);
@@ -587,7 +587,7 @@
     protected CharSequence adjustCase(CharSequence label) {
         if (mKeyboard.isShiftedOrShiftLocked() && label != null && label.length() < 3
                 && Character.isLowerCase(label.charAt(0))) {
-            label = label.toString().toUpperCase();
+            return label.toString().toUpperCase();
         }
         return label;
     }
@@ -1089,7 +1089,7 @@
         mKeyboardActionListener.onKey(Keyboard.CODE_CAPSLOCK, null, 0, 0);
     }
 
-    private void onDoubleTapShiftKey(PointerTracker tracker) {
+    private void onDoubleTapShiftKey(@SuppressWarnings("unused") PointerTracker tracker) {
         // When shift key is double tapped, the first tap is correctly processed as usual tap. And
         // the second tap is treated as this double tap event, so that we need not mark tracker
         // calling setAlreadyProcessed() nor remove the tracker from mPointerQueueueue.
@@ -1126,15 +1126,19 @@
 
             @Override
             public void swipeLeft() {
+                // Nothing to do.
             }
             @Override
             public void swipeRight() {
+                // Nothing to do.
             }
             @Override
             public void swipeUp() {
+                // Nothing to do.
             }
             @Override
             public void swipeDown() {
+                // Nothing to do.
             }
             @Override
             public void onPress(int primaryCode) {
diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java
index e612b52..8087f03 100644
--- a/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java
@@ -280,7 +280,9 @@
      */
     @Override
     @SuppressWarnings("unused") // SubtypeSwitcher.USE_SPACEBAR_LANGUAGE_SWITCHER is constant
-    public boolean isInside(Key key, int x, int y) {
+    public boolean isInside(Key key, int pointX, int pointY) {
+        int x = pointX;
+        int y = pointY;
         final int code = key.mCodes[0];
         if (code == CODE_SHIFT || code == CODE_DELETE) {
             y -= key.mHeight / 10;
diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
index 79b0cbf..4d4046b 100644
--- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
@@ -21,16 +21,10 @@
 
 import android.content.Context;
 import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.os.Handler;
-import android.os.Message;
-import android.os.SystemClock;
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
 
-import java.util.List;
-
 // TODO: We should remove this class
 public class LatinKeyboardView extends KeyboardView {
 
@@ -45,6 +39,8 @@
     private int mJumpThresholdSquare = Integer.MAX_VALUE;
     /** The y coordinate of the last row */
     private int mLastRowY;
+    private int mLastX;
+    private int mLastY;
 
     public LatinKeyboardView(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
@@ -73,7 +69,6 @@
         mJumpThresholdSquare *= mJumpThresholdSquare;
         // Assuming there are 4 rows, this is the coordinate of the last row
         mLastRowY = (k.getHeight() * 3) / 4;
-        setKeyboardLocal(k);
     }
 
     public LatinKeyboard getLatinKeyboard() {
@@ -112,7 +107,7 @@
                 && keyboard.isShiftedOrShiftLocked()
                 && !TextUtils.isEmpty(label) && label.length() < 3
                 && Character.isLowerCase(label.charAt(0))) {
-            label = label.toString().toUpperCase();
+            return label.toString().toUpperCase();
         }
         return label;
     }
@@ -197,11 +192,6 @@
     @Override
     public boolean onTouchEvent(MotionEvent me) {
         LatinKeyboard keyboard = getLatinKeyboard();
-        if (DEBUG_LINE) {
-            mLastX = (int) me.getX();
-            mLastY = (int) me.getY();
-            invalidate();
-        }
 
         // If there was a sudden jump, return without processing the actual motion event.
         if (handleSuddenJump(me))
@@ -228,106 +218,6 @@
         return super.onTouchEvent(me);
     }
 
-    /****************************  INSTRUMENTATION  *******************************/
-
-    public static final boolean DEBUG_AUTO_PLAY = false;
-    public static final boolean DEBUG_LINE = false;
-    private static final int MSG_TOUCH_DOWN = 1;
-    private static final int MSG_TOUCH_UP = 2;
-
-    Handler mHandler2;
-
-    private String mStringToPlay;
-    private int mStringIndex;
-    private boolean mDownDelivered;
-    private Key[] mAsciiKeys = new Key[256];
-    private boolean mPlaying;
-    private int mLastX;
-    private int mLastY;
-    private Paint mPaint;
-
-    private void setKeyboardLocal(LatinKeyboard k) {
-        if (DEBUG_AUTO_PLAY) {
-            findKeys();
-            if (mHandler2 == null) {
-                mHandler2 = new Handler() {
-                    @Override
-                    public void handleMessage(Message msg) {
-                        removeMessages(MSG_TOUCH_DOWN);
-                        removeMessages(MSG_TOUCH_UP);
-                        if (mPlaying == false) return;
-
-                        switch (msg.what) {
-                            case MSG_TOUCH_DOWN:
-                                if (mStringIndex >= mStringToPlay.length()) {
-                                    mPlaying = false;
-                                    return;
-                                }
-                                char c = mStringToPlay.charAt(mStringIndex);
-                                while (c > 255 || mAsciiKeys[c] == null) {
-                                    mStringIndex++;
-                                    if (mStringIndex >= mStringToPlay.length()) {
-                                        mPlaying = false;
-                                        return;
-                                    }
-                                    c = mStringToPlay.charAt(mStringIndex);
-                                }
-                                int x = mAsciiKeys[c].mX + 10;
-                                int y = mAsciiKeys[c].mY + 26;
-                                MotionEvent me = MotionEvent.obtain(SystemClock.uptimeMillis(),
-                                        SystemClock.uptimeMillis(),
-                                        MotionEvent.ACTION_DOWN, x, y, 0);
-                                LatinKeyboardView.this.dispatchTouchEvent(me);
-                                me.recycle();
-                                sendEmptyMessageDelayed(MSG_TOUCH_UP, 500); // Deliver up in 500ms if nothing else
-                                // happens
-                                mDownDelivered = true;
-                                break;
-                            case MSG_TOUCH_UP:
-                                char cUp = mStringToPlay.charAt(mStringIndex);
-                                int x2 = mAsciiKeys[cUp].mX + 10;
-                                int y2 = mAsciiKeys[cUp].mY + 26;
-                                mStringIndex++;
-
-                                MotionEvent me2 = MotionEvent.obtain(SystemClock.uptimeMillis(),
-                                        SystemClock.uptimeMillis(),
-                                        MotionEvent.ACTION_UP, x2, y2, 0);
-                                LatinKeyboardView.this.dispatchTouchEvent(me2);
-                                me2.recycle();
-                                sendEmptyMessageDelayed(MSG_TOUCH_DOWN, 500); // Deliver up in 500ms if nothing else
-                                // happens
-                                mDownDelivered = false;
-                                break;
-                        }
-                    }
-                };
-
-            }
-        }
-    }
-
-    private void findKeys() {
-        List<Key> keys = getLatinKeyboard().getKeys();
-        // Get the keys on this keyboard
-        for (int i = 0; i < keys.size(); i++) {
-            int code = keys.get(i).mCodes[0];
-            if (code >= 0 && code <= 255) {
-                mAsciiKeys[code] = keys.get(i);
-            }
-        }
-    }
-
-    public void startPlaying(String s) {
-        if (DEBUG_AUTO_PLAY) {
-            if (s == null) return;
-            mStringToPlay = s.toLowerCase();
-            mPlaying = true;
-            mDownDelivered = false;
-            mStringIndex = 0;
-            mHandler2.sendEmptyMessageDelayed(MSG_TOUCH_DOWN, 10);
-        }
-    }
-
     @Override
     public void draw(Canvas c) {
         Utils.GCUtils.getInstance().reset();
@@ -340,26 +230,6 @@
                 tryGC = Utils.GCUtils.getInstance().tryGCOrWait("LatinKeyboardView", e);
             }
         }
-        if (DEBUG_AUTO_PLAY) {
-            if (mPlaying) {
-                mHandler2.removeMessages(MSG_TOUCH_DOWN);
-                mHandler2.removeMessages(MSG_TOUCH_UP);
-                if (mDownDelivered) {
-                    mHandler2.sendEmptyMessageDelayed(MSG_TOUCH_UP, 20);
-                } else {
-                    mHandler2.sendEmptyMessageDelayed(MSG_TOUCH_DOWN, 20);
-                }
-            }
-        }
-        if (DEBUG_LINE) {
-            if (mPaint == null) {
-                mPaint = new Paint();
-                mPaint.setColor(0x80FFFFFF);
-                mPaint.setAntiAlias(false);
-            }
-            c.drawLine(mLastX, 0, mLastX, getHeight(), mPaint);
-            c.drawLine(0, mLastY, getWidth(), mLastY, mPaint);
-        }
     }
 
     @Override
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
index 8570491..65c370d 100644
--- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java
+++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
@@ -299,7 +299,7 @@
         showKeyPreviewAndUpdateKeyGraphics(keyIndex);
     }
 
-    public void onMoveEvent(int x, int y, long eventTime) {
+    public void onMoveEvent(int x, int y, @SuppressWarnings("unused") long eventTime) {
         if (DEBUG_MOVE)
             debugLog("onMoveEvent:", x, y);
         if (mKeyAlreadyProcessed)
@@ -333,7 +333,9 @@
         showKeyPreviewAndUpdateKeyGraphics(mKeyState.getKeyIndex());
     }
 
-    public void onUpEvent(int x, int y, long eventTime) {
+    public void onUpEvent(int pointX, int pointY, long eventTime) {
+        int x = pointX;
+        int y = pointY;
         if (DEBUG)
             debugLog("onUpEvent  :", x, y);
         showKeyPreviewAndUpdateKeyGraphics(NOT_A_KEY);
@@ -356,7 +358,7 @@
             mProxy.invalidateKey(mKeys[keyIndex]);
     }
 
-    public void onCancelEvent(int x, int y, long eventTime) {
+    public void onCancelEvent(int x, int y, @SuppressWarnings("unused") long eventTime) {
         if (DEBUG)
             debugLog("onCancelEvt:", x, y);
         mHandler.cancelKeyTimers();
diff --git a/java/src/com/android/inputmethod/keyboard/SlidingLocaleDrawable.java b/java/src/com/android/inputmethod/keyboard/SlidingLocaleDrawable.java
index 689791c..41f8c2a 100644
--- a/java/src/com/android/inputmethod/keyboard/SlidingLocaleDrawable.java
+++ b/java/src/com/android/inputmethod/keyboard/SlidingLocaleDrawable.java
@@ -58,7 +58,7 @@
         mContext = context;
         mRes = context.getResources();
         mBackground = background;
-        LatinKeyboard.setDefaultBounds(mBackground);
+        Keyboard.setDefaultBounds(mBackground);
         mWidth = width;
         mHeight = height;
         final TextPaint textPaint = new TextPaint();
@@ -123,7 +123,7 @@
             canvas.drawText(mNextLanguage, diff - width / 2, baseline, paint);
             canvas.drawText(mPrevLanguage, diff + width + width / 2, baseline, paint);
 
-            LatinKeyboard.setDefaultBounds(lArrow);
+            Keyboard.setDefaultBounds(lArrow);
             rArrow.setBounds(width - rArrow.getIntrinsicWidth(), 0, width,
                     rArrow.getIntrinsicHeight());
             lArrow.draw(canvas);
diff --git a/java/src/com/android/inputmethod/latin/AutoDictionary.java b/java/src/com/android/inputmethod/latin/AutoDictionary.java
index a3bf256..307b81d 100644
--- a/java/src/com/android/inputmethod/latin/AutoDictionary.java
+++ b/java/src/com/android/inputmethod/latin/AutoDictionary.java
@@ -98,7 +98,7 @@
     }
 
     @Override
-    public boolean isValidWord(CharSequence word) {
+    public synchronized boolean isValidWord(CharSequence word) {
         final int frequency = getWordFrequency(word);
         return frequency >= VALIDITY_THRESHOLD;
     }
@@ -138,7 +138,8 @@
     }
 
     @Override
-    public void addWord(String word, int addFrequency) {
+    public void addWord(String newWord, int addFrequency) {
+        String word = newWord;
         final int length = word.length();
         // Don't add very short or very long words.
         if (length < 2 || length > getMaxWordLength()) return;
@@ -224,7 +225,7 @@
         private final DatabaseHelper mDbHelper;
         private final String mLocale;
 
-        public UpdateDbTask(Context context, DatabaseHelper openHelper,
+        public UpdateDbTask(@SuppressWarnings("unused") Context context, DatabaseHelper openHelper,
                 HashMap<String, Integer> pendingWrites, String locale) {
             mMap = pendingWrites;
             mLocale = locale;
diff --git a/java/src/com/android/inputmethod/latin/CandidateView.java b/java/src/com/android/inputmethod/latin/CandidateView.java
index 74e6a01..03ba119 100644
--- a/java/src/com/android/inputmethod/latin/CandidateView.java
+++ b/java/src/com/android/inputmethod/latin/CandidateView.java
@@ -23,6 +23,7 @@
 import android.os.Message;
 import android.text.Spannable;
 import android.text.SpannableString;
+import android.text.Spanned;
 import android.text.TextUtils;
 import android.text.style.BackgroundColorSpan;
 import android.text.style.CharacterStyle;
@@ -35,6 +36,7 @@
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.View.OnLongClickListener;
+import android.view.ViewGroup;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.PopupWindow;
@@ -129,7 +131,7 @@
             cancelHidePreview();
             cancelUpdateSuggestions();
         }
-    };
+    }
 
     /**
      * Construct a CandidateView for showing suggested words for completion.
@@ -143,7 +145,8 @@
         mPreviewPopup = new PopupWindow(context);
         LayoutInflater inflater = LayoutInflater.from(context);
         mPreviewText = (TextView) inflater.inflate(R.layout.candidate_preview, null);
-        mPreviewPopup.setWindowLayoutMode(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+        mPreviewPopup.setWindowLayoutMode(ViewGroup.LayoutParams.WRAP_CONTENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT);
         mPreviewPopup.setContentView(mPreviewText);
         mPreviewPopup.setBackgroundDrawable(null);
         mPreviewPopup.setAnimationStyle(R.style.KeyPreviewAnimation);
@@ -181,6 +184,9 @@
 
     public void setSuggestions(List<CharSequence> suggestions, boolean completions,
             boolean typedWordValid, boolean haveMinimalSuggestion) {
+        // Don't update suggestions when there is zero or only one suggestion found.
+        if (suggestions != null && suggestions.size() <= 1)
+            return;
         if (mShowingAutoCorrectionInverted) {
             mHandler.postUpdateSuggestions(suggestions, completions, typedWordValid,
                     haveMinimalSuggestion);
@@ -222,7 +228,7 @@
                     style = UNDERLINE_SPAN;
                 }
                 final Spannable word = new SpannableString(suggestion);
-                word.setSpan(style, 0, wordLength, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
+                word.setSpan(style, 0, wordLength, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
                 suggestion = word;
                 existsAutoCompletion = true;
             } else if (i != 0 || (wordLength == 1 && count > 1)) {
@@ -255,10 +261,8 @@
         final TextView tv = (TextView)mWords.get(1).findViewById(R.id.candidate_word);
         final Spannable word = new SpannableString(autoCorrectedWord);
         final int wordLength = word.length();
-        word.setSpan(mInvertedBackgroundColorSpan, 0, wordLength,
-                Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
-        word.setSpan(mInvertedForegroundColorSpan, 0, wordLength,
-                Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
+        word.setSpan(mInvertedBackgroundColorSpan, 0, wordLength, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
+        word.setSpan(mInvertedForegroundColorSpan, 0, wordLength, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
         tv.setText(word);
         mShowingAutoCorrectionInverted = true;
     }
diff --git a/java/src/com/android/inputmethod/latin/ContactsDictionary.java b/java/src/com/android/inputmethod/latin/ContactsDictionary.java
index 95a3b5c..048f72d 100644
--- a/java/src/com/android/inputmethod/latin/ContactsDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ContactsDictionary.java
@@ -21,6 +21,7 @@
 import android.database.ContentObserver;
 import android.database.Cursor;
 import android.os.SystemClock;
+import android.provider.BaseColumns;
 import android.provider.ContactsContract.Contacts;
 import android.text.TextUtils;
 import android.util.Log;
@@ -28,7 +29,7 @@
 public class ContactsDictionary extends ExpandableDictionary {
 
     private static final String[] PROJECTION = {
-        Contacts._ID,
+        BaseColumns._ID,
         Contacts.DISPLAY_NAME,
     };
 
diff --git a/java/src/com/android/inputmethod/latin/Dictionary.java b/java/src/com/android/inputmethod/latin/Dictionary.java
index d04bf57..7493359 100644
--- a/java/src/com/android/inputmethod/latin/Dictionary.java
+++ b/java/src/com/android/inputmethod/latin/Dictionary.java
@@ -20,7 +20,7 @@
  * Abstract base class for a dictionary that can do a fuzzy search for words based on a set of key
  * strokes.
  */
-abstract public class Dictionary {
+public abstract class Dictionary {
     /**
      * Whether or not to replicate the typed word in the suggested list, even if it's valid.
      */
@@ -42,11 +42,11 @@
     public interface WordCallback {
         /**
          * Adds a word to a list of suggestions. The word is expected to be ordered based on
-         * the provided frequency. 
+         * the provided frequency.
          * @param word the character array containing the word
          * @param wordOffset starting offset of the word in the character array
          * @param wordLength length of valid characters in the character array
-         * @param frequency the frequency of occurence. This is normalized between 1 and 255, but
+         * @param frequency the frequency of occurrence. This is normalized between 1 and 255, but
          * can exceed those limits
          * @param dicTypeId of the dictionary where word was from
          * @param dataType tells type of this data
@@ -74,6 +74,7 @@
      * Searches for pairs in the bigram dictionary that matches the previous word and all the
      * possible words following are added through the callback object.
      * @param composer the key sequence to match
+     * @param previousWord the word before
      * @param callback the callback object to send possible word following previous word
      * @param nextLettersFrequencies array of frequencies of next letters that could follow the
      *        word so far. For instance, "bracke" can be followed by "t", so array['t'] will have
@@ -116,5 +117,6 @@
      * Override to clean up any resources.
      */
     public void close() {
+        // empty base implementation
     }
 }
diff --git a/java/src/com/android/inputmethod/latin/EditingUtil.java b/java/src/com/android/inputmethod/latin/EditingUtils.java
similarity index 83%
rename from java/src/com/android/inputmethod/latin/EditingUtil.java
rename to java/src/com/android/inputmethod/latin/EditingUtils.java
index 781d7fd..0ca06dd 100644
--- a/java/src/com/android/inputmethod/latin/EditingUtil.java
+++ b/java/src/com/android/inputmethod/latin/EditingUtils.java
@@ -28,7 +28,7 @@
 /**
  * Utility methods to deal with editing text through an InputConnection.
  */
-public class EditingUtil {
+public class EditingUtils {
     /**
      * Number of characters we want to look back in order to identify the previous word
      */
@@ -39,7 +39,9 @@
     private static Method sMethodGetSelectedText;
     private static Method sMethodSetComposingRegion;
 
-    private EditingUtil() {};
+    private EditingUtils() {
+        // Unintentional empty constructor for singleton.
+    }
 
     /**
      * Append newText to the text field represented by connection.
@@ -54,14 +56,15 @@
         connection.finishComposingText();
 
         // Add a space if the field already has text.
+        String text = newText;
         CharSequence charBeforeCursor = connection.getTextBeforeCursor(1, 0);
         if (charBeforeCursor != null
                 && !charBeforeCursor.equals(" ")
                 && (charBeforeCursor.length() > 0)) {
-            newText = " " + newText;
+            text = " " + text;
         }
 
-        connection.setComposingText(newText, 1);
+        connection.setComposingText(text, 1);
     }
 
     private static int getCursorPosition(InputConnection connection) {
@@ -76,33 +79,29 @@
     /**
      * @param connection connection to the current text field.
      * @param sep characters which may separate words
-     * @param range the range object to store the result into
      * @return the word that surrounds the cursor, including up to one trailing
      *   separator. For example, if the field contains "he|llo world", where |
      *   represents the cursor, then "hello " will be returned.
      */
-    public static String getWordAtCursor(
-            InputConnection connection, String separators, Range range) {
-        Range r = getWordRangeAtCursor(connection, separators, range);
-        return (r == null) ? null : r.word;
+    public static String getWordAtCursor(InputConnection connection, String separators) {
+        Range r = getWordRangeAtCursor(connection, separators);
+        return (r == null) ? null : r.mWord;
     }
 
     /**
      * Removes the word surrounding the cursor. Parameters are identical to
      * getWordAtCursor.
      */
-    public static void deleteWordAtCursor(
-        InputConnection connection, String separators) {
-
-        Range range = getWordRangeAtCursor(connection, separators, null);
+    public static void deleteWordAtCursor(InputConnection connection, String separators) {
+        Range range = getWordRangeAtCursor(connection, separators);
         if (range == null) return;
 
         connection.finishComposingText();
         // Move cursor to beginning of word, to avoid crash when cursor is outside
         // of valid range after deleting text.
-        int newCursor = getCursorPosition(connection) - range.charsBefore;
+        int newCursor = getCursorPosition(connection) - range.mCharsBefore;
         connection.setSelection(newCursor, newCursor);
-        connection.deleteSurroundingText(0, range.charsBefore + range.charsAfter);
+        connection.deleteSurroundingText(0, range.mCharsBefore + range.mCharsAfter);
     }
 
     /**
@@ -110,31 +109,28 @@
      */
     public static class Range {
         /** Characters before selection start */
-        public int charsBefore;
+        public final int mCharsBefore;
 
         /**
          * Characters after selection start, including one trailing word
          * separator.
          */
-        public int charsAfter;
+        public final int mCharsAfter;
 
         /** The actual characters that make up a word */
-        public String word;
-
-        public Range() {}
+        public final String mWord;
 
         public Range(int charsBefore, int charsAfter, String word) {
             if (charsBefore < 0 || charsAfter < 0) {
                 throw new IndexOutOfBoundsException();
             }
-            this.charsBefore = charsBefore;
-            this.charsAfter = charsAfter;
-            this.word = word;
+            this.mCharsBefore = charsBefore;
+            this.mCharsAfter = charsAfter;
+            this.mWord = word;
         }
     }
 
-    private static Range getWordRangeAtCursor(
-            InputConnection connection, String sep, Range range) {
+    private static Range getWordRangeAtCursor(InputConnection connection, String sep) {
         if (connection == null || sep == null) {
             return null;
         }
@@ -150,18 +146,15 @@
 
         // Find last word separator after the cursor
         int end = -1;
-        while (++end < after.length() && !isWhitespace(after.charAt(end), sep));
+        while (++end < after.length() && !isWhitespace(after.charAt(end), sep)) {
+            // Nothing to do here.
+        }
 
         int cursor = getCursorPosition(connection);
         if (start >= 0 && cursor + end <= after.length() + before.length()) {
             String word = before.toString().substring(start, before.length())
                     + after.toString().substring(0, end);
-
-            Range returnRange = range != null? range : new Range();
-            returnRange.charsBefore = before.length() - start;
-            returnRange.charsAfter = end;
-            returnRange.word = word;
-            return returnRange;
+            return new Range(before.length() - start, end, word);
         }
 
         return null;
@@ -193,9 +186,15 @@
     }
 
     public static class SelectedWord {
-        public int start;
-        public int end;
-        public CharSequence word;
+        public final int mStart;
+        public final int mEnd;
+        public final CharSequence mWord;
+
+        public SelectedWord(int start, int end, CharSequence word) {
+            mStart = start;
+            mEnd = end;
+            mWord = word;
+        }
     }
 
     /**
@@ -223,14 +222,10 @@
             int selStart, int selEnd, String wordSeparators) {
         if (selStart == selEnd) {
             // There is just a cursor, so get the word at the cursor
-            EditingUtil.Range range = new EditingUtil.Range();
-            CharSequence touching = getWordAtCursor(ic, wordSeparators, range);
-            if (!TextUtils.isEmpty(touching)) {
-                SelectedWord selWord = new SelectedWord();
-                selWord.word = touching;
-                selWord.start = selStart - range.charsBefore;
-                selWord.end = selEnd + range.charsAfter;
-                return selWord;
+            EditingUtils.Range range = getWordRangeAtCursor(ic, wordSeparators);
+            if (range != null && !TextUtils.isEmpty(range.mWord)) {
+                return new SelectedWord(selStart - range.mCharsBefore, selEnd + range.mCharsAfter,
+                        range.mWord);
             }
         } else {
             // Is the previous character empty or a word separator? If not, return null.
@@ -256,11 +251,7 @@
                 }
             }
             // Prepare the selected word
-            SelectedWord selWord = new SelectedWord();
-            selWord.start = selStart;
-            selWord.end = selEnd;
-            selWord.word = touching;
-            return selWord;
+            return new SelectedWord(selStart, selEnd, touching);
         }
         return null;
     }
@@ -324,7 +315,7 @@
         }
         if (sMethodSetComposingRegion != null) {
             try {
-                sMethodSetComposingRegion.invoke(ic, word.start, word.end);
+                sMethodSetComposingRegion.invoke(ic, word.mStart, word.mEnd);
             } catch (InvocationTargetException exc) {
                 // Ignore
             } catch (IllegalArgumentException e) {
diff --git a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java
index 2a7767d..bc08df0 100644
--- a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java
@@ -49,53 +49,65 @@
     // Use this lock before touching mUpdatingDictionary & mRequiresDownload
     private Object mUpdatingLock = new Object();
 
-    static class Node {
-        char code;
-        int frequency;
-        boolean terminal;
-        Node parent;
-        NodeArray children;
-        LinkedList<NextWord> ngrams; // Supports ngram
+    private static class Node {
+        char mCode;
+        int mFrequency;
+        boolean mTerminal;
+        Node mParent;
+        NodeArray mChildren;
+        LinkedList<NextWord> mNGrams; // Supports ngram
     }
 
-    static class NodeArray {
-        Node[] data;
-        int length = 0;
+    private static class NodeArray {
+        Node[] mData;
+        int mLength = 0;
         private static final int INCREMENT = 2;
 
         NodeArray() {
-            data = new Node[INCREMENT];
+            mData = new Node[INCREMENT];
         }
 
         void add(Node n) {
-            if (length + 1 > data.length) {
-                Node[] tempData = new Node[length + INCREMENT];
-                if (length > 0) {
-                    System.arraycopy(data, 0, tempData, 0, length);
+            if (mLength + 1 > mData.length) {
+                Node[] tempData = new Node[mLength + INCREMENT];
+                if (mLength > 0) {
+                    System.arraycopy(mData, 0, tempData, 0, mLength);
                 }
-                data = tempData;
+                mData = tempData;
             }
-            data[length++] = n;
+            mData[mLength++] = n;
         }
     }
 
-    static class NextWord {
-        Node word;
-        NextWord nextWord;
-        int frequency;
+    private static class NextWord {
+        public final Node mWord;
+        private int mFrequency;
 
-        NextWord(Node word, int frequency) {
-            this.word = word;
-            this.frequency = frequency;
+        public NextWord(Node word, int frequency) {
+            mWord = word;
+            mFrequency = frequency;
+        }
+
+        public int getFrequency() {
+            return mFrequency;
+        }
+
+        public int setFrequency(int freq) {
+            mFrequency = freq;
+            return mFrequency;
+        }
+
+        public int addFrequency(int add) {
+            mFrequency += add;
+            return mFrequency;
         }
     }
 
-
     private NodeArray mRoots;
 
     private int[][] mCodes;
 
-    ExpandableDictionary(Context context, int dicTypeId) {
+    public ExpandableDictionary(Context context, int dicTypeId) {
         mContext = context;
         clearDictionary();
         mCodes = new int[MAX_WORD_LENGTH][];
@@ -128,13 +140,14 @@
 
     /** Override to load your dictionary here, on a background thread. */
     public void loadDictionaryAsync() {
+        // empty base implementation
     }
 
-    Context getContext() {
+    public Context getContext() {
         return mContext;
     }
     
-    int getMaxWordLength() {
+    public int getMaxWordLength() {
         return MAX_WORD_LENGTH;
     }
 
@@ -147,33 +160,33 @@
         final int wordLength = word.length();
         final char c = word.charAt(depth);
         // Does children have the current character?
-        final int childrenLength = children.length;
+        final int childrenLength = children.mLength;
         Node childNode = null;
         boolean found = false;
         for (int i = 0; i < childrenLength; i++) {
-            childNode = children.data[i];
-            if (childNode.code == c) {
+            childNode = children.mData[i];
+            if (childNode.mCode == c) {
                 found = true;
                 break;
             }
         }
         if (!found) {
             childNode = new Node();
-            childNode.code = c;
-            childNode.parent = parentNode;
+            childNode.mCode = c;
+            childNode.mParent = parentNode;
             children.add(childNode);
         }
         if (wordLength == depth + 1) {
             // Terminate this word
-            childNode.terminal = true;
-            childNode.frequency = Math.max(frequency, childNode.frequency);
-            if (childNode.frequency > 255) childNode.frequency = 255;
+            childNode.mTerminal = true;
+            childNode.mFrequency = Math.max(frequency, childNode.mFrequency);
+            if (childNode.mFrequency > 255) childNode.mFrequency = 255;
             return;
         }
-        if (childNode.children == null) {
-            childNode.children = new NodeArray();
+        if (childNode.mChildren == null) {
+            childNode.mChildren = new NodeArray();
         }
-        addWordRec(childNode.children, word, depth + 1, frequency, childNode);
+        addWordRec(childNode.mChildren, word, depth + 1, frequency, childNode);
     }
 
     @Override
@@ -216,7 +229,7 @@
      */
     public int getWordFrequency(CharSequence word) {
         Node node = searchNode(mRoots, word, 0, word.length());
-        return (node == null) ? -1 : node.frequency;
+        return (node == null) ? -1 : node.mFrequency;
     }
 
     /**
@@ -241,7 +254,7 @@
     protected void getWordsRec(NodeArray roots, final WordComposer codes, final char[] word, 
             final int depth, boolean completion, int snr, int inputIndex, int skipPos,
             WordCallback callback) {
-        final int count = roots.length;
+        final int count = roots.mLength;
         final int codeSize = mInputLength;
         // Optimization: Prune out words that are too long compared to how much was typed.
         if (depth > mMaxDepth) {
@@ -255,12 +268,12 @@
         }
 
         for (int i = 0; i < count; i++) {
-            final Node node = roots.data[i];
-            final char c = node.code;
+            final Node node = roots.mData[i];
+            final char c = node.mCode;
             final char lowerC = toLowerCase(c);
-            final boolean terminal = node.terminal;
-            final NodeArray children = node.children;
-            final int freq = node.frequency;
+            final boolean terminal = node.mTerminal;
+            final NodeArray children = node.mChildren;
+            final int freq = node.mFrequency;
             if (completion) {
                 word[depth] = c;
                 if (terminal) {
@@ -340,24 +353,22 @@
     private int addOrSetBigram(String word1, String word2, int frequency, boolean addFrequency) {
         Node firstWord = searchWord(mRoots, word1, 0, null);
         Node secondWord = searchWord(mRoots, word2, 0, null);
-        LinkedList<NextWord> bigram = firstWord.ngrams;
+        LinkedList<NextWord> bigram = firstWord.mNGrams;
         if (bigram == null || bigram.size() == 0) {
-            firstWord.ngrams = new LinkedList<NextWord>();
-            bigram = firstWord.ngrams;
+            firstWord.mNGrams = new LinkedList<NextWord>();
+            bigram = firstWord.mNGrams;
         } else {
             for (NextWord nw : bigram) {
-                if (nw.word == secondWord) {
+                if (nw.mWord == secondWord) {
                     if (addFrequency) {
-                        nw.frequency += frequency;
+                        return nw.addFrequency(frequency);
                     } else {
-                        nw.frequency = frequency;
+                        return nw.setFrequency(frequency);
                     }
-                    return nw.frequency;
                 }
             }
         }
-        NextWord nw = new NextWord(secondWord, frequency);
-        firstWord.ngrams.add(nw);
+        firstWord.mNGrams.add(new NextWord(secondWord, frequency));
         return frequency;
     }
 
@@ -369,31 +380,31 @@
         final int wordLength = word.length();
         final char c = word.charAt(depth);
         // Does children have the current character?
-        final int childrenLength = children.length;
+        final int childrenLength = children.mLength;
         Node childNode = null;
         boolean found = false;
         for (int i = 0; i < childrenLength; i++) {
-            childNode = children.data[i];
-            if (childNode.code == c) {
+            childNode = children.mData[i];
+            if (childNode.mCode == c) {
                 found = true;
                 break;
             }
         }
         if (!found) {
             childNode = new Node();
-            childNode.code = c;
-            childNode.parent = parentNode;
+            childNode.mCode = c;
+            childNode.mParent = parentNode;
             children.add(childNode);
         }
         if (wordLength == depth + 1) {
             // Terminate this word
-            childNode.terminal = true;
+            childNode.mTerminal = true;
             return childNode;
         }
-        if (childNode.children == null) {
-            childNode.children = new NodeArray();
+        if (childNode.mChildren == null) {
+            childNode.mChildren = new NodeArray();
         }
-        return searchWord(childNode.children, word, depth + 1, childNode);
+        return searchWord(childNode.mChildren, word, depth + 1, childNode);
     }
 
     // @VisibleForTesting
@@ -408,8 +419,8 @@
 
     private void runReverseLookUp(final CharSequence previousWord, final WordCallback callback) {
         Node prevWord = searchNode(mRoots, previousWord, 0, previousWord.length());
-        if (prevWord != null && prevWord.ngrams != null) {
-            reverseLookUp(prevWord.ngrams, callback);
+        if (prevWord != null && prevWord.mNGrams != null) {
+            reverseLookUp(prevWord.mNGrams, callback);
         }
     }
 
@@ -430,6 +441,7 @@
             try {
                 Thread.sleep(100);
             } catch (InterruptedException e) {
+                //
             }
         }
     }
@@ -444,14 +456,14 @@
         Node node;
         int freq;
         for (NextWord nextWord : terminalNodes) {
-            node = nextWord.word;
-            freq = nextWord.frequency;
+            node = nextWord.mWord;
+            freq = nextWord.getFrequency();
             // TODO Not the best way to limit suggestion threshold
             if (freq >= UserBigramDictionary.SUGGEST_THRESHOLD) {
                 sb.setLength(0);
                 do {
-                    sb.insert(0, node.code);
-                    node = node.parent;
+                    sb.insert(0, node.mCode);
+                    node = node.mParent;
                 } while(node != null);
 
                 // TODO better way to feed char array?
@@ -468,18 +480,18 @@
     private Node searchNode(final NodeArray children, final CharSequence word, final int offset,
             final int length) {
         // TODO Consider combining with addWordRec
-        final int count = children.length;
+        final int count = children.mLength;
         char currentChar = word.charAt(offset);
         for (int j = 0; j < count; j++) {
-            final Node node = children.data[j];
-            if (node.code == currentChar) {
+            final Node node = children.mData[j];
+            if (node.mCode == currentChar) {
                 if (offset == length - 1) {
-                    if (node.terminal) {
+                    if (node.mTerminal) {
                         return node;
                     }
                 } else {
-                    if (node.children != null) {
-                        Node returnNode = searchNode(node.children, word, offset + 1, length);
+                    if (node.mChildren != null) {
+                        Node returnNode = searchNode(node.mChildren, word, offset + 1, length);
                         if (returnNode != null) return returnNode;
                     }
                 }
@@ -504,15 +516,16 @@
     }
 
     static char toLowerCase(char c) {
+        char baseChar = c;
         if (c < BASE_CHARS.length) {
-            c = BASE_CHARS[c];
+            baseChar = BASE_CHARS[c];
         }
-        if (c >= 'A' && c <= 'Z') {
-            c = (char) (c | 32);
-        } else if (c > 127) {
-            c = Character.toLowerCase(c);
+        if (baseChar >= 'A' && baseChar <= 'Z') {
+            return (char)(baseChar | 32);
+        } else if (baseChar > 127) {
+            return Character.toLowerCase(baseChar);
         }
-        return c;
+        return baseChar;
     }
 
     /**
diff --git a/java/src/com/android/inputmethod/latin/InputLanguageSelection.java b/java/src/com/android/inputmethod/latin/InputLanguageSelection.java
index a558216..27e0fbe 100644
--- a/java/src/com/android/inputmethod/latin/InputLanguageSelection.java
+++ b/java/src/com/android/inputmethod/latin/InputLanguageSelection.java
@@ -42,24 +42,28 @@
     };
 
     private static class Loc implements Comparable<Object> {
-        static Collator sCollator = Collator.getInstance();
+        private static Collator sCollator = Collator.getInstance();
 
-        String label;
-        Locale locale;
+        private String mLabel;
+        public final Locale mLocale;
 
         public Loc(String label, Locale locale) {
-            this.label = label;
-            this.locale = locale;
+            this.mLabel = label;
+            this.mLocale = locale;
+        }
+
+        public void setLabel(String label) {
+            this.mLabel = label;
         }
 
         @Override
         public String toString() {
-            return this.label;
+            return this.mLabel;
         }
 
         @Override
         public int compareTo(Object o) {
-            return sCollator.compare(this.label, ((Loc) o).label);
+            return sCollator.compare(this.mLabel, ((Loc) o).mLabel);
         }
     }
 
@@ -75,7 +79,7 @@
         PreferenceGroup parent = getPreferenceScreen();
         for (int i = 0; i < mAvailableLanguages.size(); i++) {
             CheckBoxPreference pref = new CheckBoxPreference(this);
-            Locale locale = mAvailableLanguages.get(i).locale;
+            Locale locale = mAvailableLanguages.get(i).mLocale;
             pref.setTitle(SubtypeSwitcher.getFullDisplayName(locale, true));
             boolean checked = isLocaleIn(locale, languageList);
             pref.setChecked(checked);
@@ -137,7 +141,7 @@
         for (int i = 0; i < count; i++) {
             CheckBoxPreference pref = (CheckBoxPreference) parent.getPreference(i);
             if (pref.isChecked()) {
-                Locale locale = mAvailableLanguages.get(i).locale;
+                Locale locale = mAvailableLanguages.get(i).mLocale;
                 checkedLanguages += get5Code(locale) + ",";
             }
         }
@@ -147,7 +151,7 @@
         SharedPreferencesCompat.apply(editor);
     }
 
-    ArrayList<Loc> getUniqueLocales() {
+    public ArrayList<Loc> getUniqueLocales() {
         String[] locales = getAssets().getLocales();
         Arrays.sort(locales);
         ArrayList<Loc> uniqueLocales = new ArrayList<Loc>();
@@ -174,15 +178,16 @@
                     //  same lang and a country -> upgrade to full name and
                     //    insert ours with full name
                     //  diff lang -> insert ours with lang-only name
-                    if (preprocess[finalSize-1].locale.getLanguage().equals(
+                    if (preprocess[finalSize-1].mLocale.getLanguage().equals(
                             language)) {
-                        preprocess[finalSize-1].label = SubtypeSwitcher.getFullDisplayName(
-                                preprocess[finalSize-1].locale, false);
+                        preprocess[finalSize-1].setLabel(SubtypeSwitcher.getFullDisplayName(
+                                preprocess[finalSize-1].mLocale, false));
                         preprocess[finalSize++] =
                                 new Loc(SubtypeSwitcher.getFullDisplayName(l, false), l);
                     } else {
                         String displayName;
                         if (s.equals("zz_ZZ")) {
+                            // ignore this locale
                         } else {
                             displayName = SubtypeSwitcher.getFullDisplayName(l, true);
                             preprocess[finalSize++] = new Loc(displayName, l);
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 27af98e..99b6c73 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -25,6 +25,7 @@
 import com.android.inputmethod.latin.Utils.RingCharBuffer;
 import com.android.inputmethod.voice.VoiceIMEConnector;
 
+import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
 import android.app.AlertDialog;
@@ -46,6 +47,7 @@
 import android.os.Vibrator;
 import android.preference.PreferenceActivity;
 import android.preference.PreferenceManager;
+import android.text.InputType;
 import android.text.TextUtils;
 import android.util.DisplayMetrics;
 import android.util.Log;
@@ -82,7 +84,7 @@
  * Input method implementation for Qwerty'ish keyboard.
  */
 public class LatinIME extends InputMethodService implements KeyboardActionListener,
-        SharedPreferences.OnSharedPreferenceChangeListener, Tutorial.TutorialListener {
+        SharedPreferences.OnSharedPreferenceChangeListener {
     private static final String TAG = "LatinIME";
     private static final boolean PERF_DEBUG = false;
     private static final boolean DEBUG = false;
@@ -91,7 +93,6 @@
     private static final int DELAY_UPDATE_SUGGESTIONS = 180;
     private static final int DELAY_UPDATE_OLD_SUGGESTIONS = 300;
     private static final int DELAY_UPDATE_SHIFT_STATE = 300;
-    private static final int DELAY_START_TUTORIAL = 500;
 
     // How many continuous deletes at which to start deleting at a higher speed.
     private static final int DELETE_ACCELERATE_AT = 20;
@@ -172,8 +173,6 @@
     private int mDeleteCount;
     private long mLastKeyTime;
 
-    private Tutorial mTutorial;
-
     private AudioManager mAudioManager;
     // Align sound effect volume on music volume
     private static final float FX_VOLUME = -1.0f;
@@ -246,7 +245,6 @@
         private static final int MSG_UPDATE_OLD_SUGGESTIONS = 1;
         private static final int MSG_UPDATE_SHIFT_STATE = 2;
         private static final int MSG_VOICE_RESULTS = 3;
-        private static final int MSG_START_TUTORIAL = 4;
 
         @Override
         public void handleMessage(Message msg) {
@@ -261,21 +259,10 @@
                 mKeyboardSwitcher.updateShiftState();
                 break;
             case MSG_VOICE_RESULTS:
-                mVoiceConnector.handleVoiceResults(mKeyboardSwitcher, preferCapitalization()
+                mVoiceConnector.handleVoiceResults(preferCapitalization()
                         || (mKeyboardSwitcher.isAlphabetMode()
                                 && mKeyboardSwitcher.isShiftedOrShiftLocked()));
                 break;
-            case MSG_START_TUTORIAL:
-                if (mTutorial == null) {
-                    if (mKeyboardSwitcher.isInputViewShown()) {
-                        mTutorial = new Tutorial(LatinIME.this, mKeyboardSwitcher);
-                        mTutorial.start();
-                    } else {
-                        // Try again soon if the view is not yet showing
-                        sendMessageDelayed(obtainMessage(MSG_START_TUTORIAL), 100);
-                    }
-                }
-                break;
             }
         }
 
@@ -314,10 +301,6 @@
         public void updateVoiceResults() {
             sendMessage(obtainMessage(MSG_VOICE_RESULTS));
         }
-
-        public void startTutorial() {
-            sendMessageDelayed(obtainMessage(MSG_START_TUTORIAL), DELAY_START_TUTORIAL);
-        }
     }
 
     @Override
@@ -369,8 +352,8 @@
 
         try {
             int current = xrp.getEventType();
-            while (current != XmlResourceParser.END_DOCUMENT) {
-                if (current == XmlResourceParser.START_TAG) {
+            while (current != XmlPullParser.END_DOCUMENT) {
+                if (current == XmlPullParser.START_TAG) {
                     String tag = xrp.getName();
                     if (tag != null) {
                         if (tag.equals("part")) {
@@ -501,14 +484,14 @@
     }
 
     private static boolean isPasswordVariation(int variation) {
-        return variation == EditorInfo.TYPE_TEXT_VARIATION_PASSWORD
-                || variation == EditorInfo.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
-                || variation == EditorInfo.TYPE_TEXT_VARIATION_WEB_PASSWORD;
+        return variation == InputType.TYPE_TEXT_VARIATION_PASSWORD
+                || variation == InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
+                || variation == InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD;
     }
 
     private static boolean isEmailVariation(int variation) {
-        return variation == EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
-                || variation == EditorInfo.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS;
+        return variation == InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
+                || variation == InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS;
     }
 
     @Override
@@ -533,7 +516,7 @@
         // Most such things we decide below in the switch statement, but we need to know
         // now whether this is a password text field, because we need to know now (before
         // the switch statement) whether we want to enable the voice button.
-        int variation = attribute.inputType & EditorInfo.TYPE_MASK_VARIATION;
+        int variation = attribute.inputType & InputType.TYPE_MASK_VARIATION;
         mVoiceConnector.resetVoiceStates(isPasswordVariation(variation));
         mInputTypeNoAutoCorrect = false;
         mPredictionOn = false;
@@ -542,15 +525,15 @@
         mEnteredText = null;
 
         final int mode;
-        switch (attribute.inputType & EditorInfo.TYPE_MASK_CLASS) {
-            case EditorInfo.TYPE_CLASS_NUMBER:
-            case EditorInfo.TYPE_CLASS_DATETIME:
+        switch (attribute.inputType & InputType.TYPE_MASK_CLASS) {
+            case InputType.TYPE_CLASS_NUMBER:
+            case InputType.TYPE_CLASS_DATETIME:
                 mode = KeyboardId.MODE_NUMBER;
                 break;
-            case EditorInfo.TYPE_CLASS_PHONE:
+            case InputType.TYPE_CLASS_PHONE:
                 mode = KeyboardId.MODE_PHONE;
                 break;
-            case EditorInfo.TYPE_CLASS_TEXT:
+            case InputType.TYPE_CLASS_TEXT:
                 //startPrediction();
                 mPredictionOn = true;
                 // Make sure that passwords are not displayed in candidate view
@@ -558,7 +541,7 @@
                     mPredictionOn = false;
                 }
                 if (isEmailVariation(variation)
-                        || variation == EditorInfo.TYPE_TEXT_VARIATION_PERSON_NAME) {
+                        || variation == InputType.TYPE_TEXT_VARIATION_PERSON_NAME) {
                     mAutoSpace = false;
                 } else {
                     mAutoSpace = true;
@@ -566,19 +549,19 @@
                 if (isEmailVariation(variation)) {
                     mPredictionOn = false;
                     mode = KeyboardId.MODE_EMAIL;
-                } else if (variation == EditorInfo.TYPE_TEXT_VARIATION_URI) {
+                } else if (variation == InputType.TYPE_TEXT_VARIATION_URI) {
                     mPredictionOn = false;
                     mode = KeyboardId.MODE_URL;
-                } else if (variation == EditorInfo.TYPE_TEXT_VARIATION_SHORT_MESSAGE) {
+                } else if (variation == InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE) {
                     mode = KeyboardId.MODE_IM;
-                } else if (variation == EditorInfo.TYPE_TEXT_VARIATION_FILTER) {
+                } else if (variation == InputType.TYPE_TEXT_VARIATION_FILTER) {
                     mPredictionOn = false;
                     mode = KeyboardId.MODE_TEXT;
-                } else if (variation == EditorInfo.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT) {
+                } else if (variation == InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT) {
                     mode = KeyboardId.MODE_WEB;
                     // If it's a browser edit field and auto correct is not ON explicitly, then
                     // disable auto correction, but keep suggestions on.
-                    if ((attribute.inputType & EditorInfo.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0) {
+                    if ((attribute.inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0) {
                         mInputTypeNoAutoCorrect = true;
                     }
                 } else {
@@ -586,16 +569,16 @@
                 }
 
                 // If NO_SUGGESTIONS is set, don't do prediction.
-                if ((attribute.inputType & EditorInfo.TYPE_TEXT_FLAG_NO_SUGGESTIONS) != 0) {
+                if ((attribute.inputType & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS) != 0) {
                     mPredictionOn = false;
                     mInputTypeNoAutoCorrect = true;
                 }
                 // If it's not multiline and the autoCorrect flag is not set, then don't correct
-                if ((attribute.inputType & EditorInfo.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0 &&
-                        (attribute.inputType & EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE) == 0) {
+                if ((attribute.inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0 &&
+                        (attribute.inputType & InputType.TYPE_TEXT_FLAG_MULTI_LINE) == 0) {
                     mInputTypeNoAutoCorrect = true;
                 }
-                if ((attribute.inputType & EditorInfo.TYPE_TEXT_FLAG_AUTO_COMPLETE) != 0) {
+                if ((attribute.inputType & InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE) != 0) {
                     mPredictionOn = false;
                     mCompletionOn = isFullscreenMode();
                 }
@@ -632,7 +615,6 @@
         mPredictionOn = mPredictionOn && (mCorrectionMode > 0 || isSuggestionShown());
         // If we just entered a text field, maybe it has some old text that requires correction
         checkReCorrectionOnStart();
-        checkTutorial(attribute.privateImeOptions);
         inputView.setForeground(true);
 
         mVoiceConnector.onStartInputView(mKeyboardSwitcher.getInputView().getWindowToken());
@@ -733,12 +715,14 @@
             mVoiceConnector.setVoiceInputHighlighted(false);
         } else if (!mPredicting && !mJustAccepted) {
             switch (TextEntryState.getState()) {
-                case ACCEPTED_DEFAULT:
-                    TextEntryState.reset();
-                    // fall through
-                case SPACE_AFTER_PICKED:
-                    mJustAddedAutoSpace = false;  // The user moved the cursor.
-                    break;
+            case ACCEPTED_DEFAULT:
+                TextEntryState.reset();
+                // $FALL-THROUGH$
+            case SPACE_AFTER_PICKED:
+                mJustAddedAutoSpace = false; // The user moved the cursor.
+                break;
+            default:
+                break;
             }
         }
         mJustAccepted = false;
@@ -835,7 +819,7 @@
             }
 
             List<CharSequence> stringList = new ArrayList<CharSequence>();
-            for (int i=0; i<(completions != null ? completions.length : 0); i++) {
+            for (int i = 0; i < completions.length; i++) {
                 CompletionInfo ci = completions[i];
                 if (ci != null) stringList.add(ci.getText());
             }
@@ -883,25 +867,13 @@
     @Override
     public boolean onKeyDown(int keyCode, KeyEvent event) {
         switch (keyCode) {
-            case KeyEvent.KEYCODE_BACK:
-                if (event.getRepeatCount() == 0 && mKeyboardSwitcher.getInputView() != null) {
-                    if (mKeyboardSwitcher.getInputView().handleBack()) {
-                        return true;
-                    } else if (mTutorial != null) {
-                        mTutorial.close();
-                        mTutorial = null;
-                    }
-                }
-                break;
-            case KeyEvent.KEYCODE_DPAD_DOWN:
-            case KeyEvent.KEYCODE_DPAD_UP:
-            case KeyEvent.KEYCODE_DPAD_LEFT:
-            case KeyEvent.KEYCODE_DPAD_RIGHT:
-                // If tutorial is visible, don't allow dpad to work
-                if (mTutorial != null) {
+        case KeyEvent.KEYCODE_BACK:
+            if (event.getRepeatCount() == 0 && mKeyboardSwitcher.getInputView() != null) {
+                if (mKeyboardSwitcher.getInputView().handleBack()) {
                     return true;
                 }
-                break;
+            }
+            break;
         }
         return super.onKeyDown(keyCode, event);
     }
@@ -909,26 +881,23 @@
     @Override
     public boolean onKeyUp(int keyCode, KeyEvent event) {
         switch (keyCode) {
-            case KeyEvent.KEYCODE_DPAD_DOWN:
-            case KeyEvent.KEYCODE_DPAD_UP:
-            case KeyEvent.KEYCODE_DPAD_LEFT:
-            case KeyEvent.KEYCODE_DPAD_RIGHT:
-                // If tutorial is visible, don't allow dpad to work
-                if (mTutorial != null) {
-                    return true;
-                }
-                // Enable shift key and DPAD to do selections
-                if (mKeyboardSwitcher.isInputViewShown()
-                        && mKeyboardSwitcher.isShiftedOrShiftLocked()) {
-                    event = new KeyEvent(event.getDownTime(), event.getEventTime(),
-                            event.getAction(), event.getKeyCode(), event.getRepeatCount(),
-                            event.getDeviceId(), event.getScanCode(),
-                            KeyEvent.META_SHIFT_LEFT_ON | KeyEvent.META_SHIFT_ON);
-                    InputConnection ic = getCurrentInputConnection();
-                    if (ic != null) ic.sendKeyEvent(event);
-                    return true;
-                }
-                break;
+        case KeyEvent.KEYCODE_DPAD_DOWN:
+        case KeyEvent.KEYCODE_DPAD_UP:
+        case KeyEvent.KEYCODE_DPAD_LEFT:
+        case KeyEvent.KEYCODE_DPAD_RIGHT:
+            // Enable shift key and DPAD to do selections
+            if (mKeyboardSwitcher.isInputViewShown()
+                    && mKeyboardSwitcher.isShiftedOrShiftLocked()) {
+                KeyEvent newEvent = new KeyEvent(event.getDownTime(), event.getEventTime(),
+                        event.getAction(), event.getKeyCode(), event.getRepeatCount(),
+                        event.getDeviceId(), event.getScanCode(),
+                        KeyEvent.META_SHIFT_LEFT_ON | KeyEvent.META_SHIFT_ON);
+                InputConnection ic = getCurrentInputConnection();
+                if (ic != null)
+                    ic.sendKeyEvent(newEvent);
+                return true;
+            }
+            break;
         }
         return super.onKeyUp(keyCode, event);
     }
@@ -951,7 +920,7 @@
     public boolean getCurrentAutoCapsState() {
         InputConnection ic = getCurrentInputConnection();
         EditorInfo ei = getCurrentInputEditorInfo();
-        if (mAutoCap && ic != null && ei != null && ei.inputType != EditorInfo.TYPE_NULL) {
+        if (mAutoCap && ic != null && ei != null && ei.inputType != InputType.TYPE_NULL) {
             return ic.getCursorCapsMode(ei.inputType) != 0;
         }
         return false;
@@ -1120,9 +1089,8 @@
         case Keyboard.CODE_CAPSLOCK:
             switcher.toggleCapsLock();
             break;
-        case Keyboard.CODE_VOICE: /* was a button press, was not a swipe */
-            mVoiceConnector.startListening(false,
-                    mKeyboardSwitcher.getInputView().getWindowToken(), mConfigurationChanging);
+        case Keyboard.CODE_VOICE:
+            mSubtypeSwitcher.switchToShortcutIME();
             break;
         case Keyboard.CODE_TAB:
             handleTab();
@@ -1263,7 +1231,8 @@
             abortCorrection(false);
         }
 
-        if (isAlphabet(primaryCode) && isPredictionOn() && !isCursorTouchingWord()) {
+        int code = primaryCode;
+        if (isAlphabet(code) && isPredictionOn() && !isCursorTouchingWord()) {
             if (!mPredicting) {
                 mPredicting = true;
                 mComposing.setLength(0);
@@ -1277,14 +1246,14 @@
                     || keyCodes[0] > Character.MAX_CODE_POINT) {
                 return;
             }
-            primaryCode = keyCodes[0];
-            if (switcher.isAlphabetMode() && Character.isLowerCase(primaryCode)) {
-                int upperCaseCode = Character.toUpperCase(primaryCode);
-                if (upperCaseCode != primaryCode) {
-                    primaryCode = upperCaseCode;
+            code = keyCodes[0];
+            if (switcher.isAlphabetMode() && Character.isLowerCase(code)) {
+                int upperCaseCode = Character.toUpperCase(code);
+                if (upperCaseCode != code) {
+                    code = upperCaseCode;
                 } else {
                     // Some keys, such as [eszett], have upper case as multi-characters.
-                    String upperCase = new String(new int[] {primaryCode}, 0, 1).toUpperCase();
+                    String upperCase = new String(new int[] {code}, 0, 1).toUpperCase();
                     onText(upperCase);
                     return;
                 }
@@ -1295,8 +1264,8 @@
                     && switcher.isShiftedOrShiftLocked()) {
                 mWord.setFirstCharCapitalized(true);
             }
-            mComposing.append((char) primaryCode);
-            mWord.add(primaryCode, keyCodes);
+            mComposing.append((char) code);
+            mWord.add(code, keyCodes);
             InputConnection ic = getCurrentInputConnection();
             if (ic != null) {
                 // If it's the first letter, make note of auto-caps state
@@ -1307,11 +1276,11 @@
             }
             mHandler.postUpdateSuggestions();
         } else {
-            sendKeyChar((char)primaryCode);
+            sendKeyChar((char)code);
         }
         switcher.updateShiftState();
         if (LatinIME.PERF_DEBUG) measureCps();
-        TextEntryState.typedCharacter((char) primaryCode, isWordSeparator(primaryCode));
+        TextEntryState.typedCharacter((char) code, isWordSeparator(code));
     }
 
     private void handleSeparator(int primaryCode) {
@@ -1503,7 +1472,7 @@
     private void showSuggestions(WordComposer word) {
         // long startTime = System.currentTimeMillis(); // TIME MEASUREMENT!
         // TODO Maybe need better way of retrieving previous word
-        CharSequence prevWord = EditingUtil.getPreviousWord(getCurrentInputConnection(),
+        CharSequence prevWord = EditingUtils.getPreviousWord(getCurrentInputConnection(),
                 mWordSeparators);
         List<CharSequence> stringList = mSuggest.getSuggestions(
                 mKeyboardSwitcher.getInputView(), word, false, prevWord);
@@ -1673,12 +1642,12 @@
      * @param touching The word that the cursor is touching, with position information
      * @return true if an alternative was found, false otherwise.
      */
-    private boolean applyTypedAlternatives(EditingUtil.SelectedWord touching) {
+    private boolean applyTypedAlternatives(EditingUtils.SelectedWord touching) {
         // If we didn't find a match, search for result in typed word history
         WordComposer foundWord = null;
         WordAlternatives alternatives = null;
         for (WordAlternatives entry : mWordHistory) {
-            if (TextUtils.equals(entry.getChosenWord(), touching.word)) {
+            if (TextUtils.equals(entry.getChosenWord(), touching.mWord)) {
                 if (entry instanceof TypedWordAlternatives) {
                     foundWord = ((TypedWordAlternatives) entry).word;
                 }
@@ -1688,20 +1657,20 @@
         }
         // If we didn't find a match, at least suggest completions
         if (foundWord == null
-                && (mSuggest.isValidWord(touching.word)
-                        || mSuggest.isValidWord(touching.word.toString().toLowerCase()))) {
+                && (mSuggest.isValidWord(touching.mWord)
+                        || mSuggest.isValidWord(touching.mWord.toString().toLowerCase()))) {
             foundWord = new WordComposer();
-            for (int i = 0; i < touching.word.length(); i++) {
-                foundWord.add(touching.word.charAt(i), new int[] {
-                    touching.word.charAt(i)
+            for (int i = 0; i < touching.mWord.length(); i++) {
+                foundWord.add(touching.mWord.charAt(i), new int[] {
+                    touching.mWord.charAt(i)
                 });
             }
-            foundWord.setFirstCharCapitalized(Character.isUpperCase(touching.word.charAt(0)));
+            foundWord.setFirstCharCapitalized(Character.isUpperCase(touching.mWord.charAt(0)));
         }
         // Found a match, show suggestions
         if (foundWord != null || alternatives != null) {
             if (alternatives == null) {
-                alternatives = new TypedWordAlternatives(touching.word, foundWord);
+                alternatives = new TypedWordAlternatives(touching.mWord, foundWord);
             }
             showCorrections(alternatives);
             if (foundWord != null) {
@@ -1723,10 +1692,10 @@
         if (ic == null) return;
         if (!mPredicting) {
             // Extract the selected or touching text
-            EditingUtil.SelectedWord touching = EditingUtil.getWordAtCursorOrSelection(ic,
+            EditingUtils.SelectedWord touching = EditingUtils.getWordAtCursorOrSelection(ic,
                     mLastSelectionStart, mLastSelectionEnd, mWordSeparators);
 
-            if (touching != null && touching.word.length() > 1) {
+            if (touching != null && touching.mWord.length() > 1) {
                 ic.beginBatchEdit();
 
                 if (!mVoiceConnector.applyVoiceAlternatives(touching)
@@ -1734,7 +1703,7 @@
                     abortCorrection(true);
                 } else {
                     TextEntryState.selectedForCorrection();
-                    EditingUtil.underlineWord(ic, touching);
+                    EditingUtils.underlineWord(ic, touching);
                 }
 
                 ic.endBatchEdit();
@@ -1774,19 +1743,17 @@
                 || mCorrectionMode == Suggest.CORRECTION_FULL_BIGRAM)) {
             return;
         }
-        if (suggestion != null) {
-            if (!addToBigramDictionary && mAutoDictionary.isValidWord(suggestion)
-                    || (!mSuggest.isValidWord(suggestion.toString())
-                    && !mSuggest.isValidWord(suggestion.toString().toLowerCase()))) {
-                mAutoDictionary.addWord(suggestion.toString(), frequencyDelta);
-            }
+        if (!addToBigramDictionary && mAutoDictionary.isValidWord(suggestion)
+                || (!mSuggest.isValidWord(suggestion.toString())
+                        && !mSuggest.isValidWord(suggestion.toString().toLowerCase()))) {
+            mAutoDictionary.addWord(suggestion.toString(), frequencyDelta);
+        }
 
-            if (mUserBigramDictionary != null) {
-                CharSequence prevWord = EditingUtil.getPreviousWord(getCurrentInputConnection(),
-                        mSentenceSeparators);
-                if (!TextUtils.isEmpty(prevWord)) {
-                    mUserBigramDictionary.addBigrams(prevWord.toString(), suggestion.toString());
-                }
+        if (mUserBigramDictionary != null) {
+            CharSequence prevWord = EditingUtils.getPreviousWord(getCurrentInputConnection(),
+                    mSentenceSeparators);
+            if (!TextUtils.isEmpty(prevWord)) {
+                mUserBigramDictionary.addBigrams(prevWord.toString(), suggestion.toString());
             }
         }
     }
@@ -1897,17 +1864,12 @@
 
     @Override
     public void swipeRight() {
-        if (LatinKeyboardView.DEBUG_AUTO_PLAY) {
-            CharSequence text = ((android.text.ClipboardManager)getSystemService(
-                    CLIPBOARD_SERVICE)).getText();
-            if (!TextUtils.isEmpty(text)) {
-                mKeyboardSwitcher.getInputView().startPlaying(text.toString());
-            }
-        }
+        // Nothing to do
     }
 
     @Override
     public void swipeLeft() {
+        // Nothing to do
     }
 
     @Override
@@ -1917,6 +1879,7 @@
 
     @Override
     public void swipeUp() {
+        // Nothing to do
     }
 
     @Override
@@ -2005,26 +1968,6 @@
         }
     }
 
-    private void checkTutorial(String privateImeOptions) {
-        if (privateImeOptions == null) return;
-        if (privateImeOptions.equals("com.android.setupwizard:ShowTutorial")) {
-            if (mTutorial == null) mHandler.startTutorial();
-        } else if (privateImeOptions.equals("com.android.setupwizard:HideTutorial")) {
-            if (mTutorial != null) {
-                if (mTutorial.close()) {
-                    mTutorial = null;
-                }
-            }
-        }
-    }
-
-    // Tutorial.TutorialListener
-    @Override
-    public void onTutorialDone() {
-        sendDownUpKeyEvents(-1); // Inform the setupwizard that tutorial is in last bubble
-        mTutorial = null;
-    }
-
     public void promoteToUserDictionary(String word, int frequency) {
         if (mUserDictionary.isValidWord(word)) return;
         mUserDictionary.addWord(word, frequency);
diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
index b67dd22..1526050 100644
--- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
+++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
@@ -17,16 +17,21 @@
 package com.android.inputmethod.latin;
 
 import com.android.inputmethod.keyboard.Keyboard;
+import com.android.inputmethod.keyboard.KeyboardSwitcher;
 import com.android.inputmethod.voice.SettingsUtil;
 import com.android.inputmethod.voice.VoiceIMEConnector;
 import com.android.inputmethod.voice.VoiceInput;
 
 import android.content.Context;
 import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.os.IBinder;
 import android.text.TextUtils;
 import android.util.Log;
+import android.view.inputmethod.InputMethodInfo;
 import android.view.inputmethod.InputMethodManager;
 import android.view.inputmethod.InputMethodSubtype;
 
@@ -34,6 +39,7 @@
 import java.util.Arrays;
 import java.util.List;
 import java.util.Locale;
+import java.util.Map;
 
 public class SubtypeSwitcher {
     // This flag indicates if we support language switching by swipe on space bar.
@@ -59,14 +65,16 @@
 
     /*-----------------------------------------------------------*/
     // Variants which should be changed only by reload functions.
+    private boolean mNeedsToDisplayLanguage;
+    private boolean mIsSystemLanguageSameAsInputLanguage;
+    private InputMethodInfo mShortcutInfo;
+    private InputMethodSubtype mShortcutSubtype;
+    private List<InputMethodSubtype> mAllEnabledSubtypesOfCurrentInputMethod;
     private Locale mSystemLocale;
     private Locale mInputLocale;
     private String mInputLocaleStr;
     private String mMode;
-    private List<InputMethodSubtype> mAllEnabledSubtypesOfCurrentInputMethod;
     private VoiceInput mVoiceInput;
-    private boolean mNeedsToDisplayLanguage;
-    private boolean mIsSystemLanguageSameAsInputLanguage;
     /*-----------------------------------------------------------*/
 
     public static SubtypeSwitcher getInstance() {
@@ -84,6 +92,7 @@
     }
 
     private SubtypeSwitcher() {
+        // Intentional empty constructor for singleton.
     }
 
     private void resetParams(LatinIME service) {
@@ -117,6 +126,7 @@
         } else {
             updateEnabledSubtypes();
         }
+        updateShortcutIME();
     }
 
     // Reload enabledSubtypes from the framework.
@@ -149,6 +159,22 @@
         }
     }
 
+    private void updateShortcutIME() {
+        // TODO: Update an icon for shortcut IME
+        Map<InputMethodInfo, List<InputMethodSubtype>> shortcuts =
+                mImm.getShortcutInputMethodsAndSubtypes();
+        for (InputMethodInfo imi: shortcuts.keySet()) {
+            List<InputMethodSubtype> subtypes = shortcuts.get(imi);
+            // TODO: Returns the first found IMI for now. Should handle all shortcuts as
+            // appropriate.
+            mShortcutInfo = imi;
+            // TODO: Pick up the first found subtype for now. Should handle all subtypes
+            // as appropriate.
+            mShortcutSubtype = subtypes.size() > 0 ? subtypes.get(0) : null;
+            break;
+        }
+    }
+
     // Update the current subtype. LatinIME.onCurrentInputMethodSubtypeChanged calls this function.
     public void updateSubtype(InputMethodSubtype newSubtype) {
         final String newLocale;
@@ -197,8 +223,7 @@
             if (languageChanged || modeChanged
                     || VoiceIMEConnector.getInstance().needsToShowWarningDialog()) {
                 if (mVoiceInput != null) {
-                    // TODO: Call proper function to trigger VoiceIME
-                    mService.onKey(Keyboard.CODE_VOICE, null, 0, 0);
+                    triggerVoiceIME();
                 }
             }
         } else {
@@ -233,6 +258,48 @@
                 && mIsSystemLanguageSameAsInputLanguage);
     }
 
+    ////////////////////////////
+    // Shortcut IME functions //
+    ////////////////////////////
+
+    public void switchToShortcutIME() {
+        IBinder token = mService.getWindow().getWindow().getAttributes().token;
+        if (token == null || mShortcutInfo == null) {
+            return;
+        }
+        mImm.setInputMethodAndSubtype(token, mShortcutInfo.getId(), mShortcutSubtype);
+    }
+
+    public Drawable getShortcutIcon() {
+        return getSubtypeIcon(mShortcutInfo, mShortcutSubtype);
+    }
+
+    private Drawable getSubtypeIcon(InputMethodInfo imi, InputMethodSubtype subtype) {
+        final PackageManager pm = mService.getPackageManager();
+        if (imi != null) {
+            final String imiPackageName = imi.getPackageName();
+            if (DBG) {
+                Log.d(TAG, "Update icons of IME: " + imiPackageName + ","
+                        + subtype.getLocale() + "," + subtype.getMode());
+            }
+            if (subtype != null) {
+                return pm.getDrawable(imiPackageName, subtype.getIconResId(),
+                        imi.getServiceInfo().applicationInfo);
+            } else if (imi.getSubtypes().size() > 0 && imi.getSubtypes().get(0) != null) {
+                return pm.getDrawable(imiPackageName,
+                        imi.getSubtypes().get(0).getIconResId(),
+                        imi.getServiceInfo().applicationInfo);
+            } else {
+                try {
+                    return pm.getApplicationInfo(imiPackageName, 0).loadIcon(pm);
+                } catch (PackageManager.NameNotFoundException e) {
+                    Log.w(TAG, "IME can't be found: " + imiPackageName);
+                }
+            }
+        }
+        return null;
+    }
+
     //////////////////////////////////
     // Language Switching functions //
     //////////////////////////////////
@@ -351,7 +418,7 @@
                 if (DBG) {
                     Log.d(TAG, "Set and call voice input.");
                 }
-                mService.onKey(Keyboard.CODE_VOICE, null, 0, 0);
+                triggerVoiceIME();
                 return true;
             }
         }
@@ -362,6 +429,11 @@
         return VOICE_MODE.equals(mMode);
     }
 
+    private void triggerVoiceIME() {
+        VoiceIMEConnector.getInstance().startListening(false,
+                KeyboardSwitcher.getInstance().getInputView().getWindowToken(), false);
+    }
+
     //////////////////////////////////////
     // SpaceBar Language Switch support //
     //////////////////////////////////////
diff --git a/java/src/com/android/inputmethod/latin/TextEntryState.java b/java/src/com/android/inputmethod/latin/TextEntryState.java
index 34babdc..f10b862 100644
--- a/java/src/com/android/inputmethod/latin/TextEntryState.java
+++ b/java/src/com/android/inputmethod/latin/TextEntryState.java
@@ -113,7 +113,7 @@
             sKeyLocationFile = null;
             sUserActionFile = null;
         } catch (IOException ioe) {
-            
+            // ignore
         }
     }
     
@@ -135,16 +135,18 @@
     public static void backToAcceptedDefault(CharSequence typedWord) {
         if (typedWord == null) return;
         switch (sState) {
-            case SPACE_AFTER_ACCEPTED:
-            case PUNCTUATION_AFTER_ACCEPTED:
-            case IN_WORD:
-                sState = State.ACCEPTED_DEFAULT;
-                break;
+        case SPACE_AFTER_ACCEPTED:
+        case PUNCTUATION_AFTER_ACCEPTED:
+        case IN_WORD:
+            sState = State.ACCEPTED_DEFAULT;
+            break;
+        default:
+            break;
         }
         displayState();
     }
 
-    public static void acceptedTyped(CharSequence typedWord) {
+    public static void acceptedTyped(@SuppressWarnings("unused") CharSequence typedWord) {
         sWordNotInDictionaryCount++;
         sState = State.PICKED_SUGGESTION;
         displayState();
diff --git a/java/src/com/android/inputmethod/latin/Tutorial.java b/java/src/com/android/inputmethod/latin/Tutorial.java
deleted file mode 100644
index 20767de..0000000
--- a/java/src/com/android/inputmethod/latin/Tutorial.java
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * Copyright (C) 2008 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.latin;
-
-import com.android.inputmethod.keyboard.KeyboardSwitcher;
-import com.android.inputmethod.keyboard.LatinKeyboardView;
-
-import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.os.Handler;
-import android.os.Message;
-import android.text.Layout;
-import android.text.SpannableStringBuilder;
-import android.text.StaticLayout;
-import android.view.Gravity;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.View.OnTouchListener;
-import android.widget.PopupWindow;
-import android.widget.TextView;
-
-import java.util.ArrayList;
-
-public class Tutorial implements OnTouchListener {
-
-    public interface TutorialListener {
-        public void onTutorialDone();
-    }
-
-    private final ArrayList<Bubble> mBubbles = new ArrayList<Bubble>();
-    private final KeyboardSwitcher mKeyboardSwitcher;
-    private final View mInputView;
-    private final TutorialListener mListener;
-    private final int[] mLocation = new int[2];
-
-    private static final int MSG_SHOW_BUBBLE = 0;
-
-    private int mBubbleIndex;
-
-    private final Handler mHandler = new Handler() {
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_SHOW_BUBBLE:
-                    Bubble bubba = (Bubble) msg.obj;
-                    bubba.show(mLocation[0], mLocation[1]);
-                    break;
-            }
-        }
-    };
-
-    private class Bubble {
-        private final Drawable bubbleBackground;
-        private final int x;
-        private final int y;
-        private final int width;
-        private final int gravity;
-        private final CharSequence text;
-        private final PopupWindow window;
-        private final TextView textView;
-        private final View inputView;
-
-        private Bubble(Context context, View inputView,
-                int backgroundResource, int bx, int by, int textResource1, int textResource2) {
-            bubbleBackground = context.getResources().getDrawable(backgroundResource);
-            x = bx;
-            y = by;
-            width = (int) (inputView.getWidth() * 0.9);
-            this.gravity = Gravity.TOP | Gravity.LEFT;
-            text = new SpannableStringBuilder()
-                .append(context.getResources().getText(textResource1))
-                .append("\n") 
-                .append(context.getResources().getText(textResource2));
-            this.inputView = inputView;
-            window = new PopupWindow(context);
-            window.setBackgroundDrawable(null);
-            LayoutInflater inflate =
-                (LayoutInflater) context
-                        .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-            textView = (TextView) inflate.inflate(R.layout.bubble_text, null);
-            textView.setBackgroundDrawable(bubbleBackground);
-            textView.setText(text);
-            //textView.setText(textResource1);
-            window.setContentView(textView);
-            window.setFocusable(false);
-            window.setTouchable(true);
-            window.setOutsideTouchable(false);
-        }
-
-        private int chooseSize(PopupWindow pop, View parentView, CharSequence text, TextView tv) {
-            int wid = tv.getPaddingLeft() + tv.getPaddingRight();
-            int ht = tv.getPaddingTop() + tv.getPaddingBottom();
-
-            /*
-             * Figure out how big the text would be if we laid it out to the
-             * full width of this view minus the border.
-             */
-            int cap = width - wid;
-
-            Layout l = new StaticLayout(text, tv.getPaint(), cap,
-                                        Layout.Alignment.ALIGN_NORMAL, 1, 0, true);
-            float max = 0;
-            for (int i = 0; i < l.getLineCount(); i++) {
-                max = Math.max(max, l.getLineWidth(i));
-            }
-
-            /*
-             * Now set the popup size to be big enough for the text plus the border.
-             */
-            pop.setWidth(width);
-            pop.setHeight(ht + l.getHeight());
-            return l.getHeight();
-        }
-
-        private void show(int offx, int offy) {
-            int textHeight = chooseSize(window, inputView, text, textView);
-            offy -= textView.getPaddingTop() + textHeight;
-            if (inputView.getVisibility() == View.VISIBLE 
-                    && inputView.getWindowVisibility() == View.VISIBLE) {
-                try {
-                    if ((gravity & Gravity.BOTTOM) == Gravity.BOTTOM) offy -= window.getHeight();
-                    if ((gravity & Gravity.RIGHT) == Gravity.RIGHT) offx -= window.getWidth();
-                    textView.setOnTouchListener(new View.OnTouchListener() {
-                        @Override
-                        public boolean onTouch(View view, MotionEvent me) {
-                            Tutorial.this.next();
-                            return true;
-                        }
-                    });
-                    window.showAtLocation(inputView, Gravity.NO_GRAVITY, x + offx, y + offy);
-                } catch (Exception e) {
-                    // Input view is not valid
-                }
-            }
-        }
-
-        private void hide() {
-            if (window.isShowing()) {
-                textView.setOnTouchListener(null);
-                window.dismiss();
-            }
-        }
-
-        private boolean isShowing() {
-            return window.isShowing();
-        }
-    }
-
-    public Tutorial(TutorialListener listener, KeyboardSwitcher keyboardSwitcher) {
-        mListener = listener;
-        mKeyboardSwitcher = keyboardSwitcher;
-        LatinKeyboardView inputView = keyboardSwitcher.getInputView();
-        mInputView = inputView;
-        Context context = inputView.getContext();
-        int inputWidth = inputView.getWidth();
-        final int x = inputWidth / 20; // Half of 1/10th
-        ArrayList<Bubble> bubbles = mBubbles;
-        Bubble bWelcome = new Bubble(context, inputView, 
-                R.drawable.dialog_bubble_step02, x, 0, 
-                R.string.tip_to_open_keyboard, R.string.touch_to_continue);
-        bubbles.add(bWelcome);
-        Bubble bAccents = new Bubble(context, inputView, 
-                R.drawable.dialog_bubble_step02, x, 0, 
-                R.string.tip_to_view_accents, R.string.touch_to_continue);
-        bubbles.add(bAccents);
-        Bubble b123 = new Bubble(context, inputView, 
-                R.drawable.dialog_bubble_step07, x, 0, 
-                R.string.tip_to_open_symbols, R.string.touch_to_continue);
-        bubbles.add(b123);
-        Bubble bABC = new Bubble(context, inputView, 
-                R.drawable.dialog_bubble_step07, x, 0, 
-                R.string.tip_to_close_symbols, R.string.touch_to_continue);
-        bubbles.add(bABC);
-        Bubble bSettings = new Bubble(context, inputView, 
-                R.drawable.dialog_bubble_step07, x, 0, 
-                R.string.tip_to_launch_settings, R.string.touch_to_continue);
-        bubbles.add(bSettings);
-        Bubble bDone = new Bubble(context, inputView, 
-                R.drawable.dialog_bubble_step02, x, 0, 
-                R.string.tip_to_start_typing, R.string.touch_to_finish);
-        bubbles.add(bDone);
-    }
-
-    public void start() {
-        mInputView.getLocationInWindow(mLocation);
-        mBubbleIndex = -1;
-        mInputView.setOnTouchListener(this);
-        next();
-    }
-
-    private void next() {
-        if (mBubbleIndex >= 0) {
-            // If the bubble is not yet showing, don't move to the next.
-            if (!mBubbles.get(mBubbleIndex).isShowing()) {
-                return;
-            }
-            // Hide all previous bubbles as well, as they may have had a delayed show
-            for (int i = 0; i <= mBubbleIndex; i++) {
-                mBubbles.get(i).hide();
-            }
-        }
-        mBubbleIndex++;
-        if (mBubbleIndex >= mBubbles.size()) {
-            mInputView.setOnTouchListener(null);
-            mListener.onTutorialDone();
-            return;
-        }
-        if (mBubbleIndex == 3 || mBubbleIndex == 4) {
-            mKeyboardSwitcher.changeKeyboardMode();
-        }
-        mHandler.sendMessageDelayed(
-                mHandler.obtainMessage(MSG_SHOW_BUBBLE, mBubbles.get(mBubbleIndex)), 500);
-        return;
-    }
-
-    private void hide() {
-        for (Bubble bubble : mBubbles) {
-            bubble.hide();
-        }
-        mInputView.setOnTouchListener(null);
-    }
-
-    public boolean close() {
-        mHandler.removeMessages(MSG_SHOW_BUBBLE);
-        hide();
-        return true;
-    }
-
-    @Override
-    public boolean onTouch(View v, MotionEvent event) {
-        if (event.getAction() == MotionEvent.ACTION_DOWN) {
-            next();
-        }
-        return true;
-    }
-}
diff --git a/java/src/com/android/inputmethod/latin/UserBigramDictionary.java b/java/src/com/android/inputmethod/latin/UserBigramDictionary.java
index 6d2f6b6..4750fb9 100644
--- a/java/src/com/android/inputmethod/latin/UserBigramDictionary.java
+++ b/java/src/com/android/inputmethod/latin/UserBigramDictionary.java
@@ -108,25 +108,25 @@
     private static DatabaseHelper sOpenHelper = null;
 
     private static class Bigram {
-        String word1;
-        String word2;
-        int frequency;
+        public final String mWord1;
+        public final String mWord2;
+        public final int frequency;
 
         Bigram(String word1, String word2, int frequency) {
-            this.word1 = word1;
-            this.word2 = word2;
+            this.mWord1 = word1;
+            this.mWord2 = word2;
             this.frequency = frequency;
         }
 
         @Override
         public boolean equals(Object bigram) {
             Bigram bigram2 = (Bigram) bigram;
-            return (word1.equals(bigram2.word1) && word2.equals(bigram2.word2));
+            return (mWord1.equals(bigram2.mWord1) && mWord2.equals(bigram2.mWord2));
         }
 
         @Override
         public int hashCode() {
-            return (word1 + " " + word2).hashCode();
+            return (mWord1 + " " + mWord2).hashCode();
         }
     }
 
@@ -357,7 +357,7 @@
                 Cursor c = db.query(MAIN_TABLE_NAME, new String[] { MAIN_COLUMN_ID },
                         MAIN_COLUMN_WORD1 + "=? AND " + MAIN_COLUMN_WORD2 + "=? AND "
                         + MAIN_COLUMN_LOCALE + "=?",
-                        new String[] { bi.word1, bi.word2, mLocale }, null, null, null);
+                        new String[] { bi.mWord1, bi.mWord2, mLocale }, null, null, null);
 
                 int pairId;
                 if (c.moveToFirst()) {
@@ -368,7 +368,7 @@
                 } else {
                     // new pair
                     Long pairIdLong = db.insert(MAIN_TABLE_NAME, null,
-                            getContentValues(bi.word1, bi.word2, mLocale));
+                            getContentValues(bi.mWord1, bi.mWord2, mLocale));
                     pairId = pairIdLong.intValue();
                 }
                 c.close();
diff --git a/java/src/com/android/inputmethod/latin/UserDictionary.java b/java/src/com/android/inputmethod/latin/UserDictionary.java
index a522303..7a94ae4 100644
--- a/java/src/com/android/inputmethod/latin/UserDictionary.java
+++ b/java/src/com/android/inputmethod/latin/UserDictionary.java
@@ -66,7 +66,7 @@
     @Override
     public void loadDictionaryAsync() {
         Cursor cursor = getContext().getContentResolver()
-                .query(Words.CONTENT_URI, PROJECTION, "(locale IS NULL) or (locale=?)", 
+                .query(Words.CONTENT_URI, PROJECTION, "(locale IS NULL) or (locale=?)",
                         new String[] { mLocale }, null);
         addWords(cursor);
     }
diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java
index 0a73dde..5c69809 100644
--- a/java/src/com/android/inputmethod/latin/Utils.java
+++ b/java/src/com/android/inputmethod/latin/Utils.java
@@ -110,6 +110,7 @@
         private int[] mYBuf = new int[BUFSIZE];
 
         private RingCharBuffer() {
+            // Intentional empty constructor for singleton.
         }
         public static RingCharBuffer getInstance() {
             return sRingCharBuffer;
@@ -349,6 +350,7 @@
                         try {
                             br.close();
                         } catch (IOException e) {
+                            // ignore.
                         }
                     }
                 }
diff --git a/java/src/com/android/inputmethod/voice/VoiceIMEConnector.java b/java/src/com/android/inputmethod/voice/VoiceIMEConnector.java
index 7ad6c35..2052d93 100644
--- a/java/src/com/android/inputmethod/voice/VoiceIMEConnector.java
+++ b/java/src/com/android/inputmethod/voice/VoiceIMEConnector.java
@@ -16,8 +16,7 @@
 
 package com.android.inputmethod.voice;
 
-import com.android.inputmethod.keyboard.KeyboardSwitcher;
-import com.android.inputmethod.latin.EditingUtil;
+import com.android.inputmethod.latin.EditingUtils;
 import com.android.inputmethod.latin.LatinIME;
 import com.android.inputmethod.latin.LatinIME.UIHandler;
 import com.android.inputmethod.latin.R;
@@ -133,6 +132,7 @@
     }
 
     private VoiceIMEConnector() {
+        // Intentional empty constructor for singleton.
     }
 
     public void resetVoiceStates(boolean isPasswordText) {
@@ -228,7 +228,8 @@
     }
 
     private static class CustomLinkMovementMethod extends LinkMovementMethod {
-        private static CustomLinkMovementMethod sInstance = new CustomLinkMovementMethod();
+        private static CustomLinkMovementMethod sLinkMovementMethodInstance =
+                new CustomLinkMovementMethod();
         private AlertDialog mAlertDialog;
 
         public void setVoiceWarningDialog(AlertDialog alertDialog) {
@@ -236,7 +237,7 @@
         }
 
         public static CustomLinkMovementMethod getInstance() {
-            return sInstance;
+            return sLinkMovementMethodInstance;
         }
 
         // Almost the same as LinkMovementMethod.onTouchEvent(), but overrides it for
@@ -391,9 +392,8 @@
     public void rememberReplacedWord(CharSequence suggestion,String wordSeparators) {
         if (mShowingVoiceSuggestions) {
             // Retain the replaced word in the alternatives array.
-            EditingUtil.Range range = new EditingUtil.Range();
-            String wordToBeReplaced = EditingUtil.getWordAtCursor(
-                    mContext.getCurrentInputConnection(), wordSeparators, range);
+            String wordToBeReplaced = EditingUtils.getWordAtCursor(
+                    mContext.getCurrentInputConnection(), wordSeparators);
             if (!mWordToSuggestions.containsKey(wordToBeReplaced)) {
                 wordToBeReplaced = wordToBeReplaced.toLowerCase();
             }
@@ -415,9 +415,9 @@
      * @param touching The word that the cursor is touching, with position information
      * @return true if an alternative was found, false otherwise.
      */
-    public boolean applyVoiceAlternatives(EditingUtil.SelectedWord touching) {
+    public boolean applyVoiceAlternatives(EditingUtils.SelectedWord touching) {
         // Search for result in spoken word alternatives
-        String selectedWord = touching.word.toString().trim();
+        String selectedWord = touching.mWord.toString().trim();
         if (!mWordToSuggestions.containsKey(selectedWord)) {
             selectedWord = selectedWord.toLowerCase();
         }
@@ -426,7 +426,7 @@
             List<CharSequence> suggestions = mWordToSuggestions.get(selectedWord);
             // If the first letter of touching is capitalized, make all the suggestions
             // start with a capital letter.
-            if (Character.isUpperCase(touching.word.charAt(0))) {
+            if (Character.isUpperCase(touching.mWord.charAt(0))) {
                 for (int i = 0; i < suggestions.size(); i++) {
                     String origSugg = (String) suggestions.get(i);
                     String capsSugg = origSugg.toUpperCase().charAt(0)
@@ -478,7 +478,7 @@
     }
 
 
-    public void handleVoiceResults(KeyboardSwitcher switcher, boolean capitalizeFirstWord) {
+    public void handleVoiceResults(boolean capitalizeFirstWord) {
         mAfterVoiceInput = true;
         mImmediatelyAfterVoiceInput = true;
 
@@ -508,7 +508,7 @@
 
         if (ic != null) ic.beginBatchEdit(); // To avoid extra updates on committing older text
         mContext.commitTyped(ic);
-        EditingUtil.appendText(ic, bestResult);
+        EditingUtils.appendText(ic, bestResult);
         if (ic != null) ic.endBatchEdit();
 
         mVoiceInputHighlighted = true;
diff --git a/java/src/com/android/inputmethod/voice/VoiceInput.java b/java/src/com/android/inputmethod/voice/VoiceInput.java
index d51d869..f77b4dd 100644
--- a/java/src/com/android/inputmethod/voice/VoiceInput.java
+++ b/java/src/com/android/inputmethod/voice/VoiceInput.java
@@ -16,7 +16,7 @@
 
 package com.android.inputmethod.voice;
 
-import com.android.inputmethod.latin.EditingUtil;
+import com.android.inputmethod.latin.EditingUtils;
 import com.android.inputmethod.latin.R;
 
 import android.content.ContentResolver;
@@ -241,7 +241,7 @@
     }
 
     public void incrementTextModificationInsertPunctuationCount(int count){
-        mAfterVoiceInputInsertPunctuationCount += 1;
+        mAfterVoiceInputInsertPunctuationCount += count;
         if (mAfterVoiceInputSelectionSpan > 0) {
             // If text was highlighted before inserting the char, count this as
             // a delete.
@@ -429,8 +429,7 @@
 
     public void logTextModifiedByChooseSuggestion(String suggestion, int index,
                                                   String wordSeparators, InputConnection ic) {
-        EditingUtil.Range range = new EditingUtil.Range();
-        String wordToBeReplaced = EditingUtil.getWordAtCursor(ic, wordSeparators, range);
+        String wordToBeReplaced = EditingUtils.getWordAtCursor(ic, wordSeparators);
         // If we enable phrase-based alternatives, only send up the first word
         // in suggestion and wordToBeReplaced.
         mLogger.textModifiedByChooseSuggestion(suggestion.length(), wordToBeReplaced.length(),
@@ -578,7 +577,9 @@
         public void onBufferReceived(byte[] buf) {
             try {
                 mWaveBuffer.write(buf);
-            } catch (IOException e) {}
+            } catch (IOException e) {
+                // ignore.
+            }
         }
 
         @Override
diff --git a/java/src/com/android/inputmethod/voice/WaveformImage.java b/java/src/com/android/inputmethod/voice/WaveformImage.java
index 08d87c8..8bac669 100644
--- a/java/src/com/android/inputmethod/voice/WaveformImage.java
+++ b/java/src/com/android/inputmethod/voice/WaveformImage.java
@@ -33,7 +33,9 @@
 public class WaveformImage {
     private static final int SAMPLING_RATE = 8000;
 
-    private WaveformImage() {}
+    private WaveformImage() {
+        // Intentional empty constructor.
+    }
 
     public static Bitmap drawWaveform(
         ByteArrayOutputStream waveBuffer, int w, int h, int start, int end) {
diff --git a/native/src/defines.h b/native/src/defines.h
index 98e93b9..52191be 100644
--- a/native/src/defines.h
+++ b/native/src/defines.h
@@ -24,13 +24,17 @@
 #define LOG_TAG "LatinIME: "
 #endif
 #define DEBUG_DICT true
-#define DEBUG_SHOW_FOUND_WORD false
-#define DEBUG_NODE true
+#define DEBUG_DICT_FULL true
+#define DEBUG_SHOW_FOUND_WORD DEBUG_DICT_FULL
+#define DEBUG_NODE DEBUG_DICT_FULL
+#define DEBUG_TRACE DEBUG_DICT_FULL
 #else // FLAG_DBG
 #define LOGI
 #define DEBUG_DICT false
+#define DEBUG_DICT_FULL false
 #define DEBUG_SHOW_FOUND_WORD false
 #define DEBUG_NODE false
+#define DEBUG_TRACE false
 #endif // FLAG_DBG
 
 #ifndef U_SHORT_MAX
@@ -58,6 +62,12 @@
 #define SUGGEST_WORDS_WITH_MISSING_CHARACTER true
 #define SUGGEST_WORDS_WITH_MISSING_SPACE_CHARACTER true
 #define SUGGEST_WORDS_WITH_EXCESSIVE_CHARACTER true
+#define SUGGEST_WORDS_WITH_TRANSPOSED_CHARACTERS true
+
+#define WORDS_WITH_MISSING_CHARACTER_DEMOTION_RATE 75
+#define WORDS_WITH_MISSING_SPACE_CHARACTER_DEMOTION_RATE 80
+#define WORDS_WITH_EXCESSIVE_CHARACTER_DEMOTION_RATE 75
+#define WORDS_WITH_TRANSPOSED_CHARACTERS_DEMOTION_RATE 60
 
 // This should be greater than or equal to MAX_WORD_LENGTH defined in BinaryDictionary.java
 // This is only used for the size of array. Not to be used in c functions.
diff --git a/native/src/unigram_dictionary.cpp b/native/src/unigram_dictionary.cpp
index 46332c7..7ecf1c9 100644
--- a/native/src/unigram_dictionary.cpp
+++ b/native/src/unigram_dictionary.cpp
@@ -36,7 +36,7 @@
     MAX_PROXIMITY_CHARS(maxProximityChars), IS_LATEST_DICT_VERSION(isLatestDictVersion),
     TYPED_LETTER_MULTIPLIER(typedLetterMultiplier), FULL_WORD_MULTIPLIER(fullWordMultiplier),
     ROOT_POS(isLatestDictVersion ? DICTIONARY_HEADER_SIZE : 0) {
-    LOGI("UnigramDictionary - constructor");
+    if (DEBUG_DICT) LOGI("UnigramDictionary - constructor");
 }
 
 UnigramDictionary::~UnigramDictionary() {}
@@ -45,26 +45,36 @@
         int *frequencies, int *nextLetters, int nextLettersSize)
 {
     initSuggestions(codes, codesSize, outWords, frequencies);
-    getSuggestionCandidates(codesSize, -1, -1, nextLetters, nextLettersSize);
+    const int MAX_DEPTH = min(mInputLength * MAX_DEPTH_MULTIPLIER, MAX_WORD_LENGTH);
+    getSuggestionCandidates(codesSize, -1, -1, -1, nextLetters, nextLettersSize, MAX_DEPTH);
 
     // Suggestion with missing character
     if (SUGGEST_WORDS_WITH_MISSING_CHARACTER) {
         for (int i = 0; i < codesSize; ++i) {
             if (DEBUG_DICT) LOGI("--- Suggest missing characters %d", i);
-            getSuggestionCandidates(codesSize, i, -1, NULL, 0);
+            getSuggestionCandidates(codesSize, i, -1, -1, NULL, 0, MAX_DEPTH);
         }
     }
 
     // Suggestion with excessive character
-    if (SUGGEST_WORDS_WITH_EXCESSIVE_CHARACTER) {
+    if (SUGGEST_WORDS_WITH_EXCESSIVE_CHARACTER && mInputLength > MIN_SUGGEST_DEPTH) {
         for (int i = 0; i < codesSize; ++i) {
             if (existsAdjacentProximityChars(i, codesSize)) {
                 if (DEBUG_DICT) LOGI("--- Suggest excessive characters %d", i);
-                getSuggestionCandidates(codesSize, -1, i, NULL, 0);
+                getSuggestionCandidates(codesSize, -1, i, -1, NULL, 0, MAX_DEPTH);
             }
         }
     }
 
+    // Suggestion with transposed characters
+    // Only suggest words that length is mInputLength
+    if (SUGGEST_WORDS_WITH_TRANSPOSED_CHARACTERS) {
+        for (int i = 0; i < codesSize; ++i) {
+            if (DEBUG_DICT) LOGI("--- Suggest transposed characters %d", i);
+            getSuggestionCandidates(codesSize, -1, -1, i, NULL, 0, mInputLength - 1);
+        }
+    }
+
     // Suggestions with missing space
     if (SUGGEST_WORDS_WITH_MISSING_SPACE_CHARACTER && mInputLength > MIN_SUGGEST_DEPTH) {
         for (int i = 1; i < codesSize; ++i) {
@@ -187,10 +197,13 @@
 static const char SPACE = ' ';
 
 void UnigramDictionary::getSuggestionCandidates(const int inputLength, const int skipPos,
-        const int excessivePos, int *nextLetters, const int nextLettersSize) {
-    if (DEBUG_DICT) LOGI("getSuggestionCandidates");
+        const int excessivePos, const int transposedPos, int *nextLetters,
+        const int nextLettersSize, const int maxDepth) {
+    if (DEBUG_DICT) LOGI("getSuggestionCandidates %d", maxDepth);
+    if (DEBUG_DICT) assert(transposedPos + 1 < inputLength);
+    if (DEBUG_DICT) assert(excessivePos < inputLength);
+    if (DEBUG_DICT) assert(missingPos < inputLength);
     int rootPosition = ROOT_POS;
-    const int MAX_DEPTH = min(inputLength * MAX_DEPTH_MULTIPLIER, MAX_WORD_LENGTH);
     // Get the number of child of root, then increment the position
     int childCount = Dictionary::getCount(DICT, &rootPosition);
     int depth = 0;
@@ -212,12 +225,12 @@
             int diffs = mStackDiffs[depth];
             int siblingPos = mStackSiblingPos[depth];
             int firstChildPos;
-            // depth will never be greater than MAX_DEPTH because in that case,
+            // depth will never be greater than maxDepth because in that case,
             // needsToTraverseChildrenNodes should be false
             const bool needsToTraverseChildrenNodes = processCurrentNode(siblingPos, depth,
-                    MAX_DEPTH, traverseAllNodes, snr, inputIndex, diffs, skipPos, excessivePos,
-                    nextLetters, nextLettersSize, &childCount, &firstChildPos, &traverseAllNodes,
-                    &snr, &inputIndex, &diffs, &siblingPos);
+                    maxDepth, traverseAllNodes, snr, inputIndex, diffs, skipPos, excessivePos,
+                    transposedPos, nextLetters, nextLettersSize, &childCount, &firstChildPos,
+                    &traverseAllNodes, &snr, &inputIndex, &diffs, &siblingPos);
             // Update next sibling pos
             mStackSiblingPos[depth] = siblingPos;
             if (needsToTraverseChildrenNodes) {
@@ -252,7 +265,7 @@
     }
 
     const int secondFreq = getBestWordFreq(missingSpacePos, inputLength - missingSpacePos, mWord);
-    if (DEBUG_DICT) LOGI("Second freq:  %d", secondFreq);
+    if (DEBUG_DICT) LOGI("Second  freq:  %d", secondFreq);
     if (secondFreq <= 0) return false;
 
     word[missingSpacePos] = SPACE;
@@ -262,24 +275,27 @@
 
     int pairFreq = ((firstFreq + secondFreq) / 2);
     for (int i = 0; i < inputLength; ++i) pairFreq *= TYPED_LETTER_MULTIPLIER;
+    pairFreq = pairFreq * WORDS_WITH_MISSING_SPACE_CHARACTER_DEMOTION_RATE / 100;
     addWord(word, newWordLength, pairFreq);
     return true;
 }
 
 // Keep this for comparing spec to new getWords
 void UnigramDictionary::getWordsOld(const int initialPos, const int inputLength, const int skipPos,
-        const int excessivePos, int *nextLetters, const int nextLettersSize) {
+        const int excessivePos, const int transposedPos,int *nextLetters,
+        const int nextLettersSize) {
     int initialPosition = initialPos;
     const int count = Dictionary::getCount(DICT, &initialPosition);
     getWordsRec(count, initialPosition, 0,
             min(inputLength * MAX_DEPTH_MULTIPLIER, MAX_WORD_LENGTH),
-            mInputLength <= 0, 1, 0, 0, skipPos, excessivePos, nextLetters, nextLettersSize);
+            mInputLength <= 0, 1, 0, 0, skipPos, excessivePos, transposedPos, nextLetters,
+            nextLettersSize);
 }
 
 void UnigramDictionary::getWordsRec(const int childrenCount, const int pos, const int depth,
         const int maxDepth, const bool traverseAllNodes, const int snr, const int inputIndex,
-        const int diffs, const int skipPos, const int excessivePos, int *nextLetters,
-        const int nextLettersSize) {
+        const int diffs, const int skipPos, const int excessivePos, const int transposedPos,
+        int *nextLetters, const int nextLettersSize) {
     int siblingPos = pos;
     for (int i = 0; i < childrenCount; ++i) {
         int newCount;
@@ -291,34 +307,50 @@
         int newDiffs;
         int newSiblingPos;
         const bool needsToTraverseChildrenNodes = processCurrentNode(siblingPos, depth, maxDepth,
-                traverseAllNodes, snr, inputIndex, diffs, skipPos, excessivePos, nextLetters,
-                nextLettersSize,
+                traverseAllNodes, snr, inputIndex, diffs, skipPos, excessivePos, transposedPos,
+                nextLetters, nextLettersSize,
                 &newCount, &newChildPosition, &newTraverseAllNodes, &newSnr,
                 &newInputIndex, &newDiffs, &newSiblingPos);
         siblingPos = newSiblingPos;
 
         if (needsToTraverseChildrenNodes) {
             getWordsRec(newCount, newChildPosition, newDepth, maxDepth, newTraverseAllNodes,
-                    newSnr, newInputIndex, newDiffs, skipPos, excessivePos, nextLetters,
-                    nextLettersSize);
+                    newSnr, newInputIndex, newDiffs, skipPos, excessivePos, transposedPos,
+                    nextLetters, nextLettersSize);
         }
     }
 }
 
 inline void UnigramDictionary::onTerminalWhenUserTypedLengthIsGreaterThanInputLength(
         unsigned short *word, const int inputLength, const int depth, const int snr,
-        int *nextLetters, const int nextLettersSize, const int skipPos, const int freq) {
-    if (depth >= MIN_SUGGEST_DEPTH) addWord(word, depth + 1, freq * snr);
+        int *nextLetters, const int nextLettersSize, const int skipPos, const int excessivePos,
+        const int transposedPos, const int freq) {
+    int finalFreq = freq * snr;
+    // TODO: Demote by edit distance
+    if (skipPos >= 0) finalFreq = finalFreq * WORDS_WITH_MISSING_CHARACTER_DEMOTION_RATE / 100;
+    if (excessivePos >= 0) finalFreq = finalFreq
+            * WORDS_WITH_EXCESSIVE_CHARACTER_DEMOTION_RATE / 100;
+    if (transposedPos >= 0) finalFreq = finalFreq
+            * WORDS_WITH_TRANSPOSED_CHARACTERS_DEMOTION_RATE / 100;
+
+    if (depth >= MIN_SUGGEST_DEPTH) addWord(word, depth + 1, finalFreq);
     if (depth >= inputLength && skipPos < 0) {
         registerNextLetter(mWord[mInputLength], nextLetters, nextLettersSize);
     }
 }
 
 inline void UnigramDictionary::onTerminalWhenUserTypedLengthIsSameAsInputLength(
-        unsigned short *word, const int depth, const int snr, const int skipPos, const int freq,
-        const int addedWeight) {
+        unsigned short *word, const int depth, const int snr, const int skipPos,
+        const int excessivePos, const int transposedPos, const int freq, const int addedWeight) {
     if (!sameAsTyped(word, depth + 1)) {
         int finalFreq = freq * snr * addedWeight;
+        // TODO: Demote by edit distance
+        if (skipPos >= 0) finalFreq = finalFreq * WORDS_WITH_MISSING_CHARACTER_DEMOTION_RATE / 100;
+        if (excessivePos >= 0) finalFreq = finalFreq
+                * WORDS_WITH_EXCESSIVE_CHARACTER_DEMOTION_RATE / 100;
+        if (transposedPos >= 0) finalFreq = finalFreq
+                * WORDS_WITH_TRANSPOSED_CHARACTERS_DEMOTION_RATE / 100;
+
         // Proximity collection will promote a word of the same length as
         // what user typed.
         if (skipPos < 0) finalFreq *= FULL_WORD_MULTIPLIER;
@@ -357,16 +389,18 @@
 }
 
 inline int UnigramDictionary::getMatchedProximityId(const int *currentChars,
-        const unsigned short c, const int skipPos) {
+        const unsigned short c, const int skipPos, const int excessivePos,
+        const int transposedPos) {
     const unsigned short lowerC = toLowerCase(c);
     int j = 0;
     while (currentChars[j] > 0 && j < MAX_PROXIMITY_CHARS) {
         const bool matched = (currentChars[j] == lowerC || currentChars[j] == c);
         // If skipPos is defined, not to search proximity collections.
-        // First char is what user typed.
+        // First char is what user  typed.
         if (matched) {
             return j;
-        } else if (skipPos >= 0) {
+        } else if (skipPos >= 0 || excessivePos >= 0 || transposedPos >= 0) {
+            // Not to check proximity characters
             return -1;
         }
         ++j;
@@ -376,10 +410,17 @@
 
 inline bool UnigramDictionary::processCurrentNode(const int pos, const int depth,
         const int maxDepth, const bool traverseAllNodes, const int snr, int inputIndex,
-        const int diffs, const int skipPos, const int excessivePos, int *nextLetters,
-        const int nextLettersSize, int *newCount, int *newChildPosition, bool *newTraverseAllNodes,
-        int *newSnr, int*newInputIndex, int *newDiffs, int *nextSiblingPosition) {
-    if (DEBUG_DICT) assert(skipPos < 0 || excessivePos < 0);
+        const int diffs, const int skipPos, const int excessivePos, const int transposedPos,
+        int *nextLetters, const int nextLettersSize, int *newCount, int *newChildPosition,
+        bool *newTraverseAllNodes, int *newSnr, int*newInputIndex, int *newDiffs,
+        int *nextSiblingPosition) {
+    if (DEBUG_DICT) {
+        int inputCount = 0;
+        if (skipPos >= 0) ++inputCount;
+        if (excessivePos >= 0) ++inputCount;
+        if (transposedPos >= 0) ++inputCount;
+        assert(inputCount <= 1);
+    }
     unsigned short c;
     int childPosition;
     bool terminal;
@@ -397,7 +438,7 @@
         mWord[depth] = c;
         if (traverseAllNodes && terminal) {
             onTerminalWhenUserTypedLengthIsGreaterThanInputLength(mWord, mInputLength, depth,
-                    snr, nextLetters, nextLettersSize, skipPos, freq);
+                    snr, nextLetters, nextLettersSize, skipPos, excessivePos, transposedPos, freq);
         }
         if (!needsToTraverseChildrenNodes) return false;
         *newTraverseAllNodes = traverseAllNodes;
@@ -406,7 +447,14 @@
         *newInputIndex = inputIndex;
     } else {
         int *currentChars = mInputCodes + (inputIndex * MAX_PROXIMITY_CHARS);
-        int matchedProximityCharId = getMatchedProximityId(currentChars, c, skipPos);
+
+        if (transposedPos >= 0) {
+            if (inputIndex == transposedPos) currentChars += MAX_PROXIMITY_CHARS;
+            if (inputIndex == (transposedPos + 1)) currentChars -= MAX_PROXIMITY_CHARS;
+        }
+
+        int matchedProximityCharId = getMatchedProximityId(currentChars, c, skipPos, excessivePos,
+                transposedPos);
         if (matchedProximityCharId < 0) return false;
         mWord[depth] = c;
         // If inputIndex is greater than mInputLength, that means there is no
@@ -415,13 +463,13 @@
         const bool isSameAsUserTypedLength = mInputLength == inputIndex + 1;
         if (isSameAsUserTypedLength && terminal) {
             onTerminalWhenUserTypedLengthIsSameAsInputLength(mWord, depth, snr,
-                    skipPos, freq, addedWeight);
+                    skipPos, excessivePos, transposedPos, freq, addedWeight);
         }
         if (!needsToTraverseChildrenNodes) return false;
         // Start traversing all nodes after the index exceeds the user typed length
         *newTraverseAllNodes = isSameAsUserTypedLength;
         *newSnr = snr * addedWeight;
-        *newDiffs = diffs + (matchedProximityCharId > 0);
+        *newDiffs = diffs + ((matchedProximityCharId > 0) ? 1 : 0);
         *newInputIndex = inputIndex + 1;
     }
     // Optimization: Prune out words that are too long compared to how much was typed.
diff --git a/native/src/unigram_dictionary.h b/native/src/unigram_dictionary.h
index f8af55c..abfdb8d 100644
--- a/native/src/unigram_dictionary.h
+++ b/native/src/unigram_dictionary.h
@@ -32,7 +32,8 @@
 private:
     void initSuggestions(int *codes, int codesSize, unsigned short *outWords, int *frequencies);
     void getSuggestionCandidates(const int inputLength, const int skipPos, const int excessivePos,
-            int *nextLetters, const int nextLettersSize);
+            const int transposedPos, int *nextLetters, const int nextLettersSize,
+            const int maxDepth);
     void getVersionNumber();
     bool checkIfDictVersionIsLatest();
     int getAddress(int *pos);
@@ -43,25 +44,30 @@
     unsigned short toLowerCase(unsigned short c);
     void getWordsRec(const int childrenCount, const int pos, const int depth, const int maxDepth,
             const bool traverseAllNodes, const int snr, const int inputIndex, const int diffs,
-            const int skipPos, const int excessivePos, int *nextLetters, const int nextLettersSize);
+            const int skipPos, const int excessivePos, const int transposedPos, int *nextLetters,
+            const int nextLettersSize);
     bool getMissingSpaceWords(const int inputLength, const int missingSpacePos);
     // Keep getWordsOld for comparing performance between getWords and getWordsOld
     void getWordsOld(const int initialPos, const int inputLength, const int skipPos,
-            const int excessivePos, int *nextLetters, const int nextLettersSize);
+            const int excessivePos, const int transposedPos, int *nextLetters,
+            const int nextLettersSize);
     void registerNextLetter(unsigned short c, int *nextLetters, int nextLettersSize);
     void onTerminalWhenUserTypedLengthIsGreaterThanInputLength(unsigned short *word,
             const int mInputLength, const int depth, const int snr, int *nextLetters,
-            const int nextLettersSize, const int skipPos, const int freq);
+            const int nextLettersSize, const int skipPos, const int excessivePos,
+            const int transposedPos, const int freq);
     void onTerminalWhenUserTypedLengthIsSameAsInputLength(unsigned short *word, const int depth,
-            const int snr, const int skipPos, const int freq, const int addedWeight);
+            const int snr, const int skipPos, const int excessivePos, const int transposedPos,
+            const int freq, const int addedWeight);
     bool needsToSkipCurrentNode(const unsigned short c,
             const int inputIndex, const int skipPos, const int depth);
-    int getMatchedProximityId(const int *currentChars, const unsigned short c, const int skipPos);
+    int getMatchedProximityId(const int *currentChars, const unsigned short c, const int skipPos,
+            const int excessivePos, const int transposedPos);
     // Process a node by considering proximity, missing and excessive character
     bool processCurrentNode(const int pos, const int depth,
             const int maxDepth, const bool traverseAllNodes, const int snr, int inputIndex,
-            const int diffs, const int skipPos, const int excessivePos, int *nextLetters,
-            const int nextLettersSize, int *newCount, int *newChildPosition,
+            const int diffs, const int skipPos, const int excessivePos, const int transposedPos,
+            int *nextLetters, const int nextLettersSize, int *newCount, int *newChildPosition,
             bool *newTraverseAllNodes, int *newSnr, int*newInputIndex, int *newDiffs,
             int *nextSiblingPosition);
     int getBestWordFreq(const int startInputIndex, const int inputLength, unsigned short *word);
diff --git a/tests/src/com/android/inputmethod/latin/SuggestHelper.java b/tests/src/com/android/inputmethod/latin/SuggestHelper.java
index 759bfa1..932098a 100644
--- a/tests/src/com/android/inputmethod/latin/SuggestHelper.java
+++ b/tests/src/com/android/inputmethod/latin/SuggestHelper.java
@@ -116,13 +116,6 @@
         return word;
     }
 
-    private void showList(String title, List<CharSequence> suggestions) {
-        Log.i(TAG, title);
-        for (int i = 0; i < suggestions.size(); i++) {
-            Log.i(title, suggestions.get(i) + ", ");
-        }
-    }
-
     private boolean isDefaultSuggestion(List<CharSequence> suggestions, CharSequence word) {
         // Check if either the word is what you typed or the first alternative
         return suggestions.size() > 0 &&
@@ -191,8 +184,6 @@
 
     boolean isUserBigramSuggestion(CharSequence previous, char typed,
            CharSequence expected) {
-        WordComposer word = createWordComposer(Character.toString(typed));
-
         if (mUserBigram == null) return false;
 
         flushUserBigrams();