From: csagan5 <32685696+csagan5@users.noreply.github.com>
Date: Sat, 19 Mar 2022 10:53:24 +0100
Subject: Dictionary suggestions for the Omnibox

Revert "Disable Dictionary suggestions for the Omnibox"

This reverts commit d3ec2b2d25066ec089f8351a44b919ded4270e83.

Original License: BSD-3-Clause - https://spdx.org/licenses/BSD-3-Clause.html
License: GPL-3.0-only - https://spdx.org/licenses/GPL-3.0-only.html
---
 chrome/android/java/res/layout/url_bar.xml    |   1 +
 .../chrome/browser/omnibox/UrlBar.java        | 931 ++++++++++++++++++
 .../chrome/browser/omnibox/UrlBar.java        |   3 +-
 3 files changed, 933 insertions(+), 2 deletions(-)
 create mode 100644 chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java

diff --git a/chrome/android/java/res/layout/url_bar.xml b/chrome/android/java/res/layout/url_bar.xml
--- a/chrome/android/java/res/layout/url_bar.xml
+++ b/chrome/android/java/res/layout/url_bar.xml
@@ -15,5 +15,6 @@ found in the LICENSE file.
     android:singleLine="true"
     android:imeOptions="actionGo|flagNoExtractUi|flagNoFullscreen"
     android:textSize="@dimen/location_bar_url_text_size"
+    android:inputType="textUri"
     android:hint="@string/search_or_type_web_address"
     android:importantForAutofill="no" />
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java
new file mode 100644
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java
@@ -0,0 +1,931 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.omnibox;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.os.Build;
+import android.provider.Settings;
+import android.text.Editable;
+import android.text.InputType;
+import android.text.Layout;
+import android.text.Selection;
+import android.text.SpannableStringBuilder;
+import android.text.TextUtils;
+import android.text.TextWatcher;
+import android.text.style.ReplacementSpan;
+import android.util.AttributeSet;
+import android.view.GestureDetector;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
+import android.widget.TextView;
+
+import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.text.BidiFormatter;
+import androidx.core.util.ObjectsCompat;
+import androidx.core.view.inputmethod.EditorInfoCompat;
+
+import org.chromium.base.ApiCompatibilityUtils;
+import org.chromium.base.Callback;
+import org.chromium.base.Log;
+import org.chromium.base.SysUtils;
+import org.chromium.base.ThreadUtils;
+import org.chromium.base.compat.ApiHelperForO;
+import org.chromium.base.metrics.RecordUserAction;
+import org.chromium.ui.KeyboardVisibilityDelegate;
+import org.chromium.ui.base.WindowDelegate;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * The URL text entry view for the Omnibox.
+ */
+public abstract class UrlBar extends AutocompleteEditText {
+    private static final String TAG = "UrlBar";
+
+    private static final boolean DEBUG = false;
+
+    // TextView becomes very slow on long strings, so we limit maximum length
+    // of what is displayed to the user, see limitDisplayableLength().
+    private static final int MAX_DISPLAYABLE_LENGTH = 4000;
+    private static final int MAX_DISPLAYABLE_LENGTH_LOW_END = 1000;
+
+    private boolean mFirstDrawComplete;
+
+    /**
+     * The text direction of the URL or query: LAYOUT_DIRECTION_LOCALE, LAYOUT_DIRECTION_LTR, or
+     * LAYOUT_DIRECTION_RTL.
+     * */
+    private int mUrlDirection;
+
+    private UrlBarDelegate mUrlBarDelegate;
+    private UrlTextChangeListener mUrlTextChangeListener;
+    private TextWatcher mTextChangedListener;
+    private UrlBarTextContextMenuDelegate mTextContextMenuDelegate;
+    private Callback<Integer> mUrlDirectionListener;
+
+    /**
+     * The gesture detector is used to detect long presses. Long presses require special treatment
+     * because the URL bar has custom touch event handling. See: {@link #onTouchEvent}.
+     */
+    private final GestureDetector mGestureDetector;
+
+    private final KeyboardHideHelper mKeyboardHideHelper;
+
+    private boolean mFocused;
+    private boolean mSuppressingTouchMoveEventsForThisTouch;
+    private MotionEvent mSuppressedTouchDownEvent;
+    private boolean mAllowFocus = true;
+
+    private boolean mPendingScroll;
+    private int mPreviousWidth;
+
+    @ScrollType
+    private int mPreviousScrollType;
+    private String mPreviousScrollText;
+    private int mPreviousScrollViewWidth;
+    private int mPreviousScrollResultXPosition;
+    private float mPreviousScrollFontSize;
+    private boolean mPreviousScrollWasRtl;
+
+    // Used as a hint to indicate the text may contain an ellipsize span.  This will be true if an
+    // ellispize span was applied the last time the text changed.  A true value here does not
+    // guarantee that the text does contain the span currently as newly set text may have cleared
+    // this (and it the value will only be recalculated after the text has been changed).
+    private boolean mDidEllipsizeTextHint;
+
+    /** A cached point for getting this view's location in the window. */
+    private final int[] mCachedLocation = new int[2];
+
+    /** The location of this view on the last ACTION_DOWN event. */
+    private float mDownEventViewTop;
+
+    /**
+     * The character index in the displayed text where the origin ends. This is required to
+     * ensure that the end of the origin is not scrolled out of view for long hostnames.
+     */
+    private int mOriginEndIndex;
+
+    @ScrollType
+    private int mScrollType;
+
+    /** What scrolling action should be taken after the URL bar text changes. **/
+    @IntDef({ScrollType.NO_SCROLL, ScrollType.SCROLL_TO_TLD, ScrollType.SCROLL_TO_BEGINNING})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ScrollType {
+        int NO_SCROLL = 0;
+        int SCROLL_TO_TLD = 1;
+        int SCROLL_TO_BEGINNING = 2;
+    }
+
+    /**
+     * An optional string to use with AccessibilityNodeInfo to report text content.
+     * This is particularly important for auto-fill applications, such as password managers, that
+     * rely on AccessibilityNodeInfo data to apply related form-fill data.
+     */
+    private CharSequence mTextForAutofillServices;
+    protected boolean mRequestingAutofillStructure;
+
+    /**
+     * Delegate used to communicate with the content side and the parent layout.
+     */
+    public interface UrlBarDelegate {
+        /**
+         * @return The view to be focused on a backward focus traversal.
+         */
+        @Nullable
+        View getViewForUrlBackFocus();
+
+        /**
+         * @return Whether the keyboard should be allowed to learn from the user input.
+         */
+        boolean allowKeyboardLearning();
+
+        /**
+         * Called to notify that back key has been pressed while the URL bar has focus.
+         */
+        void backKeyPressed();
+
+        /**
+         * Called to notify that a tap or long press gesture has been detected.
+         * @param isLongPress Whether or not is a long press gesture.
+         */
+        void gestureDetected(boolean isLongPress);
+    }
+
+    /** Provides updates about the URL text changes. */
+    public interface UrlTextChangeListener {
+        /**
+         * Called when the text state has changed.
+         * @param textWithoutAutocomplete The url bar text without autocompletion.
+         * @param textWithAutocomplete The url bar text with autocompletion.
+         */
+        // TODO(crbug.com/1003080): Consider splitting these into two different callbacks.
+        void onTextChanged(String textWithoutAutocomplete, String textWithAutocomplete);
+    }
+
+    /** Delegate that provides the additional functionality to the textual context menus. */
+    interface UrlBarTextContextMenuDelegate {
+        /** @return The text to be pasted into the UrlBar. */
+        @NonNull
+        String getTextToPaste();
+
+        /**
+         * Gets potential replacement text to be used instead of the current selected text for
+         * cut/copy actions.  If null is returned, the existing text will be cut or copied.
+         *
+         * @param currentText The current displayed text.
+         * @param selectionStart The selection start in the display text.
+         * @param selectionEnd The selection end in the display text.
+         * @return The text to be cut/copied instead of the currently selected text.
+         */
+        @Nullable
+        String getReplacementCutCopyText(String currentText, int selectionStart, int selectionEnd);
+    }
+
+    public UrlBar(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mUrlDirection = LAYOUT_DIRECTION_LOCALE;
+
+        // The URL Bar is derived from an text edit class, and as such is focusable by
+        // default. This means that if it is created before the first draw of the UI it
+        // will (as the only focusable element of the UI) get focus on the first draw.
+        // We react to this by greying out the tab area and bringing up the keyboard,
+        // which we don't want to do at startup. Prevent this by disabling focus until
+        // the first draw.
+        setFocusable(false);
+        setFocusableInTouchMode(false);
+
+        // The HTC Sense IME will attempt to autocomplete words in the Omnibox when Prediction is
+        // enabled.  We want to disable this feature and rely on the Omnibox's implementation.
+        // Their IME does not respect ~TYPE_TEXT_FLAG_AUTO_COMPLETE nor any of the other InputType
+        // options I tried, but setting the filter variation prevents it.  Sadly, it also removes
+        // the .com button, but the prediction was buggy as it would autocomplete words even when
+        // typing at the beginning of the omnibox text when other content was present (messing up
+        // what was previously there).  See bug: http://b/issue?id=6200071
+        String defaultIme = Settings.Secure.getString(
+                getContext().getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
+        if (defaultIme != null && defaultIme.contains("com.htc.android.htcime")) {
+            setInputType(getInputType() | InputType.TYPE_TEXT_VARIATION_FILTER);
+        }
+
+        mGestureDetector =
+                new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() {
+                    @Override
+                    public void onLongPress(MotionEvent e) {
+                        if (mUrlBarDelegate == null) return;
+                        mUrlBarDelegate.gestureDetected(true);
+                        performLongClick();
+                    }
+
+                    @Override
+                    public boolean onSingleTapUp(MotionEvent e) {
+                        if (mUrlBarDelegate == null) return true;
+                        requestFocus();
+                        mUrlBarDelegate.gestureDetected(false);
+                        return true;
+                    }
+                }, ThreadUtils.getUiThreadHandler());
+        mGestureDetector.setOnDoubleTapListener(null);
+        mKeyboardHideHelper = new KeyboardHideHelper(this, new Runnable() {
+            @Override
+            public void run() {
+                if (mUrlBarDelegate != null) mUrlBarDelegate.backKeyPressed();
+            }
+        });
+
+        ApiCompatibilityUtils.disableSmartSelectionTextClassifier(this);
+    }
+
+    public void destroy() {
+        setAllowFocus(false);
+        mUrlBarDelegate = null;
+        setOnFocusChangeListener(null);
+        mTextContextMenuDelegate = null;
+        mUrlTextChangeListener = null;
+        mTextChangedListener = null;
+    }
+
+    /**
+     * Initialize the delegate that allows interaction with the Window.
+     */
+    public void setWindowDelegate(WindowDelegate windowDelegate) {
+        mKeyboardHideHelper.setWindowDelegate(windowDelegate);
+    }
+
+    /**
+     * Set the delegate to be used for text context menu actions.
+     */
+    public void setTextContextMenuDelegate(UrlBarTextContextMenuDelegate delegate) {
+        mTextContextMenuDelegate = delegate;
+    }
+
+    @Override
+    public boolean onKeyPreIme(int keyCode, KeyEvent event) {
+        if (KeyEvent.KEYCODE_BACK == keyCode && event.getAction() == KeyEvent.ACTION_UP) {
+            mKeyboardHideHelper.monitorForKeyboardHidden();
+        }
+        return super.onKeyPreIme(keyCode, event);
+    }
+
+    /**
+     * See {@link AutocompleteEditText#setIgnoreTextChangesForAutocomplete(boolean)}.
+     * <p>
+     * {@link #setDelegate(UrlBarDelegate)} must be called with a non-null instance prior to
+     * enabling autocomplete.
+     */
+    @Override
+    public void setIgnoreTextChangesForAutocomplete(boolean ignoreAutocomplete) {
+        assert mUrlBarDelegate != null;
+        super.setIgnoreTextChangesForAutocomplete(ignoreAutocomplete);
+    }
+
+    @Override
+    protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
+        mFocused = focused;
+        super.onFocusChanged(focused, direction, previouslyFocusedRect);
+
+        if (focused) {
+            mPendingScroll = false;
+        }
+        fixupTextDirection();
+    }
+
+    /**
+     * Sets whether this {@link UrlBar} should be focusable.
+     */
+    public void setAllowFocus(boolean allowFocus) {
+        mAllowFocus = allowFocus;
+        setFocusable(allowFocus);
+        setFocusableInTouchMode(allowFocus);
+    }
+
+    /**
+     * Sets the {@link UrlBar}'s text direction based on focus and contents.
+     *
+     * Should be called whenever focus or text contents change.
+     */
+    private void fixupTextDirection() {
+        // When unfocused, force left-to-right rendering at the paragraph level (which is desired
+        // for URLs). Right-to-left runs are still rendered RTL, but will not flip the whole URL
+        // around. This is consistent with OmniboxViewViews on desktop. When focused, render text
+        // normally (to allow users to make non-URL searches and to avoid showing Android's split
+        // insertion point when an RTL user enters RTL text). Also render text normally when the
+        // text field is empty (because then it displays an instruction that is not a URL).
+        if (mFocused || length() == 0) {
+            setTextDirection(TEXT_DIRECTION_INHERIT);
+        } else {
+            setTextDirection(TEXT_DIRECTION_LTR);
+        }
+        // Always align to the same as the paragraph direction (LTR = left, RTL = right).
+        setTextAlignment(TEXT_ALIGNMENT_TEXT_START);
+    }
+
+    @Override
+    public void onWindowFocusChanged(boolean hasWindowFocus) {
+        super.onWindowFocusChanged(hasWindowFocus);
+        if (DEBUG) Log.i(TAG, "onWindowFocusChanged: " + hasWindowFocus);
+        if (hasWindowFocus) {
+            if (isFocused()) {
+                // Without the call to post(..), the keyboard was not getting shown when the
+                // window regained focus despite this being the final call in the view system
+                // flow.
+                post(new Runnable() {
+                    @Override
+                    public void run() {
+                        KeyboardVisibilityDelegate.getInstance().showKeyboard(UrlBar.this);
+                    }
+                });
+            }
+        }
+    }
+
+    @Override
+    public View focusSearch(int direction) {
+        if (mUrlBarDelegate != null && direction == View.FOCUS_BACKWARD
+                && mUrlBarDelegate.getViewForUrlBackFocus() != null) {
+            return mUrlBarDelegate.getViewForUrlBackFocus();
+        } else {
+            return super.focusSearch(direction);
+        }
+    }
+
+    @Override
+    protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
+        super.onTextChanged(text, start, lengthBefore, lengthAfter);
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+            // Due to crbug.com/1103555, Autofill had to be disabled on the UrlBar to work around
+            // an issue on Android Q+. With Autofill disabled, the Autofill compat mode no longer
+            // learns of changes to the UrlBar, which prevents it from cancelling the session if
+            // the domain changes. We restore this behavior by mimicking the relevant part of
+            // TextView.notifyListeningManagersAfterTextChanged().
+            // https://cs.android.com/android/platform/superproject/+/5d123b67756dffcfdebdb936ab2de2b29c799321:frameworks/base/core/java/android/widget/TextView.java;l=10618;drc=master;bpv=0
+            ApiHelperForO.notifyValueChangedForAutofill(this);
+        }
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        // This method contains special logic to enable long presses to be handled correctly.
+
+        // One piece of the logic is to suppress all ACTION_DOWN events received while the UrlBar is
+        // not focused, and only pass them to super.onTouchEvent() if it turns out we're about to
+        // perform a long press. Long pressing will not behave properly without sending this event,
+        // but if we always send it immediately, it will cause the keyboard to show immediately,
+        // whereas we want to wait to show it until after the URL focus animation finishes, to avoid
+        // performance issues on slow devices.
+
+        // The other piece of the logic is to suppress ACTION_MOVE events received after an
+        // ACTION_DOWN received while the UrlBar is not focused. This is because the UrlBar moves to
+        // the side as it's focusing, and a finger held still on the screen would therefore be
+        // interpreted as a drag selection.
+
+        if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
+            getLocationInWindow(mCachedLocation);
+            mDownEventViewTop = mCachedLocation[1];
+            mSuppressingTouchMoveEventsForThisTouch = !mFocused;
+        }
+
+        if (!mFocused) {
+            if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
+                mSuppressedTouchDownEvent = MotionEvent.obtain(event);
+            }
+            mGestureDetector.onTouchEvent(event);
+            return true;
+        }
+
+        if (event.getActionMasked() == MotionEvent.ACTION_UP
+                || event.getActionMasked() == MotionEvent.ACTION_CANCEL) {
+            // Minor optimization to avoid unnecessarily holding onto a MotionEvent after the touch
+            // finishes.
+            mSuppressedTouchDownEvent = null;
+        }
+
+        if (mSuppressingTouchMoveEventsForThisTouch
+                && event.getActionMasked() == MotionEvent.ACTION_MOVE) {
+            return true;
+        }
+
+        try {
+            return super.onTouchEvent(event);
+        } catch (NullPointerException e) {
+            // Working around a platform bug (b/25562038) that was fixed in N that can throw an
+            // exception during text selection. We just swallow the exception. The outcome is that
+            // the text selection handle doesn't show.
+
+            // If this happens on N or later, there's a different issue here that we might want to
+            // know about.
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) throw e;
+
+            Log.w(TAG, "Ignoring NPE in UrlBar#onTouchEvent.", e);
+            return true;
+        } catch (IndexOutOfBoundsException e) {
+            // Work around crash of unknown origin (https://crbug.com/837419).
+            Log.w(TAG, "Ignoring IndexOutOfBoundsException in UrlBar#onTouchEvent.", e);
+            return true;
+        }
+    }
+
+    @Override
+    public boolean performLongClick() {
+        if (!shouldPerformLongClick()) return false;
+
+        releaseSuppressedTouchDownEvent();
+        return super.performLongClick();
+    }
+
+    /**
+     * @return Whether or not a long click should be performed.
+     */
+    private boolean shouldPerformLongClick() {
+        getLocationInWindow(mCachedLocation);
+
+        // If the view moved between the last down event, block the long-press.
+        return mDownEventViewTop == mCachedLocation[1];
+    }
+
+    private void releaseSuppressedTouchDownEvent() {
+        if (mSuppressedTouchDownEvent != null) {
+            super.onTouchEvent(mSuppressedTouchDownEvent);
+            mSuppressedTouchDownEvent = null;
+        }
+    }
+
+    @Override
+    public void onDraw(Canvas canvas) {
+        super.onDraw(canvas);
+
+        if (!mFirstDrawComplete) {
+            mFirstDrawComplete = true;
+
+            // We have now avoided the first draw problem (see the comment in
+            // the constructor) so we want to make the URL bar focusable so that
+            // touches etc. activate it.
+            setFocusable(mAllowFocus);
+            setFocusableInTouchMode(mAllowFocus);
+        }
+
+        // Notify listeners if the URL's direction has changed.
+        updateUrlDirection();
+    }
+
+    /**
+     * If the direction of the URL has changed, update mUrlDirection and notify the
+     * UrlDirectionListeners.
+     */
+    private void updateUrlDirection() {
+        Layout layout = getLayout();
+        if (layout == null) return;
+
+        int urlDirection;
+        if (length() == 0) {
+            urlDirection = LAYOUT_DIRECTION_LOCALE;
+        } else if (layout.getParagraphDirection(0) == Layout.DIR_LEFT_TO_RIGHT) {
+            urlDirection = LAYOUT_DIRECTION_LTR;
+        } else {
+            urlDirection = LAYOUT_DIRECTION_RTL;
+        }
+
+        if (urlDirection != mUrlDirection) {
+            mUrlDirection = urlDirection;
+            if (mUrlDirectionListener != null) {
+                mUrlDirectionListener.onResult(urlDirection);
+            }
+
+            // Ensure the display text is visible after updating the URL direction.
+            scrollDisplayText();
+        }
+    }
+
+    /**
+     * @return The text direction of the URL, e.g. LAYOUT_DIRECTION_LTR.
+     */
+    public int getUrlDirection() {
+        return mUrlDirection;
+    }
+
+    /**
+     * Sets the listener for changes in the url bar's layout direction. Also calls
+     * onUrlDirectionChanged() immediately on the listener.
+     *
+     * @param listener The UrlDirectionListener to receive callbacks when the url direction changes,
+     *     or null to unregister any previously registered listener.
+     */
+    public void setUrlDirectionListener(Callback<Integer> listener) {
+        mUrlDirectionListener = listener;
+        if (mUrlDirectionListener != null) {
+            mUrlDirectionListener.onResult(mUrlDirection);
+        }
+    }
+
+    /**
+     * Set the url delegate to handle communication from the {@link UrlBar} to the rest of the UI.
+     * @param delegate The {@link UrlBarDelegate} to be used.
+     */
+    public void setDelegate(UrlBarDelegate delegate) {
+        mUrlBarDelegate = delegate;
+    }
+
+    /**
+     * Set the listener to be notified when the URL text has changed.
+     * @param listener The listener to be notified.
+     */
+    public void setUrlTextChangeListener(UrlTextChangeListener listener) {
+        mUrlTextChangeListener = listener;
+    }
+
+    /**
+     * Set the listener to be notified when the view's text has changed.
+     * @param textChangedListener The listener to be notified.
+     */
+    public void setTextChangedListener(TextWatcher textChangedListener) {
+        if (ObjectsCompat.equals(mTextChangedListener, textChangedListener)) {
+            return;
+        } else if (mTextChangedListener != null) {
+            removeTextChangedListener(mTextChangedListener);
+        }
+
+        mTextChangedListener = textChangedListener;
+        addTextChangedListener(mTextChangedListener);
+    }
+
+    /**
+     * Set the text to report to Autofill services upon call to onProvideAutofillStructure.
+     */
+    public void setTextForAutofillServices(CharSequence text) {
+        mTextForAutofillServices = text;
+    }
+
+    @Override
+    public boolean onTextContextMenuItem(int id) {
+        if (mTextContextMenuDelegate == null) return super.onTextContextMenuItem(id);
+
+        if (id == android.R.id.paste) {
+            String pasteString = mTextContextMenuDelegate.getTextToPaste();
+            if (pasteString != null) {
+                int min = 0;
+                int max = getText().length();
+
+                if (isFocused()) {
+                    final int selStart = getSelectionStart();
+                    final int selEnd = getSelectionEnd();
+
+                    min = Math.max(0, Math.min(selStart, selEnd));
+                    max = Math.max(0, Math.max(selStart, selEnd));
+                }
+
+                Selection.setSelection(getText(), max);
+                getText().replace(min, max, pasteString);
+                onPaste();
+            }
+            return true;
+        }
+
+        if ((id == android.R.id.cut || id == android.R.id.copy)) {
+            if (id == android.R.id.cut) {
+                RecordUserAction.record("Omnibox.LongPress.Cut");
+            } else {
+                RecordUserAction.record("Omnibox.LongPress.Copy");
+            }
+            String currentText = getText().toString();
+            String replacementCutCopyText = mTextContextMenuDelegate.getReplacementCutCopyText(
+                    currentText, getSelectionStart(), getSelectionEnd());
+            if (replacementCutCopyText == null) return super.onTextContextMenuItem(id);
+
+            setIgnoreTextChangesForAutocomplete(true);
+            setText(replacementCutCopyText);
+            setSelection(0, replacementCutCopyText.length());
+            setIgnoreTextChangesForAutocomplete(false);
+
+            boolean retVal = super.onTextContextMenuItem(id);
+
+            if (TextUtils.equals(getText(), replacementCutCopyText)) {
+                // Restore the old text if the operation did modify the text.
+                setIgnoreTextChangesForAutocomplete(true);
+                setText(currentText);
+
+                // Move the cursor to the end.
+                setSelection(getText().length());
+                setIgnoreTextChangesForAutocomplete(false);
+            }
+
+            return retVal;
+        }
+
+        if (id == android.R.id.shareText) {
+            RecordUserAction.record("Omnibox.LongPress.Share");
+        }
+
+        return super.onTextContextMenuItem(id);
+    }
+
+    /**
+     * Specified how text should be scrolled within the UrlBar.
+     *
+     * @param scrollType What type of scroll should be applied to the text.
+     * @param scrollToIndex The index that should be scrolled to, which only applies to
+     *                      {@link ScrollType#SCROLL_TO_TLD}.
+     */
+    public void setScrollState(@ScrollType int scrollType, int scrollToIndex) {
+        if (scrollType == ScrollType.SCROLL_TO_TLD) {
+            mOriginEndIndex = scrollToIndex;
+        } else {
+            mOriginEndIndex = 0;
+        }
+        mScrollType = scrollType;
+        scrollDisplayText();
+    }
+
+    /**
+     * Scrolls the omnibox text to a position determined by the current scroll type.
+     *
+     * @see #setScrollState(int, int)
+     */
+    private void scrollDisplayText() {
+        if (isLayoutRequested()) {
+            mPendingScroll = mScrollType != ScrollType.NO_SCROLL;
+            return;
+        }
+        scrollDisplayTextInternal(mScrollType);
+    }
+
+    /**
+     * Scrolls the omnibox text to the position specified, based on the {@link ScrollType}.
+     *
+     * @param scrollType What type of scroll to perform.
+     *                   SCROLL_TO_TLD: Scrolls the omnibox text to bring the TLD into view.
+     *                   SCROLL_TO_BEGINNING: Scrolls text that's too long to fit in the omnibox
+     *                                        to the beginning so we can see the first character.
+     */
+    private void scrollDisplayTextInternal(@ScrollType int scrollType) {
+        mPendingScroll = false;
+
+        if (mFocused) return;
+
+        Editable text = getText();
+        if (TextUtils.isEmpty(text)) scrollType = ScrollType.SCROLL_TO_BEGINNING;
+
+        // Ensure any selection from the focus state is cleared.
+        setSelection(0);
+
+        float currentTextSize = getTextSize();
+        boolean currentIsRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
+
+        int measuredWidth = getMeasuredWidth() - (getPaddingLeft() + getPaddingRight());
+        if (scrollType == mPreviousScrollType && TextUtils.equals(text, mPreviousScrollText)
+                && measuredWidth == mPreviousScrollViewWidth
+                // Font size is float but it changes in discrete range (eg small font, big font),
+                // therefore false negative using regular equality is unlikely.
+                && currentTextSize == mPreviousScrollFontSize
+                && currentIsRtl == mPreviousScrollWasRtl) {
+            scrollTo(mPreviousScrollResultXPosition, getScrollY());
+            return;
+        }
+
+        switch (scrollType) {
+            case ScrollType.SCROLL_TO_TLD:
+                scrollToTLD();
+                break;
+            case ScrollType.SCROLL_TO_BEGINNING:
+                scrollToBeginning();
+                break;
+            default:
+                // Intentional return to avoid clearing scroll state when no scroll was applied.
+                return;
+        }
+
+        mPreviousScrollType = scrollType;
+        mPreviousScrollText = text.toString();
+        mPreviousScrollViewWidth = measuredWidth;
+        mPreviousScrollFontSize = currentTextSize;
+        mPreviousScrollResultXPosition = getScrollX();
+        mPreviousScrollWasRtl = currentIsRtl;
+    }
+
+    /**
+     * Scrolls the omnibox text to show the very beginning of the text entered.
+     */
+    private void scrollToBeginning() {
+        Editable text = getText();
+        float scrollPos = 0f;
+        if (TextUtils.isEmpty(text)) {
+            if (getLayoutDirection() == LAYOUT_DIRECTION_RTL
+                    && BidiFormatter.getInstance().isRtl(getHint())) {
+                // Compared to below that uses getPrimaryHorizontal(1) due to 0 returning an
+                // invalid value, if the text is empty, getPrimaryHorizontal(0) returns the actual
+                // max scroll amount.
+                scrollPos = (int) getLayout().getPrimaryHorizontal(0) - getMeasuredWidth();
+            }
+        } else if (BidiFormatter.getInstance().isRtl(text)) {
+            // RTL.
+            float endPointX = getLayout().getPrimaryHorizontal(text.length());
+            int measuredWidth = getMeasuredWidth();
+            float width = getLayout().getPaint().measureText(text.toString());
+            scrollPos = Math.max(0, endPointX - measuredWidth + width);
+        }
+        scrollTo((int) scrollPos, getScrollY());
+    }
+
+    /**
+     * Scrolls the omnibox text to bring the TLD into view.
+     */
+    private void scrollToTLD() {
+        Editable url = getText();
+        int measuredWidth = getMeasuredWidth() - (getPaddingLeft() + getPaddingRight());
+
+        Layout textLayout = getLayout();
+        assert getLayout().getLineCount() == 1;
+        final int originEndIndex = Math.min(mOriginEndIndex, url.length());
+        if (mOriginEndIndex > url.length()) {
+            // If discovered locally, please update crbug.com/859219 with the steps to reproduce.
+            assert false : "Attempting to scroll past the end of the URL: " + url + ", end index: "
+                           + mOriginEndIndex;
+        }
+        float endPointX = textLayout.getPrimaryHorizontal(originEndIndex);
+        // Compare the position offset of the last character and the character prior to determine
+        // the LTR-ness of the final component of the URL.
+        float priorToEndPointX = url.length() == 1
+                ? 0
+                : textLayout.getPrimaryHorizontal(Math.max(0, originEndIndex - 1));
+
+        float scrollPos;
+        if (priorToEndPointX < endPointX) {
+            // LTR
+            scrollPos = Math.max(0, endPointX - measuredWidth);
+        } else {
+            // RTL
+
+            // To handle BiDirectional text, search backward from the two existing offsets to find
+            // the first LTR character.  Ensure the final RTL component of the domain is visible
+            // above any of the prior LTR pieces.
+            int rtlStartIndexForEndingRun = originEndIndex - 1;
+            for (int i = originEndIndex - 2; i >= 0; i--) {
+                float indexOffsetDrawPosition = textLayout.getPrimaryHorizontal(i);
+                if (indexOffsetDrawPosition > endPointX) {
+                    rtlStartIndexForEndingRun = i;
+                } else {
+                    // getPrimaryHorizontal determines the index position for the next character
+                    // based on the previous characters.  In bi-directional text, the first RTL
+                    // character following LTR text will have an LTR-appearing horizontal offset
+                    // as it is based on the preceding LTR text.  Thus, the start of the RTL
+                    // character run will be after and including the first LTR horizontal index.
+                    rtlStartIndexForEndingRun = Math.max(0, rtlStartIndexForEndingRun - 1);
+                    break;
+                }
+            }
+            float width = textLayout.getPaint().measureText(
+                    url.subSequence(rtlStartIndexForEndingRun, originEndIndex).toString());
+            if (width < measuredWidth) {
+                scrollPos = Math.max(0, endPointX + width - measuredWidth);
+            } else {
+                scrollPos = endPointX + measuredWidth;
+            }
+        }
+        scrollTo((int) scrollPos, getScrollY());
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+
+        if (mPendingScroll) {
+            scrollDisplayTextInternal(mScrollType);
+        } else if (mPreviousWidth != (right - left)) {
+            scrollDisplayTextInternal(mScrollType);
+            mPreviousWidth = right - left;
+        }
+    }
+
+    @Override
+    public boolean bringPointIntoView(int offset) {
+        // TextView internally attempts to keep the selection visible, but in the unfocused state
+        // this class ensures that the TLD is visible.
+        if (!mFocused) return false;
+        assert !mPendingScroll;
+
+        return super.bringPointIntoView(offset);
+    }
+
+    @Override
+    public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
+        InputConnection connection = super.onCreateInputConnection(outAttrs);
+        if (mUrlBarDelegate == null || !mUrlBarDelegate.allowKeyboardLearning()) {
+            outAttrs.imeOptions |= EditorInfoCompat.IME_FLAG_NO_PERSONALIZED_LEARNING;
+        }
+        return connection;
+    }
+
+    @Override
+    public void setText(CharSequence text, BufferType type) {
+        if (DEBUG) Log.i(TAG, "setText -- text: %s", text);
+        super.setText(text, type);
+        fixupTextDirection();
+    }
+
+    private void limitDisplayableLength() {
+        // To limit displayable length we replace middle portion of the string with ellipsis.
+        // That affects only presentation of the text, and doesn't affect other aspects like
+        // copying to the clipboard, getting text with getText(), etc.
+        final int maxLength =
+                SysUtils.isLowEndDevice() ? MAX_DISPLAYABLE_LENGTH_LOW_END : MAX_DISPLAYABLE_LENGTH;
+
+        Editable text = getText();
+        int textLength = text.length();
+        if (textLength <= maxLength) {
+            if (mDidEllipsizeTextHint) {
+                EllipsisSpan[] spans = text.getSpans(0, textLength, EllipsisSpan.class);
+                if (spans != null && spans.length > 0) {
+                    assert spans.length == 1 : "Should never apply more than a single EllipsisSpan";
+                    for (int i = 0; i < spans.length; i++) {
+                        text.removeSpan(spans[i]);
+                    }
+                }
+            }
+            mDidEllipsizeTextHint = false;
+            return;
+        }
+
+        mDidEllipsizeTextHint = true;
+
+        int spanLeft = text.nextSpanTransition(0, textLength, EllipsisSpan.class);
+        if (spanLeft != textLength) return;
+
+        spanLeft = maxLength / 2;
+        text.setSpan(EllipsisSpan.INSTANCE, spanLeft, textLength - spanLeft,
+                Editable.SPAN_INCLUSIVE_EXCLUSIVE);
+    }
+
+    @Override
+    public Editable getText() {
+        if (mRequestingAutofillStructure) {
+            // crbug.com/1109186: mTextForAutofillServices must not be null here, but Autofill
+            // requests can be triggered before it is initialized.
+            return new SpannableStringBuilder(
+                    mTextForAutofillServices != null ? mTextForAutofillServices : "");
+        }
+        return super.getText();
+    }
+
+    @Override
+    public CharSequence getAccessibilityClassName() {
+        // When UrlBar is used as a read-only TextView, force Talkback to pronounce it like
+        // TextView. Otherwise Talkback will say "Edit box, http://...". crbug.com/636988
+        if (isEnabled()) {
+            return super.getAccessibilityClassName();
+        } else {
+            return TextView.class.getName();
+        }
+    }
+
+    @Override
+    public void replaceAllTextFromAutocomplete(String text) {
+        if (DEBUG) Log.i(TAG, "replaceAllTextFromAutocomplete: " + text);
+        setText(text);
+    }
+
+    @Override
+    public void onAutocompleteTextStateChanged(boolean updateDisplay) {
+        if (DEBUG) {
+            Log.i(TAG, "onAutocompleteTextStateChanged: DIS[%b]", updateDisplay);
+        }
+        if (mUrlTextChangeListener == null) return;
+        if (updateDisplay) limitDisplayableLength();
+        // crbug.com/764749
+        Log.w(TAG, "Text change observed, triggering autocomplete.");
+
+        mUrlTextChangeListener.onTextChanged(
+                getTextWithoutAutocomplete(), getTextWithAutocomplete());
+    }
+
+    /**
+     * Span that displays ellipsis instead of the text. Used to hide portion of
+     * very large string to get decent performance from TextView.
+     */
+    private static class EllipsisSpan extends ReplacementSpan {
+        private static final String ELLIPSIS = "...";
+
+        public static final EllipsisSpan INSTANCE = new EllipsisSpan();
+
+        @Override
+        public int getSize(
+                Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) {
+            return (int) paint.measureText(ELLIPSIS);
+        }
+
+        @Override
+        public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top,
+                int y, int bottom, Paint paint) {
+            canvas.drawText(ELLIPSIS, x, y, paint);
+        }
+    }
+}
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java
--- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java
+++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java
@@ -222,8 +222,7 @@ public abstract class UrlBar extends AutocompleteEditText {
             setFocusableInTouchMode(mAllowFocus);
         });
 
-        setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_URI
-                | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
+        setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_URI);
 
         // The HTC Sense IME will attempt to autocomplete words in the Omnibox when Prediction is
         // enabled.  We want to disable this feature and rely on the Omnibox's implementation.
--
2.25.1
