Merge "Stop inserting a space after a manually picked word."
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java b/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java
index 4e29002..adb5f47 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java
@@ -325,7 +325,7 @@
             return null;
         }
         if (Utils.codePointCount(text) == 1) {
-            return new String[] { text };
+            return text.codePointAt(0) == COMMA ? null : new String[] { text };
         }
 
         ArrayList<String> list = null;
@@ -333,10 +333,13 @@
         for (int pos = 0; pos < size; pos++) {
             final char c = text.charAt(pos);
             if (c == COMMA) {
-                if (list == null) {
-                    list = new ArrayList<String>();
+                // Skip empty entry.
+                if (pos - start > 0) {
+                    if (list == null) {
+                        list = new ArrayList<String>();
+                    }
+                    list.add(text.substring(start, pos));
                 }
-                list.add(text.substring(start, pos));
                 // Skip comma
                 start = pos + 1;
             } else if (c == ESCAPE_CHAR) {
@@ -344,10 +347,13 @@
                 pos++;
             }
         }
+        final String remain = (size - start > 0) ? text.substring(start) : null;
         if (list == null) {
-            return new String[] { text.substring(start) };
+            return remain != null ? new String[] { remain } : null;
         } else {
-            list.add(text.substring(start));
+            if (remain != null) {
+                list.add(remain);
+            }
             return list.toArray(new String[list.size()]);
         }
     }
diff --git a/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserCsvTests.java b/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserCsvTests.java
index 721c801..a0ce86d 100644
--- a/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserCsvTests.java
+++ b/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserCsvTests.java
@@ -42,7 +42,8 @@
         final String actual[] = KeySpecParser.parseCsvString(value, mTestResources,
                 R.string.empty_string);
         if (expected.length == 0) {
-            assertNull(message, actual);
+            assertNull(message + ": expected=null actual=" + Arrays.toString(actual),
+                    actual);
             return;
         }
         assertEquals(message + ": expected=" + Arrays.toString(expected)
@@ -74,6 +75,11 @@
 
     public void testParseCsvTextZero() {
         assertTextArray("Empty string", "");
+        assertTextArray("Empty entry", ",");
+        assertTextArray("Empty entry at beginning", ",a", "a");
+        assertTextArray("Empty entry at end", "a,", "a");
+        assertTextArray("Empty entry at middle", "a,,b", "a", "b");
+        assertTextArray("Empty entries with escape", ",a,b\\,c,,d,", "a", "b\\,c", "d");
     }
 
     public void testParseCsvTextSingle() {
@@ -82,7 +88,7 @@
         assertTextArray("Single escape", "\\", "\\");
         assertTextArray("Space", " ", " ");
         assertTextArray("Single label", "abc", "abc");
-        assertTextArray("Single srrogate pairs label", SURROGATE2, SURROGATE2);
+        assertTextArray("Single surrogate pairs label", SURROGATE2, SURROGATE2);
         assertTextArray("Spaces", "   ", "   ");
         assertTextArray("Spaces in label", "a b c", "a b c");
         assertTextArray("Spaces at beginning of label", " abc", " abc");
diff --git a/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserTests.java b/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserTests.java
index ec5c17b..429e16d 100644
--- a/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserTests.java
+++ b/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserTests.java
@@ -27,15 +27,18 @@
 public class KeySpecParserTests extends AndroidTestCase {
     private Resources mRes;
 
-    private static final int ICON_SETTINGS_KEY = R.styleable.Keyboard_iconSettingsKey;
     private static final int ICON_UNDEFINED = KeyboardIconsSet.ICON_UNDEFINED;
 
-    private static final String CODE_SETTINGS = "@integer/key_settings";
-    private static final String ICON_SETTINGS = "@icon/settingsKey";
+    private static final String CODE_SETTINGS_RES = "integer/key_settings";
+    private static final String ICON_SETTINGS_NAME = "settingsKey";
+
+    private static final String CODE_SETTINGS = "@" + CODE_SETTINGS_RES;
+    private static final String ICON_SETTINGS = "@icon/" + ICON_SETTINGS_NAME;
     private static final String CODE_NON_EXISTING = "@integer/non_existing";
     private static final String ICON_NON_EXISTING = "@icon/non_existing";
 
     private int mCodeSettings;
+    private int mSettingsIconId;
 
     @Override
     protected void setUp() {
@@ -43,8 +46,9 @@
         mRes = res;
 
         final String packageName = res.getResourcePackageName(R.string.english_ime_name);
-        final int codeId = res.getIdentifier(CODE_SETTINGS.substring(1), null, packageName);
+        final int codeId = res.getIdentifier(CODE_SETTINGS_RES, null, packageName);
         mCodeSettings = res.getInteger(codeId);
+        mSettingsIconId = KeyboardIconsSet.getIconId(ICON_SETTINGS_NAME);
     }
 
     private void assertParser(String message, String moreKeySpec, String expectedLabel,
@@ -202,13 +206,13 @@
 
     public void testIconAndCode() {
         assertParser("Icon with outputText", ICON_SETTINGS + "|abc",
-                null, "abc", ICON_SETTINGS_KEY, Keyboard.CODE_OUTPUT_TEXT);
+                null, "abc", mSettingsIconId, Keyboard.CODE_OUTPUT_TEXT);
         assertParser("Icon with outputText starts with at", ICON_SETTINGS + "|@bc",
-                null, "@bc", ICON_SETTINGS_KEY, Keyboard.CODE_OUTPUT_TEXT);
+                null, "@bc", mSettingsIconId, Keyboard.CODE_OUTPUT_TEXT);
         assertParser("Icon with outputText contains at", ICON_SETTINGS + "|a@c",
-                null, "a@c", ICON_SETTINGS_KEY, Keyboard.CODE_OUTPUT_TEXT);
+                null, "a@c", mSettingsIconId, Keyboard.CODE_OUTPUT_TEXT);
         assertParser("Icon with escaped at outputText", ICON_SETTINGS + "|\\@bc",
-                null, "@bc", ICON_SETTINGS_KEY, Keyboard.CODE_OUTPUT_TEXT);
+                null, "@bc", mSettingsIconId, Keyboard.CODE_OUTPUT_TEXT);
         assertParser("Label starts with at and code", "@bc|" + CODE_SETTINGS,
                 "@bc", null, ICON_UNDEFINED, mCodeSettings);
         assertParser("Label contains at and code", "a@c|" + CODE_SETTINGS,
@@ -216,7 +220,7 @@
         assertParser("Escaped at label with code", "\\@bc|" + CODE_SETTINGS,
                 "@bc", null, ICON_UNDEFINED, mCodeSettings);
         assertParser("Icon with code", ICON_SETTINGS + "|" + CODE_SETTINGS,
-                null, null, ICON_SETTINGS_KEY, mCodeSettings);
+                null, null, mSettingsIconId, mCodeSettings);
     }
 
     public void testFormatError() {
@@ -229,11 +233,11 @@
         assertParserError("Empty outputText with label", "a|",
                 "a", null, ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED);
         assertParserError("Empty outputText with icon", ICON_SETTINGS + "|",
-                null, null, ICON_SETTINGS_KEY, Keyboard.CODE_UNSPECIFIED);
+                null, null, mSettingsIconId, Keyboard.CODE_UNSPECIFIED);
         assertParserError("Empty icon and code", "|",
                 null, null, ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED);
         assertParserError("Icon without code", ICON_SETTINGS,
-                null, null, ICON_SETTINGS_KEY, Keyboard.CODE_UNSPECIFIED);
+                null, null, mSettingsIconId, Keyboard.CODE_UNSPECIFIED);
         assertParserError("Non existing icon", ICON_NON_EXISTING + "|abc",
                 null, "abc", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
         assertParserError("Non existing code", "abc|" + CODE_NON_EXISTING,
@@ -245,10 +249,10 @@
         assertParserError("Multiple bar with label and code", "a|" + CODE_SETTINGS + "|c",
                 "a", null, ICON_UNDEFINED, mCodeSettings);
         assertParserError("Multiple bar with icon and outputText", ICON_SETTINGS + "|b|c",
-                null, null, ICON_SETTINGS_KEY, Keyboard.CODE_UNSPECIFIED);
+                null, null, mSettingsIconId, Keyboard.CODE_UNSPECIFIED);
         assertParserError("Multiple bar with icon and code",
                 ICON_SETTINGS + "|" + CODE_SETTINGS + "|c",
-                null, null, ICON_SETTINGS_KEY, mCodeSettings);
+                null, null, mSettingsIconId, mCodeSettings);
     }
 
     private static void assertMoreKeys(String message, String[] moreKeys,