merge in jb-release history after reset to jb-dev
diff --git a/java/res/values-hdpi/keyboard_key_feedback_background_holo.xml b/java/res/values-hdpi/keyboard_key_feedback_background_holo.xml
deleted file mode 100644
index 8ab3226..0000000
--- a/java/res/values-hdpi/keyboard_key_feedback_background_holo.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 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.
-*/
--->
-
-<resources>
-    <dimen name="keyboard_key_feedback_background_holo_width">46.67dp</dimen>
-    <dimen name="keyboard_key_feedback_background_holo_height">58.67dp</dimen>
-</resources>
diff --git a/java/res/values-land/dimens.xml b/java/res/values-land/dimens.xml
index 1157b27..6259725 100644
--- a/java/res/values-land/dimens.xml
+++ b/java/res/values-land/dimens.xml
@@ -53,7 +53,7 @@
     <fraction name="key_uppercase_letter_ratio">40%</fraction>
     <fraction name="key_preview_text_ratio">90%</fraction>
     <fraction name="spacebar_text_ratio">40.000%</fraction>
-    <dimen name="key_preview_offset">12.8dp</dimen>
+    <dimen name="key_preview_offset">0.0dp</dimen>
 
     <dimen name="key_preview_offset_ics">1.6dp</dimen>
     <!-- popup_key_height x -0.5 -->
diff --git a/java/res/values-mdpi/keyboard_key_feedback_background_holo.xml b/java/res/values-mdpi/keyboard_key_feedback_background_holo.xml
deleted file mode 100644
index 10fef3d..0000000
--- a/java/res/values-mdpi/keyboard_key_feedback_background_holo.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 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.
-*/
--->
-
-<resources>
-    <dimen name="keyboard_key_feedback_background_holo_width">46dp</dimen>
-    <dimen name="keyboard_key_feedback_background_holo_height">58dp</dimen>
-</resources>
diff --git a/java/res/values-xhdpi/keyboard_key_feedback_background_holo.xml b/java/res/values-xhdpi/keyboard_key_feedback_background_holo.xml
deleted file mode 100644
index fba6026..0000000
--- a/java/res/values-xhdpi/keyboard_key_feedback_background_holo.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 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.
-*/
--->
-
-<resources>
-    <dimen name="keyboard_key_feedback_background_holo_width">47dp</dimen>
-    <dimen name="keyboard_key_feedback_background_holo_height">57dp</dimen>
-</resources>
diff --git a/java/res/values/attrs.xml b/java/res/values/attrs.xml
index 844b8e9..4bf5414 100644
--- a/java/res/values/attrs.xml
+++ b/java/res/values/attrs.xml
@@ -91,10 +91,6 @@
         <attr name="keyPreviewLeftBackground" format="reference" />
         <!-- The background for the right edge key press feedback. -->
         <attr name="keyPreviewRightBackground" format="reference" />
-        <!-- The width of rectangle part of the key press feedback background. -->
-        <attr name="keyPreviewBackgroundWidth" format="dimension" />
-        <!-- The height of rectangle part of the key press feedback background. -->
-        <attr name="keyPreviewBackgroundHeight" format="dimension" />
         <!-- The text color for key press feedback. -->
         <attr name="keyPreviewTextColor" format="color" />
         <!-- Vertical offset of the key press feedback from the key. -->
diff --git a/java/res/values/dimens.xml b/java/res/values/dimens.xml
index 7eb57c3..d8d58df 100644
--- a/java/res/values/dimens.xml
+++ b/java/res/values/dimens.xml
@@ -27,7 +27,6 @@
 
     <dimen name="popup_key_height">52.8dp</dimen>
 
-    <dimen name="more_keys_keyboard_horizontal_edges_padding">16dp</dimen>
     <dimen name="more_keys_keyboard_key_horizontal_padding">8dp</dimen>
 
     <fraction name="keyboard_top_padding">1.556%p</fraction>
@@ -66,7 +65,7 @@
     <fraction name="key_preview_text_ratio">82%</fraction>
     <fraction name="spacebar_text_ratio">33.735%</fraction>
     <dimen name="key_preview_height">80dp</dimen>
-    <dimen name="key_preview_offset">16.0dp</dimen>
+    <dimen name="key_preview_offset">-8.0dp</dimen>
 
     <dimen name="key_label_horizontal_padding">4dp</dimen>
     <dimen name="key_hint_letter_padding">1dp</dimen>
diff --git a/java/res/values/styles.xml b/java/res/values/styles.xml
index 1f8c375..b3c921e 100644
--- a/java/res/values/styles.xml
+++ b/java/res/values/styles.xml
@@ -108,8 +108,6 @@
     </style>
     <style name="MoreKeysKeyboardPanelStyle">
         <item name="android:background">@drawable/keyboard_popup_panel_background</item>
-        <item name="android:paddingLeft">@dimen/more_keys_keyboard_horizontal_edges_padding</item>
-        <item name="android:paddingRight">@dimen/more_keys_keyboard_horizontal_edges_padding</item>
     </style>
     <style name="SuggestionsStripBackgroundStyle">
         <item name="android:background">@drawable/keyboard_suggest_strip</item>
@@ -311,8 +309,6 @@
         <item name="keyPreviewBackground">@drawable/keyboard_key_feedback_ics</item>
         <item name="keyPreviewLeftBackground">@drawable/keyboard_key_feedback_left_ics</item>
         <item name="keyPreviewRightBackground">@drawable/keyboard_key_feedback_right_ics</item>
-        <item name="keyPreviewBackgroundWidth">@dimen/keyboard_key_feedback_background_holo_width</item>
-        <item name="keyPreviewBackgroundHeight">@dimen/keyboard_key_feedback_background_holo_height</item>
         <item name="keyPreviewTextColor">#FFFFFFFF</item>
         <item name="keyPreviewOffset">@dimen/key_preview_offset_ics</item>
         <item name="shadowColor">#00000000</item>
@@ -346,8 +342,6 @@
     </style>
     <style name="MoreKeysKeyboardPanelStyle.IceCreamSandwich">
         <item name="android:background">@drawable/keyboard_popup_panel_background_holo</item>
-        <item name="android:paddingLeft">@dimen/more_keys_keyboard_horizontal_edges_padding_ics</item>
-        <item name="android:paddingRight">@dimen/more_keys_keyboard_horizontal_edges_padding_ics</item>
     </style>
     <style name="SuggestionsStripBackgroundStyle.IceCreamSandwich">
         <item name="android:background">@drawable/keyboard_suggest_strip_holo</item>
diff --git a/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java b/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java
index 667b109..2ea7d83 100644
--- a/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java
+++ b/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java
@@ -58,7 +58,6 @@
         // These only need to be initialized if the kill switch is off.
         sInstance.initInternal(inputMethod);
         KeyCodeDescriptionMapper.init();
-        AccessibleInputMethodServiceProxy.init(inputMethod);
         AccessibleKeyboardViewProxy.init(inputMethod);
     }
 
diff --git a/java/src/com/android/inputmethod/accessibility/AccessibleInputMethodServiceProxy.java b/java/src/com/android/inputmethod/accessibility/AccessibleInputMethodServiceProxy.java
deleted file mode 100644
index 961176b..0000000
--- a/java/src/com/android/inputmethod/accessibility/AccessibleInputMethodServiceProxy.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * 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.accessibility;
-
-import android.content.Context;
-import android.inputmethodservice.InputMethodService;
-import android.media.AudioManager;
-import android.os.Vibrator;
-import android.view.KeyEvent;
-
-public class AccessibleInputMethodServiceProxy implements AccessibleKeyboardActionListener {
-    private static final AccessibleInputMethodServiceProxy sInstance =
-            new AccessibleInputMethodServiceProxy();
-
-    /**
-     * Duration of the key click vibration in milliseconds.
-     */
-    private static final long VIBRATE_KEY_CLICK = 50;
-
-    private static final float FX_VOLUME = -1.0f;
-
-    private InputMethodService mInputMethod;
-    private Vibrator mVibrator;
-    private AudioManager mAudioManager;
-
-    public static void init(InputMethodService inputMethod) {
-        sInstance.initInternal(inputMethod);
-    }
-
-    public static AccessibleInputMethodServiceProxy getInstance() {
-        return sInstance;
-    }
-
-    private AccessibleInputMethodServiceProxy() {
-        // Not publicly instantiable.
-    }
-
-    private void initInternal(InputMethodService inputMethod) {
-        mInputMethod = inputMethod;
-        mVibrator = (Vibrator) inputMethod.getSystemService(Context.VIBRATOR_SERVICE);
-        mAudioManager = (AudioManager) inputMethod.getSystemService(Context.AUDIO_SERVICE);
-    }
-
-    /**
-     * Handle flick gestures by mapping them to directional pad keys.
-     */
-    @Override
-    public void onFlickGesture(int direction) {
-        switch (direction) {
-        case FlickGestureDetector.FLICK_LEFT:
-            sendDownUpKeyEvents(KeyEvent.KEYCODE_DPAD_LEFT);
-            break;
-        case FlickGestureDetector.FLICK_RIGHT:
-            sendDownUpKeyEvents(KeyEvent.KEYCODE_DPAD_RIGHT);
-            break;
-        }
-    }
-
-    /**
-     * Provide haptic feedback and send the specified keyCode to the input
-     * connection as a pair of down/up events.
-     *
-     * @param keyCode
-     */
-    private void sendDownUpKeyEvents(int keyCode) {
-        mVibrator.vibrate(VIBRATE_KEY_CLICK);
-        mAudioManager.playSoundEffect(AudioManager.FX_KEYPRESS_STANDARD, FX_VOLUME);
-        mInputMethod.sendDownUpKeyEvents(keyCode);
-    }
-}
diff --git a/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardActionListener.java b/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardActionListener.java
deleted file mode 100644
index 31d17d0..0000000
--- a/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardActionListener.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * 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.accessibility;
-
-public interface AccessibleKeyboardActionListener {
-    /**
-     * @param direction the direction of the flick gesture, one of
-     *            <ul>
-     *              <li>{@link FlickGestureDetector#FLICK_UP}
-     *              <li>{@link FlickGestureDetector#FLICK_DOWN}
-     *              <li>{@link FlickGestureDetector#FLICK_LEFT}
-     *              <li>{@link FlickGestureDetector#FLICK_RIGHT}
-     *            </ul>
-     */
-    public void onFlickGesture(int direction);
-}
diff --git a/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java b/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java
index c85a551..ba814e3 100644
--- a/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java
+++ b/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java
@@ -17,8 +17,6 @@
 package com.android.inputmethod.accessibility;
 
 import android.content.Context;
-import android.graphics.Color;
-import android.graphics.Paint;
 import android.inputmethodservice.InputMethodService;
 import android.support.v4.view.AccessibilityDelegateCompat;
 import android.support.v4.view.ViewCompat;
@@ -38,16 +36,13 @@
     private static final AccessibleKeyboardViewProxy sInstance = new AccessibleKeyboardViewProxy();
 
     private InputMethodService mInputMethod;
-    private FlickGestureDetector mGestureDetector;
     private LatinKeyboardView mView;
-    private AccessibleKeyboardActionListener mListener;
     private AccessibilityEntityProvider mAccessibilityNodeProvider;
 
     private Key mLastHoverKey = null;
 
     public static void init(InputMethodService inputMethod) {
         sInstance.initInternal(inputMethod);
-        sInstance.mListener = AccessibleInputMethodServiceProxy.getInstance();
     }
 
     public static AccessibleKeyboardViewProxy getInstance() {
@@ -59,14 +54,7 @@
     }
 
     private void initInternal(InputMethodService inputMethod) {
-        final Paint paint = new Paint();
-        paint.setTextAlign(Paint.Align.LEFT);
-        paint.setTextSize(14.0f);
-        paint.setAntiAlias(true);
-        paint.setColor(Color.YELLOW);
-
         mInputMethod = inputMethod;
-        mGestureDetector = new KeyboardFlickGestureDetector(inputMethod);
     }
 
     /**
@@ -112,19 +100,6 @@
      * @return {@code true} if the event is handled
      */
     public boolean dispatchHoverEvent(MotionEvent event, PointerTracker tracker) {
-        if (mGestureDetector.onHoverEvent(event, this, tracker))
-            return true;
-
-        return onHoverEventInternal(event, tracker);
-    }
-
-    /**
-     * Handles touch exploration events when Accessibility is turned on.
-     *
-     * @param event The touch exploration hover event.
-     * @return {@code true} if the event was handled
-     */
-    /* package */boolean onHoverEventInternal(MotionEvent event, PointerTracker tracker) {
         final int x = (int) event.getX();
         final int y = (int) event.getY();
         final Key key = tracker.getKeyOn(x, y);
@@ -214,20 +189,6 @@
         mView.getParent().requestSendAccessibilityEvent(mView, event);
     }
 
-    private class KeyboardFlickGestureDetector extends FlickGestureDetector {
-        public KeyboardFlickGestureDetector(Context context) {
-            super(context);
-        }
-
-        @Override
-        public boolean onFlick(MotionEvent e1, MotionEvent e2, int direction) {
-            if (mListener != null) {
-                mListener.onFlickGesture(direction);
-            }
-            return true;
-        }
-    }
-
     /**
      * Notifies the user of changes in the keyboard shift state.
      */
diff --git a/java/src/com/android/inputmethod/accessibility/FlickGestureDetector.java b/java/src/com/android/inputmethod/accessibility/FlickGestureDetector.java
deleted file mode 100644
index e8ec376..0000000
--- a/java/src/com/android/inputmethod/accessibility/FlickGestureDetector.java
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * 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.accessibility;
-
-import android.content.Context;
-import android.os.Message;
-import android.view.MotionEvent;
-import android.view.ViewConfiguration;
-
-import com.android.inputmethod.keyboard.PointerTracker;
-import com.android.inputmethod.latin.StaticInnerHandlerWrapper;
-
-/**
- * Detects flick gestures within a stream of hover events.
- * <p>
- * A flick gesture is defined as a stream of hover events with the following
- * properties:
- * <ul>
- *   <li>Begins with a {@link MotionEvent#ACTION_HOVER_ENTER} event
- *   <li>Contains any number of {@link MotionEvent#ACTION_HOVER_MOVE}
- *       events
- *   <li>Ends with a {@link MotionEvent#ACTION_HOVER_EXIT} event
- *   <li>Maximum duration of 250 milliseconds
- *   <li>Minimum distance between enter and exit points must be at least equal to
- *       scaled double tap slop (see
- *       {@link ViewConfiguration#getScaledDoubleTapSlop()})
- * </ul>
- * <p>
- * Initial enter events are intercepted and cached until the stream fails to
- * satisfy the constraints defined above, at which point the cached enter event
- * is sent to its source {@link AccessibleKeyboardViewProxy} and subsequent move
- * and exit events are ignored.
- */
-public abstract class FlickGestureDetector {
-    public static final int FLICK_UP = 0;
-    public static final int FLICK_RIGHT = 1;
-    public static final int FLICK_LEFT = 2;
-    public static final int FLICK_DOWN = 3;
-
-    private final FlickHandler mFlickHandler;
-    private final int mFlickRadiusSquare;
-
-    private AccessibleKeyboardViewProxy mCachedView;
-    private PointerTracker mCachedTracker;
-    private MotionEvent mCachedHoverEnter;
-
-    private static class FlickHandler extends StaticInnerHandlerWrapper<FlickGestureDetector> {
-        private static final int MSG_FLICK_TIMEOUT = 1;
-
-        /** The maximum duration of a flick gesture in milliseconds. */
-        private static final int DELAY_FLICK_TIMEOUT = 250;
-
-        public FlickHandler(FlickGestureDetector outerInstance) {
-            super(outerInstance);
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            final FlickGestureDetector gestureDetector = getOuterInstance();
-
-            switch (msg.what) {
-            case MSG_FLICK_TIMEOUT:
-                gestureDetector.clearFlick(true);
-            }
-        }
-
-        public void startFlickTimeout() {
-            cancelFlickTimeout();
-            sendEmptyMessageDelayed(MSG_FLICK_TIMEOUT, DELAY_FLICK_TIMEOUT);
-        }
-
-        public void cancelFlickTimeout() {
-            removeMessages(MSG_FLICK_TIMEOUT);
-        }
-    }
-
-    /**
-     * Creates a new flick gesture detector.
-     *
-     * @param context The parent context.
-     */
-    public FlickGestureDetector(Context context) {
-        final int doubleTapSlop = ViewConfiguration.get(context).getScaledDoubleTapSlop();
-
-        mFlickHandler = new FlickHandler(this);
-        mFlickRadiusSquare = doubleTapSlop * doubleTapSlop;
-    }
-
-    /**
-     * Processes motion events to detect flick gestures.
-     *
-     * @param event The current event.
-     * @param view The source of the event.
-     * @param tracker A pointer tracker for the event.
-     * @return {@code true} if the event was handled.
-     */
-    public boolean onHoverEvent(MotionEvent event, AccessibleKeyboardViewProxy view,
-            PointerTracker tracker) {
-        // Always cache and consume the first hover event.
-        if (event.getAction() == MotionEvent.ACTION_HOVER_ENTER) {
-            mCachedView = view;
-            mCachedTracker = tracker;
-            mCachedHoverEnter = MotionEvent.obtain(event);
-            mFlickHandler.startFlickTimeout();
-            return true;
-        }
-
-        // Stop if the event has already been canceled.
-        if (mCachedHoverEnter == null) {
-            return false;
-        }
-
-        final float distanceSquare = calculateDistanceSquare(mCachedHoverEnter, event);
-
-        switch (event.getAction()) {
-        case MotionEvent.ACTION_HOVER_MOVE:
-            // Consume all valid move events before timeout.
-            return true;
-        case MotionEvent.ACTION_HOVER_EXIT:
-            // Ignore exit events outside the flick radius.
-            if (distanceSquare < mFlickRadiusSquare) {
-                clearFlick(true);
-                return false;
-            } else {
-                return dispatchFlick(mCachedHoverEnter, event);
-            }
-        default:
-            return false;
-        }
-    }
-
-    /**
-     * Clears the cached flick information and optionally forwards the event to
-     * the source view's internal hover event handler.
-     *
-     * @param sendCachedEvent Set to {@code true} to forward the hover event to
-     *            the source view.
-     */
-    private void clearFlick(boolean sendCachedEvent) {
-        mFlickHandler.cancelFlickTimeout();
-
-        if (mCachedHoverEnter != null) {
-            if (sendCachedEvent) {
-                mCachedView.onHoverEventInternal(mCachedHoverEnter, mCachedTracker);
-            }
-            mCachedHoverEnter.recycle();
-            mCachedHoverEnter = null;
-        }
-
-        mCachedTracker = null;
-        mCachedView = null;
-    }
-
-    /**
-     * Computes the direction of a flick gesture and forwards it to
-     * {@link #onFlick(MotionEvent, MotionEvent, int)} for handling.
-     *
-     * @param e1 The {@link MotionEvent#ACTION_HOVER_ENTER} event where the flick started.
-     * @param e2 The {@link MotionEvent#ACTION_HOVER_EXIT} event where the flick ended.
-     * @return {@code true} if the flick event was handled.
-     */
-    private boolean dispatchFlick(MotionEvent e1, MotionEvent e2) {
-        clearFlick(false);
-
-        final float dX = e2.getX() - e1.getX();
-        final float dY = e2.getY() - e1.getY();
-        final int direction;
-
-        if (dY > dX) {
-            if (dY > -dX) {
-                direction = FLICK_DOWN;
-            } else {
-                direction = FLICK_LEFT;
-            }
-        } else {
-            if (dY > -dX) {
-                direction = FLICK_RIGHT;
-            } else {
-                direction = FLICK_UP;
-            }
-        }
-
-        return onFlick(e1, e2, direction);
-    }
-
-    private float calculateDistanceSquare(MotionEvent e1, MotionEvent e2) {
-        final float dX = e2.getX() - e1.getX();
-        final float dY = e2.getY() - e1.getY();
-        return (dX * dX) + (dY * dY);
-    }
-
-    /**
-     * Handles a detected flick gesture.
-     *
-     * @param e1 The {@link MotionEventCompatUtils#ACTION_HOVER_ENTER} event
-     *            where the flick started.
-     * @param e2 The {@link MotionEventCompatUtils#ACTION_HOVER_EXIT} event
-     *            where the flick ended.
-     * @param direction The direction of the flick event, one of:
-     *            <ul>
-     *              <li>{@link #FLICK_UP}
-     *              <li>{@link #FLICK_DOWN}
-     *              <li>{@link #FLICK_LEFT}
-     *              <li>{@link #FLICK_RIGHT}
-     *            </ul>
-     * @return {@code true} if the flick event was handled.
-     */
-    public abstract boolean onFlick(MotionEvent e1, MotionEvent e2, int direction);
-}
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
index 0d2e9f0..9be193b 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
@@ -272,8 +272,6 @@
         public final Drawable mPreviewBackground;
         public final Drawable mPreviewLeftBackground;
         public final Drawable mPreviewRightBackground;
-        public final int mPreviewBackgroundWidth;
-        public final int mPreviewBackgroundHeight;
         public final int mPreviewTextColor;
         public final int mPreviewOffset;
         public final int mPreviewHeight;
@@ -283,6 +281,31 @@
         private final float mPreviewTextRatio;
         private final float mKeyLetterRatio;
 
+        // The graphical geometry of the key preview.
+        // <-width->
+        // +-------+   ^
+        // |       |   |
+        // |preview| height (visible)
+        // |       |   |
+        // +       + ^ v
+        //  \     /  |offset
+        // +-\   /-+ v
+        // |  +-+  |
+        // |parent |
+        // |    key|
+        // +-------+
+        // The background of a {@link TextView} being used for a key preview may have invisible
+        // paddings. To align the more keys keyboard panel's visible part with the visible part of
+        // the background, we need to record the width and height of key preview that don't include
+        // invisible paddings.
+        public int mPreviewVisibleWidth;
+        public int mPreviewVisibleHeight;
+        // The key preview may have an arbitrary offset and its background that may have a bottom
+        // padding. To align the more keys keyboard and the key preview we also need to record the
+        // offset between the top edge of parent key and the bottom of the visible part of key
+        // preview background.
+        public int mPreviewVisibleOffset;
+
         public int mPreviewTextSize;
         public int mKeyLetterSize;
         public final int[] mCoordinates = new int[2];
@@ -298,10 +321,6 @@
             setAlpha(mPreviewBackground, PREVIEW_ALPHA);
             setAlpha(mPreviewLeftBackground, PREVIEW_ALPHA);
             setAlpha(mPreviewRightBackground, PREVIEW_ALPHA);
-            mPreviewBackgroundWidth = a.getDimensionPixelSize(
-                    R.styleable.KeyboardView_keyPreviewBackgroundWidth, 0);
-            mPreviewBackgroundHeight = a.getDimensionPixelSize(
-                    R.styleable.KeyboardView_keyPreviewBackgroundHeight, 0);
             mPreviewOffset = a.getDimensionPixelOffset(
                     R.styleable.KeyboardView_keyPreviewOffset, 0);
             mPreviewHeight = a.getDimensionPixelSize(
@@ -839,13 +858,6 @@
     }
 
     @Override
-    public void showKeyPreview(PointerTracker tracker) {
-        if (mShowKeyPreviewPopup) {
-            showKey(tracker);
-        }
-    }
-
-    @Override
     public void dismissKeyPreview(PointerTracker tracker) {
         mDrawingHandler.dismissKeyPreview(mDelayAfterPreview, tracker);
     }
@@ -861,7 +873,10 @@
                 keyPreview, ViewLayoutUtils.newLayoutParam(mPreviewPlacer, 0, 0));
     }
 
-    private void showKey(PointerTracker tracker) {
+    @Override
+    public void showKeyPreview(PointerTracker tracker) {
+        if (!mShowKeyPreviewPopup) return;
+
         final TextView previewText = tracker.getKeyPreviewText();
         // If the key preview has no parent view yet, add it to the ViewGroup which can place
         // key preview absolutely in SoftInputWindow.
@@ -878,8 +893,6 @@
             return;
 
         final KeyPreviewDrawParams params = mKeyPreviewDrawParams;
-        final int keyDrawX = key.mX + key.mVisualInsetsLeft;
-        final int keyDrawWidth = key.mWidth - key.mVisualInsetsLeft - key.mVisualInsetsRight;
         final String label = key.isShiftedLetterActivated() ? key.mHintLabel : key.mLabel;
         // What we show as preview should match what we show on a key top in onBufferDraw().
         if (label != null) {
@@ -902,13 +915,24 @@
 
         previewText.measure(
                 ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
-        final int previewWidth = Math.max(previewText.getMeasuredWidth(), keyDrawWidth
-                + previewText.getPaddingLeft() + previewText.getPaddingRight());
+        final int keyDrawWidth = key.mWidth - key.mVisualInsetsLeft - key.mVisualInsetsRight;
+        final int previewWidth = previewText.getMeasuredWidth();
         final int previewHeight = params.mPreviewHeight;
+        // The width and height of visible part of the key preview background. The content marker
+        // of the background 9-patch have to cover the visible part of the background.
+        params.mPreviewVisibleWidth = previewWidth - previewText.getPaddingLeft()
+                - previewText.getPaddingRight();
+        params.mPreviewVisibleHeight = previewHeight - previewText.getPaddingTop()
+                - previewText.getPaddingBottom();
+        // The distance between the top edge of the parent key and the bottom of the visible part
+        // of the key preview background.
+        params.mPreviewVisibleOffset = params.mPreviewOffset - previewText.getPaddingBottom();
         getLocationInWindow(params.mCoordinates);
-        int previewX = keyDrawX - (previewWidth - keyDrawWidth) / 2 + params.mCoordinates[0];
-        final int previewY = key.mY - previewHeight
-                + params.mCoordinates[1] + params.mPreviewOffset;
+        // The key preview is horizontally aligned with the center of the visible part of the
+        // parent key. If it doesn't fit in this {@link KeyboardView}, it is moved inward to fit and
+        // the left/right background is used if such background is specified.
+        int previewX = key.mX + key.mVisualInsetsLeft - (previewWidth - keyDrawWidth) / 2
+                + params.mCoordinates[0];
         if (previewX < 0) {
             previewX = 0;
             if (params.mPreviewLeftBackground != null) {
@@ -920,6 +944,10 @@
                 previewText.setBackgroundDrawable(params.mPreviewRightBackground);
             }
         }
+        // The key preview is placed vertically above the top edge of the parent key with an
+        // arbitrary offset.
+        final int previewY = key.mY - previewHeight + params.mPreviewOffset
+                + params.mCoordinates[1];
 
         // Set the preview background state
         previewText.getBackground().setState(
diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
index 84564c8..aeca839 100644
--- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
@@ -527,9 +527,8 @@
 
         final MoreKeysKeyboardView moreKeysKeyboardView =
                 (MoreKeysKeyboardView)container.findViewById(R.id.more_keys_keyboard_view);
-        final Keyboard parentKeyboard = getKeyboard();
-        final Keyboard moreKeysKeyboard = new MoreKeysKeyboard.Builder(
-                this, parentKeyboard.mMoreKeysTemplate, parentKey, parentKeyboard).build();
+        final Keyboard moreKeysKeyboard = new MoreKeysKeyboard.Builder(container, parentKey, this)
+                .build();
         moreKeysKeyboardView.setKeyboard(moreKeysKeyboard);
         container.measure(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
 
@@ -598,10 +597,19 @@
         mMoreKeysPanel = moreKeysPanel;
         mMoreKeysPanelPointerTrackerId = tracker.mPointerId;
 
-        final Keyboard keyboard = getKeyboard();
-        final int pointX = (mConfigShowMoreKeysKeyboardAtTouchedPoint) ? tracker.getLastX()
+        final boolean keyPreviewEnabled = isKeyPreviewPopupEnabled() && !parentKey.noKeyPreview();
+        // The more keys keyboard is usually horizontally aligned with the center of the parent key.
+        // If showMoreKeysKeyboardAtTouchedPoint is true and the key preview is disabled, the more
+        // keys keyboard is placed at the touch point of the parent key.
+        final int pointX = (mConfigShowMoreKeysKeyboardAtTouchedPoint && !keyPreviewEnabled)
+                ? tracker.getLastX()
                 : parentKey.mX + parentKey.mWidth / 2;
-        final int pointY = parentKey.mY - keyboard.mVerticalGap;
+        // The more keys keyboard is usually vertically aligned with the top edge of the parent key
+        // (plus vertical gap). If the key preview is enabled, the more keys keyboard is vertically
+        // aligned with the bottom edge of the visible part of the key preview.
+        final int pointY = parentKey.mY + (keyPreviewEnabled
+                ? mKeyPreviewDrawParams.mPreviewVisibleOffset
+                : -parentKey.mVerticalGap);
         moreKeysPanel.showMoreKeysPanel(
                 this, this, pointX, pointY, mMoreKeysWindow, mKeyboardActionListener);
         final int translatedX = moreKeysPanel.translateX(tracker.getLastX());
diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java
index 7154086..b6a06e1 100644
--- a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java
@@ -18,6 +18,7 @@
 
 import android.graphics.Paint;
 import android.graphics.drawable.Drawable;
+import android.view.View;
 
 import com.android.inputmethod.keyboard.internal.KeySpecParser.MoreKeySpec;
 import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
@@ -251,30 +252,38 @@
             }
         }
 
-        public Builder(KeyboardView view, int xmlId, Key parentKey, Keyboard parentKeyboard) {
-            super(view.getContext(), new MoreKeysKeyboardParams());
-            load(xmlId, parentKeyboard.mId);
+        /**
+         * The builder of MoreKeysKeyboard.
+         * @param containerView the container of {@link MoreKeysKeyboardView}.
+         * @param parentKey the {@link Key} that invokes more keys keyboard.
+         * @param parentKeyboardView the {@link KeyboardView} that contains the parentKey.
+         */
+        public Builder(View containerView, Key parentKey, KeyboardView parentKeyboardView) {
+            super(containerView.getContext(), new MoreKeysKeyboardParams());
+            final Keyboard parentKeyboard = parentKeyboardView.getKeyboard();
+            load(parentKeyboard.mMoreKeysTemplate, parentKeyboard.mId);
 
             // TODO: More keys keyboard's vertical gap is currently calculated heuristically.
             // Should revise the algorithm.
             mParams.mVerticalGap = parentKeyboard.mVerticalGap / 2;
             mParentKey = parentKey;
 
-            final int previewWidth = view.mKeyPreviewDrawParams.mPreviewBackgroundWidth;
-            final int previewHeight = view.mKeyPreviewDrawParams.mPreviewBackgroundHeight;
             final int width, height;
-            // Use pre-computed width and height if these values are available and more keys
-            // keyboard has only one key to mitigate visual flicker between key preview and more
-            // keys keyboard.
-            final boolean validKeyPreview = view.isKeyPreviewPopupEnabled()
-                    && !parentKey.noKeyPreview() && (previewWidth > 0) && (previewHeight > 0);
-            final boolean singleMoreKeyWithPreview = validKeyPreview
-                    && parentKey.mMoreKeys.length == 1;
+            final boolean singleMoreKeyWithPreview = parentKeyboardView.isKeyPreviewPopupEnabled()
+                    && !parentKey.noKeyPreview() && parentKey.mMoreKeys.length == 1;
             if (singleMoreKeyWithPreview) {
-                width = previewWidth;
-                height = previewHeight + mParams.mVerticalGap;
+                // Use pre-computed width and height if this more keys keyboard has only one key to
+                // mitigate visual flicker between key preview and more keys keyboard.
+                // Caveats for the visual assets: To achieve this effect, both the key preview
+                // backgrounds and the more keys keyboard panel background have the exact same
+                // left/right/top paddings. The bottom paddings of both backgrounds don't need to
+                // be considered because the vertical positions of both backgrounds were already
+                // adjusted with their bottom paddings deducted.
+                width = parentKeyboardView.mKeyPreviewDrawParams.mPreviewVisibleWidth;
+                height = parentKeyboardView.mKeyPreviewDrawParams.mPreviewVisibleHeight
+                        + mParams.mVerticalGap;
             } else {
-                width = getMaxKeyWidth(view, parentKey, mParams.mDefaultKeyWidth);
+                width = getMaxKeyWidth(parentKeyboardView, parentKey, mParams.mDefaultKeyWidth);
                 height = parentKeyboard.mMostCommonKeyHeight;
             }
             final int dividerWidth;
@@ -288,8 +297,9 @@
                 dividerWidth = 0;
             }
             mParams.setParameters(parentKey.mMoreKeys.length, parentKey.getMoreKeysColumn(),
-                    width, height, parentKey.mX + parentKey.mWidth / 2, view.getMeasuredWidth(),
-                    parentKey.isFixedColumnOrderMoreKeys(), dividerWidth);
+                    width, height, parentKey.mX + parentKey.mWidth / 2,
+                    parentKeyboardView.getMeasuredWidth(), parentKey.isFixedColumnOrderMoreKeys(),
+                    dividerWidth);
         }
 
         private static int getMaxKeyWidth(KeyboardView view, Key parentKey, int minKeyWidth) {
diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java
index e60fc95..b4fa86d 100644
--- a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java
@@ -141,10 +141,8 @@
         final MoreKeysKeyboard pane = (MoreKeysKeyboard)getKeyboard();
         final int defaultCoordX = pane.getDefaultCoordX();
         // The coordinates of panel's left-top corner in parentView's coordinate system.
-        final int x = pointX - defaultCoordX - container.getPaddingLeft()
-                + parentView.getPaddingLeft();
-        final int y = pointY - container.getMeasuredHeight() + container.getPaddingBottom()
-                + parentView.getPaddingTop();
+        final int x = pointX - defaultCoordX - container.getPaddingLeft();
+        final int y = pointY - container.getMeasuredHeight() + container.getPaddingBottom();
 
         window.setContentView(container);
         window.setWidth(container.getMeasuredWidth());
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
index 37d9b6a..c62c3dd 100644
--- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java
+++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
@@ -606,7 +606,7 @@
                         if (ProductionFlag.IS_EXPERIMENTAL) {
                             ResearchLogger.pointerTracker_onMoveEvent(x, y, lastX, lastY);
                         }
-                        onUpEventInternal(lastX, lastY, eventTime);
+                        onUpEventInternal();
                         onDownEventInternal(x, y, eventTime);
                     } else {
                         mKeyAlreadyProcessed = true;
@@ -646,7 +646,7 @@
             }
             queue.remove(this);
         }
-        onUpEventInternal(x, y, eventTime);
+        onUpEventInternal();
     }
 
     // Let this pointer tracker know that one of newer-than-this pointer trackers got an up event.
@@ -655,24 +655,15 @@
     public void onPhantomUpEvent(int x, int y, long eventTime) {
         if (DEBUG_EVENT)
             printTouchEvent("onPhntEvent:", x, y, eventTime);
-        onUpEventInternal(x, y, eventTime);
+        onUpEventInternal();
         mKeyAlreadyProcessed = true;
     }
 
-    private void onUpEventInternal(int x, int y, long eventTime) {
+    private void onUpEventInternal() {
         mTimerProxy.cancelKeyTimers();
         mIsInSlidingKeyInput = false;
-        final int keyX, keyY;
-        if (isMajorEnoughMoveToBeOnNewKey(x, y, onMoveKey(x, y))) {
-            keyX = x;
-            keyY = y;
-        } else {
-            // Use previous fixed key coordinates.
-            keyX = mKeyX;
-            keyY = mKeyY;
-        }
-        final Key key = onUpKey(keyX, keyY, eventTime);
-        setReleasedKeyGraphics(key);
+        // Release the last pressed key.
+        setReleasedKeyGraphics(mCurrentKey);
         if (mIsShowingMoreKeysPanel) {
             mDrawingProxy.dismissMoreKeysPanel();
             mIsShowingMoreKeysPanel = false;
@@ -680,7 +671,7 @@
         if (mKeyAlreadyProcessed)
             return;
         if (!mIsRepeatableKey) {
-            detectAndSendKey(key, keyX, keyY);
+            detectAndSendKey(mCurrentKey, mKeyX, mKeyY);
         }
     }
 
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 796d4ac..213c0ac 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -1026,13 +1026,25 @@
     }
 
     public boolean getCurrentAutoCapsState() {
+        if (!mSettingsValues.mAutoCap) return false;
+
+        final EditorInfo ei = getCurrentInputEditorInfo();
+        if (ei == null) return false;
+
+        final int inputType = ei.inputType;
+        if ((inputType & InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS) != 0) return true;
+
+        final boolean noNeedToCheckCapsMode = (inputType & (InputType.TYPE_TEXT_FLAG_CAP_SENTENCES
+                | InputType.TYPE_TEXT_FLAG_CAP_WORDS)) == 0;
+        if (noNeedToCheckCapsMode) return false;
+
         final InputConnection ic = getCurrentInputConnection();
-        EditorInfo ei = getCurrentInputEditorInfo();
-        if (mSettingsValues.mAutoCap && ic != null && ei != null
-                && ei.inputType != InputType.TYPE_NULL) {
-            return ic.getCursorCapsMode(ei.inputType) != 0;
-        }
-        return false;
+        if (ic == null) return false;
+        // TODO: This blocking IPC call is heavy. Consider doing this without using IPC calls.
+        // Note: getCursorCapsMode() returns the current capitalization mode that is any
+        // combination of CAP_MODE_CHARACTERS, CAP_MODE_WORDS, and CAP_MODE_SENTENCES. 0 means none
+        // of them.
+        return ic.getCursorCapsMode(inputType) != 0;
     }
 
     // "ic" may be null
@@ -1478,22 +1490,23 @@
             sendKeyCodePoint(Keyboard.CODE_SPACE);
         }
 
-        if ((isAlphabet(primaryCode)
+        // NOTE: isCursorTouchingWord() is a blocking IPC call, so it often takes several
+        // dozen milliseconds. Avoid calling it as much as possible, since we are on the UI
+        // thread here.
+        if (!isComposingWord && (isAlphabet(primaryCode)
                 || mSettingsValues.isSymbolExcludedFromWordSeparators(primaryCode))
                 && isSuggestionsRequested() && !isCursorTouchingWord()) {
-            if (!isComposingWord) {
-                // Reset entirely the composing state anyway, then start composing a new word unless
-                // the character is a single quote. The idea here is, single quote is not a
-                // separator and it should be treated as a normal character, except in the first
-                // position where it should not start composing a word.
-                isComposingWord = (Keyboard.CODE_SINGLE_QUOTE != primaryCode);
-                // Here we don't need to reset the last composed word. It will be reset
-                // when we commit this one, if we ever do; if on the other hand we backspace
-                // it entirely and resume suggestions on the previous word, we'd like to still
-                // have touch coordinates for it.
-                resetComposingState(false /* alsoResetLastComposedWord */);
-                clearSuggestions();
-            }
+            // Reset entirely the composing state anyway, then start composing a new word unless
+            // the character is a single quote. The idea here is, single quote is not a
+            // separator and it should be treated as a normal character, except in the first
+            // position where it should not start composing a word.
+            isComposingWord = (Keyboard.CODE_SINGLE_QUOTE != primaryCode);
+            // Here we don't need to reset the last composed word. It will be reset
+            // when we commit this one, if we ever do; if on the other hand we backspace
+            // it entirely and resume suggestions on the previous word, we'd like to still
+            // have touch coordinates for it.
+            resetComposingState(false /* alsoResetLastComposedWord */);
+            clearSuggestions();
         }
         if (isComposingWord) {
             mWordComposer.add(
diff --git a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java
index e64e7a6..8a29dcc 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java
@@ -149,10 +149,8 @@
         final MoreSuggestions pane = (MoreSuggestions)getKeyboard();
         final int defaultCoordX = pane.mOccupiedWidth / 2;
         // The coordinates of panel's left-top corner in parentView's coordinate system.
-        final int x = pointX - defaultCoordX - container.getPaddingLeft()
-                + parentView.getPaddingLeft();
-        final int y = pointY - container.getMeasuredHeight() + container.getPaddingBottom()
-                + parentView.getPaddingTop();
+        final int x = pointX - defaultCoordX - container.getPaddingLeft();
+        final int y = pointY - container.getMeasuredHeight() + container.getPaddingBottom();
 
         window.setContentView(container);
         window.setWidth(container.getMeasuredWidth());