diff --git a/java/res/values-v18/emoji-categories.xml b/java/res/values-v18/emoji-categories.xml
index 17a2053d2a740ed43a84da0c6d539c839921fa27..2ea08159be6ab1a6ad24c6c16e5553ccef1a7719 100644
--- a/java/res/values-v18/emoji-categories.xml
+++ b/java/res/values-v18/emoji-categories.xml
@@ -17,19 +17,6 @@
 <!-- Note: This emoji code point list is valid on JB-MR2 (API == 18).
      There is another emoji code point list for KLP and later under res/xml/values-v19. -->
 <resources>
-    <!-- Dummy codeArrays for recents emoji keyboard.
-         Do not remove these keys, because they are used as a template. -->
-    <array
-        name="emoji_recents"
-        format="string"
-    >
-        <item>52</item>
-        <item>45</item>
-        <item>43</item>
-        <item>45</item>
-        <item>4E</item>
-        <item>54</item>
-    </array>
     <array
         name="emoji_nature"
         format="string"
diff --git a/java/res/values-v19/emoji-categories.xml b/java/res/values-v19/emoji-categories.xml
index a6affc42112f767654ca7f10835538d8ad8a5de0..658bbfa8347479d18fbcd3e8a763081c2c66a033 100644
--- a/java/res/values-v19/emoji-categories.xml
+++ b/java/res/values-v19/emoji-categories.xml
@@ -17,19 +17,6 @@
 <!-- Note: This emoji code point list is valid on KLP and later (API >= 19).
      There is another emoji code point list for JB-MR2 under res/xml/values and values-v18.-->
 <resources>
-    <!-- Dummy codeArrays for recents emoji keyboard.
-         Do not remove these keys, because they are used as a template. -->
-    <array
-        name="emoji_recents"
-        format="string"
-    >
-        <item>52</item>
-        <item>45</item>
-        <item>43</item>
-        <item>45</item>
-        <item>4E</item>
-        <item>54</item>
-    </array>
     <array
         name="emoji_nature"
         format="string"
diff --git a/java/res/values/emoji-categories.xml b/java/res/values/emoji-categories.xml
index 99d7b238905bbb5a83dc4ffb240267bf0b9a3fab..8f3dead88fc63222fc78cc2913ea4dfeb006b215 100644
--- a/java/res/values/emoji-categories.xml
+++ b/java/res/values/emoji-categories.xml
@@ -28,12 +28,9 @@
         name="emoji_recents"
         format="string"
     >
-        <item>52</item>
-        <item>45</item>
-        <item>43</item>
-        <item>45</item>
-        <item>4E</item>
-        <item>54</item>
+        <!-- These code point should be aligned with {@link RecentsKeyboard#TEMPLATE_KEY_CODE_*. -->
+        <item>30</item>
+        <item>31</item>
     </array>
     <array
         name="emoji_nature"
diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java
index 143c6e848a48e15a7f486580122a432ac1d01bc6..3ea68806b70ce2870e04371376a43def5e5cc216 100644
--- a/java/src/com/android/inputmethod/keyboard/Key.java
+++ b/java/src/com/android/inputmethod/keyboard/Key.java
@@ -764,8 +764,9 @@ public class Key implements Comparable<Key> {
     }
 
     public final int getDrawX() {
+        final int x = getX();
         final OptionalAttributes attrs = mOptionalAttributes;
-        return (attrs == null) ? mX : mX + attrs.mVisualInsetsLeft;
+        return (attrs == null) ? x : x + attrs.mVisualInsetsLeft;
     }
 
     public final int getDrawWidth() {
@@ -823,9 +824,9 @@ public class Key implements Comparable<Key> {
      * @return the square of the distance of the point from the nearest edge of the key
      */
     public int squaredDistanceToEdge(final int x, final int y) {
-        final int left = mX;
+        final int left = getX();
         final int right = left + mWidth;
-        final int top = mY;
+        final int top = getY();
         final int bottom = top + mHeight;
         final int edgeX = x < left ? left : (x > right ? right : x);
         final int edgeY = y < top ? top : (y > bottom ? bottom : y);
diff --git a/java/src/com/android/inputmethod/keyboard/internal/RecentsKeyboard.java b/java/src/com/android/inputmethod/keyboard/internal/RecentsKeyboard.java
new file mode 100644
index 0000000000000000000000000000000000000000..629c6046002f7ad502a0024ca72af3b50bd2be54
--- /dev/null
+++ b/java/src/com/android/inputmethod/keyboard/internal/RecentsKeyboard.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2013 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.keyboard.internal;
+
+import android.text.TextUtils;
+
+import com.android.inputmethod.keyboard.Key;
+import com.android.inputmethod.keyboard.Keyboard;
+import com.android.inputmethod.latin.utils.CollectionUtils;
+
+import java.util.ArrayDeque;
+import java.util.Random;
+
+/**
+ * This is a Keyboard class to host recently used keys.
+ */
+// TODO: Save/restore recent keys from/to preferences.
+public class RecentsKeyboard extends Keyboard {
+    private static final int TEMPLATE_KEY_CODE_0 = 0x30;
+    private static final int TEMPLATE_KEY_CODE_1 = 0x31;
+
+    private final int mLeftPadding;
+    private final int mHorizontalStep;
+    private final int mVerticalStep;
+    private final int mColumnsNum;
+    private final int mMaxRecentKeyCount;
+    private final ArrayDeque<RecentKey> mRecentKeys = CollectionUtils.newArrayDeque();
+
+    private Key[] mCachedRecentKeys;
+
+    public RecentsKeyboard(final Keyboard templateKeyboard) {
+        super(templateKeyboard);
+        final Key key0 = getTemplateKey(TEMPLATE_KEY_CODE_0);
+        final Key key1 = getTemplateKey(TEMPLATE_KEY_CODE_1);
+        mLeftPadding = key0.getX();
+        mHorizontalStep = Math.abs(key1.getX() - key0.getX());
+        mVerticalStep = key0.getHeight() + mVerticalGap;
+        mColumnsNum = mBaseWidth / mHorizontalStep;
+        final int rowsNum = mBaseHeight / mVerticalStep;
+        mMaxRecentKeyCount = mColumnsNum * rowsNum;
+    }
+
+    private Key getTemplateKey(final int code) {
+        for (final Key key : super.getKeys()) {
+            if (key.getCode() == code) {
+                return key;
+            }
+        }
+        throw new RuntimeException("Can't find template key: code=" + code);
+    }
+
+    private final Random random = new Random();
+
+    public void addRecentKey(final Key usedKey) {
+        synchronized (mRecentKeys) {
+            mCachedRecentKeys = null;
+            final RecentKey key = (usedKey instanceof RecentKey)
+                    ? (RecentKey)usedKey : new RecentKey(usedKey);
+            while (mRecentKeys.remove(key)) {
+                // Remove duplicate keys.
+            }
+            mRecentKeys.addFirst(key);
+            while (mRecentKeys.size() > mMaxRecentKeyCount) {
+                mRecentKeys.removeLast();
+            }
+            int index = 0;
+            for (final RecentKey recentKey : mRecentKeys) {
+                final int keyX = getKeyX(index);
+                final int keyY = getKeyY(index);
+                final int x = keyX+random.nextInt(recentKey.getWidth());
+                final int y = keyY+random.nextInt(recentKey.getHeight());
+                recentKey.updateCorrdinates(keyX, keyY);
+                index++;
+            }
+        }
+    }
+
+    private int getKeyX(final int index) {
+        final int column = index % mColumnsNum;
+        return column * mHorizontalStep + mLeftPadding;
+    }
+
+    private int getKeyY(final int index) {
+        final int row = index / mColumnsNum;
+        return row * mVerticalStep + mTopPadding;
+    }
+
+    @Override
+    public Key[] getKeys() {
+        synchronized (mRecentKeys) {
+            if (mCachedRecentKeys != null) {
+                return mCachedRecentKeys;
+            }
+            mCachedRecentKeys = mRecentKeys.toArray(new Key[mRecentKeys.size()]);
+            return mCachedRecentKeys;
+        }
+    }
+
+    @Override
+    public Key[] getNearestKeys(final int x, final int y) {
+        // TODO: Calculate the nearest key index in mRecentKeys from x and y.
+        return getKeys();
+    }
+
+    static final class RecentKey extends Key {
+        private int mCurrentX;
+        private int mCurrentY;
+
+        public RecentKey(final Key originalKey) {
+            super(originalKey);
+        }
+
+        public void updateCorrdinates(final int x, final int y) {
+            mCurrentX = x;
+            mCurrentY = y;
+            getHitBox().offsetTo(x, y);
+        }
+
+        @Override
+        public int getX() {
+            return mCurrentX;
+        }
+
+        @Override
+        public int getY() {
+            return mCurrentY;
+        }
+
+        @Override
+        public boolean equals(final Object o) {
+            if (!(o instanceof Key)) return false;
+            final Key key = (Key)o;
+            if (getCode() != key.getCode()) return false;
+            if (!TextUtils.equals(getLabel(), key.getLabel())) return false;
+            return TextUtils.equals(getOutputText(), key.getOutputText());
+        }
+
+        @Override
+        public String toString() {
+            return "RecentKey: " + super.toString();
+        }
+    }
+}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/ScrollKeyboardView.java b/java/src/com/android/inputmethod/keyboard/internal/ScrollKeyboardView.java
index 2628f59a8eb13973ff37e46429ac10e3245f4472..b8ee976e896958a107f6afd6be387199ebc584db 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/ScrollKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/ScrollKeyboardView.java
@@ -33,6 +33,7 @@ import com.android.inputmethod.latin.R;
  * This is an extended {@link KeyboardView} class that hosts a scroll keyboard.
  * Multi-touch unsupported. No {@link PointerTracker}s. No gesture support.
  */
+// TODO: Implement key popup preview.
 public final class ScrollKeyboardView extends KeyboardView implements
         ScrollViewWithNotifier.ScrollListener, GestureDetector.OnGestureListener {
     private static final boolean PAGINATION = false;