diff --git a/java/res/layout/input_view.xml b/java/res/layout/input_view.xml
index 13560e0cfaa5f7b58538c630d276a997d40a8820..2e0cddc282fa2c68a027c95ec6ec729e49567667 100644
--- a/java/res/layout/input_view.xml
+++ b/java/res/layout/input_view.xml
@@ -18,7 +18,7 @@
 */
 -->
 
-<LinearLayout
+<com.android.inputmethod.latin.InputView
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
     android:orientation="vertical"
@@ -61,4 +61,4 @@
         android:layout_alignParentBottom="true"
         android:layout_width="match_parent"
         android:layout_height="wrap_content" />
-</LinearLayout>
+</com.android.inputmethod.latin.InputView>
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index 2d123699e06e52f255dd3b2157cc4a42e722b86d..a4684358dc54f194283aef82aa809a62a5fb3384 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -32,6 +32,7 @@ import android.view.inputmethod.EditorInfo;
 import com.android.inputmethod.accessibility.AccessibleKeyboardViewProxy;
 import com.android.inputmethod.keyboard.internal.ModifierKeyState;
 import com.android.inputmethod.keyboard.internal.ShiftKeyState;
+import com.android.inputmethod.latin.InputView;
 import com.android.inputmethod.latin.LatinIME;
 import com.android.inputmethod.latin.LatinImeLogger;
 import com.android.inputmethod.latin.LocaleUtils;
@@ -62,7 +63,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
     private SubtypeSwitcher mSubtypeSwitcher;
     private SharedPreferences mPrefs;
 
-    private View mCurrentInputView;
+    private InputView mCurrentInputView;
     private LatinKeyboardView mKeyboardView;
     private LatinIME mInputMethodService;
     private String mPackageName;
@@ -230,6 +231,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
     private void setKeyboard(final Keyboard keyboard) {
         final Keyboard oldKeyboard = mKeyboardView.getKeyboard();
         mKeyboardView.setKeyboard(keyboard);
+        mCurrentInputView.setKeyboardGeometry(keyboard.mTopPadding);
         mCurrentId = keyboard.mId;
         mSwitchState = getSwitchState(mCurrentId);
         updateShiftLockState(keyboard);
@@ -762,7 +764,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
         for (int i = 0; i < Utils.GCUtils.GC_TRY_LOOP_MAX && tryGC; ++i) {
             try {
                 setContextThemeWrapper(mInputMethodService, newThemeIndex);
-                mCurrentInputView = LayoutInflater.from(mThemeContext).inflate(
+                mCurrentInputView = (InputView)LayoutInflater.from(mThemeContext).inflate(
                         R.layout.input_view, null);
                 tryGC = false;
             } catch (OutOfMemoryError e) {
diff --git a/java/src/com/android/inputmethod/latin/InputView.java b/java/src/com/android/inputmethod/latin/InputView.java
new file mode 100644
index 0000000000000000000000000000000000000000..0dcb811b51cc8b35fc344c9cb5ef4134465ca056
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/InputView.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2011 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.latin;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.LinearLayout;
+
+public class InputView extends LinearLayout {
+    private View mSuggestionsContainer;
+    private View mKeyboardView;
+    private int mKeyboardTopPadding;
+
+    private boolean mIsForwardingEvent;
+    private final Rect mInputViewRect = new Rect();
+    private final Rect mEventForwardingRect = new Rect();
+    private final Rect mEventReceivingRect = new Rect();
+
+    public InputView(Context context, AttributeSet attrs) {
+        super(context, attrs, 0);
+    }
+
+    public void setKeyboardGeometry(int keyboardTopPadding) {
+        mKeyboardTopPadding = keyboardTopPadding;
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        mSuggestionsContainer = findViewById(R.id.suggestions_container);
+        mKeyboardView = findViewById(R.id.keyboard_view);
+    }
+
+    @Override
+    public boolean dispatchTouchEvent(MotionEvent me) {
+        if (mSuggestionsContainer.getVisibility() == VISIBLE
+                && mKeyboardView.getVisibility() == VISIBLE
+                && forwardTouchEvent(me)) {
+            return true;
+        }
+        return super.dispatchTouchEvent(me);
+    }
+
+    // The touch events that hit the top padding of keyboard should be forwarded to SuggestionsView.
+    private boolean forwardTouchEvent(MotionEvent me) {
+        final Rect rect = mInputViewRect;
+        this.getGlobalVisibleRect(rect);
+        final int x = (int)me.getX() + rect.left;
+        final int y = (int)me.getY() + rect.top;
+
+        final Rect forwardingRect = mEventForwardingRect;
+        mKeyboardView.getGlobalVisibleRect(forwardingRect);
+        if (!mIsForwardingEvent && !forwardingRect.contains(x, y)) {
+            return false;
+        }
+
+        final int forwardingLimitY = forwardingRect.top + mKeyboardTopPadding;
+        boolean sendToTarget = false;
+
+        switch (me.getAction()) {
+        case MotionEvent.ACTION_DOWN:
+            if (y < forwardingLimitY) {
+                // This down event and further move and up events should be forwarded to the target.
+                mIsForwardingEvent = true;
+                sendToTarget = true;
+            }
+            break;
+        case MotionEvent.ACTION_MOVE:
+            sendToTarget = mIsForwardingEvent;
+            break;
+        case MotionEvent.ACTION_UP:
+        case MotionEvent.ACTION_CANCEL:
+            sendToTarget = mIsForwardingEvent;
+            mIsForwardingEvent = false;
+            break;
+        }
+
+        if (!sendToTarget) {
+            return false;
+        }
+
+        final Rect receivingRect = mEventReceivingRect;
+        mSuggestionsContainer.getGlobalVisibleRect(receivingRect);
+        final int translatedX = x - receivingRect.left;
+        final int translatedY;
+        if (y < forwardingLimitY) {
+            // The forwarded event should have coordinates that are inside of the target.
+            translatedY = Math.min(y - receivingRect.top, receivingRect.height() - 1);
+        } else {
+            translatedY = y - receivingRect.top;
+        }
+        me.setLocation(translatedX, translatedY);
+        mSuggestionsContainer.dispatchTouchEvent(me);
+        return true;
+    }
+}