diff --git a/java/res/layout/input_view.xml b/java/res/layout/input_view.xml
index 1ffb8a32a73659d1d89ecc23f9cd4880581b1c74..0b682d19876c0a3a80bbf791079d7c9bba748f6c 100644
--- a/java/res/layout/input_view.xml
+++ b/java/res/layout/input_view.xml
@@ -20,34 +20,41 @@
 
 <com.android.inputmethod.latin.InputView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="vertical"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
->
+    android:gravity="bottom|center_horizontal"
+    android:orientation="vertical" >
     <!-- The height of key_preview_backing view will automatically be determined by code. -->
     <View
         android:id="@+id/key_preview_backing"
         android:layout_width="match_parent"
         android:layout_height="0dp" />
+    <LinearLayout
+        android:id="@+id/main_keyboard_frame"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:orientation="vertical" >
 
-    <!-- To ensure that key preview popup is correctly placed when the current system locale is
-         one of RTL locales, layoutDirection="ltr" is needed in the SDK version 17+. -->
-    <com.android.inputmethod.latin.suggestions.SuggestionStripView
-        android:id="@+id/suggestion_strip_view"
-        android:layoutDirection="ltr"
-        android:layout_width="match_parent"
-        android:layout_height="@dimen/suggestions_strip_height"
-        android:gravity="center_vertical"
-        android:paddingRight="@dimen/suggestions_strip_padding"
-        android:paddingLeft="@dimen/suggestions_strip_padding"
-        style="?attr/suggestionStripViewStyle" />
+        <!-- To ensure that key preview popup is correctly placed when the current system locale is
+             one of RTL locales, layoutDirection="ltr" is needed in the SDK version 17+. -->
+        <com.android.inputmethod.latin.suggestions.SuggestionStripView
+            android:id="@+id/suggestion_strip_view"
+            android:layoutDirection="ltr"
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/suggestions_strip_height"
+            android:gravity="center_vertical"
+            android:paddingRight="@dimen/suggestions_strip_padding"
+            android:paddingLeft="@dimen/suggestions_strip_padding"
+            style="?attr/suggestionStripViewStyle" />
 
-    <!-- To ensure that key preview popup is correctly placed when the current system locale is
-         one of RTL locales, layoutDirection="ltr" is needed in the SDK version 17+. -->
-    <com.android.inputmethod.keyboard.MainKeyboardView
-        android:id="@+id/keyboard_view"
-        android:layoutDirection="ltr"
-        android:layout_alignParentBottom="true"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content" />
+        <!-- To ensure that key preview popup is correctly placed when the current system locale is
+             one of RTL locales, layoutDirection="ltr" is needed in the SDK version 17+. -->
+        <com.android.inputmethod.keyboard.MainKeyboardView
+            android:id="@+id/keyboard_view"
+            android:layoutDirection="ltr"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" />
+    </LinearLayout>
+    <include
+        layout="@layout/emoji_keyboard_view" />
 </com.android.inputmethod.latin.InputView>
diff --git a/java/res/values/emoji-categories.xml b/java/res/values/emoji-categories.xml
index 8f3dead88fc63222fc78cc2913ea4dfeb006b215..ce82a8b40b24e550bd5be48659745e28df3e1122 100644
--- a/java/res/values/emoji-categories.xml
+++ b/java/res/values/emoji-categories.xml
@@ -36,26 +36,73 @@
         name="emoji_nature"
         format="string"
     >
+        <item>2744</item> <!-- SNOWFLAKE -->
     </array>
     <array
         name="emoji_symbols"
         format="string"
     >
+        <item>2460</item> <!-- CIRCLED DIGIT ONE -->
+        <item>2461</item> <!-- CIRCLED DIGIT TWO -->
+        <item>2462</item> <!-- CIRCLED DIGIT THREE -->
+        <item>2463</item> <!-- CIRCLED DIGIT FOUR -->
+        <item>2464</item> <!-- CIRCLED DIGIT FIVE -->
+        <item>2465</item> <!-- CIRCLED DIGIT SIX -->
+        <item>2466</item> <!-- CIRCLED DIGIT SEVEN -->
+        <item>2467</item> <!-- CIRCLED DIGIT EIGHT -->
+        <item>2468</item> <!-- CIRCLED DIGIT NINE -->
+        <item>2469</item> <!-- CIRCLED DIGIT TEN -->
+        <item>00ae</item> <!-- REGISTERED SIGN -->
+        <item>00a9</item> <!-- COPYRIGHT SIGN -->
+        <item>2122</item> <!-- TRADE MARK SIGN -->
+        <item>2734</item> <!-- EIGHT POINTED BLACK STAR -->
+        <item>2733</item> <!-- EIGHT POINTED PINWHEEL STAR -->
+        <item>2716</item> <!-- HEAVY MULTIPLICATION MARK -->
+        <item>2195</item> <!-- UP DOWN ARROW -->
+        <item>2197</item> <!-- NORTH EAST ARROW -->
+        <item>27a1</item> <!-- BLACK RIGHTWARDS ARROW -->
+        <item>2198</item> <!-- SOUTH EAST ARROW -->
+        <item>2199</item> <!-- SOUTH WEST ARROW -->
+        <item>2196</item> <!-- NORTH EAST ARROW -->
+        <item>2194</item> <!-- LEFT RIGHT ARROW -->
+        <item>25c0</item> <!-- BLACK LEFT-POINTING TRIANGLE -->
+        <item>25b6</item> <!-- BLACK ROGHT-POINTING TRIANGLE -->
+        <item>2747</item> <!-- SPARKLE -->
+        <item>25aa</item> <!-- BLACK SMALL SQUARE -->
+        <item>203c</item> <!-- DOUBLE EXCLAMATION MARK -->
+        <item>2660</item> <!-- BLACK SPADE SUIT -->
+        <item>2665</item> <!-- BLACK HEART SUIT -->
+        <item>2663</item> <!-- BLACK CLUB SUIT -->
+        <item>2666</item> <!-- BLACK DIAMOND SUIT -->
+        <item>21a9</item> <!-- LEFTWARDS ARROW WITH HOOK -->
+        <item>21aa</item> <!-- RIGHTWARDS ARROW WITH HOOK -->
     </array>
     <array
         name="emoji_faces"
         format="string"
     >
+        <item>270C</item> <!-- VICTORY HAND -->
+        <item>2764</item> <!-- HEAVY BLACK HEART -->
     </array>
     <array
         name="emoji_objects"
         format="string"
     >
+        <item>260e</item> <!-- BLACK TELEPHONE -->
+        <item>2709</item> <!-- ENVELOPE -->
+        <item>2712</item> <!-- BLACK NIB -->
+        <item>270f</item> <!-- PENCIL -->
+        <item>2702</item> <!-- BLACK SCISSORS -->
+        <item>2669</item> <!-- QUARTER NOTE -->
+        <item>266a</item> <!-- EIGHTH NOTE -->
+        <item>266c</item> <!-- BEAMED SIXTEENTH NOTES -->
     </array>
     <array
         name="emoji_places"
         format="string"
     >
+        <item>2708</item> <!-- AIRPLANE -->
+        <item>2668</item> <!-- HOT SPRINGS -->
     </array>
     <array
         name="emoji_emoticons"
diff --git a/java/res/values/themes-common.xml b/java/res/values/themes-common.xml
index 473a1257ec7ef7722aa0d773b8e42fc5271f0a98..8e9cfc90bfb08ca581afbfeb5567e6c26a62c526 100644
--- a/java/res/values/themes-common.xml
+++ b/java/res/values/themes-common.xml
@@ -104,7 +104,14 @@
     <style
         name="MainKeyboardView"
         parent="KeyboardView" />
-    <style name="EmojiKeyboardView" />
+    <!-- Though {@link EmojiKeyboardView} doesn't extend {@link KeyboardView}, some views inside it,
+         for instance delete button, need themed {@link KeyboardView} attributes. -->
+    <style
+        name="EmojiKeyboardView"
+        parent="KeyboardView"
+    >
+        <item name="emojiTabLabelColor">@color/emoji_tab_label_color_ics</item>
+    </style>
     <style name="MoreKeysKeyboard" />
     <style
         name="MoreKeysKeyboardView"
diff --git a/java/res/values/themes-gb.xml b/java/res/values/themes-gb.xml
index d39003d949bc20f0ed34fa2bb839c0773a10bb16..7f8dd235b44009b810eb4c532b5569c887fc7c04 100644
--- a/java/res/values/themes-gb.xml
+++ b/java/res/values/themes-gb.xml
@@ -96,6 +96,8 @@
         <item name="spacebarTextColor">@color/spacebar_text_color_gb</item>
         <item name="spacebarTextShadowColor">@color/spacebar_text_shadow_color_gb</item>
     </style>
+    <!-- Though {@link EmojiKeyboardView} doesn't extend {@link KeyboardView}, some views inside it,
+         for instance delete button, need themed {@link KeyboardView} attributes. -->
     <style
         name="EmojiKeyboardView.GB"
         parent="KeyboardView.GB"
diff --git a/java/res/values/themes-ics.xml b/java/res/values/themes-ics.xml
index f5b74838bdf22dea2d1ff224446609197fae62e8..f3b6b13212cd09346f2fb945a62c8461655b4bb0 100644
--- a/java/res/values/themes-ics.xml
+++ b/java/res/values/themes-ics.xml
@@ -97,6 +97,8 @@
         <item name="spacebarTextColor">@color/spacebar_text_color_ics</item>
         <item name="spacebarTextShadowColor">@color/spacebar_text_shadow_color_ics</item>
     </style>
+    <!-- Though {@link EmojiKeyboardView} doesn't extend {@link KeyboardView}, some views inside it,
+         for instance delete button, need themed {@link KeyboardView} attributes. -->
     <style
         name="EmojiKeyboardView.ICS"
         parent="KeyboardView.ICS"
diff --git a/java/res/xml-sw600dp/key_f2.xml b/java/res/xml-sw600dp/key_f2.xml
index ca3b30b54487cd8b86887e262c161d984f8b153c..56f233da965a1e9d0d482786dcaef90913d445b9 100644
--- a/java/res/xml-sw600dp/key_f2.xml
+++ b/java/res/xml-sw600dp/key_f2.xml
@@ -39,7 +39,7 @@
         </case>
         <default>
             <Key
-                latin:keyStyle="smileyKeyStyle" />
+                latin:keyStyle="emojiKeyStyle" />
         </default>
     </switch>
 </merge>
diff --git a/java/res/xml-sw600dp/key_styles_common.xml b/java/res/xml-sw600dp/key_styles_common.xml
index fc9342b91fb1f7099161f23cd077b98d4253ca3c..3b20281bead809f7dc8d92669b7409acd4f3d372 100644
--- a/java/res/xml-sw600dp/key_styles_common.xml
+++ b/java/res/xml-sw600dp/key_styles_common.xml
@@ -123,7 +123,8 @@
         latin:styleName="emojiKeyStyle"
         latin:code="!code/key_emoji"
         latin:keyIcon="!icon/emoji_key"
-        latin:keyActionFlags="noKeyPreview" />
+        latin:keyActionFlags="noKeyPreview"
+        latin:backgroundType="functional" />
     <key-style
         latin:styleName="settingsKeyStyle"
         latin:code="!code/key_settings"
diff --git a/java/res/xml-sw768dp/key_styles_common.xml b/java/res/xml-sw768dp/key_styles_common.xml
index 538930948267ef7722c5b5513ca5d5f54dc9bcb0..5ee9ac591fe6bd4c67a593d4ad156d7c5198c3f3 100644
--- a/java/res/xml-sw768dp/key_styles_common.xml
+++ b/java/res/xml-sw768dp/key_styles_common.xml
@@ -113,7 +113,8 @@
         latin:styleName="emojiKeyStyle"
         latin:code="!code/key_emoji"
         latin:keyIcon="!icon/emoji_key"
-        latin:keyActionFlags="noKeyPreview" />
+        latin:keyActionFlags="noKeyPreview"
+        latin:backgroundType="functional" />
     <key-style
         latin:styleName="settingsKeyStyle"
         latin:code="!code/key_settings"
diff --git a/java/res/xml/key_styles_common.xml b/java/res/xml/key_styles_common.xml
index dabe1e7eb25e22211978b5d239212b61449478c7..c1c2c3e06b0d2116fc29ecf71d8f3ad8ad5ae283 100644
--- a/java/res/xml/key_styles_common.xml
+++ b/java/res/xml/key_styles_common.xml
@@ -67,30 +67,6 @@
         latin:backgroundType="functional" />
     <include
         latin:keyboardLayout="@xml/key_styles_enter" />
-    <switch>
-        <!-- Shift + Enter in textMultiLine field. -->
-        <case
-            latin:isMultiLine="true"
-            latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLockShifted"
-        >
-            <key-style
-                latin:styleName="enterKeyStyle"
-                latin:parentStyle="shiftEnterKeyStyle" />
-        </case>
-        <!-- Smiley in textShortMessage field.
-             Overrides common enter key style. -->
-        <case
-            latin:mode="im"
-        >
-            <key-style
-                latin:styleName="enterKeyStyle"
-                latin:keyLabel=":-)"
-                latin:keyOutputText=":-) "
-                latin:keyLabelFlags="hasPopupHint"
-                latin:moreKeys="!text/more_keys_for_smiley"
-                latin:backgroundType="functional" />
-        </case>
-    </switch>
     <key-style
         latin:styleName="spaceKeyStyle"
         latin:code="!code/key_space"
@@ -129,7 +105,8 @@
         latin:styleName="emojiKeyStyle"
         latin:code="!code/key_emoji"
         latin:keyIcon="!icon/emoji_key"
-        latin:keyActionFlags="noKeyPreview" />
+        latin:keyActionFlags="noKeyPreview"
+        latin:backgroundType="functional" />
     <key-style
         latin:styleName="tabKeyStyle"
         latin:code="!code/key_tab"
diff --git a/java/res/xml/row_symbols4.xml b/java/res/xml/row_symbols4.xml
index 5c15da6a5eb90d2f33173228f1d043d03be345da..bea139aba616680ee5a1f0d0cc756cfc46934601 100644
--- a/java/res/xml/row_symbols4.xml
+++ b/java/res/xml/row_symbols4.xml
@@ -50,7 +50,7 @@
             latin:keyboardLayout="@xml/key_symbols_period"
             latin:backgroundType="functional" />
         <Key
-            latin:keyStyle="enterKeyStyle"
+            latin:keyStyle="emojiKeyStyle"
             latin:keyWidth="fillRight" />
     </Row>
 </merge>
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index 098c8b3df1c887ca74ff43241dc46e2132d7a1fe..0208249d1bd21810ecb8bb78bba80c9592d38569 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -66,7 +66,9 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
     private SharedPreferences mPrefs;
 
     private InputView mCurrentInputView;
+    private View mMainKeyboardFrame;
     private MainKeyboardView mKeyboardView;
+    private EmojiKeyboardView mEmojiKeyboardView;
     private LatinIME mLatinIME;
     private Resources mResources;
 
@@ -167,6 +169,8 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
     }
 
     private void setKeyboard(final Keyboard keyboard) {
+        // Make {@link MainKeyboardView} visible and hide {@link EmojiKeyboardView}.
+        setMainKeyboardFrame();
         final MainKeyboardView keyboardView = mKeyboardView;
         final Keyboard oldKeyboard = keyboardView.getKeyboard();
         keyboardView.setKeyboard(keyboard);
@@ -253,6 +257,18 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
         setKeyboard(mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_SYMBOLS));
     }
 
+    private void setMainKeyboardFrame() {
+        mMainKeyboardFrame.setVisibility(View.VISIBLE);
+        mEmojiKeyboardView.setVisibility(View.GONE);
+    }
+
+    // Implements {@link KeyboardState.SwitchActions}.
+    @Override
+    public void setEmojiKeyboard() {
+        mMainKeyboardFrame.setVisibility(View.GONE);
+        mEmojiKeyboardView.setVisibility(View.VISIBLE);
+    }
+
     // Implements {@link KeyboardState.SwitchActions}.
     @Override
     public void requestUpdatingShiftState() {
@@ -304,10 +320,16 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
         setContextThemeWrapper(mLatinIME, mKeyboardTheme);
         mCurrentInputView = (InputView)LayoutInflater.from(mThemeContext).inflate(
                 R.layout.input_view, null);
+        mMainKeyboardFrame = mCurrentInputView.findViewById(R.id.main_keyboard_frame);
+        mEmojiKeyboardView = (EmojiKeyboardView)mCurrentInputView.findViewById(
+                R.id.emoji_keyboard_view);
 
         mKeyboardView = (MainKeyboardView) mCurrentInputView.findViewById(R.id.keyboard_view);
         mKeyboardView.setHardwareAcceleratedDrawingEnabled(isHardwareAcceleratedDrawingEnabled);
         mKeyboardView.setKeyboardActionListener(mLatinIME);
+        mEmojiKeyboardView.setHardwareAcceleratedDrawingEnabled(
+                isHardwareAcceleratedDrawingEnabled);
+        mEmojiKeyboardView.setKeyboardActionListener(mLatinIME);
 
         // This always needs to be set since the accessibility state can
         // potentially change without the input view being re-created.
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
index 0b10a1d1aa26bb854fcbc1137a888e8537a587ac..089db12a2851333b5fea4b06d09da6c59ea9d87a 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
@@ -46,6 +46,7 @@ public final class KeyboardState {
         public void setAlphabetShiftLockedKeyboard();
         public void setAlphabetShiftLockShiftedKeyboard();
         public void setSymbolsKeyboard();
+        public void setEmojiKeyboard();
 
         /**
          * Request to call back {@link KeyboardState#onUpdateShiftState(int, int)}.
@@ -71,7 +72,10 @@ public final class KeyboardState {
     private static final int SWITCH_STATE_MOMENTARY_ALPHA_SHIFT = 5;
     private int mSwitchState = SWITCH_STATE_ALPHA;
 
+    // TODO: Consolidate these two mode booleans into one integer to distinguish between alphabet,
+    // symbols, and emoji mode.
     private boolean mIsAlphabetMode;
+    private boolean mIsEmojiMode;
     private AlphabetShiftState mAlphabetShiftState = new AlphabetShiftState();
     private boolean mPrevMainKeyboardWasShiftLocked;
     private int mRecapitalizeMode;
@@ -86,6 +90,7 @@ public final class KeyboardState {
         public boolean mIsValid;
         public boolean mIsAlphabetMode;
         public boolean mIsAlphabetShiftLocked;
+        public boolean mIsEmojiMode;
         public int mShiftMode;
 
         @Override
@@ -94,6 +99,8 @@ public final class KeyboardState {
             if (mIsAlphabetMode) {
                 if (mIsAlphabetShiftLocked) return "ALPHABET_SHIFT_LOCKED";
                 return "ALPHABET_" + shiftModeToString(mShiftMode);
+            } else if (mIsEmojiMode) {
+                return "EMOJI";
             } else {
                 return "SYMBOLS";
             }
@@ -125,6 +132,7 @@ public final class KeyboardState {
     public void onSaveKeyboardState() {
         final SavedKeyboardState state = mSavedKeyboardState;
         state.mIsAlphabetMode = mIsAlphabetMode;
+        state.mIsEmojiMode = mIsEmojiMode;
         if (mIsAlphabetMode) {
             state.mIsAlphabetShiftLocked = mAlphabetShiftState.isShiftLocked();
             state.mShiftMode = mAlphabetShiftState.isAutomaticShifted() ? AUTOMATIC_SHIFT
@@ -145,6 +153,8 @@ public final class KeyboardState {
         }
         if (!state.mIsValid || state.mIsAlphabetMode) {
             setAlphabetKeyboard();
+        } else if (state.mIsEmojiMode) {
+            setEmojiKeyboard();
         } else {
             setSymbolsKeyboard();
         }
@@ -254,6 +264,7 @@ public final class KeyboardState {
 
         mSwitchActions.setAlphabetKeyboard();
         mIsAlphabetMode = true;
+        mIsEmojiMode = false;
         mRecapitalizeMode = RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE;
         mSwitchState = SWITCH_STATE_ALPHA;
         mSwitchActions.requestUpdatingShiftState();
@@ -270,6 +281,15 @@ public final class KeyboardState {
         mSwitchState = SWITCH_STATE_SYMBOL_BEGIN;
     }
 
+    private void setEmojiKeyboard() {
+        if (DEBUG_ACTION) {
+            Log.d(TAG, "setEmojiKeyboard");
+        }
+        mIsAlphabetMode = false;
+        mIsEmojiMode = true;
+        mSwitchActions.setEmojiKeyboard();
+    }
+
     public void onPressKey(final int code, final boolean isSinglePointer, final int autoCaps) {
         if (DEBUG_EVENT) {
             Log.d(TAG, "onPressKey: code=" + Constants.printableCode(code)
@@ -547,6 +567,8 @@ public final class KeyboardState {
         // If the code is a letter, update keyboard shift state.
         if (Constants.isLetterCode(code)) {
             updateAlphabetShiftState(autoCaps, RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE);
+        } else if (code == Constants.CODE_EMOJI) {
+            setEmojiKeyboard();
         }
     }
 
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 25fdf57bc689f511676de95599f3de99c55bbd5e..fbf75b1c2e4a3febe5d1796e8f059f2b132bc613 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -1549,7 +1549,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
             handleLanguageSwitchKey();
             break;
         case Constants.CODE_EMOJI:
-            // TODO: Implement emoji keyboard switch.
+            // Note: Switching emoji keyboard is being handled in
+            // {@link KeyboardState#onCodeInput(int,int)}.
             break;
         case Constants.CODE_ENTER:
             final EditorInfo editorInfo = getCurrentInputEditorInfo();
diff --git a/tests/src/com/android/inputmethod/keyboard/internal/MockKeyboardSwitcher.java b/tests/src/com/android/inputmethod/keyboard/internal/MockKeyboardSwitcher.java
index 682d8fc634ea7449145c4a172ca07699a72d10de..b209b00853014cacc6fe6961c158b6b2e2170e5b 100644
--- a/tests/src/com/android/inputmethod/keyboard/internal/MockKeyboardSwitcher.java
+++ b/tests/src/com/android/inputmethod/keyboard/internal/MockKeyboardSwitcher.java
@@ -112,6 +112,11 @@ public class MockKeyboardSwitcher implements KeyboardState.SwitchActions {
         mLayout = MockConstants.SYMBOLS;
     }
 
+    @Override
+    public void setEmojiKeyboard() {
+        // Just ignore.
+    }
+
     @Override
     public void requestUpdatingShiftState() {
         mState.onUpdateShiftState(mAutoCapsState, RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE);