Index: content/public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java |
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java b/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java |
index e075d8e4d400dbef2f502c3f262b3455eed249a6..4d8c29efedf345c6bcb566e4e03bac29a54ba49a 100644 |
--- a/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java |
+++ b/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java |
@@ -4,6 +4,8 @@ |
package org.chromium.content.browser.input; |
+import android.graphics.Matrix; |
+import android.os.Build; |
import android.os.Handler; |
import android.os.ResultReceiver; |
import android.os.SystemClock; |
@@ -15,7 +17,10 @@ import android.text.style.UnderlineSpan; |
import android.view.KeyCharacterMap; |
import android.view.KeyEvent; |
import android.view.View; |
+import android.view.inputmethod.CursorAnchorInfo; |
import android.view.inputmethod.EditorInfo; |
+import android.view.inputmethod.InputConnection; |
+import android.view.inputmethod.InputMethodManager; |
import org.chromium.base.CalledByNative; |
import org.chromium.base.JNINamespace; |
@@ -143,6 +148,53 @@ public class ImeAdapter { |
private int mTextInputFlags; |
private String mLastComposeText; |
+ private static class CursorAnchorInfoSource { |
+ private String mText; |
+ private int mSelectionStart; |
+ private int mSelectionEnd; |
+ private int mCompositionStart; |
+ private int mCompositionEnd; |
+ private float[] mLastCharacterBounds; |
+ } |
+ private CursorAnchorInfoSource mCursorAnchorInfoSource = new CursorAnchorInfoSource(); |
+ |
+ private static class CursorAnchorInfoBuilderWrapper { |
+ |
+ public static boolean isSupported() { |
+ return false; |
+ } |
+ |
+ public static CursorAnchorInfoBuilderWrapper create() { |
+ return new CursorAnchorInfoBuilderWrapper(); |
+ } |
+ |
+ protected CursorAnchorInfoBuilderWrapper() { |
+ } |
+ |
+ public void update(CursorAnchorInfoSource source, Matrix matrix, boolean hasInertionMarker, |
+ float insertionMarkerX, float insertionMarkerTop, float insertionMarkerBottom) { |
+ // This is a stub for platforms that do not support CursorAnchorInfo. |
+ } |
+ |
+ public boolean hasData() { |
+ // This is a stub for platforms that do not support CursorAnchorInfo. |
+ return false; |
+ } |
+ |
+ public void reset() { |
+ // This is a stub for platforms that do not support CursorAnchorInfo. |
+ } |
+ |
+ public void send(InputMethodManagerWrapper inputMethodManagerWrapper, View view) { |
+ // This is a stub for platforms that do not support CursorAnchorInfo. |
+ } |
+ } |
+ |
+ private CursorAnchorInfoBuilderWrapper mCursorAnchorInfoBuilder = |
+ CursorAnchorInfoBuilderWrapper.create(); |
+ private boolean mCursorAnchorInfoMonitorEnabled = false; |
+ private boolean mOneshotUpdateCursorAnchorInfoEnabled = false; |
+ |
@VisibleForTesting |
int mLastSyntheticKeyCode; |
@@ -621,6 +673,82 @@ public class ImeAdapter { |
return true; |
} |
+ /** |
+ * @return Whether the {@link CursorAnchorInfo} is available or not on this device. |
+ */ |
+ public boolean isCursorAnchorInfoSupported() { |
+ return CursorAnchorInfoBuilderWrapper.isSupported(); |
+ } |
+ |
+ /** |
+ * Start or stop calling |
+ * {@link InputMethodManager#updateCursorAnchorInfo(View, CursorAnchorInfo)}. |
+ * @param enabled {@code true} if {@link InputConnection#requestCursorUpdates(int)} is called |
+ * with {@link InputConnection#CURSOR_UPDATE_MONITOR} bit. |
+ */ |
+ public void setCursorAnchorInfoMonitorEnabled(boolean enabled) { |
+ mCursorAnchorInfoMonitorEnabled = enabled; |
+ } |
+ |
+ /** |
+ * Make sure {@link InputMethodManager#updateCursorAnchorInfo(View, CursorAnchorInfo)} is called |
+ * at least once immediately when the latest position becomes available. |
+ * @param view The view to be passed to |
+ * {@link InputMethodManager#updateCursorAnchorInfo(View, CursorAnchorInfo)} if the latest |
+ * position is already available. Otherwise ignored. |
+ */ |
+ public void scheduleOneshotUpdateCursorAnchorInfo(View view) { |
+ if (!mCursorAnchorInfoBuilder.hasData()) { |
+ // If there is no data, send the data later when it becomes available. |
+ mOneshotUpdateCursorAnchorInfoEnabled = true; |
+ return; |
+ } |
+ mCursorAnchorInfoBuilder.send(mInputMethodManagerWrapper, view); |
+ mOneshotUpdateCursorAnchorInfoEnabled = false; |
+ } |
+ |
+ /** |
+ * Update the parameters that are to be passed to the IME through |
+ * {@link InputMethodManager#updateCursorAnchorInfo(View, CursorAnchorInfo)}. |
+ * @param text The text in the focused text field. |
+ * @param selectionStart Index where the text selection starts. {@code -1} if there is no |
+ * selection. |
+ * @param selectionEnd Index where the text selection ends. {@code -1} if there is no |
+ * selection. |
+ * @param compositionStart Index where the text composition starts. {@code -1} if there is no |
+ * selection. |
+ * @param compositionEnd Index where the text composition ends. {@code -1} if there is no |
+ * selection. |
+ */ |
+ public void updateCursorAnchorInfoSource(String text, int selectionStart, int selectionEnd, |
+ int compositionStart, int compositionEnd) { |
+ mCursorAnchorInfoSource.mText = text; |
+ mCursorAnchorInfoSource.mSelectionStart = selectionStart; |
+ mCursorAnchorInfoSource.mSelectionEnd = selectionEnd; |
+ mCursorAnchorInfoSource.mCompositionStart = compositionStart; |
+ mCursorAnchorInfoSource.mCompositionEnd = compositionEnd; |
+ } |
+ |
+ /** |
+ * Call {@link InputMethodManager#updateCursorAnchorInfo(View, CursorAnchorInfo)} if it is |
+ * available and the active IME is actually requested it. |
+ * @param view The view to be passed to |
+ * {@link InputMethodManager#updateCursorAnchorInfo(View, CursorAnchorInfo)} |
+ * @param matrix The matrix from CSS coordinates to the absolute display coordinates. |
+ * @param hasInsertionMaerker Whether the insertion marker exists or not. |
+ * @param insertionMarkerX The X position of the insertion marker, in CSS coordinates. |
+ * @param insertionMarkerTop The top position of the insertion marker, in CSS coordinates. |
+ * @param insertionMarkerBottom The bottom position of the insertion marker, in CSS coordinates. |
+ */ |
+ public void updateCursorAnchorInfo(View view, Matrix matrix, boolean hasInsertionMaerker, |
+ float insertionMarkerX, float insertionMarkerTop, float insertionMarkerBottom) { |
+ mCursorAnchorInfoBuilder.update(mCursorAnchorInfoSource, matrix, hasInsertionMaerker, |
+ insertionMarkerX, insertionMarkerTop, insertionMarkerBottom); |
+ if (!mCursorAnchorInfoMonitorEnabled && !mOneshotUpdateCursorAnchorInfoEnabled) return; |
+ mCursorAnchorInfoBuilder.send(mInputMethodManagerWrapper, view); |
+ mOneshotUpdateCursorAnchorInfoEnabled = false; |
+ } |
+ |
// Calls from C++ to Java |
@CalledByNative |
@@ -699,7 +827,7 @@ public class ImeAdapter { |
@CalledByNative |
private void setCharacterBounds(float[] characterBounds) { |
- // TODO(yukawa): Implement this. |
+ mCursorAnchorInfoSource.mLastCharacterBounds = characterBounds; |
} |
@CalledByNative |
@@ -710,6 +838,7 @@ public class ImeAdapter { |
} |
mNativeImeAdapterAndroid = 0; |
mTextInputType = 0; |
+ mCursorAnchorInfoBuilder.reset(); |
} |
private native boolean nativeSendSyntheticKeyEvent(long nativeImeAdapterAndroid, |