Merge "Make insertSpaceOnPickSuggestionManually final."
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardId.java b/java/src/com/android/inputmethod/keyboard/KeyboardId.java
index 3b3ff07..b4172d4 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardId.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardId.java
@@ -73,15 +73,6 @@
     private final int mHashCode;
 
     public KeyboardId(int xmlId, int elementState, Locale locale, int orientation, int width,
-            int mode, EditorInfo editorInfo, boolean settingsKeyEnabled,
-            boolean clobberSettingsKey, boolean shortcutKeyEnabled, boolean hasShortcutKey) {
-        this(xmlId, elementState, locale, orientation, width, mode,
-                (editorInfo != null ? editorInfo.inputType : 0),
-                (editorInfo != null ? editorInfo.imeOptions : 0),
-                settingsKeyEnabled, clobberSettingsKey, shortcutKeyEnabled, hasShortcutKey);
-    }
-
-    private KeyboardId(int xmlId, int elementState, Locale locale, int orientation, int width,
             int mode, int inputType, int imeOptions, boolean settingsKeyEnabled,
             boolean clobberSettingsKey, boolean shortcutKeyEnabled, boolean hasShortcutKey) {
         this.mLocale = locale;
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSet.java b/java/src/com/android/inputmethod/keyboard/KeyboardSet.java
index a28cfa8..34296fa 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSet.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSet.java
@@ -17,11 +17,9 @@
 package com.android.inputmethod.keyboard;
 
 import android.content.Context;
-import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
-import android.util.DisplayMetrics;
 import android.util.Xml;
 import android.view.inputmethod.EditorInfo;
 
@@ -42,9 +40,9 @@
 
 /**
  * This class has a set of {@link KeyboardId}s. Each of them represents a different keyboard
- * specific to a keyboard state, such as alphabet, symbols, and so on.  Layouts in the same
- * {@link KeyboardSet} are related to each other.
- * A {@link KeyboardSet} needs to be created for each {@link android.view.inputmethod.EditorInfo}.
+ * specific to a keyboard state, such as alphabet, symbols, and so on. Layouts in the same
+ * {@link KeyboardSet} are related to each other. A {@link KeyboardSet} needs to be created for each
+ * {@link android.view.inputmethod.EditorInfo}.
  */
 public class KeyboardSet {
     private static final String TAG_KEYBOARD_SET = "KeyboardSet";
@@ -55,56 +53,67 @@
     public final KeyboardId mSymbolsId;
     public final KeyboardId mSymbolsShiftedId;
 
-    KeyboardSet(Builder builder) {
-        mAlphabetId = builder.getKeyboardId(false, false);
-        mSymbolsId = builder.getKeyboardId(true, false);
-        mSymbolsShiftedId = builder.getKeyboardId(true, true);
+    KeyboardSet(Params params) {
+        mAlphabetId = Builder.getKeyboardId(false, false, params);
+        mSymbolsId = Builder.getKeyboardId(true, false, params);
+        mSymbolsShiftedId = Builder.getKeyboardId(true, true, params);
+    }
+
+    private static class Params {
+        int mMode;
+        int mInputTypes;
+        int mImeOptions;
+        boolean mSettingsKeyEnabled;
+        boolean mVoiceKeyEnabled;
+        boolean mVoiceKeyOnMain;
+        boolean mNoSettingsKey;
+        Locale mLocale;
+        int mOrientation;
+        int mWidth;
+        final HashMap<Integer, Integer> mElementKeyboards =
+                new HashMap<Integer, Integer>();
+
+        Params() {}
     }
 
     public static class Builder {
         private final Resources mResources;
-        private final EditorInfo mEditorInfo;
 
-        private final HashMap<Integer, Integer> mElementKeyboards =
-                new HashMap<Integer, Integer>();
-
-        private final int mMode;
-        private final boolean mSettingsKeyEnabled;
-        private final boolean mVoiceKeyEnabled;
-        private final boolean mVoiceKeyOnMain;
-        private final boolean mNoSettingsKey;
-        private final Locale mLocale;
-        private final Configuration mConf;
-        private final DisplayMetrics mMetrics;
+        private final Params mParams = new Params();
 
         public Builder(Context context, EditorInfo editorInfo, SettingsValues settingsValues) {
             mResources = context.getResources();
-            mEditorInfo = editorInfo;
             final SubtypeSwitcher subtypeSwitcher = SubtypeSwitcher.getInstance();
             final String packageName = context.getPackageName();
+            final Params params = mParams;
 
-            mMode = Utils.getKeyboardMode(mEditorInfo);
-            mSettingsKeyEnabled = settingsValues.isSettingsKeyEnabled();
+            params.mMode = Utils.getKeyboardMode(editorInfo);
+            if (editorInfo != null) {
+                params.mInputTypes = editorInfo.inputType;
+                params.mImeOptions = editorInfo.imeOptions;
+            }
+            params.mSettingsKeyEnabled = settingsValues.isSettingsKeyEnabled();
             @SuppressWarnings("deprecation")
             final boolean noMicrophone = Utils.inPrivateImeOptions(
                     packageName, LatinIME.IME_OPTION_NO_MICROPHONE, editorInfo)
                     || Utils.inPrivateImeOptions(
                             null, LatinIME.IME_OPTION_NO_MICROPHONE_COMPAT, editorInfo);
-            mVoiceKeyEnabled = settingsValues.isVoiceKeyEnabled(editorInfo) && !noMicrophone;
-            mVoiceKeyOnMain = settingsValues.isVoiceKeyOnMain();
-            mNoSettingsKey = Utils.inPrivateImeOptions(
+            params.mVoiceKeyEnabled = settingsValues.isVoiceKeyEnabled(editorInfo) && !noMicrophone;
+            params.mVoiceKeyOnMain = settingsValues.isVoiceKeyOnMain();
+            params.mNoSettingsKey = Utils.inPrivateImeOptions(
                     packageName, LatinIME.IME_OPTION_NO_SETTINGS_KEY, editorInfo);
             final boolean forceAscii = Utils.inPrivateImeOptions(
                     packageName, LatinIME.IME_OPTION_FORCE_ASCII, editorInfo);
             final boolean asciiCapable = subtypeSwitcher.currentSubtypeContainsExtraValueKey(
                     LatinIME.SUBTYPE_EXTRA_VALUE_ASCII_CAPABLE);
-            mLocale = (forceAscii && !asciiCapable) ? Locale.US : subtypeSwitcher.getInputLocale();
-            mConf = mResources.getConfiguration();
-            mMetrics = mResources.getDisplayMetrics();
+            params.mLocale = (forceAscii && !asciiCapable)
+                    ? Locale.US : subtypeSwitcher.getInputLocale();
+            params.mOrientation = mResources.getConfiguration().orientation;
+            params.mWidth = mResources.getDisplayMetrics().widthPixels;
         }
 
         public KeyboardSet build() {
-            final Locale savedLocale = LocaleUtils.setSystemLocale(mResources, mLocale);
+            final Locale savedLocale = LocaleUtils.setSystemLocale(mResources, mParams.mLocale);
             try {
                 parseKeyboardSet(mResources, R.xml.keyboard_set);
             } catch (Exception e) {
@@ -112,16 +121,18 @@
             } finally {
                 LocaleUtils.setSystemLocale(mResources, savedLocale);
             }
-            return new KeyboardSet(this);
+            return new KeyboardSet(mParams);
         }
 
-        KeyboardId getKeyboardId(boolean isSymbols, boolean isShift) {
-            final int elementState = getElementState(mMode, isSymbols, isShift);
-            final int xmlId = mElementKeyboards.get(elementState);
-            final boolean hasShortcutKey = mVoiceKeyEnabled && (isSymbols != mVoiceKeyOnMain);
-            return new KeyboardId(xmlId, elementState, mLocale, mConf.orientation,
-                    mMetrics.widthPixels, mMode, mEditorInfo, mSettingsKeyEnabled, mNoSettingsKey,
-                    mVoiceKeyEnabled, hasShortcutKey);
+        static KeyboardId getKeyboardId(boolean isSymbols, boolean isShift, Params params) {
+            final int elementState = getElementState(params.mMode, isSymbols, isShift);
+            final int xmlId = params.mElementKeyboards.get(elementState);
+            final boolean hasShortcutKey = params.mVoiceKeyEnabled
+                    && (isSymbols != params.mVoiceKeyOnMain);
+            return new KeyboardId(xmlId, elementState, params.mLocale, params.mOrientation,
+                    params.mWidth, params.mMode, params.mInputTypes, params.mImeOptions,
+                    params.mSettingsKeyEnabled, params.mNoSettingsKey, params.mVoiceKeyEnabled,
+                    hasShortcutKey);
         }
 
         private static int getElementState(int mode, boolean isSymbols, boolean isShift) {
@@ -198,7 +209,7 @@
                         R.styleable.KeyboardSet_Element_elementName, 0);
                 final int elementKeyboard = a.getResourceId(
                         R.styleable.KeyboardSet_Element_elementKeyboard, 0);
-                mElementKeyboards.put(elementName, elementKeyboard);
+                mParams.mElementKeyboards.put(elementName, elementKeyboard);
             } finally {
                 a.recycle();
             }
@@ -208,7 +219,8 @@
     public static String parseKeyboardLocale(Resources res, int resId)
             throws XmlPullParserException, IOException {
         final XmlPullParser parser = res.getXml(resId);
-        if (parser == null) return "";
+        if (parser == null)
+            return "";
         int event;
         while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) {
             if (event == XmlPullParser.START_TAG) {
diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
index 49b8ce7..c09541f 100644
--- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
@@ -21,6 +21,7 @@
 import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.os.Message;
+import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.GestureDetector;
@@ -38,9 +39,11 @@
 import com.android.inputmethod.keyboard.PointerTracker.DrawingProxy;
 import com.android.inputmethod.keyboard.PointerTracker.TimerProxy;
 import com.android.inputmethod.latin.LatinIME;
+import com.android.inputmethod.latin.LatinImeLogger;
 import com.android.inputmethod.latin.R;
 import com.android.inputmethod.latin.StaticInnerHandlerWrapper;
 import com.android.inputmethod.latin.Utils;
+import com.android.inputmethod.latin.Utils.UsabilityStudyLogUtils;
 
 import java.util.WeakHashMap;
 
@@ -62,6 +65,9 @@
     // Timing constants
     private final int mKeyRepeatInterval;
 
+    // TODO: Kill process when the usability study mode was changed.
+    private static final boolean ENABLE_USABILITY_STUDY_LOG = LatinImeLogger.sUsabilityStudy;
+
     // Mini keyboard
     private PopupWindow mMoreKeysWindow;
     private MoreKeysPanel mMoreKeysPanel;
@@ -513,6 +519,30 @@
             x = (int)me.getX(index);
             y = (int)me.getY(index);
         }
+        if (ENABLE_USABILITY_STUDY_LOG) {
+            final String eventTag;
+            switch (action) {
+                case MotionEvent.ACTION_UP:
+                    eventTag = "[Up]";
+                    break;
+                case MotionEvent.ACTION_DOWN:
+                    eventTag = "[Down]";
+                    break;
+                case MotionEvent.ACTION_POINTER_UP:
+                    eventTag = "[PointerUp]";
+                    break;
+                case MotionEvent.ACTION_POINTER_DOWN:
+                    eventTag = "[PointerDown]";
+                    break;
+                default:
+                    eventTag = "[Action" + action + "]";
+                    break;
+            }
+            if (!TextUtils.isEmpty(eventTag)) {
+                UsabilityStudyLogUtils.getInstance().write(
+                        eventTag + eventTime + "," + id + "," + x + "," + y + "\t\t");
+            }
+        }
 
         if (mKeyTimerHandler.isInKeyRepeat()) {
             final PointerTracker tracker = getPointerTracker(id);
@@ -569,6 +599,10 @@
                     py = (int)me.getY(i);
                 }
                 tracker.onMoveEvent(px, py, eventTime);
+                if (ENABLE_USABILITY_STUDY_LOG) {
+                    UsabilityStudyLogUtils.getInstance().write("[Move]"  + eventTime + ","
+                            + me.getPointerId(i) + "," + px + "," + py + "\t\t");
+                }
             }
         } else {
             getPointerTracker(id).processMotionEvent(action, x, y, eventTime, this);
diff --git a/java/src/com/android/inputmethod/latin/LatinImeLogger.java b/java/src/com/android/inputmethod/latin/LatinImeLogger.java
index da5058d..6f1adfe 100644
--- a/java/src/com/android/inputmethod/latin/LatinImeLogger.java
+++ b/java/src/com/android/inputmethod/latin/LatinImeLogger.java
@@ -29,6 +29,7 @@
 
     public static boolean sDBG = false;
     public static boolean sVISUALDEBUG = false;
+    public static boolean sUsabilityStudy = false;
 
     @Override
     public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
diff --git a/tests/src/com/android/inputmethod/latin/SuggestTestsBase.java b/tests/src/com/android/inputmethod/latin/SuggestTestsBase.java
index 7b4c6a9..bfb0301 100644
--- a/tests/src/com/android/inputmethod/latin/SuggestTestsBase.java
+++ b/tests/src/com/android/inputmethod/latin/SuggestTestsBase.java
@@ -19,6 +19,7 @@
 import android.content.res.AssetFileDescriptor;
 import android.content.res.Configuration;
 import android.test.AndroidTestCase;
+import android.text.InputType;
 import android.text.TextUtils;
 import android.util.DisplayMetrics;
 
@@ -51,7 +52,7 @@
         }
         return new KeyboardId(com.android.inputmethod.latin.R.xml.kbd_qwerty,
                 KeyboardId.ELEMENT_ALPHABET, locale, orientation, width, KeyboardId.MODE_TEXT,
-                null, false, false, false, false);
+                InputType.TYPE_CLASS_TEXT, 0, false, false, false, false);
     }
 
     protected InputStream openTestRawResource(int resIdInTest) {