am 0b288985: Merge "Fix emoji recent key behavior"

* commit '0b288985b7e6a74f94943f15be6d6d55d6cca872':
  Fix emoji recent key behavior
diff --git a/java/src/com/android/inputmethod/keyboard/EmojiKeyboardView.java b/java/src/com/android/inputmethod/keyboard/EmojiKeyboardView.java
index eb48d01..db7c845 100644
--- a/java/src/com/android/inputmethod/keyboard/EmojiKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/EmojiKeyboardView.java
@@ -580,10 +580,18 @@
     }
 
     private void setCurrentCategoryId(final int categoryId, final boolean force) {
-        if (mEmojiCategory.getCurrentCategoryId() == categoryId && !force) {
+        final int oldCategoryId = mEmojiCategory.getCurrentCategoryId();
+        if (oldCategoryId == categoryId && !force) {
             return;
         }
 
+        if (oldCategoryId == CATEGORY_ID_RECENTS) {
+            // Needs to save pending updates for recent keys when we get out of the recents
+            // category because we don't want to move the recent emojis around while the user
+            // is in the recents category.
+            mEmojiKeyboardAdapter.flushPendingRecentKeys();
+        }
+
         mEmojiCategory.setCurrentCategoryId(categoryId);
         final int newTabId = mEmojiCategory.getTabIdFromCategoryId(categoryId);
         final int newCategoryPageId = mEmojiCategory.getPageIdFromCategoryId(categoryId);
@@ -612,8 +620,18 @@
             mRecentsKeyboard = mEmojiCategory.getKeyboard(CATEGORY_ID_RECENTS, 0);
         }
 
+        public void flushPendingRecentKeys() {
+            mRecentsKeyboard.flushPendingRecentKeys();
+            final KeyboardView recentKeyboardView =
+                    mActiveKeyboardView.get(mEmojiCategory.getRecentTabId());
+            if (recentKeyboardView != null) {
+                recentKeyboardView.invalidateAllKeys();
+            }
+        }
+
         public void addRecentKey(final Key key) {
             if (mEmojiCategory.isInRecentTab()) {
+                mRecentsKeyboard.addPendingKey(key);
                 return;
             }
             mRecentsKeyboard.addKeyFirst(key);
diff --git a/java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java b/java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java
index 0dd71e2..587f95a 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java
@@ -39,6 +39,7 @@
     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;
+    private final Object mLock = new Object();
 
     private final SharedPreferences mPrefs;
     private final int mLeftPadding;
@@ -48,6 +49,7 @@
     private final int mMaxKeyCount;
     private final boolean mIsRecents;
     private final ArrayDeque<GridKey> mGridKeys = CollectionUtils.newArrayDeque();
+    private final ArrayDeque<Key> mPendingKeys = CollectionUtils.newArrayDeque();
 
     private Key[] mCachedGridKeys;
 
@@ -74,6 +76,21 @@
         throw new RuntimeException("Can't find template key: code=" + code);
     }
 
+    public void addPendingKey(final Key usedKey) {
+        synchronized (mLock) {
+            mPendingKeys.addLast(usedKey);
+        }
+    }
+
+    public void flushPendingRecentKeys() {
+        synchronized (mLock) {
+            while (!mPendingKeys.isEmpty()) {
+                addKey(mPendingKeys.pollFirst(), true);
+            }
+            saveRecentKeys();
+        }
+    }
+
     public void addKeyFirst(final Key usedKey) {
         addKey(usedKey, true);
         if (mIsRecents) {
@@ -89,7 +106,7 @@
         if (usedKey == null) {
             return;
         }
-        synchronized (mGridKeys) {
+        synchronized (mLock) {
             mCachedGridKeys = null;
             final GridKey key = new GridKey(usedKey);
             while (mGridKeys.remove(key)) {
@@ -167,7 +184,7 @@
 
     @Override
     public Key[] getKeys() {
-        synchronized (mGridKeys) {
+        synchronized (mLock) {
             if (mCachedGridKeys != null) {
                 return mCachedGridKeys;
             }