| Index: content/public/android/java/src/org/chromium/content/browser/input/CursorAnchorInfoController.java
|
| diff --git a/content/public/android/java/src/org/chromium/content/browser/input/CursorAnchorInfoController.java b/content/public/android/java/src/org/chromium/content/browser/input/CursorAnchorInfoController.java
|
| index 718db1632ed332fb1d255499929383050720e4aa..7e3171456c6cbb36bd9a7729cdb65d5f1da192c9 100644
|
| --- a/content/public/android/java/src/org/chromium/content/browser/input/CursorAnchorInfoController.java
|
| +++ b/content/public/android/java/src/org/chromium/content/browser/input/CursorAnchorInfoController.java
|
| @@ -14,7 +14,9 @@ import org.chromium.base.VisibleForTesting;
|
| import org.chromium.base.annotations.SuppressFBWarnings;
|
| import org.chromium.content.browser.RenderCoordinates;
|
|
|
| +import java.util.ArrayList;
|
| import java.util.Arrays;
|
| +import java.util.HashMap;
|
|
|
| import javax.annotation.Nonnull;
|
| import javax.annotation.Nullable;
|
| @@ -45,6 +47,12 @@ final class CursorAnchorInfoController {
|
| int getComposingTextEnd();
|
| }
|
|
|
| + /**
|
| + * An interface implemented by classes that want to listener to
|
| + * CursorAnchorInfo updates.
|
| + */
|
| + public interface Listener { void onCursorAnchorInfoUpdate(CursorAnchorInfo info); }
|
| +
|
| // Current focus and monitoring states.
|
| private boolean mIsEditable;
|
| private boolean mHasPendingImmediateRequest;
|
| @@ -82,6 +90,10 @@ final class CursorAnchorInfoController {
|
| @Nonnull
|
| private final ViewDelegate mViewDelegate;
|
|
|
| + @Nonnull
|
| + private final HashMap<View, ArrayList<Listener>> mListeners =
|
| + new HashMap<View, ArrayList<Listener>>();
|
| +
|
| private CursorAnchorInfoController(InputMethodManagerWrapper inputMethodManagerWrapper,
|
| ComposingTextDelegate composingTextDelegate, ViewDelegate viewDelegate) {
|
| mInputMethodManagerWrapper = inputMethodManagerWrapper;
|
| @@ -92,8 +104,8 @@ final class CursorAnchorInfoController {
|
| public static CursorAnchorInfoController create(
|
| InputMethodManagerWrapper inputMethodManagerWrapper,
|
| ComposingTextDelegate composingTextDelegate) {
|
| - return new CursorAnchorInfoController(inputMethodManagerWrapper,
|
| - composingTextDelegate, new ViewDelegate() {
|
| + return new CursorAnchorInfoController(
|
| + inputMethodManagerWrapper, composingTextDelegate, new ViewDelegate() {
|
| @Override
|
| public void getLocationOnScreen(View view, int[] location) {
|
| view.getLocationOnScreen(location);
|
| @@ -110,10 +122,9 @@ final class CursorAnchorInfoController {
|
| @VisibleForTesting
|
| public static CursorAnchorInfoController createForTest(
|
| InputMethodManagerWrapper inputMethodManagerWrapper,
|
| - ComposingTextDelegate composingTextDelegate,
|
| - ViewDelegate viewDelegate) {
|
| - return new CursorAnchorInfoController(inputMethodManagerWrapper, composingTextDelegate,
|
| - viewDelegate);
|
| + ComposingTextDelegate composingTextDelegate, ViewDelegate viewDelegate) {
|
| + return new CursorAnchorInfoController(
|
| + inputMethodManagerWrapper, composingTextDelegate, viewDelegate);
|
| }
|
|
|
| /**
|
| @@ -193,10 +204,10 @@ final class CursorAnchorInfoController {
|
| mInsertionMarkerBottom = insertionMarkerBottom;
|
| }
|
|
|
| - // Notify to IME if there is a pending request, or if it is in monitor mode and we have
|
| - // some change in the state.
|
| + // Notify to IME if there is a pending request, or if we're monitoring
|
| + // for the view and we have some change in the state.
|
| if (mHasPendingImmediateRequest
|
| - || (mMonitorModeEnabled && mLastCursorAnchorInfo == null)) {
|
| + || (monitoringForView(view) && mLastCursorAnchorInfo == null)) {
|
| updateCursorAnchorInfo(view);
|
| }
|
| }
|
| @@ -212,12 +223,15 @@ final class CursorAnchorInfoController {
|
| View view) {
|
| if (!mIsEditable) return false;
|
|
|
| - if (mMonitorModeEnabled && !monitorRequest) {
|
| - // Invalidate saved cursor anchor info if monitor request is cancelled since no longer
|
| - // new values will be arrived from renderer and immediate request may return too old
|
| - // position.
|
| - invalidateLastCursorAnchorInfo();
|
| + if (!monitorRequest && monitoringForView(view)) {
|
| + // Invalidate saved cursor anchor info if we're no longer going to
|
| + // be monitoring for this view to prevent returning stale values for
|
| + // immediate requests.
|
| + if (!mListeners.containsKey(view) || mListeners.get(view).isEmpty()) {
|
| + invalidateLastCursorAnchorInfo();
|
| + }
|
| }
|
| +
|
| mMonitorModeEnabled = monitorRequest;
|
| if (immediateRequest) {
|
| mHasPendingImmediateRequest = true;
|
| @@ -226,6 +240,27 @@ final class CursorAnchorInfoController {
|
| return true;
|
| }
|
|
|
| + public void addListener(Listener listener, View view) {
|
| + if (!mListeners.containsKey(view)) {
|
| + mListeners.put(view, new ArrayList<Listener>());
|
| + }
|
| + mListeners.get(view).add(listener);
|
| +
|
| + mHasPendingImmediateRequest = true;
|
| + }
|
| +
|
| + public void removeListener(Listener listener, View view) {
|
| + mListeners.get(view).remove(listener);
|
| + }
|
| +
|
| + private boolean monitoringForView(View view) {
|
| + if (mMonitorModeEnabled) {
|
| + return true;
|
| + }
|
| +
|
| + return mListeners.containsKey(view) && !mListeners.get(view).isEmpty();
|
| + }
|
| +
|
| /**
|
| * Computes the CursorAnchorInfo instance and notify to InputMethodManager if needed.
|
| */
|
| @@ -277,6 +312,12 @@ final class CursorAnchorInfoController {
|
| if (mInputMethodManagerWrapper != null) {
|
| mInputMethodManagerWrapper.updateCursorAnchorInfo(view, mLastCursorAnchorInfo);
|
| }
|
| +
|
| + if (mListeners.containsKey(view)) {
|
| + for (Listener listener : mListeners.get(view)) {
|
| + listener.onCursorAnchorInfoUpdate(mLastCursorAnchorInfo);
|
| + }
|
| + }
|
| mHasPendingImmediateRequest = false;
|
| }
|
| }
|
|
|