diff --git a/java/src/com/android/inputmethod/keyboard/EmojiKeyboardView.java b/java/src/com/android/inputmethod/keyboard/EmojiKeyboardView.java index 702ed2075..546fa8140 100644 --- a/java/src/com/android/inputmethod/keyboard/EmojiKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/EmojiKeyboardView.java @@ -505,10 +505,7 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange @Override public void onKeyClick(final Key key) { - // TODO: Save emoticons to recents - if (mEmojiCategory.getCurrentCategoryId() != CATEGORY_ID_EMOTICONS) { - mEmojiKeyboardAdapter.addRecentKey(key); - } + mEmojiKeyboardAdapter.addRecentKey(key); mEmojiCategory.saveLastTypedCategoryPage(); final int code = key.getCode(); if (code == Constants.CODE_OUTPUT_TEXT) { diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java index 23f037fbd..bc1383aff 100644 --- a/java/src/com/android/inputmethod/keyboard/Keyboard.java +++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java @@ -155,6 +155,15 @@ public class Keyboard { return mKeys; } + public Key getKeyFromOutputText(final String outputText) { + for (final Key key : getKeys()) { + if (outputText.equals(key.getOutputText())) { + return key; + } + } + return null; + } + public Key getKey(final int code) { if (code == Constants.CODE_UNSPECIFIED) { return null; diff --git a/java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java b/java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java index f203eb7d7..2976e2323 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java +++ b/java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java @@ -18,25 +18,27 @@ package com.android.inputmethod.keyboard.internal; import android.content.SharedPreferences; import android.text.TextUtils; +import android.util.Log; import com.android.inputmethod.keyboard.EmojiKeyboardView; import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.keyboard.Keyboard; -import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.settings.Settings; import com.android.inputmethod.latin.utils.CollectionUtils; +import com.android.inputmethod.latin.utils.StringUtils; import java.util.ArrayDeque; +import java.util.ArrayList; import java.util.Collection; +import java.util.List; /** * This is a Keyboard class where you can add keys dynamically shown in a grid layout */ public class DynamicGridKeyboard extends Keyboard { + private static final String TAG = DynamicGridKeyboard.class.getSimpleName(); private static final int TEMPLATE_KEY_CODE_0 = 0x30; private static final int TEMPLATE_KEY_CODE_1 = 0x31; - // Recent codes are saved as an integer array, so we use comma as a separater. - private static final String RECENT_KEY_SEPARATOR = Constants.STRING_COMMA; private final SharedPreferences mPrefs; private final int mLeftPadding; @@ -84,6 +86,9 @@ public class DynamicGridKeyboard extends Keyboard { } private void addKey(final Key usedKey, final boolean addFirst) { + if (usedKey == null) { + return; + } synchronized (mGridKeys) { mCachedGridKeys = null; final GridKey key = new GridKey(usedKey); @@ -109,27 +114,44 @@ public class DynamicGridKeyboard extends Keyboard { } private void saveRecentKeys() { - final StringBuilder sb = new StringBuilder(); + final ArrayList keys = CollectionUtils.newArrayList(); for (final Key key : mGridKeys) { - sb.append(key.getCode()).append(RECENT_KEY_SEPARATOR); + if (key.getOutputText() != null) { + keys.add(key.getOutputText()); + } else { + keys.add(key.getCode()); + } } - Settings.writeEmojiRecentKeys(mPrefs, sb.toString()); + final String jsonStr = StringUtils.listToJsonStr(keys); + Settings.writeEmojiRecentKeys(mPrefs, jsonStr); + } + + private static Key getKey(final Collection keyboards, final Object o) { + for (final DynamicGridKeyboard kbd : keyboards) { + if (o instanceof Integer) { + final int code = (Integer) o; + final Key key = kbd.getKey(code); + if (key != null) { + return key; + } + } else if (o instanceof String) { + final String outputText = (String) o; + final Key key = kbd.getKeyFromOutputText(outputText); + if (key != null) { + return key; + } + } else { + Log.w(TAG, "Invalid object: " + o); + } + } + return null; } public void loadRecentKeys(Collection keyboards) { final String str = Settings.readEmojiRecentKeys(mPrefs); - for (String s : str.split(RECENT_KEY_SEPARATOR)) { - if (TextUtils.isEmpty(s)) { - continue; - } - final int code = Integer.valueOf(s); - for (DynamicGridKeyboard kbd : keyboards) { - final Key key = kbd.getKey(code); - if (key != null) { - addKeyLast(key); - break; - } - } + final List keys = StringUtils.jsonStrToList(str); + for (final Object o : keys) { + addKeyLast(getKey(keyboards, o)); } } diff --git a/java/src/com/android/inputmethod/latin/Constants.java b/java/src/com/android/inputmethod/latin/Constants.java index 029ba02ed..04ca60dbb 100644 --- a/java/src/com/android/inputmethod/latin/Constants.java +++ b/java/src/com/android/inputmethod/latin/Constants.java @@ -221,7 +221,6 @@ public final class Constants { } public static final int MAX_INT_BIT_COUNT = 32; - public static final String STRING_COMMA = ","; private Constants() { // This utility class is not publicly instantiable. diff --git a/java/src/com/android/inputmethod/latin/utils/StringUtils.java b/java/src/com/android/inputmethod/latin/utils/StringUtils.java index be4184093..121aecf0f 100644 --- a/java/src/com/android/inputmethod/latin/utils/StringUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/StringUtils.java @@ -16,16 +16,25 @@ package com.android.inputmethod.latin.utils; -import android.text.TextUtils; - import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.settings.SettingsValues; +import android.text.TextUtils; +import android.util.JsonReader; +import android.util.JsonWriter; +import android.util.Log; + +import java.io.IOException; +import java.io.StringReader; +import java.io.StringWriter; import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.Locale; public final class StringUtils { + private static final String TAG = StringUtils.class.getSimpleName(); public static final int CAPITALIZE_NONE = 0; // No caps, or mixed case public static final int CAPITALIZE_FIRST = 1; // First only public static final int CAPITALIZE_ALL = 2; // All caps @@ -390,4 +399,67 @@ public final class StringUtils { } return bytes; } + + public static List jsonStrToList(String s) { + final ArrayList retval = CollectionUtils.newArrayList(); + final JsonReader reader = new JsonReader(new StringReader(s)); + try { + reader.beginArray(); + while(reader.hasNext()) { + reader.beginObject(); + while (reader.hasNext()) { + final String name = reader.nextName(); + if (name.equals(Integer.class.getSimpleName())) { + retval.add(reader.nextInt()); + } else if (name.equals(String.class.getSimpleName())) { + retval.add(reader.nextString()); + } else { + Log.w(TAG, "Invalid name: " + name); + reader.skipValue(); + } + } + reader.endObject(); + } + reader.endArray(); + return retval; + } catch (IOException e) { + } finally { + try { + reader.close(); + } catch (IOException e) { + } + } + return Collections.emptyList(); + } + + public static String listToJsonStr(List list) { + if (list == null || list.isEmpty()) { + return ""; + } + final StringWriter sw = new StringWriter(); + final JsonWriter writer = new JsonWriter(sw); + try { + writer.beginArray(); + for (final Object o : list) { + writer.beginObject(); + if (o instanceof Integer) { + writer.name(Integer.class.getSimpleName()).value((Integer)o); + } else if (o instanceof String) { + writer.name(String.class.getSimpleName()).value((String)o); + } + writer.endObject(); + } + writer.endArray(); + return sw.toString(); + } catch (IOException e) { + } finally { + try { + if (writer != null) { + writer.close(); + } + } catch (IOException e) { + } + } + return ""; + } } diff --git a/tests/src/com/android/inputmethod/latin/utils/StringUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/StringUtilsTests.java index c6fa943fe..4e396a1cf 100644 --- a/tests/src/com/android/inputmethod/latin/utils/StringUtilsTests.java +++ b/tests/src/com/android/inputmethod/latin/utils/StringUtilsTests.java @@ -21,6 +21,8 @@ import com.android.inputmethod.latin.settings.SettingsValues; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; +import java.util.Arrays; +import java.util.List; import java.util.Locale; @SmallTest @@ -268,4 +270,14 @@ public class StringUtilsTests extends AndroidTestCase { final String bytesStr2 = StringUtils.byteArrayToHexString(bytes2); assertTrue(bytesStr.equals(bytesStr2)); } + + public void testJsonStringUtils() { + final Object[] objs = new Object[] { 1, "aaa", "bbb", 3 }; + final List objArray = Arrays.asList(objs); + final String str = StringUtils.listToJsonStr(objArray); + final List newObjArray = StringUtils.jsonStrToList(str); + for (int i = 0; i < objs.length; ++i) { + assertEquals(objs[i], newObjArray.get(i)); + } + } }