LatinIME portion of "green plus" feature.

Removes the feature that adds strings to the user dictionary,
aka the "green highlight with a plus sign".

Bug 19237189.

Change-Id: I2387129a3add2d69d625f2ff16ed8cab3f10a735
diff --git a/java/res/layout/suggestions_strip.xml b/java/res/layout/suggestions_strip.xml
index aefdb8ca..47e9a91 100644
--- a/java/res/layout/suggestions_strip.xml
+++ b/java/res/layout/suggestions_strip.xml
@@ -33,30 +33,6 @@
         android:soundEffectsEnabled="false" />
     <!-- Provide audio and haptic feedback by ourselves based on the keyboard settings.
          We just need to ignore the system's audio and haptic feedback settings. -->
-    <LinearLayout
-        android:id="@+id/add_to_dictionary_strip"
-        android:orientation="horizontal"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:layout_marginLeft="@dimen/config_suggestions_strip_horizontal_margin"
-        android:layout_marginRight="@dimen/config_suggestions_strip_horizontal_margin"
-        android:hapticFeedbackEnabled="false"
-        android:soundEffectsEnabled="false">
-        <TextView
-            android:id="@+id/word_to_save"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            style="?attr/suggestionWordStyle" />
-        <include
-            android:id="@+id/word_to_save_divider"
-            layout="@layout/suggestion_divider" />
-        <TextView
-            android:id="@+id/hint_add_to_dictionary"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:gravity="center_vertical|start"
-            style="?attr/suggestionWordStyle" />
-    </LinearLayout>
     <!-- Provide audio and haptic feedback by ourselves based on the keyboard settings.
          We just need to ignore the system's audio and haptic feedback settings. -->
     <LinearLayout
diff --git a/java/res/values/donottranslate-text-decorator.xml b/java/res/values/donottranslate-text-decorator.xml
deleted file mode 100644
index 2693645..0000000
--- a/java/res/values/donottranslate-text-decorator.xml
+++ /dev/null
@@ -1,76 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2014, 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>
-    <!-- The extra margin in dp around the hit area of the commit/add-to-dictionary indicator -->
-    <integer name="text_decorator_hit_area_margin_in_dp">
-        4
-    </integer>
-
-    <!-- Background color to be used to highlight the target text when the add-to-dictionary
-         indicator is visible. -->
-    <color name="text_decorator_add_to_dictionary_indicator_text_highlight_color">
-        #D1E7B7
-    </color>
-
-    <!-- Foreground color of the commit indicator. -->
-    <color name="text_decorator_add_to_dictionary_indicator_background_color">
-        #4EB848
-    </color>
-
-    <!-- Foreground color of the add-to-dictionary indicator. -->
-    <color name="text_decorator_add_to_dictionary_indicator_foreground_color">
-        #FFFFFF
-    </color>
-
-    <!-- Viewport size of "text_decorator_add_to_dictionary_indicator_path". -->
-    <integer name="text_decorator_add_to_dictionary_indicator_path_size">
-        480
-    </integer>
-
-    <!-- Coordinates of the closed path to be used to render the add-to-dictionary indicator.
-         The format is: X[0], Y[0], X[1], Y[1], ..., X[N-1], Y[N-1] -->
-    <integer-array name="text_decorator_add_to_dictionary_indicator_path">
-        <item>380</item>
-        <item>260</item>
-        <item>260</item>
-        <item>260</item>
-        <item>260</item>
-        <item>380</item>
-        <item>220</item>
-        <item>380</item>
-        <item>220</item>
-        <item>260</item>
-        <item>100</item>
-        <item>260</item>
-        <item>100</item>
-        <item>220</item>
-        <item>220</item>
-        <item>220</item>
-        <item>220</item>
-        <item>100</item>
-        <item>260</item>
-        <item>100</item>
-        <item>260</item>
-        <item>220</item>
-        <item>380</item>
-        <item>220</item>
-    </integer-array>
-</resources>
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index 9dc57e3..46476e2 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -127,7 +127,6 @@
             mKeyboardTextsSet.setLocale(mRichImm.getCurrentSubtypeLocales()[0], mThemeContext);
         } catch (KeyboardLayoutSetException e) {
             Log.w(TAG, "loading keyboard failed: " + e.mKeyboardId, e.getCause());
-            return;
         }
     }
 
diff --git a/java/src/com/android/inputmethod/keyboard/TextDecorator.java b/java/src/com/android/inputmethod/keyboard/TextDecorator.java
deleted file mode 100644
index 892d367..0000000
--- a/java/src/com/android/inputmethod/keyboard/TextDecorator.java
+++ /dev/null
@@ -1,372 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.inputmethod.keyboard;
-
-import android.graphics.Matrix;
-import android.graphics.RectF;
-import android.inputmethodservice.InputMethodService;
-import android.os.Message;
-import android.text.TextUtils;
-import android.util.Log;
-import android.view.View;
-import android.view.inputmethod.CursorAnchorInfo;
-
-import com.android.inputmethod.annotations.UsedForTesting;
-import com.android.inputmethod.compat.CursorAnchorInfoCompatWrapper;
-import com.android.inputmethod.latin.utils.LeakGuardHandlerWrapper;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-
-/**
- * A controller class of the add-to-dictionary indicator (a.k.a. TextDecorator). This class
- * is designed to be independent of UI subsystems such as {@link View}. All the UI related
- * operations are delegated to {@link TextDecoratorUi} via {@link TextDecoratorUiOperator}.
- */
-public class TextDecorator {
-    private static final String TAG = TextDecorator.class.getSimpleName();
-    private static final boolean DEBUG = false;
-
-    private static final int INVALID_CURSOR_INDEX = -1;
-
-    private static final int MODE_MONITOR = 0;
-    private static final int MODE_WAITING_CURSOR_INDEX = 1;
-    private static final int MODE_SHOWING_INDICATOR = 2;
-
-    private int mMode = MODE_MONITOR;
-
-    private String mLastComposingText = null;
-    private boolean mHasRtlCharsInLastComposingText = false;
-    private RectF mComposingTextBoundsForLastComposingText = new RectF();
-
-    private boolean mIsFullScreenMode = false;
-    private String mWaitingWord = null;
-    private int mWaitingCursorStart = INVALID_CURSOR_INDEX;
-    private int mWaitingCursorEnd = INVALID_CURSOR_INDEX;
-    @Nullable
-    private CursorAnchorInfoCompatWrapper mCursorAnchorInfoWrapper = null;
-
-    @Nonnull
-    private final Listener mListener;
-
-    @Nonnull
-    private TextDecoratorUiOperator mUiOperator = EMPTY_UI_OPERATOR;
-
-    public interface Listener {
-        /**
-         * Called when the user clicks the indicator to add the word into the dictionary.
-         * @param word the word which the user clicked on.
-         */
-        void onClickComposingTextToAddToDictionary(final String word);
-    }
-
-    public TextDecorator(@Nullable final Listener listener) {
-        mListener = (listener != null) ? listener : EMPTY_LISTENER;
-    }
-
-    /**
-     * Sets the UI operator for {@link TextDecorator}. Any user visible operations will be
-     * delegated to the associated UI operator.
-     * @param uiOperator the UI operator to be associated.
-     */
-    public void setUiOperator(@Nonnull final TextDecoratorUiOperator uiOperator) {
-        mUiOperator.disposeUi();
-        mUiOperator = uiOperator;
-        mUiOperator.setOnClickListener(getOnClickHandler());
-    }
-
-    private final Runnable mDefaultOnClickHandler = new Runnable() {
-        @Override
-        public void run() {
-            onClickIndicator();
-        }
-    };
-
-    @UsedForTesting
-    final Runnable getOnClickHandler() {
-        return mDefaultOnClickHandler;
-    }
-
-    /**
-     * Shows the "Add to dictionary" indicator and associates it with associating the given word.
-     *
-     * @param word the word which should be associated with the indicator. This object will be
-     * passed back in {@link Listener#onClickComposingTextToAddToDictionary(String)}.
-     * @param selectionStart the cursor index (inclusive) when the indicator should be displayed.
-     * @param selectionEnd the cursor index (exclusive) when the indicator should be displayed.
-     */
-    public void showAddToDictionaryIndicator(final String word, final int selectionStart,
-            final int selectionEnd) {
-        mWaitingWord = word;
-        mWaitingCursorStart = selectionStart;
-        mWaitingCursorEnd = selectionEnd;
-        mMode = MODE_WAITING_CURSOR_INDEX;
-        layoutLater();
-        return;
-    }
-
-    /**
-     * Must be called when the input method is about changing to for from the full screen mode.
-     * @param fullScreenMode {@code true} if the input method is entering the full screen mode.
-     * {@code false} is the input method is finishing the full screen mode.
-     */
-    public void notifyFullScreenMode(final boolean fullScreenMode) {
-        final boolean fullScreenModeChanged = (mIsFullScreenMode != fullScreenMode);
-        mIsFullScreenMode = fullScreenMode;
-        if (fullScreenModeChanged) {
-            layoutLater();
-        }
-    }
-
-    /**
-     * Resets previous requests and makes indicator invisible.
-     */
-    public void reset() {
-        mWaitingWord = null;
-        mMode = MODE_MONITOR;
-        mWaitingCursorStart = INVALID_CURSOR_INDEX;
-        mWaitingCursorEnd = INVALID_CURSOR_INDEX;
-        cancelLayoutInternalExpectedly("Resetting internal state.");
-    }
-
-    /**
-     * Must be called when the {@link InputMethodService#onUpdateCursorAnchorInfo(CursorAnchorInfo)}
-     * is called.
-     *
-     * <p>CAVEAT: Currently the input method author is responsible for ignoring
-     * {@link InputMethodService#onUpdateCursorAnchorInfo(CursorAnchorInfo)} called in full screen
-     * mode.</p>
-     * @param info the compatibility wrapper object for the received {@link CursorAnchorInfo}.
-     */
-    public void onUpdateCursorAnchorInfo(@Nullable final CursorAnchorInfoCompatWrapper info) {
-        mCursorAnchorInfoWrapper = info;
-        // Do not use layoutLater() to minimize the latency.
-        layoutImmediately();
-    }
-
-    private void cancelLayoutInternalUnexpectedly(final String message) {
-        mUiOperator.hideUi();
-        Log.d(TAG, message);
-    }
-
-    private void cancelLayoutInternalExpectedly(final String message) {
-        mUiOperator.hideUi();
-        if (DEBUG) {
-            Log.d(TAG, message);
-        }
-    }
-
-    private void layoutLater() {
-        mLayoutInvalidator.invalidateLayout();
-    }
-
-
-    private void layoutImmediately() {
-        // Clear pending layout requests.
-        mLayoutInvalidator.cancelInvalidateLayout();
-        layoutMain();
-    }
-
-    void layoutMain() {
-        final CursorAnchorInfoCompatWrapper info = mCursorAnchorInfoWrapper;
-
-        if (info == null) {
-            cancelLayoutInternalExpectedly("CursorAnchorInfo isn't available.");
-            return;
-        }
-
-        final Matrix matrix = info.getMatrix();
-        if (matrix == null) {
-            cancelLayoutInternalUnexpectedly("Matrix is null");
-        }
-
-        final CharSequence composingText = info.getComposingText();
-        if (!TextUtils.isEmpty(composingText)) {
-            final int composingTextStart = info.getComposingTextStart();
-            final int lastCharRectIndex = composingTextStart + composingText.length() - 1;
-            final RectF lastCharRect = info.getCharacterBounds(lastCharRectIndex);
-            final int lastCharRectFlags = info.getCharacterBoundsFlags(lastCharRectIndex);
-            final boolean hasInvisibleRegionInLastCharRect =
-                    (lastCharRectFlags & CursorAnchorInfoCompatWrapper.FLAG_HAS_INVISIBLE_REGION)
-                            != 0;
-            if (lastCharRect == null || matrix == null || hasInvisibleRegionInLastCharRect) {
-                mUiOperator.hideUi();
-                return;
-            }
-
-            // Note that the following layout information is fragile, and must be invalidated
-            // even when surrounding text next to the composing text is changed because it can
-            // affect how the composing text is rendered.
-            // TODO: Investigate if we can change the input logic to make the target text
-            // composing state so that we can retrieve the character bounds reliably.
-            final String composingTextString = composingText.toString();
-            final float top = lastCharRect.top;
-            final float bottom = lastCharRect.bottom;
-            float left = lastCharRect.left;
-            float right = lastCharRect.right;
-            boolean useRtlLayout = false;
-            for (int i = composingText.length() - 1; i >= 0; --i) {
-                final int characterIndex = composingTextStart + i;
-                final RectF characterBounds = info.getCharacterBounds(characterIndex);
-                final int characterBoundsFlags = info.getCharacterBoundsFlags(characterIndex);
-                if (characterBounds == null) {
-                    break;
-                }
-                if (characterBounds.top != top) {
-                    break;
-                }
-                if (characterBounds.bottom != bottom) {
-                    break;
-                }
-                if ((characterBoundsFlags & CursorAnchorInfoCompatWrapper.FLAG_IS_RTL) != 0) {
-                    // This is for both RTL text and bi-directional text. RTL languages usually mix
-                    // RTL characters with LTR characters and in this case we should display the
-                    // indicator on the left, while in LTR languages that normally never happens.
-                    // TODO: Try to come up with a better algorithm.
-                    useRtlLayout = true;
-                }
-                left = Math.min(characterBounds.left, left);
-                right = Math.max(characterBounds.right, right);
-            }
-            mLastComposingText = composingTextString;
-            mHasRtlCharsInLastComposingText = useRtlLayout;
-            mComposingTextBoundsForLastComposingText.set(left, top, right, bottom);
-        }
-
-        final int selectionStart = info.getSelectionStart();
-        final int selectionEnd = info.getSelectionEnd();
-        switch (mMode) {
-            case MODE_MONITOR:
-                mUiOperator.hideUi();
-                return;
-            case MODE_WAITING_CURSOR_INDEX:
-                if (selectionStart != mWaitingCursorStart || selectionEnd != mWaitingCursorEnd) {
-                    mUiOperator.hideUi();
-                    return;
-                }
-                mMode = MODE_SHOWING_INDICATOR;
-                break;
-            case MODE_SHOWING_INDICATOR:
-                if (selectionStart != mWaitingCursorStart || selectionEnd != mWaitingCursorEnd) {
-                    mUiOperator.hideUi();
-                    mMode = MODE_MONITOR;
-                    mWaitingCursorStart = INVALID_CURSOR_INDEX;
-                    mWaitingCursorEnd = INVALID_CURSOR_INDEX;
-                    return;
-                }
-                break;
-            default:
-                cancelLayoutInternalUnexpectedly("Unexpected internal mode=" + mMode);
-                return;
-        }
-
-        if (!TextUtils.equals(mLastComposingText, mWaitingWord)) {
-            cancelLayoutInternalUnexpectedly("mLastComposingText doesn't match mWaitingWord");
-            return;
-        }
-
-        if ((info.getInsertionMarkerFlags() &
-                CursorAnchorInfoCompatWrapper.FLAG_HAS_INVISIBLE_REGION) != 0) {
-            mUiOperator.hideUi();
-            return;
-        }
-
-        mUiOperator.layoutUi(matrix, mComposingTextBoundsForLastComposingText,
-                mHasRtlCharsInLastComposingText);
-    }
-
-    void onClickIndicator() {
-        if (mMode != MODE_SHOWING_INDICATOR) {
-            return;
-        }
-        mListener.onClickComposingTextToAddToDictionary(mWaitingWord);
-    }
-
-    private final LayoutInvalidator mLayoutInvalidator = new LayoutInvalidator(this);
-
-    /**
-     * Used for managing pending layout tasks for {@link TextDecorator#layoutLater()}.
-     */
-    private static final class LayoutInvalidator {
-        private final HandlerImpl mHandler;
-        public LayoutInvalidator(@Nonnull final TextDecorator ownerInstance) {
-            mHandler = new HandlerImpl(ownerInstance);
-        }
-
-        private static final int MSG_LAYOUT = 0;
-
-        private static final class HandlerImpl
-                extends LeakGuardHandlerWrapper<TextDecorator> {
-            public HandlerImpl(@Nonnull final TextDecorator ownerInstance) {
-                super(ownerInstance);
-            }
-
-            @Override
-            public void handleMessage(final Message msg) {
-                final TextDecorator owner = getOwnerInstance();
-                if (owner == null) {
-                    return;
-                }
-                switch (msg.what) {
-                    case MSG_LAYOUT:
-                        owner.layoutMain();
-                        break;
-                }
-            }
-        }
-
-        /**
-         * Puts a layout task into the scheduler. Does nothing if one or more layout tasks are
-         * already scheduled.
-         */
-        public void invalidateLayout() {
-            if (!mHandler.hasMessages(MSG_LAYOUT)) {
-                mHandler.obtainMessage(MSG_LAYOUT).sendToTarget();
-            }
-        }
-
-        /**
-         * Clears the pending layout tasks.
-         */
-        public void cancelInvalidateLayout() {
-            mHandler.removeMessages(MSG_LAYOUT);
-        }
-    }
-
-    @Nonnull
-    private final static Listener EMPTY_LISTENER = new Listener() {
-        @Override
-        public void onClickComposingTextToAddToDictionary(final String word) {
-        }
-    };
-
-    @Nonnull
-    private final static TextDecoratorUiOperator EMPTY_UI_OPERATOR = new TextDecoratorUiOperator() {
-        @Override
-        public void disposeUi() {
-        }
-        @Override
-        public void hideUi() {
-        }
-        @Override
-        public void setOnClickListener(Runnable listener) {
-        }
-        @Override
-        public void layoutUi(Matrix matrix, RectF composingTextBounds, boolean useRtlLayout) {
-        }
-    };
-}
diff --git a/java/src/com/android/inputmethod/keyboard/TextDecoratorUi.java b/java/src/com/android/inputmethod/keyboard/TextDecoratorUi.java
deleted file mode 100644
index d87dc1b..0000000
--- a/java/src/com/android/inputmethod/keyboard/TextDecoratorUi.java
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.inputmethod.keyboard;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Matrix;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.RectF;
-import android.graphics.drawable.ColorDrawable;
-import android.inputmethodservice.InputMethodService;
-import android.util.DisplayMetrics;
-import android.util.TypedValue;
-import android.view.Gravity;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.ViewGroup;
-import android.view.ViewGroup.LayoutParams;
-import android.view.ViewParent;
-import android.widget.PopupWindow;
-import android.widget.RelativeLayout;
-
-import com.android.inputmethod.latin.R;
-
-/**
- * Used as the UI component of {@link TextDecorator}.
- */
-public final class TextDecoratorUi implements TextDecoratorUiOperator {
-    private static final boolean VISUAL_DEBUG = false;
-    private static final int VISUAL_DEBUG_HIT_AREA_COLOR = 0x80ff8000;
-
-    private final RelativeLayout mLocalRootView;
-    private final AddToDictionaryIndicatorView mAddToDictionaryIndicatorView;
-    private final PopupWindow mTouchEventWindow;
-    private final View mTouchEventWindowClickListenerView;
-    private final float mHitAreaMarginInPixels;
-    private final RectF mDisplayRect;
-
-    /**
-     * This constructor is designed to be called from {@link InputMethodService#setInputView(View)}.
-     * Other usages are not supported.
-     *
-     * @param context the context of the input method.
-     * @param inputView the view that is passed to {@link InputMethodService#setInputView(View)}.
-     */
-    public TextDecoratorUi(final Context context, final View inputView) {
-        final Resources resources = context.getResources();
-        final int hitAreaMarginInDP = resources.getInteger(
-                R.integer.text_decorator_hit_area_margin_in_dp);
-        mHitAreaMarginInPixels = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
-                hitAreaMarginInDP, resources.getDisplayMetrics());
-        final DisplayMetrics displayMetrics = resources.getDisplayMetrics();
-        mDisplayRect = new RectF(0.0f, 0.0f, displayMetrics.widthPixels,
-                displayMetrics.heightPixels);
-
-        mLocalRootView = new RelativeLayout(context);
-        mLocalRootView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
-                LayoutParams.MATCH_PARENT));
-        // TODO: Use #setBackground(null) for API Level >= 16.
-        mLocalRootView.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
-
-        final ViewGroup contentView = getContentView(inputView);
-        mAddToDictionaryIndicatorView = new AddToDictionaryIndicatorView(context);
-        mLocalRootView.addView(mAddToDictionaryIndicatorView);
-        if (contentView != null) {
-            contentView.addView(mLocalRootView);
-        }
-
-        // This popup window is used to avoid the limitation that the input method is not able to
-        // observe the touch events happening outside of InputMethodService.Insets#touchableRegion.
-        // We don't use this popup window for rendering the UI for performance reasons though.
-        mTouchEventWindow = new PopupWindow(context);
-        if (VISUAL_DEBUG) {
-            mTouchEventWindow.setBackgroundDrawable(new ColorDrawable(VISUAL_DEBUG_HIT_AREA_COLOR));
-        } else {
-            mTouchEventWindow.setBackgroundDrawable(null);
-        }
-        mTouchEventWindowClickListenerView = new View(context);
-        mTouchEventWindow.setContentView(mTouchEventWindowClickListenerView);
-    }
-
-    @Override
-    public void disposeUi() {
-        if (mLocalRootView != null) {
-            final ViewParent parent = mLocalRootView.getParent();
-            if (parent != null && parent instanceof ViewGroup) {
-                ((ViewGroup) parent).removeView(mLocalRootView);
-            }
-            mLocalRootView.removeAllViews();
-        }
-        if (mTouchEventWindow != null) {
-            mTouchEventWindow.dismiss();
-        }
-    }
-
-    @Override
-    public void hideUi() {
-        mAddToDictionaryIndicatorView.setVisibility(View.GONE);
-        mTouchEventWindow.dismiss();
-    }
-
-    private static final RectF getIndicatorBoundsInScreenCoordinates(final Matrix matrix,
-            final RectF composingTextBounds, final boolean showAtLeftSide) {
-        final float indicatorSize = composingTextBounds.height();
-        final RectF indicatorBounds;
-        if (showAtLeftSide) {
-            indicatorBounds = new RectF(composingTextBounds.left - indicatorSize,
-                    composingTextBounds.top, composingTextBounds.left,
-                    composingTextBounds.top + indicatorSize);
-        } else {
-            indicatorBounds = new RectF(composingTextBounds.right, composingTextBounds.top,
-                    composingTextBounds.right + indicatorSize,
-                    composingTextBounds.top + indicatorSize);
-        }
-        matrix.mapRect(indicatorBounds);
-        return indicatorBounds;
-    }
-
-    @Override
-    public void layoutUi(final Matrix matrix, final RectF composingTextBounds,
-            final boolean useRtlLayout) {
-        RectF indicatorBoundsInScreenCoordinates = getIndicatorBoundsInScreenCoordinates(matrix,
-                composingTextBounds, useRtlLayout /* showAtLeftSide */);
-        if (indicatorBoundsInScreenCoordinates.left < mDisplayRect.left ||
-                mDisplayRect.right < indicatorBoundsInScreenCoordinates.right) {
-            // The indicator is clipped by the screen. Show the indicator at the opposite side.
-            indicatorBoundsInScreenCoordinates = getIndicatorBoundsInScreenCoordinates(matrix,
-                    composingTextBounds, !useRtlLayout /* showAtLeftSide */);
-        }
-
-        mAddToDictionaryIndicatorView.setBounds(indicatorBoundsInScreenCoordinates);
-
-        final RectF hitAreaBoundsInScreenCoordinates = new RectF();
-        matrix.mapRect(hitAreaBoundsInScreenCoordinates, composingTextBounds);
-        hitAreaBoundsInScreenCoordinates.union(indicatorBoundsInScreenCoordinates);
-        hitAreaBoundsInScreenCoordinates.inset(-mHitAreaMarginInPixels, -mHitAreaMarginInPixels);
-
-        final int[] originScreen = new int[2];
-        mLocalRootView.getLocationOnScreen(originScreen);
-        final int viewOriginX = originScreen[0];
-        final int viewOriginY = originScreen[1];
-        mAddToDictionaryIndicatorView.setX(indicatorBoundsInScreenCoordinates.left - viewOriginX);
-        mAddToDictionaryIndicatorView.setY(indicatorBoundsInScreenCoordinates.top - viewOriginY);
-        mAddToDictionaryIndicatorView.setVisibility(View.VISIBLE);
-
-        if (mTouchEventWindow.isShowing()) {
-            mTouchEventWindow.update((int)hitAreaBoundsInScreenCoordinates.left - viewOriginX,
-                    (int)hitAreaBoundsInScreenCoordinates.top - viewOriginY,
-                    (int)hitAreaBoundsInScreenCoordinates.width(),
-                    (int)hitAreaBoundsInScreenCoordinates.height());
-        } else {
-            mTouchEventWindow.setWidth((int)hitAreaBoundsInScreenCoordinates.width());
-            mTouchEventWindow.setHeight((int)hitAreaBoundsInScreenCoordinates.height());
-            mTouchEventWindow.showAtLocation(mLocalRootView, Gravity.NO_GRAVITY,
-                    (int)hitAreaBoundsInScreenCoordinates.left - viewOriginX,
-                    (int)hitAreaBoundsInScreenCoordinates.top - viewOriginY);
-        }
-    }
-
-    @Override
-    public void setOnClickListener(final Runnable listener) {
-        mTouchEventWindowClickListenerView.setOnClickListener(new OnClickListener() {
-            @Override
-            public void onClick(final View arg0) {
-                listener.run();
-            }
-        });
-    }
-
-    private static class IndicatorView extends View {
-        private final Path mPath;
-        private final Path mTmpPath = new Path();
-        private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-        private final Matrix mMatrix = new Matrix();
-        private final int mBackgroundColor;
-        private final int mForegroundColor;
-        private final RectF mBounds = new RectF();
-        public IndicatorView(Context context, final int pathResourceId,
-                final int sizeResourceId, final int backgroundColorResourceId,
-                final int foregroundColroResourceId) {
-            super(context);
-            final Resources resources = context.getResources();
-            mPath = createPath(resources, pathResourceId, sizeResourceId);
-            mBackgroundColor = resources.getColor(backgroundColorResourceId);
-            mForegroundColor = resources.getColor(foregroundColroResourceId);
-        }
-
-        public void setBounds(final RectF rect) {
-            mBounds.set(rect);
-        }
-
-        @Override
-        protected void onDraw(Canvas canvas) {
-            mPaint.setColor(mBackgroundColor);
-            mPaint.setStyle(Paint.Style.FILL);
-            canvas.drawRect(0.0f, 0.0f, mBounds.width(), mBounds.height(), mPaint);
-
-            mMatrix.reset();
-            mMatrix.postScale(mBounds.width(), mBounds.height());
-            mPath.transform(mMatrix, mTmpPath);
-            mPaint.setColor(mForegroundColor);
-            canvas.drawPath(mTmpPath, mPaint);
-        }
-
-        private static Path createPath(final Resources resources, final int pathResourceId,
-                final int sizeResourceId) {
-            final int size = resources.getInteger(sizeResourceId);
-            final float normalizationFactor = 1.0f / size;
-            final int[] array = resources.getIntArray(pathResourceId);
-
-            final Path path = new Path();
-            for (int i = 0; i < array.length; i += 2) {
-                if (i == 0) {
-                    path.moveTo(array[i] * normalizationFactor, array[i + 1] * normalizationFactor);
-                } else {
-                    path.lineTo(array[i] * normalizationFactor, array[i + 1] * normalizationFactor);
-                }
-            }
-            path.close();
-            return path;
-        }
-    }
-
-    private static ViewGroup getContentView(final View view) {
-        final View rootView = view.getRootView();
-        if (rootView == null) {
-            return null;
-        }
-
-        final ViewGroup windowContentView = (ViewGroup)rootView.findViewById(android.R.id.content);
-        if (windowContentView == null) {
-            return null;
-        }
-        return windowContentView;
-    }
-
-    private static final class AddToDictionaryIndicatorView extends TextDecoratorUi.IndicatorView {
-        public AddToDictionaryIndicatorView(final Context context) {
-            super(context, R.array.text_decorator_add_to_dictionary_indicator_path,
-                    R.integer.text_decorator_add_to_dictionary_indicator_path_size,
-                    R.color.text_decorator_add_to_dictionary_indicator_background_color,
-                    R.color.text_decorator_add_to_dictionary_indicator_foreground_color);
-        }
-    }
-}
\ No newline at end of file
diff --git a/java/src/com/android/inputmethod/keyboard/TextDecoratorUiOperator.java b/java/src/com/android/inputmethod/keyboard/TextDecoratorUiOperator.java
deleted file mode 100644
index 9e30e41..0000000
--- a/java/src/com/android/inputmethod/keyboard/TextDecoratorUiOperator.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.inputmethod.keyboard;
-
-import android.graphics.Matrix;
-import android.graphics.RectF;
-
-/**
- * This interface defines how UI operations required for {@link TextDecorator} are delegated to
- * the actual UI implementation class.
- */
-public interface TextDecoratorUiOperator {
-    /**
-     * Called to notify that the UI is ready to be disposed.
-     */
-    void disposeUi();
-
-    /**
-     * Called when the UI should become invisible.
-     */
-    void hideUi();
-
-    /**
-     * Called to set the new click handler.
-     * @param onClickListener the callback object whose {@link Runnable#run()} should be called when
-     * the indicator is clicked.
-     */
-    void setOnClickListener(final Runnable onClickListener);
-
-    /**
-     * Called when the layout should be updated.
-     * @param matrix The matrix that transforms the local coordinates into the screen coordinates.
-     * @param composingTextBounds The bounding box of the composing text, in local coordinates.
-     * @param useRtlLayout {@code true} if the indicator should be optimized for RTL layout.
-     */
-    void layoutUi(final Matrix matrix, final RectF composingTextBounds, final boolean useRtlLayout);
-}
diff --git a/java/src/com/android/inputmethod/keyboard/emoji/EmojiPalettesView.java b/java/src/com/android/inputmethod/keyboard/emoji/EmojiPalettesView.java
index 309430e..9ab4652 100644
--- a/java/src/com/android/inputmethod/keyboard/emoji/EmojiPalettesView.java
+++ b/java/src/com/android/inputmethod/keyboard/emoji/EmojiPalettesView.java
@@ -259,7 +259,7 @@
 
     @Override
     public void onPageScrolled(final int position, final float positionOffset,
-            final int positionOffsetPixels) {
+                               final int positionOffsetPixels) {
         mEmojiPalettesAdapter.onPageScrolled();
         final Pair<Integer, Integer> newPos =
                 mEmojiCategory.getCategoryIdAndPageIdFromPagePosition(position);
@@ -358,7 +358,7 @@
     }
 
     private static void setupAlphabetKey(final TextView alphabetKey, final String label,
-            final KeyDrawParams params) {
+                                         final KeyDrawParams params) {
         alphabetKey.setText(label);
         alphabetKey.setTextColor(params.mFunctionalTextColor);
         alphabetKey.setTextSize(TypedValue.COMPLEX_UNIT_PX, params.mLabelSize);
@@ -366,7 +366,7 @@
     }
 
     public void startEmojiPalettes(final String switchToAlphaLabel,
-            final KeyVisualAttributes keyVisualAttr, final KeyboardIconsSet iconSet) {
+                                   final KeyVisualAttributes keyVisualAttr, final KeyboardIconsSet iconSet) {
         final int deleteIconResId = iconSet.getIconResourceId(KeyboardIconsSet.NAME_DELETE_KEY);
         if (deleteIconResId != 0) {
             mDeleteKey.setImageResource(deleteIconResId);
@@ -427,4 +427,4 @@
             mTabHost.setCurrentTab(newTabId);
         }
     }
-}
+}
\ No newline at end of file
diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java
index 74ff6e6..401b528 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java
@@ -124,10 +124,6 @@
     void waitForLoadingDictionariesForTesting(final long timeout, final TimeUnit unit)
             throws InterruptedException;
 
-    boolean isUserDictionaryEnabled();
-
-    void addWordToUserDictionary(final Context context, final String word);
-
     void addToUserHistory(final String suggestion, final boolean wasAutoCapitalized,
             @Nonnull final NgramContext ngramContext, final int timeStampInSeconds,
             final boolean blockPotentiallyOffensive);
diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorImpl.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorImpl.java
index dc63298..3c390db 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorImpl.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorImpl.java
@@ -73,7 +73,6 @@
 
     private DictionaryGroup[] mDictionaryGroups = new DictionaryGroup[] { new DictionaryGroup() };
     private DictionaryGroup mMostProbableDictionaryGroup = mDictionaryGroups[0];
-    private boolean mIsUserDictEnabled = false;
     private volatile CountDownLatch mLatchForWaitingLoadingMainDictionaries = new CountDownLatch(0);
     // To synchronize assigning mDictionaryGroup to ensure closing dictionaries.
     private final Object mLock = new Object();
@@ -458,7 +457,6 @@
             oldDictionaryGroups = mDictionaryGroups;
             mDictionaryGroups = newDictionaryGroups;
             mMostProbableDictionaryGroup = newDictionaryGroups[0];
-            mIsUserDictEnabled = UserBinaryDictionary.isEnabled(context);
             if (hasAtLeastOneUninitializedMainDictionary()) {
                 asyncReloadUninitializedMainDictionaries(context, newLocales, listener);
             }
@@ -629,19 +627,6 @@
         }
     }
 
-    public boolean isUserDictionaryEnabled() {
-        return mIsUserDictEnabled;
-    }
-
-    public void addWordToUserDictionary(final Context context, final String word) {
-        final Locale locale = getMostProbableLocale();
-        if (locale == null) {
-            return;
-        }
-        // TODO: add a toast telling what language this is being added to?
-        UserBinaryDictionary.addWordToUserDictionary(context, locale, word);
-    }
-
     public void addToUserHistory(final String suggestion, final boolean wasAutoCapitalized,
             @Nonnull final NgramContext ngramContext, final int timeStampInSeconds,
             final boolean blockPotentiallyOffensive) {
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 15827fc..8227008 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -20,7 +20,6 @@
 import static com.android.inputmethod.latin.common.Constants.ImeOption.NO_MICROPHONE;
 import static com.android.inputmethod.latin.common.Constants.ImeOption.NO_MICROPHONE_COMPAT;
 
-import android.annotation.TargetApi;
 import android.app.AlertDialog;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -32,13 +31,11 @@
 import android.content.res.Resources;
 import android.inputmethodservice.InputMethodService;
 import android.media.AudioManager;
-import android.os.Build;
 import android.os.Debug;
 import android.os.IBinder;
 import android.os.Message;
 import android.preference.PreferenceManager;
 import android.text.InputType;
-import android.text.TextUtils;
 import android.util.Log;
 import android.util.PrintWriterPrinter;
 import android.util.Printer;
@@ -47,18 +44,14 @@
 import android.view.KeyEvent;
 import android.view.View;
 import android.view.ViewGroup.LayoutParams;
-import android.view.ViewTreeObserver;
 import android.view.Window;
 import android.view.WindowManager;
 import android.view.inputmethod.CompletionInfo;
-import android.view.inputmethod.CursorAnchorInfo;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputMethodSubtype;
-import android.widget.TextView;
 
 import com.android.inputmethod.accessibility.AccessibilityUtils;
 import com.android.inputmethod.annotations.UsedForTesting;
-import com.android.inputmethod.compat.CursorAnchorInfoCompatWrapper;
 import com.android.inputmethod.compat.InputMethodServiceCompatUtils;
 import com.android.inputmethod.compat.ViewOutlineProviderCompatUtils;
 import com.android.inputmethod.compat.ViewOutlineProviderCompatUtils.InsetsUpdater;
@@ -72,7 +65,6 @@
 import com.android.inputmethod.keyboard.KeyboardId;
 import com.android.inputmethod.keyboard.KeyboardSwitcher;
 import com.android.inputmethod.keyboard.MainKeyboardView;
-import com.android.inputmethod.keyboard.TextDecoratorUi;
 import com.android.inputmethod.latin.Suggest.OnGetSuggestedWordsCallback;
 import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
 import com.android.inputmethod.latin.common.Constants;
@@ -90,8 +82,6 @@
 import com.android.inputmethod.latin.suggestions.SuggestionStripViewAccessor;
 import com.android.inputmethod.latin.touchinputconsumer.GestureConsumer;
 import com.android.inputmethod.latin.utils.ApplicationUtils;
-import com.android.inputmethod.latin.utils.CapsModeUtils;
-import com.android.inputmethod.latin.utils.CursorAnchorInfoUtils;
 import com.android.inputmethod.latin.utils.DialogUtils;
 import com.android.inputmethod.latin.utils.ImportantNoticeUtils;
 import com.android.inputmethod.latin.utils.IntentUtils;
@@ -149,7 +139,6 @@
     private View mInputView;
     private InsetsUpdater mInsetsUpdater;
     private SuggestionStripView mSuggestionStripView;
-    private TextView mExtractEditText;
 
     private RichInputMethodManager mRichImm;
     @UsedForTesting final KeyboardSwitcher mKeyboardSwitcher;
@@ -776,57 +765,11 @@
         if (hasSuggestionStripView()) {
             mSuggestionStripView.setListener(this, view);
         }
-        mInputLogic.setTextDecoratorUi(new TextDecoratorUi(this, view));
     }
 
     @Override
-    public void setExtractView(final View view) {
-        final TextView prevExtractEditText = mExtractEditText;
-        super.setExtractView(view);
-        TextView nextExtractEditText = null;
-        if (view != null) {
-            final View extractEditText = view.findViewById(android.R.id.inputExtractEditText);
-            if (extractEditText instanceof TextView) {
-                nextExtractEditText = (TextView)extractEditText;
-            }
-        }
-        if (prevExtractEditText == nextExtractEditText) {
-            return;
-        }
-        if (prevExtractEditText != null) {
-            prevExtractEditText.getViewTreeObserver().removeOnPreDrawListener(
-                    mExtractTextViewPreDrawListener);
-        }
-        mExtractEditText = nextExtractEditText;
-        if (mExtractEditText != null) {
-            mExtractEditText.getViewTreeObserver().addOnPreDrawListener(
-                    mExtractTextViewPreDrawListener);
-        }
-    }
-
-    void updateCursorAnchorInfo() {
-        // CursorAnchorInfo is used on L and later.
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
-            if (isFullscreenMode() && mExtractEditText != null) {
-                mInputLogic.onUpdateCursorAnchorInfo(
-                        CursorAnchorInfoUtils.extractFromTextView(mExtractEditText));
-            }
-        }
-    }
-
-    private final ViewTreeObserver.OnPreDrawListener mExtractTextViewPreDrawListener =
-            new ViewTreeObserver.OnPreDrawListener() {
-                @Override
-                public boolean onPreDraw() {
-                    updateCursorAnchorInfo();
-                    return true;
-                }
-            };
-
-    @Override
     public void setCandidatesView(final View view) {
         // To ensure that CandidatesView will never be set.
-        return;
     }
 
     @Override
@@ -1095,15 +1038,6 @@
         }
     }
 
-    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
-    @Override
-    public void onUpdateCursorAnchorInfo(final CursorAnchorInfo info) {
-        if (isFullscreenMode()) {
-            return;
-        }
-        mInputLogic.onUpdateCursorAnchorInfo(CursorAnchorInfoCompatWrapper.wrap(info));
-    }
-
     /**
      * This is called when the user has clicked on the extracted text view,
      * when running in fullscreen mode.  The default implementation hides
@@ -1284,7 +1218,6 @@
     @Override
     public void updateFullscreenMode() {
         super.updateFullscreenMode();
-        mInputLogic.onUpdateFullscreenMode(isFullscreenMode());
         updateSoftInputWindowLayoutParameters();
     }
 
@@ -1332,18 +1265,6 @@
         return keyboard.getCoordinates(codePoints);
     }
 
-    // Callback for the {@link SuggestionStripView}, to call when the "add to dictionary" hint is
-    // pressed.
-    @Override
-    public void addWordToUserDictionary(final String word) {
-        if (TextUtils.isEmpty(word)) {
-            // Probably never supposed to happen, but just in case.
-            return;
-        }
-        mDictionaryFacilitator.addWordToUserDictionary(this /* context */, word);
-        mInputLogic.onAddWordToUserDictionary();
-    }
-
     // Callback for the {@link SuggestionStripView}, to call when the important notice strip is
     // pressed.
     @Override
@@ -1538,19 +1459,6 @@
         return null != mSuggestionStripView;
     }
 
-    @Override
-    public boolean isShowingAddToDictionaryHint() {
-        return hasSuggestionStripView() && mSuggestionStripView.isShowingAddToDictionaryHint();
-    }
-
-    @Override
-    public void dismissAddToDictionaryHint() {
-        if (!hasSuggestionStripView()) {
-            return;
-        }
-        mSuggestionStripView.dismissAddToDictionaryHint();
-    }
-
     private void setSuggestedWords(final SuggestedWords suggestedWords) {
         final SettingsValues currentSettingsValues = mSettings.getCurrent();
         mInputLogic.setSuggestedWords(suggestedWords);
@@ -1639,21 +1547,6 @@
         updateStateAfterInputTransaction(completeInputTransaction);
     }
 
-    @Override
-    public void suggestAddingToDictionary(final String word, final boolean isFromSuggestionStrip) {
-        if (!hasSuggestionStripView()) {
-            return;
-        }
-        final String wordToShow;
-        if (CapsModeUtils.isAutoCapsMode(mInputLogic.mLastComposedWord.mCapitalizedMode)) {
-            wordToShow = word.toLowerCase(mDictionaryFacilitator.getMostProbableLocale());
-        } else {
-            wordToShow = word;
-        }
-        mSuggestionStripView.showAddToDictionaryHint(wordToShow,
-                isFromSuggestionStrip /* shouldShowWordToSave */);
-    }
-
     // This will show either an empty suggestion strip (if prediction is enabled) or
     // punctuation suggestions (if it's disabled).
     @Override
diff --git a/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java b/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java
index 2d2b3d0..1ed2103 100644
--- a/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java
@@ -16,7 +16,6 @@
 
 package com.android.inputmethod.latin;
 
-import android.content.ContentProviderClient;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.database.ContentObserver;
@@ -29,7 +28,6 @@
 import android.util.Log;
 
 import com.android.inputmethod.annotations.ExternallyReferenced;
-import com.android.inputmethod.compat.UserDictionaryCompatUtils;
 import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
 
 import java.io.File;
@@ -54,13 +52,13 @@
     private static final int USER_DICT_SHORTCUT_FREQUENCY = 14;
 
     private static final String[] PROJECTION_QUERY_WITH_SHORTCUT = new String[] {
-        Words.WORD,
-        Words.SHORTCUT,
-        Words.FREQUENCY,
+            Words.WORD,
+            Words.SHORTCUT,
+            Words.FREQUENCY,
     };
     private static final String[] PROJECTION_QUERY_WITHOUT_SHORTCUT = new String[] {
-        Words.WORD,
-        Words.FREQUENCY,
+            Words.WORD,
+            Words.FREQUENCY,
     };
 
     private static final String NAME = "userunigram";
@@ -70,7 +68,8 @@
     final private boolean mAlsoUseMoreRestrictiveLocales;
 
     protected UserBinaryDictionary(final Context context, final Locale locale,
-            final boolean alsoUseMoreRestrictiveLocales, final File dictFile, final String name) {
+                                   final boolean alsoUseMoreRestrictiveLocales,
+                                   final File dictFile, final String name) {
         super(context, getDictName(name, locale, dictFile), locale, Dictionary.TYPE_USER, dictFile);
         if (null == locale) throw new NullPointerException(); // Catch the error earlier
         final String localeStr = locale.toString();
@@ -105,9 +104,11 @@
 
     // Note: This method is called by {@link DictionaryFacilitator} using Java reflection.
     @ExternallyReferenced
-    public static UserBinaryDictionary getDictionary(final Context context, final Locale locale,
-            final File dictFile, final String dictNamePrefix, @Nullable final String account) {
-        return new UserBinaryDictionary(context, locale, false /* alsoUseMoreRestrictiveLocales */,
+    public static UserBinaryDictionary getDictionary(
+            final Context context, final Locale locale, final File dictFile,
+            final String dictNamePrefix, @Nullable final String account) {
+        return new UserBinaryDictionary(
+                context, locale, false /* alsoUseMoreRestrictiveLocales */,
                 dictFile, dictNamePrefix + NAME);
     }
 
@@ -187,7 +188,8 @@
     }
 
     private void addWordsFromProjectionLocked(final String[] query, String request,
-            final String[] requestArguments) throws IllegalArgumentException {
+                                              final String[] requestArguments)
+            throws IllegalArgumentException {
         Cursor cursor = null;
         try {
             cursor = mContext.getContentResolver().query(
@@ -204,31 +206,6 @@
         }
     }
 
-    public static boolean isEnabled(final Context context) {
-        final ContentResolver cr = context.getContentResolver();
-        final ContentProviderClient client = cr.acquireContentProviderClient(Words.CONTENT_URI);
-        if (client != null) {
-            client.release();
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Adds a word to the user dictionary and makes it persistent.
-     *
-     * @param context the context
-     * @param locale the locale
-     * @param word the word to add. If the word is capitalized, then the dictionary will
-     * recognize it as a capitalized word when searched.
-     */
-    public static void addWordToUserDictionary(final Context context, final Locale locale,
-            final String word) {
-        // Update the user dictionary provider
-        UserDictionaryCompatUtils.addWord(context, word,
-                HISTORICAL_DEFAULT_USER_DICTIONARY_FREQUENCY, null, locale);
-    }
-
     private static int scaleFrequencyFromDefaultToLatinIme(final int defaultFrequency) {
         // The default frequency for the user dictionary is 250 for historical reasons.
         // Latin IME considers a good value for the default user dictionary frequency
diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
index 4842438..18927ce 100644
--- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
+++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
@@ -17,7 +17,6 @@
 package com.android.inputmethod.latin.inputlogic;
 
 import android.graphics.Color;
-import android.inputmethodservice.InputMethodService;
 import android.os.SystemClock;
 import android.text.SpannableString;
 import android.text.Spanned;
@@ -28,17 +27,13 @@
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
 import android.view.inputmethod.CorrectionInfo;
-import android.view.inputmethod.CursorAnchorInfo;
 import android.view.inputmethod.EditorInfo;
 
-import com.android.inputmethod.compat.CursorAnchorInfoCompatWrapper;
 import com.android.inputmethod.compat.SuggestionSpanUtils;
 import com.android.inputmethod.event.Event;
 import com.android.inputmethod.event.InputTransaction;
 import com.android.inputmethod.keyboard.KeyboardSwitcher;
 import com.android.inputmethod.keyboard.ProximityInfo;
-import com.android.inputmethod.keyboard.TextDecorator;
-import com.android.inputmethod.keyboard.TextDecoratorUiOperator;
 import com.android.inputmethod.latin.Dictionary;
 import com.android.inputmethod.latin.DictionaryFacilitator;
 import com.android.inputmethod.latin.LastComposedWord;
@@ -91,14 +86,6 @@
     public final Suggest mSuggest;
     private final DictionaryFacilitator mDictionaryFacilitator;
 
-    private final TextDecorator mTextDecorator = new TextDecorator(new TextDecorator.Listener() {
-        @Override
-        public void onClickComposingTextToAddToDictionary(final String word) {
-            mLatinIME.addWordToUserDictionary(word);
-            mLatinIME.dismissAddToDictionaryHint();
-        }
-    });
-
     public LastComposedWord mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD;
     // This has package visibility so it can be accessed from InputLogicHandler.
     /* package */ final WordComposer mWordComposer;
@@ -174,7 +161,6 @@
             mConnection.requestCursorUpdates(true /* enableMonitor */,
                     true /* requestImmediateCallback */);
         }
-        mTextDecorator.reset();
     }
 
     /**
@@ -269,20 +255,6 @@
     }
 
     /**
-     * Determines whether "Touch again to save" should be shown or not.
-     * @param suggestionInfo the suggested word chosen by the user.
-     * @return {@code true} if we should show the "Touch again to save" hint.
-     */
-    private boolean shouldShowAddToDictionaryHint(final SuggestedWordInfo suggestionInfo) {
-        // We should show the "Touch again to save" hint if the user pressed the first entry
-        // AND it's in none of our current dictionaries (main, user or otherwise).
-        return (suggestionInfo.isKindOf(SuggestedWordInfo.KIND_TYPED)
-                || suggestionInfo.isKindOf(SuggestedWordInfo.KIND_OOV_CORRECTION))
-                && !mDictionaryFacilitator.isValidWord(suggestionInfo.mWord, true /* ignoreCase */)
-                && mDictionaryFacilitator.isUserDictionaryEnabled();
-    }
-
-    /**
      * A suggestion was picked from the suggestion strip.
      * @param settingsValues the current values of the settings.
      * @param suggestionInfo the suggestion info.
@@ -340,7 +312,6 @@
             return inputTransaction;
         }
 
-        final boolean shouldShowAddToDictionaryHint = shouldShowAddToDictionaryHint(suggestionInfo);
         commitChosenWord(settingsValues, suggestion, LastComposedWord.COMMIT_TYPE_MANUAL_PICK,
                 LastComposedWord.NOT_A_SEPARATOR);
         mConnection.endBatchEdit();
@@ -350,14 +321,9 @@
         mSpaceState = SpaceState.PHANTOM;
         inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW);
 
-        if (shouldShowAddToDictionaryHint) {
-            mSuggestionStripViewAccessor.suggestAddingToDictionary(suggestion,
-                    true /* isFromSuggestionStrip */);
-        } else {
-            // If we're not showing the "Touch again to save", then update the suggestion strip.
-            // That's going to be predictions (or punctuation suggestions), so INPUT_STYLE_NONE.
-            handler.postUpdateSuggestionStrip(SuggestedWords.INPUT_STYLE_NONE);
-        }
+        // If we're not showing the "Touch again to save", then update the suggestion strip.
+        // That's going to be predictions (or punctuation suggestions), so INPUT_STYLE_NONE.
+        handler.postUpdateSuggestionStrip(SuggestedWords.INPUT_STYLE_NONE);
 
         StatsUtils.onPickSuggestionManually(mSuggestedWords, suggestionInfo);
         StatsUtils.onWordCommitSuggestionPickedManually(
@@ -431,11 +397,6 @@
 
         // The cursor has been moved : we now accept to perform recapitalization
         mRecapitalizeStatus.enable();
-        // We moved the cursor and need to invalidate the indicator right now.
-        mTextDecorator.reset();
-        // Remaining background color that was used for the add-to-dictionary indicator should be
-        // removed.
-        mConnection.removeBackgroundColorFromHighlightedTextIfNecessary();
         // We moved the cursor. If we are touching a word, we need to resume suggestion.
         mLatinIME.mHandler.postResumeSuggestions(true /* shouldDelay */);
         // Stop the last recapitalization, if started.
@@ -808,12 +769,6 @@
             final LatinIME.UIHandler handler) {
         if (!mWordComposer.isComposingWord()) {
             mConnection.removeBackgroundColorFromHighlightedTextIfNecessary();
-            // In case the "add to dictionary" hint was still displayed.
-            // TODO: Do we really need to check if we have composing text here?
-            if (mSuggestionStripViewAccessor.isShowingAddToDictionaryHint()) {
-                mSuggestionStripViewAccessor.dismissAddToDictionaryHint();
-                mTextDecorator.reset();
-            }
         }
 
         final int codePoint = event.mCodePoint;
@@ -1639,20 +1594,8 @@
                     0 /* start */, lastCharIndex /* end */, 0 /* flags */);
         }
 
-        final boolean shouldShowAddToDictionaryForTypedWord =
-                shouldShowAddToDictionaryForTypedWord(mLastComposedWord, settingsValues);
-
         if (inputTransaction.mSettingsValues.mSpacingAndPunctuations.mCurrentLanguageHasSpaces) {
-            // For languages with spaces, we revert to the typed string, but the cursor is still
-            // after the separator so we don't resume suggestions. If the user wants to correct
-            // the word, they have to press backspace again.
-            if (shouldShowAddToDictionaryForTypedWord) {
-                mConnection.commitTextWithBackgroundColor(textToCommit, 1,
-                        settingsValues.mTextHighlightColorForAddToDictionaryIndicator,
-                        originallyTypedWordString.length());
-            } else {
-                mConnection.commitText(textToCommit, 1);
-            }
+            mConnection.commitText(textToCommit, 1);
             if (usePhantomSpace) {
                 mSpaceState = SpaceState.PHANTOM;
             }
@@ -1662,33 +1605,13 @@
             final int[] codePoints = StringUtils.toCodePointArray(stringToCommit);
             mWordComposer.setComposingWord(codePoints,
                     mLatinIME.getCoordinatesForCurrentKeyboard(codePoints));
-            if (shouldShowAddToDictionaryForTypedWord) {
-                setComposingTextInternalWithBackgroundColor(textToCommit, 1,
-                        settingsValues.mTextHighlightColorForAddToDictionaryIndicator,
-                        originallyTypedWordString.length());
-            } else {
-                setComposingTextInternal(textToCommit, 1);
-            }
+            setComposingTextInternal(textToCommit, 1);
         }
         // Don't restart suggestion yet. We'll restart if the user deletes the separator.
         mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD;
 
-        if (shouldShowAddToDictionaryForTypedWord) {
-            // Due to the API limitation as of L, we cannot reliably retrieve the reverted text
-            // when the separator causes line breaking. Until this API limitation is addressed in
-            // the framework, show the indicator only when the separator doesn't contain
-            // line-breaking characters.
-            if (!StringUtils.hasLineBreakCharacter(separatorString)) {
-                mTextDecorator.showAddToDictionaryIndicator(originallyTypedWordString,
-                        mConnection.getExpectedSelectionStart(),
-                        mConnection.getExpectedSelectionEnd());
-            }
-            mSuggestionStripViewAccessor.suggestAddingToDictionary(originallyTypedWordString,
-                    false /* isFromSuggestionStrip */);
-        } else {
-            // We have a separator between the word and the cursor: we should show predictions.
-            inputTransaction.setRequiresUpdateSuggestions();
-        }
+        // We have a separator between the word and the cursor: we should show predictions.
+        inputTransaction.setRequiresUpdateSuggestions();
     }
 
     /**
@@ -2215,7 +2138,7 @@
      *
      * <p>Currently using this method is optional and you can still directly call
      * {@link RichInputConnection#setComposingText(CharSequence, int)}, but it is recommended to
-     * use this method whenever possible to optimize the behavior of {@link TextDecorator}.<p>
+     * use this method whenever possible.<p>
      * <p>TODO: Should we move this mechanism to {@link RichInputConnection}?</p>
      *
      * @param newComposingText the composing text to be set
@@ -2300,71 +2223,4 @@
     public int getComposingLength() {
         return mWordComposer.size();
     }
-
-    //////////////////////////////////////////////////////////////////////////////////////////////
-    // Following methods are tentatively placed in this class for the integration with
-    // TextDecorator.
-    // TODO: Decouple things that are not related to the input logic.
-    //////////////////////////////////////////////////////////////////////////////////////////////
-
-    /**
-     * Sets the UI operator for {@link TextDecorator}.
-     * @param uiOperator the UI operator which should be associated with {@link TextDecorator}.
-     */
-    public void setTextDecoratorUi(@Nonnull final TextDecoratorUiOperator uiOperator) {
-        mTextDecorator.setUiOperator(uiOperator);
-    }
-
-    /**
-     * Must be called from {@link InputMethodService#onUpdateCursorAnchorInfo(CursorAnchorInfo)} is
-     * called.
-     * @param info The wrapper object with which we can access cursor/anchor info.
-     */
-    public void onUpdateCursorAnchorInfo(final CursorAnchorInfoCompatWrapper info) {
-        mTextDecorator.onUpdateCursorAnchorInfo(info);
-    }
-
-    /**
-     * Must be called when {@link InputMethodService#updateFullscreenMode} is called.
-     * @param isFullscreen {@code true} if the input method is in full-screen mode.
-     */
-    public void onUpdateFullscreenMode(final boolean isFullscreen) {
-        mTextDecorator.notifyFullScreenMode(isFullscreen);
-    }
-
-    /**
-     * Must be called from {@link LatinIME#addWordToUserDictionary(String)}.
-     */
-    public void onAddWordToUserDictionary() {
-        mConnection.removeBackgroundColorFromHighlightedTextIfNecessary();
-        mTextDecorator.reset();
-    }
-
-    /**
-     * Returns whether the add to dictionary indicator should be shown or not.
-     * @param lastComposedWord the last composed word information.
-     * @param settingsValues the current settings value.
-     * @return {@code true} if the commit indicator should be shown.
-     */
-    private boolean shouldShowAddToDictionaryForTypedWord(final LastComposedWord lastComposedWord,
-            final SettingsValues settingsValues) {
-        if (!mConnection.isCursorAnchorInfoMonitorEnabled()) {
-            // We cannot help in this case because we are heavily relying on this new API.
-            return false;
-        }
-        if (!settingsValues.mShouldShowLxxSuggestionUi) {
-            return false;
-        }
-        if (TextUtils.isEmpty(lastComposedWord.mTypedWord)) {
-            return false;
-        }
-        if (TextUtils.equals(lastComposedWord.mTypedWord, lastComposedWord.mCommittedWord)) {
-            return false;
-        }
-        if (!mDictionaryFacilitator.isUserDictionaryEnabled()) {
-            return false;
-        }
-        return !mDictionaryFacilitator.isValidWord(lastComposedWord.mTypedWord,
-                true /* ignoreCase */);
-    }
 }
diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
index a080515..9a1bb77 100644
--- a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
+++ b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
@@ -102,9 +102,6 @@
     private final boolean mSuggestionsEnabledPerUserSettings;
     private final AsyncResultHolder<AppWorkaroundsUtils> mAppWorkarounds;
 
-    // TextDecorator
-    public final int mTextHighlightColorForAddToDictionaryIndicator;
-
     // Debug settings
     public final boolean mIsInternal;
     public final boolean mHasCustomKeyPreviewAnimationParams;
@@ -183,8 +180,6 @@
         mAutoCorrectionEnabledPerUserSettings = mAutoCorrectEnabled
                 && !mInputAttributes.mInputTypeNoAutoCorrect;
         mSuggestionsEnabledPerUserSettings = readSuggestionsEnabled(prefs);
-        mTextHighlightColorForAddToDictionaryIndicator = res.getColor(
-                R.color.text_decorator_add_to_dictionary_indicator_text_highlight_color);
         mIsInternal = Settings.isInternal(prefs);
         mHasCustomKeyPreviewAnimationParams = prefs.getBoolean(
                 DebugSettings.PREF_HAS_CUSTOM_KEY_PREVIEW_ANIMATION_PARAMS, false);
@@ -431,8 +426,6 @@
         sb.append("\n   mAppWorkarounds = ");
         final AppWorkaroundsUtils awu = mAppWorkarounds.get(null, 0);
         sb.append("" + (null == awu ? "null" : awu.toString()));
-        sb.append("\n   mTextHighlightColorForAddToDictionaryIndicator = ");
-        sb.append("" + mTextHighlightColorForAddToDictionaryIndicator);
         sb.append("\n   mIsInternal = ");
         sb.append("" + mIsInternal);
         sb.append("\n   mKeyPreviewShowUpDuration = ");
diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java
index 7991a24..a9d1207 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java
@@ -28,7 +28,6 @@
 import android.graphics.Typeface;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
-import android.support.v4.view.ViewCompat;
 import android.text.Spannable;
 import android.text.SpannableString;
 import android.text.Spanned;
@@ -50,7 +49,6 @@
 import com.android.inputmethod.latin.R;
 import com.android.inputmethod.latin.SuggestedWords;
 import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
-import com.android.inputmethod.latin.common.LocaleUtils;
 import com.android.inputmethod.latin.settings.Settings;
 import com.android.inputmethod.latin.settings.SettingsValues;
 import com.android.inputmethod.latin.utils.ResourceUtils;
@@ -95,8 +93,6 @@
     private final int mTypedWordPositionWhenAutocorrect;
     private final Drawable mMoreSuggestionsHint;
     private static final String MORE_SUGGESTIONS_HINT = "\u2026";
-    private static final String LEFTWARDS_ARROW = "\u2190";
-    private static final String RIGHTWARDS_ARROW = "\u2192";
 
     private static final CharacterStyle BOLD_SPAN = new StyleSpan(Typeface.BOLD);
     private static final CharacterStyle UNDERLINE_SPAN = new UnderlineSpan();
@@ -540,55 +536,6 @@
         return countInStrip;
     }
 
-    public void layoutAddToDictionaryHint(final String word, final ViewGroup addToDictionaryStrip,
-            final boolean shouldShowWordToSave) {
-        final boolean showsHintWithWord = shouldShowWordToSave
-                || !Settings.getInstance().getCurrent().mShouldShowLxxSuggestionUi;
-        final int stripWidth = addToDictionaryStrip.getWidth();
-        final int width = stripWidth - (showsHintWithWord ? mDividerWidth + mPadding * 2 : 0);
-
-        final TextView wordView = (TextView)addToDictionaryStrip.findViewById(R.id.word_to_save);
-        wordView.setTextColor(mColorTypedWord);
-        final int wordWidth = (int)(width * mCenterSuggestionWeight);
-        final CharSequence wordToSave = getEllipsizedTextWithSettingScaleX(
-                word, wordWidth, wordView.getPaint());
-        final float wordScaleX = wordView.getTextScaleX();
-        wordView.setText(wordToSave);
-        wordView.setTextScaleX(wordScaleX);
-        setLayoutWeight(wordView, mCenterSuggestionWeight, ViewGroup.LayoutParams.MATCH_PARENT);
-        final int wordVisibility = showsHintWithWord ? View.VISIBLE : View.GONE;
-        wordView.setVisibility(wordVisibility);
-        addToDictionaryStrip.findViewById(R.id.word_to_save_divider).setVisibility(wordVisibility);
-
-        final Resources res = addToDictionaryStrip.getResources();
-        final CharSequence hintText;
-        final int hintWidth;
-        final float hintWeight;
-        final TextView hintView = (TextView)addToDictionaryStrip.findViewById(
-                R.id.hint_add_to_dictionary);
-        if (showsHintWithWord) {
-            final boolean isRtlLanguage = (ViewCompat.getLayoutDirection(addToDictionaryStrip)
-                    == ViewCompat.LAYOUT_DIRECTION_RTL);
-            final String arrow = isRtlLanguage ? RIGHTWARDS_ARROW : LEFTWARDS_ARROW;
-            final boolean isRtlSystem = LocaleUtils.isRtlLanguage(res.getConfiguration().locale);
-            final CharSequence hint = res.getText(R.string.hint_add_to_dictionary);
-            hintText = (isRtlLanguage == isRtlSystem) ? (arrow + hint) : (hint + arrow);
-            hintWidth = width - wordWidth;
-            hintWeight = 1.0f - mCenterSuggestionWeight;
-            hintView.setGravity(Gravity.CENTER_VERTICAL | Gravity.START);
-        } else {
-            hintText = res.getText(R.string.hint_add_to_dictionary_without_word);
-            hintWidth = width;
-            hintWeight = 1.0f;
-            hintView.setGravity(Gravity.CENTER);
-        }
-        hintView.setTextColor(mColorAutoCorrect);
-        final float hintScaleX = getTextScaleX(hintText, hintWidth, hintView.getPaint());
-        hintView.setText(hintText); // TextView.setText() resets text scale x to 1.0.
-        hintView.setTextScaleX(hintScaleX);
-        setLayoutWeight(hintView, hintWeight, ViewGroup.LayoutParams.MATCH_PARENT);
-    }
-
     public void layoutImportantNotice(final View importantNoticeStrip,
             final String importantNoticeTitle) {
         final TextView titleView = (TextView)importantNoticeStrip.findViewById(
diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
index b71bd1f..4b84949 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
@@ -58,7 +58,6 @@
 public final class SuggestionStripView extends RelativeLayout implements OnClickListener,
         OnLongClickListener {
     public interface Listener {
-        public void addWordToUserDictionary(String word);
         public void showImportantNoticeContents();
         public void pickSuggestionManually(SuggestedWordInfo word);
         public void onCodeInput(int primaryCode, int x, int y, boolean isKeyRepeat);
@@ -69,7 +68,6 @@
 
     private final ViewGroup mSuggestionsStrip;
     private final ImageButton mVoiceKey;
-    private final ViewGroup mAddToDictionaryStrip;
     private final View mImportantNoticeStrip;
     MainKeyboardView mMainKeyboardView;
 
@@ -91,15 +89,12 @@
     private static class StripVisibilityGroup {
         private final View mSuggestionStripView;
         private final View mSuggestionsStrip;
-        private final View mAddToDictionaryStrip;
         private final View mImportantNoticeStrip;
 
         public StripVisibilityGroup(final View suggestionStripView,
-                final ViewGroup suggestionsStrip, final ViewGroup addToDictionaryStrip,
-                final View importantNoticeStrip) {
+                final ViewGroup suggestionsStrip, final View importantNoticeStrip) {
             mSuggestionStripView = suggestionStripView;
             mSuggestionsStrip = suggestionsStrip;
-            mAddToDictionaryStrip = addToDictionaryStrip;
             mImportantNoticeStrip = importantNoticeStrip;
             showSuggestionsStrip();
         }
@@ -109,35 +104,22 @@
                     : ViewCompat.LAYOUT_DIRECTION_LTR;
             ViewCompat.setLayoutDirection(mSuggestionStripView, layoutDirection);
             ViewCompat.setLayoutDirection(mSuggestionsStrip, layoutDirection);
-            ViewCompat.setLayoutDirection(mAddToDictionaryStrip, layoutDirection);
             ViewCompat.setLayoutDirection(mImportantNoticeStrip, layoutDirection);
         }
 
         public void showSuggestionsStrip() {
             mSuggestionsStrip.setVisibility(VISIBLE);
-            mAddToDictionaryStrip.setVisibility(INVISIBLE);
-            mImportantNoticeStrip.setVisibility(INVISIBLE);
-        }
-
-        public void showAddToDictionaryStrip() {
-            mSuggestionsStrip.setVisibility(INVISIBLE);
-            mAddToDictionaryStrip.setVisibility(VISIBLE);
             mImportantNoticeStrip.setVisibility(INVISIBLE);
         }
 
         public void showImportantNoticeStrip() {
             mSuggestionsStrip.setVisibility(INVISIBLE);
-            mAddToDictionaryStrip.setVisibility(INVISIBLE);
             mImportantNoticeStrip.setVisibility(VISIBLE);
         }
 
         public boolean isShowingImportantNoticeStrip() {
             return mImportantNoticeStrip.getVisibility() == VISIBLE;
         }
-
-        public boolean isShowingAddToDictionaryStrip() {
-            return mAddToDictionaryStrip.getVisibility() == VISIBLE;
-        }
     }
 
     /**
@@ -158,10 +140,9 @@
 
         mSuggestionsStrip = (ViewGroup)findViewById(R.id.suggestions_strip);
         mVoiceKey = (ImageButton)findViewById(R.id.suggestions_strip_voice_key);
-        mAddToDictionaryStrip = (ViewGroup)findViewById(R.id.add_to_dictionary_strip);
         mImportantNoticeStrip = findViewById(R.id.important_notice_strip);
         mStripVisibilityGroup = new StripVisibilityGroup(this, mSuggestionsStrip,
-                mAddToDictionaryStrip, mImportantNoticeStrip);
+                mImportantNoticeStrip);
 
         for (int pos = 0; pos < SuggestedWords.MAX_SUGGESTIONS; pos++) {
             final TextView word = new TextView(context, null, R.attr.suggestionWordStyle);
@@ -227,27 +208,6 @@
         mLayoutHelper.setMoreSuggestionsHeight(remainingHeight);
     }
 
-    public boolean isShowingAddToDictionaryHint() {
-        return mStripVisibilityGroup.isShowingAddToDictionaryStrip();
-    }
-
-    public void showAddToDictionaryHint(final String word, final boolean shouldShowWordToSave) {
-        mLayoutHelper.layoutAddToDictionaryHint(word, mAddToDictionaryStrip, shouldShowWordToSave);
-        // {@link TextView#setTag()} is used to hold the word to be added to dictionary. The word
-        // will be extracted at {@link #onClick(View)}.
-        mAddToDictionaryStrip.setTag(word);
-        mAddToDictionaryStrip.setOnClickListener(this);
-        mStripVisibilityGroup.showAddToDictionaryStrip();
-    }
-
-    public boolean dismissAddToDictionaryHint() {
-        if (isShowingAddToDictionaryHint()) {
-            clear();
-            return true;
-        }
-        return false;
-    }
-
     // This method checks if we should show the important notice (checks on permanent storage if
     // it has been shown once already or not, and if in the setup wizard). If applicable, it shows
     // the notice. In all cases, it returns true if it was shown, false otherwise.
@@ -494,15 +454,8 @@
                     false /* isKeyRepeat */);
             return;
         }
-        final Object tag = view.getTag();
-        // {@link String} tag is set at {@link #suggestAddingToDictionary(String,CharSequence)}.
-        if (tag instanceof String) {
-            final String wordToSave = (String)tag;
-            mListener.addWordToUserDictionary(wordToSave);
-            clear();
-            return;
-        }
 
+        final Object tag = view.getTag();
         // {@link Integer} tag is set at
         // {@link SuggestionStripLayoutHelper#setupWordViewsTextAndColor(SuggestedWords,int)} and
         // {@link SuggestionStripLayoutHelper#layoutPunctuationSuggestions(SuggestedWords,ViewGroup}
diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripViewAccessor.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripViewAccessor.java
index 5c86a02..68f417e 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripViewAccessor.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripViewAccessor.java
@@ -22,9 +22,6 @@
  * An object that gives basic control of a suggestion strip and some info on it.
  */
 public interface SuggestionStripViewAccessor {
-    public void suggestAddingToDictionary(final String word, final boolean isFromSuggestionStrip);
-    public boolean isShowingAddToDictionaryHint();
-    public void dismissAddToDictionaryHint();
     public void setNeutralSuggestionStrip();
     public void showSuggestionStrip(final SuggestedWords suggestedWords);
 }
diff --git a/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryAddWordFragment.java b/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryAddWordFragment.java
deleted file mode 100644
index 1634430..0000000
--- a/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryAddWordFragment.java
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.inputmethod.latin.userdictionary;
-
-import com.android.inputmethod.latin.R;
-import com.android.inputmethod.latin.userdictionary.UserDictionaryAddWordContents.LocaleRenderer;
-import com.android.inputmethod.latin.userdictionary.UserDictionaryLocalePicker.LocationChangedListener;
-
-import android.app.Fragment;
-import android.os.Bundle;
-import android.preference.PreferenceActivity;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.ArrayAdapter;
-import android.widget.Spinner;
-
-import java.util.ArrayList;
-import java.util.Locale;
-
-// Caveat: This class is basically taken from
-// packages/apps/Settings/src/com/android/settings/inputmethod/UserDictionaryAddWordFragment.java
-// in order to deal with some devices that have issues with the user dictionary handling
-
-/**
- * Fragment to add a word/shortcut to the user dictionary.
- *
- * As opposed to the UserDictionaryActivity, this is only invoked within Settings
- * from the UserDictionarySettings.
- */
-public class UserDictionaryAddWordFragment extends Fragment
-        implements AdapterView.OnItemSelectedListener, LocationChangedListener {
-
-    private static final int OPTIONS_MENU_ADD = Menu.FIRST;
-    private static final int OPTIONS_MENU_DELETE = Menu.FIRST + 1;
-
-    private UserDictionaryAddWordContents mContents;
-    private View mRootView;
-    private boolean mIsDeleting = false;
-
-    @Override
-    public void onActivityCreated(final Bundle savedInstanceState) {
-        super.onActivityCreated(savedInstanceState);
-        setHasOptionsMenu(true);
-        getActivity().getActionBar().setTitle(R.string.edit_personal_dictionary);
-        // Keep the instance so that we remember mContents when configuration changes (eg rotation)
-        setRetainInstance(true);
-    }
-
-    @Override
-    public View onCreateView(final LayoutInflater inflater, final ViewGroup container,
-            final Bundle savedState) {
-        mRootView = inflater.inflate(R.layout.user_dictionary_add_word_fullscreen, null);
-        mIsDeleting = false;
-        // If we have a non-null mContents object, it's the old value before a configuration
-        // change (eg rotation) so we need to use its values. Otherwise, read from the arguments.
-        if (null == mContents) {
-            mContents = new UserDictionaryAddWordContents(mRootView, getArguments());
-        } else {
-            // We create a new mContents object to account for the new situation : a word has
-            // been added to the user dictionary when we started rotating, and we are now editing
-            // it. That means in particular if the word undergoes any change, the old version should
-            // be updated, so the mContents object needs to switch to EDIT mode if it was in
-            // INSERT mode.
-            mContents = new UserDictionaryAddWordContents(mRootView,
-                    mContents /* oldInstanceToBeEdited */);
-        }
-        getActivity().getActionBar().setSubtitle(UserDictionarySettingsUtils.getLocaleDisplayName(
-                getActivity(), mContents.getCurrentUserDictionaryLocale()));
-        return mRootView;
-    }
-
-    @Override
-    public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
-        final MenuItem actionItemAdd = menu.add(0, OPTIONS_MENU_ADD, 0,
-                R.string.user_dict_settings_add_menu_title).setIcon(R.drawable.ic_menu_add);
-        actionItemAdd.setShowAsAction(
-                MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
-        final MenuItem actionItemDelete = menu.add(0, OPTIONS_MENU_DELETE, 0,
-                R.string.user_dict_settings_delete).setIcon(android.R.drawable.ic_menu_delete);
-        actionItemDelete.setShowAsAction(
-                MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
-    }
-
-    /**
-     * Callback for the framework when a menu option is pressed.
-     *
-     * @param item the item that was pressed
-     * @return false to allow normal menu processing to proceed, true to consume it here
-     */
-    @Override
-    public boolean onOptionsItemSelected(MenuItem item) {
-        if (item.getItemId() == OPTIONS_MENU_ADD) {
-            // added the entry in "onPause"
-            getActivity().onBackPressed();
-            return true;
-        }
-        if (item.getItemId() == OPTIONS_MENU_DELETE) {
-            mContents.delete(getActivity());
-            mIsDeleting = true;
-            getActivity().onBackPressed();
-            return true;
-        }
-        return false;
-    }
-
-    @Override
-    public void onResume() {
-        super.onResume();
-        // We are being shown: display the word
-        updateSpinner();
-    }
-
-    private void updateSpinner() {
-        final ArrayList<LocaleRenderer> localesList = mContents.getLocalesList(getActivity());
-
-        final Spinner localeSpinner =
-                (Spinner)mRootView.findViewById(R.id.user_dictionary_add_locale);
-        final ArrayAdapter<LocaleRenderer> adapter = new ArrayAdapter<>(
-                getActivity(), android.R.layout.simple_spinner_item, localesList);
-        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
-        localeSpinner.setAdapter(adapter);
-        localeSpinner.setOnItemSelectedListener(this);
-    }
-
-    @Override
-    public void onPause() {
-        super.onPause();
-        // We are being hidden: commit changes to the user dictionary, unless we were deleting it
-        if (!mIsDeleting) {
-            mContents.apply(getActivity(), null);
-        }
-    }
-
-    @Override
-    public void onItemSelected(final AdapterView<?> parent, final View view, final int pos,
-            final long id) {
-        final LocaleRenderer locale = (LocaleRenderer)parent.getItemAtPosition(pos);
-        if (locale.isMoreLanguages()) {
-            PreferenceActivity preferenceActivity = (PreferenceActivity)getActivity();
-            preferenceActivity.startPreferenceFragment(new UserDictionaryLocalePicker(), true);
-        } else {
-            mContents.updateLocale(locale.getLocaleString());
-        }
-    }
-
-    @Override
-    public void onNothingSelected(final AdapterView<?> parent) {
-        // I'm not sure we can come here, but if we do, that's the right thing to do.
-        final Bundle args = getArguments();
-        mContents.updateLocale(args.getString(UserDictionaryAddWordContents.EXTRA_LOCALE));
-    }
-
-    // Called by the locale picker
-    @Override
-    public void onLocaleSelected(final Locale locale) {
-        mContents.updateLocale(locale.toString());
-        getActivity().onBackPressed();
-    }
-}
diff --git a/java/src/com/android/inputmethod/latin/userdictionary/UserDictionarySettings.java b/java/src/com/android/inputmethod/latin/userdictionary/UserDictionarySettings.java
index 1d7e7d6..fabd49f 100644
--- a/java/src/com/android/inputmethod/latin/userdictionary/UserDictionarySettings.java
+++ b/java/src/com/android/inputmethod/latin/userdictionary/UserDictionarySettings.java
@@ -240,8 +240,6 @@
         args.putString(UserDictionaryAddWordContents.EXTRA_LOCALE, mLocale);
         android.preference.PreferenceActivity pa =
                 (android.preference.PreferenceActivity)getActivity();
-        pa.startPreferencePanel(UserDictionaryAddWordFragment.class.getName(),
-                args, R.string.user_dict_settings_add_dialog_title, null, null, 0);
     }
 
     private String getWord(final int position) {
diff --git a/java/src/com/android/inputmethod/latin/utils/FragmentUtils.java b/java/src/com/android/inputmethod/latin/utils/FragmentUtils.java
index 147e57b..c87a7c0 100644
--- a/java/src/com/android/inputmethod/latin/utils/FragmentUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/FragmentUtils.java
@@ -29,7 +29,6 @@
 import com.android.inputmethod.latin.settings.SettingsFragment;
 import com.android.inputmethod.latin.settings.ThemeSettingsFragment;
 import com.android.inputmethod.latin.spellcheck.SpellCheckerSettingsFragment;
-import com.android.inputmethod.latin.userdictionary.UserDictionaryAddWordFragment;
 import com.android.inputmethod.latin.userdictionary.UserDictionaryList;
 import com.android.inputmethod.latin.userdictionary.UserDictionaryLocalePicker;
 import com.android.inputmethod.latin.userdictionary.UserDictionarySettings;
@@ -52,7 +51,6 @@
         sLatinImeFragments.add(DebugSettingsFragment.class.getName());
         sLatinImeFragments.add(SettingsFragment.class.getName());
         sLatinImeFragments.add(SpellCheckerSettingsFragment.class.getName());
-        sLatinImeFragments.add(UserDictionaryAddWordFragment.class.getName());
         sLatinImeFragments.add(UserDictionaryList.class.getName());
         sLatinImeFragments.add(UserDictionaryLocalePicker.class.getName());
         sLatinImeFragments.add(UserDictionarySettings.class.getName());