diff --git a/java/res/values-land/dimens.xml b/java/res/values-land/dimens.xml
index c954e60da5f865de096c40756c6420bb9a8bdea5..42a746b609c08ff005559b078bcebb6608290866 100644
--- a/java/res/values-land/dimens.xml
+++ b/java/res/values-land/dimens.xml
@@ -75,5 +75,9 @@
     <dimen name="gesture_floating_preview_vertical_padding">15dp</dimen>
 
     <!-- Emoji keyboard -->
-    <fraction name="emoji_keyboard_key_width">8.3333%p</fraction>
+    <fraction name="emoji_keyboard_key_width">10%p</fraction>
+    <fraction name="emoji_keyboard_row_height">50%p</fraction>
+    <fraction name="emoji_keyboard_key_letter_size">60%p</fraction>
+    <integer name="emoji_keyboard_max_key_count">20</integer>
+
 </resources>
diff --git a/java/res/values/dimens.xml b/java/res/values/dimens.xml
index 7de93e6e343c9626b48015ef02da63e915633dd6..88e327f2608370021e18df2fbc9aa897fb01b1fd 100644
--- a/java/res/values/dimens.xml
+++ b/java/res/values/dimens.xml
@@ -117,6 +117,9 @@
 
     <!-- Emoji keyboard -->
     <fraction name="emoji_keyboard_key_width">14.2857%p</fraction>
+    <fraction name="emoji_keyboard_row_height">33%p</fraction>
+    <fraction name="emoji_keyboard_key_letter_size">90%p</fraction>
+    <integer name="emoji_keyboard_max_key_count">21</integer>
 
     <!-- Inset used in Accessibility mode to avoid accidental key presses when a finger slides off the screen. -->
     <dimen name="accessibility_edge_slop">8dp</dimen>
@@ -124,4 +127,5 @@
     <integer name="user_dictionary_max_word_length" translatable="false">48</integer>
 
     <dimen name="language_on_spacebar_horizontal_margin">1dp</dimen>
+
 </resources>
diff --git a/java/res/xml/kbd_emoji_recents.xml b/java/res/xml/kbd_emoji_recents.xml
index f56b79ab7f6eaa8818cc93500cee7d980dc63fec..73926ecc0a13a16afd322bb39d8a6c527ffc6d17 100644
--- a/java/res/xml/kbd_emoji_recents.xml
+++ b/java/res/xml/kbd_emoji_recents.xml
@@ -21,8 +21,9 @@
 <Keyboard
     xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
     latin:keyWidth="@fraction/emoji_keyboard_key_width"
-    latin:keyLetterSize="90%p"
+    latin:keyLetterSize="@fraction/emoji_keyboard_key_letter_size"
     latin:keyLabelSize="60%p"
+    latin:rowHeight="@fraction/emoji_keyboard_row_height"
 >
     <GridRows
         latin:codesArray="@array/emoji_recents"
diff --git a/java/src/com/android/inputmethod/keyboard/EmojiKeyboardView.java b/java/src/com/android/inputmethod/keyboard/EmojiKeyboardView.java
index 2e05dd382b53ba7bbca5ded17d0a59c188722eba..002674eae80cd106e70d644100daf3062523d2eb 100644
--- a/java/src/com/android/inputmethod/keyboard/EmojiKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/EmojiKeyboardView.java
@@ -28,6 +28,7 @@ import android.support.v4.view.PagerAdapter;
 import android.support.v4.view.ViewPager;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.util.Pair;
 import android.util.SparseArray;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -38,9 +39,7 @@ import android.widget.TabHost;
 import android.widget.TabHost.OnTabChangeListener;
 import android.widget.TextView;
 
-import com.android.inputmethod.keyboard.internal.CodesArrayParser;
 import com.android.inputmethod.keyboard.internal.DynamicGridKeyboard;
-import com.android.inputmethod.keyboard.internal.KeyboardParams;
 import com.android.inputmethod.keyboard.internal.ScrollKeyboardView;
 import com.android.inputmethod.keyboard.internal.ScrollViewWithNotifier;
 import com.android.inputmethod.latin.Constants;
@@ -90,7 +89,17 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
     private static final int CATEGORY_SYMBOLS = 5;
     private static final int CATEGORY_EMOTICONS = 6;
 
+    private static class CategoryProperties {
+        public int mCategory;
+        public int mPageCount;
+        public CategoryProperties(final int category, final int pageCount) {
+            mCategory = category;
+            mPageCount = pageCount;
+        }
+    }
+
     private static class EmojiCategory {
+        private static final int DEFAULT_PAGE_KEY_COUNT = 21;
         private static final int DEFAULT_MAX_ROW_SIZE = 3;
         private static final String[] sCategoryName = {
                 "recents",
@@ -118,10 +127,12 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
                 KeyboardId.ELEMENT_EMOJI_CATEGORY4,
                 KeyboardId.ELEMENT_EMOJI_CATEGORY5,
                 KeyboardId.ELEMENT_EMOJI_CATEGORY6, };
-        private Resources mRes;
+        private final Resources mRes;
+        private final int mMaxPageKeyCount;
         private final KeyboardLayoutSet mLayoutSet;
         private final HashMap<String, Integer> mCategoryNameToIdMap = CollectionUtils.newHashMap();
-        private final ArrayList<Integer> mShownCategories = new ArrayList<Integer>();
+        private final ArrayList<CategoryProperties> mShownCategories =
+                CollectionUtils.newArrayList();
         private final ConcurrentHashMap<Long, DynamicGridKeyboard>
                 mCategoryKeyboardMap = new ConcurrentHashMap<Long, DynamicGridKeyboard>();
 
@@ -129,32 +140,42 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
 
         public EmojiCategory(final Resources res, final KeyboardLayoutSet layoutSet) {
             mRes = res;
+            mMaxPageKeyCount = res.getInteger(R.integer.emoji_keyboard_max_key_count);
             mLayoutSet = layoutSet;
             for (int i = 0; i < sCategoryName.length; ++i) {
                 mCategoryNameToIdMap.put(sCategoryName[i], i);
             }
-            mShownCategories.add(CATEGORY_RECENTS);
+            addShownCategory(CATEGORY_RECENTS);
             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
-                mShownCategories.add(CATEGORY_PEOPLE);
-                mShownCategories.add(CATEGORY_OBJECTS);
-                mShownCategories.add(CATEGORY_NATURE);
-                mShownCategories.add(CATEGORY_PLACES);
+                addShownCategory(CATEGORY_PEOPLE);
+                addShownCategory(CATEGORY_OBJECTS);
+                addShownCategory(CATEGORY_NATURE);
+                addShownCategory(CATEGORY_PLACES);
                 // TODO: Restore last saved category
                 mCurrentCategory = CATEGORY_PEOPLE;
             } else {
                 // TODO: Restore last saved category
                 mCurrentCategory = CATEGORY_SYMBOLS;
             }
-            mShownCategories.add(CATEGORY_SYMBOLS);
-            mShownCategories.add(CATEGORY_EMOTICONS);
+            addShownCategory(CATEGORY_SYMBOLS);
+            addShownCategory(CATEGORY_EMOTICONS);
         }
 
-        public String getCategoryName(int category) {
-            return sCategoryName[category];
+        private void addShownCategory(int category) {
+            // Load a keyboard of category
+            getKeyboard(category, 0);
+            final CategoryProperties properties =
+                    new CategoryProperties(category, getCategoryPageCount(category));
+            mShownCategories.add(properties);
+        }
+
+        public String getCategoryName(int category, int categoryPageId) {
+            return sCategoryName[category] + "-" + categoryPageId;
         }
 
         public int getCategoryId(String name) {
-            return mCategoryNameToIdMap.get(name);
+            final String[] strings = name.split("-");
+            return mCategoryNameToIdMap.get(strings[0]);
         }
 
         public int getCategoryIcon(int category) {
@@ -165,7 +186,7 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
             return sCategoryLabel[category];
         }
 
-        public ArrayList<Integer> getShownCategories() {
+        public ArrayList<CategoryProperties> getShownCategories() {
             return mShownCategories;
         }
 
@@ -184,7 +205,7 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
 
         public int getTabIdFromCategory(int category) {
             for (int i = 0; i < mShownCategories.size(); ++i) {
-                if (mShownCategories.get(i) == category) {
+                if (mShownCategories.get(i).mCategory == category) {
                     return i;
                 }
             }
@@ -192,12 +213,53 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
             return 0;
         }
 
+        // Returns the view pager's page position for the category
+        public int getPageIdFromCategory(int category) {
+            int sum = 0;
+            for (int i = 0; i < mShownCategories.size(); ++i) {
+                final CategoryProperties props = mShownCategories.get(i);
+                if (props.mCategory == category) {
+                    return sum;
+                }
+                sum += props.mPageCount;
+            }
+            Log.w(TAG, "category not found: " + category);
+            return 0;
+        }
+
         public int getRecentTabId() {
             return getTabIdFromCategory(CATEGORY_RECENTS);
         }
 
-        public int getCategoryFromTabId(int tabId) {
-            return mShownCategories.get(tabId);
+        private int getCategoryPageCount(int category) {
+            final Keyboard keyboard = mLayoutSet.getKeyboard(sCategoryElementId[category]);
+            return (keyboard.getKeys().length - 1) / mMaxPageKeyCount + 1;
+        }
+
+        // Returns a pair of the category id and the category page id from the view pager's page
+        // position. The category page id is numbered in each category. And the view page position
+        // is the position of the current shown page in the view pager which contains all pages of
+        // all categories.
+        public Pair<Integer, Integer> getCategoryIdAndPageIdFromPagePosition(int position) {
+            int sum = 0;
+            for (CategoryProperties properties : mShownCategories) {
+                final int temp = sum;
+                sum += properties.mPageCount;
+                if (sum > position) {
+                    return new Pair<Integer, Integer>(properties.mCategory, position - temp);
+                }
+            }
+            return null;
+        }
+
+        // Returns a keyboard from the view pager's page position.
+        public DynamicGridKeyboard getKeyboardFromPagePosition(int position) {
+            final Pair<Integer, Integer> categoryAndId =
+                    getCategoryIdAndPageIdFromPagePosition(position);
+            if (categoryAndId != null) {
+                return getKeyboard(categoryAndId.first, categoryAndId.second);
+            }
+            return null;
         }
 
         public DynamicGridKeyboard getKeyboard(int category, int id) {
@@ -206,25 +268,29 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
                 final DynamicGridKeyboard kbd;
                 if (!mCategoryKeyboardMap.containsKey(key)) {
                     if (category != CATEGORY_RECENTS) {
-                        kbd = new DynamicGridKeyboard(
-                                mLayoutSet.getKeyboard(KeyboardId.ELEMENT_EMOJI_RECENTS),
-                                DEFAULT_MAX_ROW_SIZE);
                         final Keyboard keyboard =
                                 mLayoutSet.getKeyboard(sCategoryElementId[category]);
                         // TODO: Calculate maxPageCount dynamically
-                        final Key[][] sortedKeys = sortKeys(keyboard.getKeys(), 21);
-                        for (Key emojiKey : sortedKeys[0]) {
-                            if (emojiKey == null) {
-                                break;
+                        final Key[][] sortedKeys = sortKeys(keyboard.getKeys(), mMaxPageKeyCount);
+                        for (int i = 0; i < sortedKeys.length; ++i) {
+                            final DynamicGridKeyboard tempKbd = new DynamicGridKeyboard(
+                                    mLayoutSet.getKeyboard(KeyboardId.ELEMENT_EMOJI_RECENTS),
+                                    mMaxPageKeyCount);
+                            for (Key emojiKey : sortedKeys[i]) {
+                                if (emojiKey == null) {
+                                    break;
+                                }
+                                tempKbd.addKeyLast(emojiKey);
                             }
-                            kbd.addKeyLast(emojiKey);
+                            mCategoryKeyboardMap.put((((long) category) << 32) | i, tempKbd);
                         }
+                        kbd = mCategoryKeyboardMap.get(key);
                     } else {
                         kbd = new DynamicGridKeyboard(
                                 mLayoutSet.getKeyboard(KeyboardId.ELEMENT_EMOJI_RECENTS),
-                                DEFAULT_MAX_ROW_SIZE);
+                                mMaxPageKeyCount);
+                        mCategoryKeyboardMap.put(key, kbd);
                     }
-                    mCategoryKeyboardMap.put(key, kbd);
                 } else {
                     kbd = mCategoryKeyboardMap.get(key);
                 }
@@ -232,6 +298,14 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
             }
         }
 
+        public int getTotalPageCountOfAllCategories() {
+            int sum = 0;
+            for (CategoryProperties properties : mShownCategories) {
+                sum += properties.mPageCount;
+            }
+            return sum;
+        }
+
         private Key[][] sortKeys(Key[] inKeys, int maxPageCount) {
             Key[] keys = Arrays.copyOf(inKeys, inKeys.length);
             Arrays.sort(keys, 0, keys.length, new Comparator<Key>() {
@@ -287,10 +361,10 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
         final KeyboardLayoutSet.Builder builder = new KeyboardLayoutSet.Builder(
                 context, null /* editorInfo */);
         final Resources res = context.getResources();
+        final EmojiLayoutParams emojiLp = new EmojiLayoutParams(res);
         builder.setSubtype(SubtypeSwitcher.getInstance().getEmojiSubtype());
         builder.setKeyboardGeometry(ResourceUtils.getDefaultKeyboardWidth(res),
-                (int)ResourceUtils.getDefaultKeyboardHeight(res)
-                        + res.getDimensionPixelSize(R.dimen.suggestions_strip_height));
+                emojiLp.mEmojiKeyboardHeight);
         builder.setOptions(false, false, false /* lanuageSwitchKeyEnabled */);
         mLayoutSet = builder.build();
         mEmojiCategory = new EmojiCategory(context.getResources(), builder.build());
@@ -311,7 +385,7 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
     }
 
     private void addTab(final TabHost host, final int category) {
-        final String tabId = mEmojiCategory.getCategoryName(category);
+        final String tabId = mEmojiCategory.getCategoryName(category, 0 /* categoryPageId */);
         final TabHost.TabSpec tspec = host.newTabSpec(tabId);
         tspec.setContent(R.id.emoji_keyboard_dummy);
         if (mEmojiCategory.getCategoryIcon(category) != 0) {
@@ -334,8 +408,8 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
     protected void onFinishInflate() {
         mTabHost = (TabHost)findViewById(R.id.emoji_category_tabhost);
         mTabHost.setup();
-        for (final int i : mEmojiCategory.getShownCategories()) {
-            addTab(mTabHost, i);
+        for (final CategoryProperties properties : mEmojiCategory.getShownCategories()) {
+            addTab(mTabHost, properties.mCategory);
         }
         mTabHost.setOnTabChangedListener(this);
         mTabHost.getTabWidget().setStripEnabled(true);
@@ -384,7 +458,8 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
 
     @Override
     public void onPageSelected(final int position) {
-        setCurrentCategory(mEmojiCategory.getCategoryFromTabId(position), false /* force */);
+        setCurrentCategory(mEmojiCategory.getCategoryIdAndPageIdFromPagePosition(position).first,
+                false /* force */);
     }
 
     @Override
@@ -439,8 +514,10 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
 
         mEmojiCategory.setCurrentCategory(category);
         final int newTabId = mEmojiCategory.getTabIdFromCategory(category);
-        if (force || mEmojiPager.getCurrentItem() != newTabId) {
-            mEmojiPager.setCurrentItem(newTabId, true /* smoothScroll */);
+        final int newCategoryPageId = mEmojiCategory.getPageIdFromCategory(category);
+        if (force || mEmojiCategory.getCategoryIdAndPageIdFromPagePosition(
+                mEmojiPager.getCurrentItem()).first != category) {
+            mEmojiPager.setCurrentItem(newCategoryPageId, true /* smoothScroll */);
         }
         if (force || mTabHost.getCurrentTab() != newTabId) {
             mTabHost.setCurrentTab(newTabId);
@@ -480,7 +557,7 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
 
         @Override
         public int getCount() {
-            return mEmojiCategory.getShownCategories().size();
+            return mEmojiCategory.getTotalPageCountOfAllCategories();
         }
 
         @Override
@@ -499,7 +576,7 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
         @Override
         public Object instantiateItem(final ViewGroup container, final int position) {
             final Keyboard keyboard =
-                    mEmojiCategory.getKeyboard(mEmojiCategory.getCategoryFromTabId(position), 0);
+                    mEmojiCategory.getKeyboardFromPagePosition(position);
             final LayoutInflater inflater = LayoutInflater.from(container.getContext());
             final View view = inflater.inflate(
                     R.layout.emoji_keyboard_page, container, false /* attachToRoot */);
diff --git a/java/src/com/android/inputmethod/keyboard/EmojiLayoutParams.java b/java/src/com/android/inputmethod/keyboard/EmojiLayoutParams.java
index 6486fc9db47913c794416bbc942239d7e154d5ce..5570d594d94f3ecd3cad9e84baed61e29c853e60 100644
--- a/java/src/com/android/inputmethod/keyboard/EmojiLayoutParams.java
+++ b/java/src/com/android/inputmethod/keyboard/EmojiLayoutParams.java
@@ -27,6 +27,8 @@ import android.widget.LinearLayout;
 public class EmojiLayoutParams {
     private static final int DEFAULT_KEYBOARD_ROWS = 4;
 
+    public final int mEmojiPagerHeight;
+    private final int mEmojiPagerBottomMargin;
     public final int mEmojiKeyboardHeight;
     public final int mEmojiActionBarHeight;
     public final int mKeyVerticalGap;
@@ -49,13 +51,15 @@ public class EmojiLayoutParams {
                 + mKeyVerticalGap;
         mEmojiActionBarHeight = ((int) baseheight) / DEFAULT_KEYBOARD_ROWS
                 - (mKeyVerticalGap - mBottomPadding) / 2;
-        mEmojiKeyboardHeight = defaultKeyboardHeight - mEmojiActionBarHeight;
+        mEmojiPagerHeight = defaultKeyboardHeight - mEmojiActionBarHeight;
+        mEmojiPagerBottomMargin = mKeyVerticalGap / 2;
+        mEmojiKeyboardHeight = mEmojiPagerHeight - mEmojiPagerBottomMargin - 1;
     }
 
     public void setPagerProps(ViewPager vp) {
         final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) vp.getLayoutParams();
-        lp.height = mEmojiKeyboardHeight - mKeyVerticalGap / 2;
-        lp.bottomMargin = mKeyVerticalGap / 2;
+        lp.height = mEmojiPagerHeight - mEmojiPagerBottomMargin;
+        lp.bottomMargin = mEmojiPagerBottomMargin;
         vp.setLayoutParams(lp);
     }
 
diff --git a/java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java b/java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java
index 22708975aa10db32e223fd31a1be36975116b291..1e5ee59f053354908d440d389b1c2919aa2be104 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java
@@ -41,7 +41,7 @@ public class DynamicGridKeyboard extends Keyboard {
 
     private Key[] mCachedGridKeys;
 
-    public DynamicGridKeyboard(final Keyboard templateKeyboard, final int maxRows) {
+    public DynamicGridKeyboard(final Keyboard templateKeyboard, final int maxKeyCount) {
         super(templateKeyboard);
         final Key key0 = getTemplateKey(TEMPLATE_KEY_CODE_0);
         final Key key1 = getTemplateKey(TEMPLATE_KEY_CODE_1);
@@ -49,7 +49,7 @@ public class DynamicGridKeyboard extends Keyboard {
         mHorizontalStep = Math.abs(key1.getX() - key0.getX());
         mVerticalStep = key0.getHeight() + mVerticalGap;
         mColumnsNum = mBaseWidth / mHorizontalStep;
-        mMaxKeyCount = mColumnsNum * maxRows;
+        mMaxKeyCount = maxKeyCount;
     }
 
     private Key getTemplateKey(final int code) {