summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/api/current.txt1
-rw-r--r--core/java/android/inputmethodservice/RemoteInputConnection.java20
-rw-r--r--core/java/android/view/inputmethod/CursorAnchorInfo.java4
-rw-r--r--core/java/android/view/inputmethod/EditorBoundsInfo.java6
-rw-r--r--core/java/android/view/inputmethod/InputConnection.java45
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java4
-rw-r--r--core/java/android/widget/AbsListView.java5
-rw-r--r--core/java/com/android/internal/inputmethod/EditableInputConnection.java7
-rw-r--r--core/java/com/android/internal/inputmethod/IInputContextInvoker.java24
-rw-r--r--core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java32
-rw-r--r--core/java/com/android/internal/view/IInputContext.aidl4
-rw-r--r--core/tests/coretests/src/android/view/ViewInputConnectionTest.java5
12 files changed, 145 insertions, 12 deletions
diff --git a/core/api/current.txt b/core/api/current.txt
index ddfbb44e44a6..213ed8337b97 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -52948,6 +52948,7 @@ package android.view.inputmethod {
method public default boolean performSpellCheck();
method public boolean reportFullscreenMode(boolean);
method public boolean requestCursorUpdates(int);
+ method public default boolean requestCursorUpdates(int, int);
method public boolean sendKeyEvent(android.view.KeyEvent);
method public boolean setComposingRegion(int, int);
method public default boolean setComposingRegion(int, int, @Nullable android.view.inputmethod.TextAttribute);
diff --git a/core/java/android/inputmethodservice/RemoteInputConnection.java b/core/java/android/inputmethodservice/RemoteInputConnection.java
index 6b7815d0f732..5b0129ee814c 100644
--- a/core/java/android/inputmethodservice/RemoteInputConnection.java
+++ b/core/java/android/inputmethodservice/RemoteInputConnection.java
@@ -433,6 +433,26 @@ public final class RemoteInputConnection implements InputConnection {
mCancellationGroup, MAX_WAIT_TIME_MILLIS);
}
+ @Override
+ @AnyThread
+ public boolean requestCursorUpdates(@CursorUpdateMode int cursorUpdateMode,
+ @CursorUpdateFilter int cursorUpdateFilter) {
+ if (mCancellationGroup.isCanceled()) {
+ return false;
+ }
+
+ final InputMethodServiceInternal ims = mImsInternal.getAndWarnIfNull();
+ if (ims == null) {
+ return false;
+ }
+
+ final int displayId = ims.getContext().getDisplayId();
+ final CompletableFuture<Boolean> value =
+ mInvoker.requestCursorUpdates(cursorUpdateMode, cursorUpdateFilter, displayId);
+ return CompletableFutureUtil.getResultOrFalse(value, TAG, "requestCursorUpdates()",
+ mCancellationGroup, MAX_WAIT_TIME_MILLIS);
+ }
+
@AnyThread
public Handler getHandler() {
// Nothing should happen when called from input method.
diff --git a/core/java/android/view/inputmethod/CursorAnchorInfo.java b/core/java/android/view/inputmethod/CursorAnchorInfo.java
index 8600f55eee70..7f07146776ab 100644
--- a/core/java/android/view/inputmethod/CursorAnchorInfo.java
+++ b/core/java/android/view/inputmethod/CursorAnchorInfo.java
@@ -575,7 +575,9 @@ public final class CursorAnchorInfo implements Parcelable {
}
/**
- * Returns {@link EditorBoundsInfo} editor related bounds.
+ * Returns {@link EditorBoundsInfo} for the current editor, or {@code null} if IME is not
+ * subscribed with {@link InputConnection#CURSOR_UPDATE_FILTER_EDITOR_BOUNDS}
+ * or {@link InputConnection#CURSOR_UPDATE_MONITOR}.
*/
@Nullable
public EditorBoundsInfo getEditorBoundsInfo() {
diff --git a/core/java/android/view/inputmethod/EditorBoundsInfo.java b/core/java/android/view/inputmethod/EditorBoundsInfo.java
index 081dc819f10b..df82438b7132 100644
--- a/core/java/android/view/inputmethod/EditorBoundsInfo.java
+++ b/core/java/android/view/inputmethod/EditorBoundsInfo.java
@@ -30,13 +30,13 @@ import java.util.Objects;
public final class EditorBoundsInfo implements Parcelable {
/**
- * Container of rectangular position of Editor in the current window.
+ * The bounding box of the of currently focused text editor in local coordinates.
*/
private final RectF mEditorBounds;
/**
- * Container of rectangular position of Editor with additional padding around for initiating
- * Stylus Handwriting in the current window.
+ * The bounding box of the of currently focused text editor with additional padding around it
+ * for initiating Stylus Handwriting in the current window.
*/
private final RectF mHandwritingBounds;
diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java
index 78509fe6e0b5..dac1be6f5a13 100644
--- a/core/java/android/view/inputmethod/InputConnection.java
+++ b/core/java/android/view/inputmethod/InputConnection.java
@@ -1043,6 +1043,23 @@ public interface InputConnection {
int CURSOR_UPDATE_FILTER_INSERTION_MARKER = 1 << 4;
/**
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(value = {CURSOR_UPDATE_IMMEDIATE, CURSOR_UPDATE_MONITOR}, flag = true,
+ prefix = { "CURSOR_UPDATE_" })
+ @interface CursorUpdateMode{}
+
+ /**
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(value = {CURSOR_UPDATE_FILTER_EDITOR_BOUNDS, CURSOR_UPDATE_FILTER_CHARACTER_BOUNDS,
+ CURSOR_UPDATE_FILTER_INSERTION_MARKER}, flag = true,
+ prefix = { "CURSOR_UPDATE_FILTER_" })
+ @interface CursorUpdateFilter{}
+
+ /**
* Called by the input method to ask the editor for calling back
* {@link InputMethodManager#updateCursorAnchorInfo(android.view.View, CursorAnchorInfo)} to
* notify cursor/anchor locations.
@@ -1063,6 +1080,34 @@ public interface InputConnection {
boolean requestCursorUpdates(int cursorUpdateMode);
/**
+ * Called by the input method to ask the editor for calling back
+ * {@link InputMethodManager#updateCursorAnchorInfo(android.view.View, CursorAnchorInfo)} to
+ * notify cursor/anchor locations.
+ *
+ * @param cursorUpdateMode combination of update modes:
+ * {@link #CURSOR_UPDATE_IMMEDIATE}, {@link #CURSOR_UPDATE_MONITOR}
+ * @param cursorUpdateFilter any combination of data filters:
+ * {@link #CURSOR_UPDATE_FILTER_CHARACTER_BOUNDS}, {@link #CURSOR_UPDATE_FILTER_EDITOR_BOUNDS},
+ * {@link #CURSOR_UPDATE_FILTER_INSERTION_MARKER}.
+ *
+ * <p>Pass {@code 0} to disable them. However, if an unknown flag is provided, request will be
+ * rejected and method will return {@code false}.</p>
+ * @return {@code true} if the request is scheduled. {@code false} to indicate that when the
+ * application will not call {@link InputMethodManager#updateCursorAnchorInfo(
+ * android.view.View, CursorAnchorInfo)}.
+ * Since Android {@link android.os.Build.VERSION_CODES#N} until
+ * {@link android.os.Build.VERSION_CODES#TIRAMISU}, this API returned {@code false} when
+ * the target application does not implement this method.
+ */
+ default boolean requestCursorUpdates(@CursorUpdateMode int cursorUpdateMode,
+ @CursorUpdateFilter int cursorUpdateFilter) {
+ if (cursorUpdateFilter == 0) {
+ return requestCursorUpdates(cursorUpdateMode);
+ }
+ return false;
+ }
+
+ /**
* Called by the system to enable application developers to specify a dedicated thread on which
* {@link InputConnection} methods are called back.
*
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 27174630bfa3..a8e094b35cd5 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -1912,8 +1912,8 @@ public final class InputMethodManager {
// TODO (b/210039666): Pipe IME displayId from InputBindResult and use it here.
// instead of mDisplayId.
mServedInputConnection.requestCursorUpdatesFromImm(
- CURSOR_UPDATE_IMMEDIATE | CURSOR_UPDATE_MONITOR
- | CURSOR_UPDATE_FILTER_EDITOR_BOUNDS,
+ CURSOR_UPDATE_IMMEDIATE | CURSOR_UPDATE_MONITOR,
+ CURSOR_UPDATE_FILTER_EDITOR_BOUNDS,
mDisplayId);
}
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 1d8e9a36fb3f..231ae084dd6c 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -6180,6 +6180,11 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
@Override
+ public boolean requestCursorUpdates(int cursorUpdateMode, int cursorUpdateFilter) {
+ return getTarget().requestCursorUpdates(cursorUpdateMode, cursorUpdateFilter);
+ }
+
+ @Override
public Handler getHandler() {
return getTarget().getHandler();
}
diff --git a/core/java/com/android/internal/inputmethod/EditableInputConnection.java b/core/java/com/android/internal/inputmethod/EditableInputConnection.java
index 630c271d9418..f8b268fbc1f2 100644
--- a/core/java/com/android/internal/inputmethod/EditableInputConnection.java
+++ b/core/java/com/android/internal/inputmethod/EditableInputConnection.java
@@ -205,6 +205,13 @@ public final class EditableInputConnection extends BaseInputConnection
}
@Override
+ public boolean requestCursorUpdates(
+ @CursorUpdateMode int cursorUpdateMode, @CursorUpdateFilter int cursorUpdateFilter) {
+ // TODO(b/210039666): use separate attrs for updateMode and updateFilter.
+ return requestCursorUpdates(cursorUpdateMode | cursorUpdateFilter);
+ }
+
+ @Override
public boolean requestCursorUpdates(int cursorUpdateMode) {
if (DEBUG) Log.v(TAG, "requestUpdateCursorAnchorInfo " + cursorUpdateMode);
diff --git a/core/java/com/android/internal/inputmethod/IInputContextInvoker.java b/core/java/com/android/internal/inputmethod/IInputContextInvoker.java
index e6fafe0ac56a..e8838c8bfcae 100644
--- a/core/java/com/android/internal/inputmethod/IInputContextInvoker.java
+++ b/core/java/com/android/internal/inputmethod/IInputContextInvoker.java
@@ -603,6 +603,30 @@ public final class IInputContextInvoker {
}
/**
+ * Invokes {@link IInputContext#requestCursorUpdatesWithFilter(InputConnectionCommandHeader,
+ * int, int, int, AndroidFuture)}.
+ *
+ * @param cursorUpdateMode {@code cursorUpdateMode} parameter to be passed.
+ * @param cursorUpdateFilter {@code cursorUpdateFilter} parameter to be passed.
+ * @param imeDisplayId the display ID that is associated with the IME.
+ * @return {@link AndroidFuture<Boolean>} that can be used to retrieve the invocation
+ * result. {@link RemoteException} will be treated as an error.
+ */
+ @AnyThread
+ @NonNull
+ public AndroidFuture<Boolean> requestCursorUpdates(int cursorUpdateMode, int cursorUpdateFilter,
+ int imeDisplayId) {
+ final AndroidFuture<Boolean> future = new AndroidFuture<>();
+ try {
+ mIInputContext.requestCursorUpdatesWithFilter(createHeader(), cursorUpdateMode,
+ cursorUpdateFilter, imeDisplayId, future);
+ } catch (RemoteException e) {
+ future.completeExceptionally(e);
+ }
+ return future;
+ }
+
+ /**
* Invokes {@link IInputContext#commitContent(InputConnectionCommandHeader, InputContentInfo,
* int, Bundle, AndroidFuture)}.
*
diff --git a/core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java b/core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java
index 780de0eb4da2..f81fd376fef0 100644
--- a/core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java
+++ b/core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java
@@ -935,17 +935,20 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
* Dispatches {@link InputConnection#requestCursorUpdates(int)}.
*
* <p>This method is intended to be called only from {@link InputMethodManager}.</p>
- * @param cursorUpdateMode the mode for {@link InputConnection#requestCursorUpdates(int)}
+ * @param cursorUpdateMode the mode for {@link InputConnection#requestCursorUpdates(int, int)}
+ * @param cursorUpdateFilter the filter for
+ * {@link InputConnection#requestCursorUpdates(int, int)}
* @param imeDisplayId displayId on which IME is displayed.
*/
@Dispatching(cancellable = true)
- public void requestCursorUpdatesFromImm(int cursorUpdateMode, int imeDisplayId) {
+ public void requestCursorUpdatesFromImm(int cursorUpdateMode, int cursorUpdateFilter,
+ int imeDisplayId) {
final int currentSessionId = mCurrentSessionId.get();
dispatchWithTracing("requestCursorUpdatesFromImm", () -> {
if (currentSessionId != mCurrentSessionId.get()) {
return; // cancelled
}
- requestCursorUpdatesInternal(cursorUpdateMode, imeDisplayId);
+ requestCursorUpdatesInternal(cursorUpdateMode, cursorUpdateFilter, imeDisplayId);
});
}
@@ -957,11 +960,28 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
if (header.mSessionId != mCurrentSessionId.get()) {
return false; // cancelled
}
- return requestCursorUpdatesInternal(cursorUpdateMode, imeDisplayId);
+ return requestCursorUpdatesInternal(
+ cursorUpdateMode, 0 /* cursorUpdateFilter */, imeDisplayId);
});
}
- private boolean requestCursorUpdatesInternal(int cursorUpdateMode, int imeDisplayId) {
+ @Dispatching(cancellable = true)
+ @Override
+ public void requestCursorUpdatesWithFilter(InputConnectionCommandHeader header,
+ int cursorUpdateMode, int cursorUpdateFilter, int imeDisplayId,
+ AndroidFuture future /* T=Boolean */) {
+ dispatchWithTracing("requestCursorUpdates", future, () -> {
+ if (header.mSessionId != mCurrentSessionId.get()) {
+ return false; // cancelled
+ }
+ return requestCursorUpdatesInternal(
+ cursorUpdateMode, cursorUpdateFilter, imeDisplayId);
+ });
+ }
+
+ private boolean requestCursorUpdatesInternal(
+ @InputConnection.CursorUpdateMode int cursorUpdateMode,
+ @InputConnection.CursorUpdateFilter int cursorUpdateFilter, int imeDisplayId) {
final InputConnection ic = getInputConnection();
if (ic == null || !isActive()) {
Log.w(TAG, "requestCursorAnchorInfo on inactive InputConnection");
@@ -972,7 +992,7 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
return false;
}
try {
- return ic.requestCursorUpdates(cursorUpdateMode);
+ return ic.requestCursorUpdates(cursorUpdateMode, cursorUpdateFilter);
} catch (AbstractMethodError ignored) {
// TODO(b/199934664): See if we can remove this by providing a default impl.
return false;
diff --git a/core/java/com/android/internal/view/IInputContext.aidl b/core/java/com/android/internal/view/IInputContext.aidl
index 7da0f116c358..909a5379993c 100644
--- a/core/java/com/android/internal/view/IInputContext.aidl
+++ b/core/java/com/android/internal/view/IInputContext.aidl
@@ -98,6 +98,10 @@ import com.android.internal.inputmethod.InputConnectionCommandHeader;
void requestCursorUpdates(in InputConnectionCommandHeader header, int cursorUpdateMode,
int imeDisplayId, in AndroidFuture future /* T=Boolean */);
+ void requestCursorUpdatesWithFilter(in InputConnectionCommandHeader header,
+ int cursorUpdateMode, int cursorUpdateFilter, int imeDisplayId,
+ in AndroidFuture future /* T=Boolean */);
+
void commitContent(in InputConnectionCommandHeader header, in InputContentInfo inputContentInfo,
int flags, in Bundle opts, in AndroidFuture future /* T=Boolean */);
diff --git a/core/tests/coretests/src/android/view/ViewInputConnectionTest.java b/core/tests/coretests/src/android/view/ViewInputConnectionTest.java
index d60c0c688e1a..fda294c73db3 100644
--- a/core/tests/coretests/src/android/view/ViewInputConnectionTest.java
+++ b/core/tests/coretests/src/android/view/ViewInputConnectionTest.java
@@ -549,6 +549,11 @@ public class ViewInputConnectionTest {
}
@Override
+ public boolean requestCursorUpdates(int cursorUpdateMode, int cursorUpdateFilter) {
+ return false;
+ }
+
+ @Override
public Handler getHandler() {
return null;
}