Revert "A unified data class to represent all the InputConnection call"
This reverts commit 2757c24880 [1].
Reason for revert:
We will try another approach to implement InputConnection task
cancellation without InputConnectionCommand.
[1]: I86eba7185b4b0664c1b0b3da794dfc5eeddc725c
Bug: 194151409
Change-Id: I0ef1e1b498b77caf7704742d88c7c81944d75c42
Test: atest CtsInputMethodTestCases:InputConnectionEndToEndTest
This commit is contained in:
@@ -17,11 +17,7 @@
|
||||
package com.android.internal.inputmethod;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
import android.view.inputmethod.ExtractedText;
|
||||
import android.view.inputmethod.SurroundingText;
|
||||
|
||||
import java.util.function.BooleanSupplier;
|
||||
import java.util.function.IntSupplier;
|
||||
@@ -141,143 +137,4 @@ public final class CallbackUtils {
|
||||
callback.onResult(result);
|
||||
} catch (RemoteException ignored) { }
|
||||
}
|
||||
|
||||
/**
|
||||
* A utility method to reply associated with {@link InputConnectionCommand}.
|
||||
*
|
||||
* @param command {@link InputConnectionCommand} to be replied.
|
||||
* @param result a {@link String} value to be replied.
|
||||
* @param tag tag name to be used for debug output when the invocation fails.
|
||||
*/
|
||||
public static void onResult(@NonNull InputConnectionCommand command, boolean result,
|
||||
@Nullable String tag) {
|
||||
if (command.mResultCallbackType != InputConnectionCommand.ResultCallbackType.BOOLEAN) {
|
||||
if (tag != null) {
|
||||
Log.e(tag, InputMethodDebug.inputConnectionCommandTypeToString(command.mCommandType)
|
||||
+ ": Failed to return result=" + result + " due to callback type mismatch."
|
||||
+ " expected=String actual=" + command.mResultCallbackType);
|
||||
}
|
||||
return;
|
||||
}
|
||||
try {
|
||||
IBooleanResultCallback.Stub.asInterface(command.mResultCallback).onResult(result);
|
||||
} catch (Throwable e) {
|
||||
if (tag != null) {
|
||||
Log.e(tag, InputMethodDebug.inputConnectionCommandTypeToString(command.mCommandType)
|
||||
+ ": Failed to return result=" + result, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A utility method to reply associated with {@link InputConnectionCommand}.
|
||||
*
|
||||
* @param command {@link InputConnectionCommand} to be replied.
|
||||
* @param result an int result value to be replied.
|
||||
* @param tag tag name to be used for debug output when the invocation fails.
|
||||
*/
|
||||
public static void onResult(@NonNull InputConnectionCommand command, int result,
|
||||
@Nullable String tag) {
|
||||
if (command.mResultCallbackType != InputConnectionCommand.ResultCallbackType.INT) {
|
||||
if (tag != null) {
|
||||
Log.e(tag, InputMethodDebug.inputConnectionCommandTypeToString(command.mCommandType)
|
||||
+ ": Failed to return result=" + result + " due to callback type mismatch."
|
||||
+ " expected=int actual=" + command.mResultCallbackType);
|
||||
}
|
||||
return;
|
||||
}
|
||||
try {
|
||||
IIntResultCallback.Stub.asInterface(command.mResultCallback).onResult(result);
|
||||
} catch (Throwable e) {
|
||||
if (tag != null) {
|
||||
Log.e(tag, InputMethodDebug.inputConnectionCommandTypeToString(command.mCommandType)
|
||||
+ ": Failed to return result=" + result, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A utility method to reply associated with {@link InputConnectionCommand}.
|
||||
*
|
||||
* @param command {@link InputConnectionCommand} to be replied.
|
||||
* @param result a {@link CharSequence} result value to be replied.
|
||||
* @param tag tag name to be used for debug output when the invocation fails.
|
||||
*/
|
||||
public static void onResult(@NonNull InputConnectionCommand command,
|
||||
@Nullable CharSequence result, @Nullable String tag) {
|
||||
if (command.mResultCallbackType
|
||||
!= InputConnectionCommand.ResultCallbackType.CHAR_SEQUENCE) {
|
||||
if (tag != null) {
|
||||
Log.e(tag, InputMethodDebug.inputConnectionCommandTypeToString(command.mCommandType)
|
||||
+ ": Failed to return result=" + result + " due to callback type mismatch."
|
||||
+ " expected=CharSequence actual=" + command.mResultCallbackType);
|
||||
}
|
||||
return;
|
||||
}
|
||||
try {
|
||||
ICharSequenceResultCallback.Stub.asInterface(command.mResultCallback).onResult(result);
|
||||
} catch (Throwable e) {
|
||||
if (tag != null) {
|
||||
Log.e(tag, InputMethodDebug.inputConnectionCommandTypeToString(command.mCommandType)
|
||||
+ ": Failed to return result=" + result, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A utility method to reply associated with {@link InputConnectionCommand}.
|
||||
*
|
||||
* @param command {@link InputConnectionCommand} to be replied.
|
||||
* @param result a {@link ExtractedText} result value to be replied.
|
||||
* @param tag tag name to be used for debug output when the invocation fails.
|
||||
*/
|
||||
public static void onResult(@NonNull InputConnectionCommand command,
|
||||
@Nullable ExtractedText result, @Nullable String tag) {
|
||||
if (command.mResultCallbackType
|
||||
!= InputConnectionCommand.ResultCallbackType.EXTRACTED_TEXT) {
|
||||
if (tag != null) {
|
||||
Log.e(tag, InputMethodDebug.inputConnectionCommandTypeToString(command.mCommandType)
|
||||
+ ": Failed to return result=" + result + " due to callback type mismatch."
|
||||
+ " expected=ExtractedText actual=" + command.mResultCallbackType);
|
||||
}
|
||||
return;
|
||||
}
|
||||
try {
|
||||
IExtractedTextResultCallback.Stub.asInterface(command.mResultCallback).onResult(result);
|
||||
} catch (Throwable e) {
|
||||
if (tag != null) {
|
||||
Log.e(tag, InputMethodDebug.inputConnectionCommandTypeToString(command.mCommandType)
|
||||
+ ": Failed to return result=" + result, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A utility method to reply associated with {@link InputConnectionCommand}.
|
||||
*
|
||||
* @param command {@link InputConnectionCommand} to be replied.
|
||||
* @param result a {@link SurroundingText} result value to be replied.
|
||||
* @param tag tag name to be used for debug output when the invocation fails.
|
||||
*/
|
||||
public static void onResult(@NonNull InputConnectionCommand command,
|
||||
@Nullable SurroundingText result, @Nullable String tag) {
|
||||
if (command.mResultCallbackType
|
||||
!= InputConnectionCommand.ResultCallbackType.SURROUNDING_TEXT) {
|
||||
if (tag != null) {
|
||||
Log.e(tag, InputMethodDebug.inputConnectionCommandTypeToString(command.mCommandType)
|
||||
+ ": Failed to return result=" + result + " due to callback type mismatch."
|
||||
+ " expected=SurroundingText actual=" + command.mResultCallbackType);
|
||||
}
|
||||
return;
|
||||
}
|
||||
try {
|
||||
ISurroundingTextResultCallback.Stub.asInterface(command.mResultCallback)
|
||||
.onResult(result);
|
||||
} catch (Throwable e) {
|
||||
if (tag != null) {
|
||||
Log.e(tag, InputMethodDebug.inputConnectionCommandTypeToString(command.mCommandType)
|
||||
+ ": Failed to return result=" + result, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ package com.android.internal.inputmethod;
|
||||
|
||||
import android.annotation.AnyThread;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.os.Bundle;
|
||||
import android.os.RemoteException;
|
||||
import android.view.KeyEvent;
|
||||
@@ -33,7 +32,7 @@ import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A stateless wrapper of {@link com.android.internal.view.IInputContext} to encapsulate boilerplate
|
||||
* code around {@link InputConnectionCommand}, {@link Completable} and {@link RemoteException}.
|
||||
* code around {@link Completable} and {@link RemoteException}.
|
||||
*/
|
||||
public final class IInputContextInvoker {
|
||||
|
||||
@@ -56,7 +55,8 @@ public final class IInputContextInvoker {
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements {@link android.view.inputmethod.InputConnection#getTextAfterCursor(int, int)}.
|
||||
* Invokes {@link IInputContext#getTextAfterCursor(int, int,
|
||||
* com.android.internal.inputmethod.ICharSequenceResultCallback)}.
|
||||
*
|
||||
* @param length {@code length} parameter to be passed.
|
||||
* @param flags {@code flags} parameter to be passed.
|
||||
@@ -67,9 +67,8 @@ public final class IInputContextInvoker {
|
||||
@NonNull
|
||||
public Completable.CharSequence getTextAfterCursor(int length, int flags) {
|
||||
final Completable.CharSequence value = Completable.createCharSequence();
|
||||
final InputConnectionCommand command = Commands.getTextAfterCursor(length, flags, value);
|
||||
try {
|
||||
mIInputContext.doEdit(command);
|
||||
mIInputContext.getTextAfterCursor(length, flags, ResultCallbacks.of(value));
|
||||
} catch (RemoteException e) {
|
||||
value.onError(ThrowableHolder.of(e));
|
||||
}
|
||||
@@ -77,7 +76,7 @@ public final class IInputContextInvoker {
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements {@link android.view.inputmethod.InputConnection#getTextBeforeCursor(int, int)}.
|
||||
* Invokes {@link IInputContext#getTextBeforeCursor(int, int, ICharSequenceResultCallback)}.
|
||||
*
|
||||
* @param length {@code length} parameter to be passed.
|
||||
* @param flags {@code flags} parameter to be passed.
|
||||
@@ -88,9 +87,8 @@ public final class IInputContextInvoker {
|
||||
@NonNull
|
||||
public Completable.CharSequence getTextBeforeCursor(int length, int flags) {
|
||||
final Completable.CharSequence value = Completable.createCharSequence();
|
||||
final InputConnectionCommand command = Commands.getTextBeforeCursor(length, flags, value);
|
||||
try {
|
||||
mIInputContext.doEdit(command);
|
||||
mIInputContext.getTextBeforeCursor(length, flags, ResultCallbacks.of(value));
|
||||
} catch (RemoteException e) {
|
||||
value.onError(ThrowableHolder.of(e));
|
||||
}
|
||||
@@ -98,7 +96,7 @@ public final class IInputContextInvoker {
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements {@link android.view.inputmethod.InputConnection#getSelectedText(int)}.
|
||||
* Invokes {@link IInputContext#getSelectedText(int, ICharSequenceResultCallback)}.
|
||||
*
|
||||
* @param flags {@code flags} parameter to be passed.
|
||||
* @return {@link Completable.CharSequence} that can be used to retrieve the invocation result.
|
||||
@@ -108,9 +106,8 @@ public final class IInputContextInvoker {
|
||||
@NonNull
|
||||
public Completable.CharSequence getSelectedText(int flags) {
|
||||
final Completable.CharSequence value = Completable.createCharSequence();
|
||||
final InputConnectionCommand command = Commands.getSelectedText(flags, value);
|
||||
try {
|
||||
mIInputContext.doEdit(command);
|
||||
mIInputContext.getSelectedText(flags, ResultCallbacks.of(value));
|
||||
} catch (RemoteException e) {
|
||||
value.onError(ThrowableHolder.of(e));
|
||||
}
|
||||
@@ -118,8 +115,8 @@ public final class IInputContextInvoker {
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements
|
||||
* {@link android.view.inputmethod.InputConnection#getSurroundingText(int, int, int)}.
|
||||
* Invokes
|
||||
* {@link IInputContext#getSurroundingText(int, int, int, ISurroundingTextResultCallback)}.
|
||||
*
|
||||
* @param beforeLength {@code beforeLength} parameter to be passed.
|
||||
* @param afterLength {@code afterLength} parameter to be passed.
|
||||
@@ -132,10 +129,9 @@ public final class IInputContextInvoker {
|
||||
public Completable.SurroundingText getSurroundingText(int beforeLength, int afterLength,
|
||||
int flags) {
|
||||
final Completable.SurroundingText value = Completable.createSurroundingText();
|
||||
final InputConnectionCommand command =
|
||||
Commands.getSurroundingText(beforeLength, afterLength, flags, value);
|
||||
try {
|
||||
mIInputContext.doEdit(command);
|
||||
mIInputContext.getSurroundingText(beforeLength, afterLength, flags,
|
||||
ResultCallbacks.of(value));
|
||||
} catch (RemoteException e) {
|
||||
value.onError(ThrowableHolder.of(e));
|
||||
}
|
||||
@@ -143,7 +139,7 @@ public final class IInputContextInvoker {
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements {@link android.view.inputmethod.InputConnection#getCursorCapsMode(int)}.
|
||||
* Invokes {@link IInputContext#getCursorCapsMode(int, IIntResultCallback)}.
|
||||
*
|
||||
* @param reqModes {@code reqModes} parameter to be passed.
|
||||
* @return {@link Completable.Int} that can be used to retrieve the invocation result.
|
||||
@@ -153,9 +149,8 @@ public final class IInputContextInvoker {
|
||||
@NonNull
|
||||
public Completable.Int getCursorCapsMode(int reqModes) {
|
||||
final Completable.Int value = Completable.createInt();
|
||||
final InputConnectionCommand command = Commands.getCursorCapsMode(reqModes, value);
|
||||
try {
|
||||
mIInputContext.doEdit(command);
|
||||
mIInputContext.getCursorCapsMode(reqModes, ResultCallbacks.of(value));
|
||||
} catch (RemoteException e) {
|
||||
value.onError(ThrowableHolder.of(e));
|
||||
}
|
||||
@@ -163,8 +158,8 @@ public final class IInputContextInvoker {
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements
|
||||
* {@link android.view.inputmethod.InputConnection#getExtractedText(ExtractedTextRequest, int)}.
|
||||
* Invokes {@link IInputContext#getExtractedText(ExtractedTextRequest, int,
|
||||
* IExtractedTextResultCallback)}.
|
||||
*
|
||||
* @param request {@code request} parameter to be passed.
|
||||
* @param flags {@code flags} parameter to be passed.
|
||||
@@ -175,9 +170,8 @@ public final class IInputContextInvoker {
|
||||
@NonNull
|
||||
public Completable.ExtractedText getExtractedText(ExtractedTextRequest request, int flags) {
|
||||
final Completable.ExtractedText value = Completable.createExtractedText();
|
||||
final InputConnectionCommand command = Commands.getExtractedText(request, flags, value);
|
||||
try {
|
||||
mIInputContext.doEdit(command);
|
||||
mIInputContext.getExtractedText(request, flags, ResultCallbacks.of(value));
|
||||
} catch (RemoteException e) {
|
||||
value.onError(ThrowableHolder.of(e));
|
||||
}
|
||||
@@ -185,7 +179,7 @@ public final class IInputContextInvoker {
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements {@link android.view.inputmethod.InputConnection#commitText(CharSequence, int)}.
|
||||
* Invokes {@link IInputContext#commitText(CharSequence, int)}.
|
||||
*
|
||||
* @param text {@code text} parameter to be passed.
|
||||
* @param newCursorPosition {@code newCursorPosition} parameter to be passed.
|
||||
@@ -194,9 +188,8 @@ public final class IInputContextInvoker {
|
||||
*/
|
||||
@AnyThread
|
||||
public boolean commitText(CharSequence text, int newCursorPosition) {
|
||||
final InputConnectionCommand command = Commands.commitText(text, newCursorPosition);
|
||||
try {
|
||||
mIInputContext.doEdit(command);
|
||||
mIInputContext.commitText(text, newCursorPosition);
|
||||
return true;
|
||||
} catch (RemoteException e) {
|
||||
return false;
|
||||
@@ -204,7 +197,7 @@ public final class IInputContextInvoker {
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements {@link android.view.inputmethod.InputConnection#commitCompletion(CompletionInfo)}.
|
||||
* Invokes {@link IInputContext#commitCompletion(CompletionInfo)}.
|
||||
*
|
||||
* @param text {@code text} parameter to be passed.
|
||||
* @return {@code true} if the invocation is completed without {@link RemoteException}.
|
||||
@@ -212,9 +205,8 @@ public final class IInputContextInvoker {
|
||||
*/
|
||||
@AnyThread
|
||||
public boolean commitCompletion(CompletionInfo text) {
|
||||
final InputConnectionCommand command = Commands.commitCompletion(text);
|
||||
try {
|
||||
mIInputContext.doEdit(command);
|
||||
mIInputContext.commitCompletion(text);
|
||||
return true;
|
||||
} catch (RemoteException e) {
|
||||
return false;
|
||||
@@ -222,7 +214,7 @@ public final class IInputContextInvoker {
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements {@link android.view.inputmethod.InputConnection#commitCorrection(CorrectionInfo)}.
|
||||
* Invokes {@link IInputContext#commitCorrection(CorrectionInfo)}.
|
||||
*
|
||||
* @param correctionInfo {@code correctionInfo} parameter to be passed.
|
||||
* @return {@code true} if the invocation is completed without {@link RemoteException}.
|
||||
@@ -230,9 +222,8 @@ public final class IInputContextInvoker {
|
||||
*/
|
||||
@AnyThread
|
||||
public boolean commitCorrection(CorrectionInfo correctionInfo) {
|
||||
final InputConnectionCommand command = Commands.commitCorrection(correctionInfo);
|
||||
try {
|
||||
mIInputContext.doEdit(command);
|
||||
mIInputContext.commitCorrection(correctionInfo);
|
||||
return true;
|
||||
} catch (RemoteException e) {
|
||||
return false;
|
||||
@@ -240,7 +231,7 @@ public final class IInputContextInvoker {
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements {@link android.view.inputmethod.InputConnection#setSelection(int, int)}.
|
||||
* Invokes {@link IInputContext#setSelection(int, int)}.
|
||||
*
|
||||
* @param start {@code start} parameter to be passed.
|
||||
* @param end {@code start} parameter to be passed.
|
||||
@@ -249,9 +240,8 @@ public final class IInputContextInvoker {
|
||||
*/
|
||||
@AnyThread
|
||||
public boolean setSelection(int start, int end) {
|
||||
final InputConnectionCommand command = Commands.setSelection(start, end);
|
||||
try {
|
||||
mIInputContext.doEdit(command);
|
||||
mIInputContext.setSelection(start, end);
|
||||
return true;
|
||||
} catch (RemoteException e) {
|
||||
return false;
|
||||
@@ -259,7 +249,7 @@ public final class IInputContextInvoker {
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements {@link android.view.inputmethod.InputConnection#performEditorAction(int)}.
|
||||
* Invokes {@link IInputContext#performEditorAction(int)}.
|
||||
*
|
||||
* @param actionCode {@code start} parameter to be passed.
|
||||
* @return {@code true} if the invocation is completed without {@link RemoteException}.
|
||||
@@ -267,9 +257,8 @@ public final class IInputContextInvoker {
|
||||
*/
|
||||
@AnyThread
|
||||
public boolean performEditorAction(int actionCode) {
|
||||
final InputConnectionCommand command = Commands.performEditorAction(actionCode);
|
||||
try {
|
||||
mIInputContext.doEdit(command);
|
||||
mIInputContext.performEditorAction(actionCode);
|
||||
return true;
|
||||
} catch (RemoteException e) {
|
||||
return false;
|
||||
@@ -277,7 +266,7 @@ public final class IInputContextInvoker {
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements {@link android.view.inputmethod.InputConnection#performContextMenuAction(int)}.
|
||||
* Invokes {@link IInputContext#performContextMenuAction(id)}.
|
||||
*
|
||||
* @param id {@code id} parameter to be passed.
|
||||
* @return {@code true} if the invocation is completed without {@link RemoteException}.
|
||||
@@ -285,9 +274,8 @@ public final class IInputContextInvoker {
|
||||
*/
|
||||
@AnyThread
|
||||
public boolean performContextMenuAction(int id) {
|
||||
final InputConnectionCommand command = Commands.performContextMenuAction(id);
|
||||
try {
|
||||
mIInputContext.doEdit(command);
|
||||
mIInputContext.performContextMenuAction(id);
|
||||
return true;
|
||||
} catch (RemoteException e) {
|
||||
return false;
|
||||
@@ -295,7 +283,7 @@ public final class IInputContextInvoker {
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements {@link android.view.inputmethod.InputConnection#setComposingRegion(int, int)}.
|
||||
* Invokes {@link IInputContext#setComposingRegion(int, int)}.
|
||||
*
|
||||
* @param start {@code id} parameter to be passed.
|
||||
* @param end {@code id} parameter to be passed.
|
||||
@@ -304,9 +292,8 @@ public final class IInputContextInvoker {
|
||||
*/
|
||||
@AnyThread
|
||||
public boolean setComposingRegion(int start, int end) {
|
||||
final InputConnectionCommand command = Commands.setComposingRegion(start, end);
|
||||
try {
|
||||
mIInputContext.doEdit(command);
|
||||
mIInputContext.setComposingRegion(start, end);
|
||||
return true;
|
||||
} catch (RemoteException e) {
|
||||
return false;
|
||||
@@ -314,8 +301,7 @@ public final class IInputContextInvoker {
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements
|
||||
* {@link android.view.inputmethod.InputConnection#setComposingText(CharSequence, int)}.
|
||||
* Invokes {@link IInputContext#setComposingText(CharSequence, int)}.
|
||||
*
|
||||
* @param text {@code text} parameter to be passed.
|
||||
* @param newCursorPosition {@code newCursorPosition} parameter to be passed.
|
||||
@@ -324,9 +310,8 @@ public final class IInputContextInvoker {
|
||||
*/
|
||||
@AnyThread
|
||||
public boolean setComposingText(CharSequence text, int newCursorPosition) {
|
||||
final InputConnectionCommand command = Commands.setComposingText(text, newCursorPosition);
|
||||
try {
|
||||
mIInputContext.doEdit(command);
|
||||
mIInputContext.setComposingText(text, newCursorPosition);
|
||||
return true;
|
||||
} catch (RemoteException e) {
|
||||
return false;
|
||||
@@ -334,16 +319,15 @@ public final class IInputContextInvoker {
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements {@link android.view.inputmethod.InputConnection#finishComposingText()}.
|
||||
* Invokes {@link IInputContext#finishComposingText()}.
|
||||
*
|
||||
* @return {@code true} if the invocation is completed without {@link RemoteException}.
|
||||
* {@code false} otherwise.
|
||||
*/
|
||||
@AnyThread
|
||||
public boolean finishComposingText() {
|
||||
final InputConnectionCommand command = Commands.finishComposingText();
|
||||
try {
|
||||
mIInputContext.doEdit(command);
|
||||
mIInputContext.finishComposingText();
|
||||
return true;
|
||||
} catch (RemoteException e) {
|
||||
return false;
|
||||
@@ -351,16 +335,15 @@ public final class IInputContextInvoker {
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements {@link android.view.inputmethod.InputConnection#beginBatchEdit()}.
|
||||
* Invokes {@link IInputContext#beginBatchEdit()}.
|
||||
*
|
||||
* @return {@code true} if the invocation is completed without {@link RemoteException}.
|
||||
* {@code false} otherwise.
|
||||
*/
|
||||
@AnyThread
|
||||
public boolean beginBatchEdit() {
|
||||
final InputConnectionCommand command = Commands.beginBatchEdit();
|
||||
try {
|
||||
mIInputContext.doEdit(command);
|
||||
mIInputContext.beginBatchEdit();
|
||||
return true;
|
||||
} catch (RemoteException e) {
|
||||
return false;
|
||||
@@ -368,16 +351,15 @@ public final class IInputContextInvoker {
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements {@link android.view.inputmethod.InputConnection#endBatchEdit()}.
|
||||
* Invokes {@link IInputContext#endBatchEdit()}.
|
||||
*
|
||||
* @return {@code true} if the invocation is completed without {@link RemoteException}.
|
||||
* {@code false} otherwise.
|
||||
*/
|
||||
@AnyThread
|
||||
public boolean endBatchEdit() {
|
||||
final InputConnectionCommand command = Commands.endBatchEdit();
|
||||
try {
|
||||
mIInputContext.doEdit(command);
|
||||
mIInputContext.endBatchEdit();
|
||||
return true;
|
||||
} catch (RemoteException e) {
|
||||
return false;
|
||||
@@ -385,7 +367,7 @@ public final class IInputContextInvoker {
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements {@link android.view.inputmethod.InputConnection#sendKeyEvent(KeyEvent)}.
|
||||
* Invokes {@link IInputContext#sendKeyEvent(KeyEvent)}.
|
||||
*
|
||||
* @param event {@code event} parameter to be passed.
|
||||
* @return {@code true} if the invocation is completed without {@link RemoteException}.
|
||||
@@ -393,9 +375,8 @@ public final class IInputContextInvoker {
|
||||
*/
|
||||
@AnyThread
|
||||
public boolean sendKeyEvent(KeyEvent event) {
|
||||
final InputConnectionCommand command = Commands.sendKeyEvent(event);
|
||||
try {
|
||||
mIInputContext.doEdit(command);
|
||||
mIInputContext.sendKeyEvent(event);
|
||||
return true;
|
||||
} catch (RemoteException e) {
|
||||
return false;
|
||||
@@ -403,7 +384,7 @@ public final class IInputContextInvoker {
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements {@link android.view.inputmethod.InputConnection#clearMetaKeyStates(int)}.
|
||||
* Invokes {@link IInputContext#clearMetaKeyStates(int)}.
|
||||
*
|
||||
* @param states {@code states} parameter to be passed.
|
||||
* @return {@code true} if the invocation is completed without {@link RemoteException}.
|
||||
@@ -411,9 +392,8 @@ public final class IInputContextInvoker {
|
||||
*/
|
||||
@AnyThread
|
||||
public boolean clearMetaKeyStates(int states) {
|
||||
final InputConnectionCommand command = Commands.clearMetaKeyStates(states);
|
||||
try {
|
||||
mIInputContext.doEdit(command);
|
||||
mIInputContext.clearMetaKeyStates(states);
|
||||
return true;
|
||||
} catch (RemoteException e) {
|
||||
return false;
|
||||
@@ -421,7 +401,7 @@ public final class IInputContextInvoker {
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements {@link android.view.inputmethod.InputConnection#deleteSurroundingText(int, int)}.
|
||||
* Invokes {@link IInputContext#deleteSurroundingText(int, int)}.
|
||||
*
|
||||
* @param beforeLength {@code beforeLength} parameter to be passed.
|
||||
* @param afterLength {@code afterLength} parameter to be passed.
|
||||
@@ -430,10 +410,8 @@ public final class IInputContextInvoker {
|
||||
*/
|
||||
@AnyThread
|
||||
public boolean deleteSurroundingText(int beforeLength, int afterLength) {
|
||||
final InputConnectionCommand command =
|
||||
Commands.deleteSurroundingText(beforeLength, afterLength);
|
||||
try {
|
||||
mIInputContext.doEdit(command);
|
||||
mIInputContext.deleteSurroundingText(beforeLength, afterLength);
|
||||
return true;
|
||||
} catch (RemoteException e) {
|
||||
return false;
|
||||
@@ -441,8 +419,7 @@ public final class IInputContextInvoker {
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements
|
||||
* {@link android.view.inputmethod.InputConnection#deleteSurroundingTextInCodePoints(int, int)}.
|
||||
* Invokes {@link IInputContext#deleteSurroundingTextInCodePoints(int, int)}.
|
||||
*
|
||||
* @param beforeLength {@code beforeLength} parameter to be passed.
|
||||
* @param afterLength {@code afterLength} parameter to be passed.
|
||||
@@ -451,10 +428,8 @@ public final class IInputContextInvoker {
|
||||
*/
|
||||
@AnyThread
|
||||
public boolean deleteSurroundingTextInCodePoints(int beforeLength, int afterLength) {
|
||||
final InputConnectionCommand command =
|
||||
Commands.deleteSurroundingTextInCodePoints(beforeLength, afterLength);
|
||||
try {
|
||||
mIInputContext.doEdit(command);
|
||||
mIInputContext.deleteSurroundingTextInCodePoints(beforeLength, afterLength);
|
||||
return true;
|
||||
} catch (RemoteException e) {
|
||||
return false;
|
||||
@@ -462,16 +437,15 @@ public final class IInputContextInvoker {
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements {@link android.view.inputmethod.InputConnection#performSpellCheck()}.
|
||||
* Invokes {@link IInputContext#performSpellCheck()}.
|
||||
*
|
||||
* @return {@code true} if the invocation is completed without {@link RemoteException}.
|
||||
* {@code false} otherwise.
|
||||
*/
|
||||
@AnyThread
|
||||
public boolean performSpellCheck() {
|
||||
final InputConnectionCommand command = Commands.performSpellCheck();
|
||||
try {
|
||||
mIInputContext.doEdit(command);
|
||||
mIInputContext.performSpellCheck();
|
||||
return true;
|
||||
} catch (RemoteException e) {
|
||||
return false;
|
||||
@@ -479,8 +453,7 @@ public final class IInputContextInvoker {
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements
|
||||
* {@link android.view.inputmethod.InputConnection#performPrivateCommand(String, Bundle)}.
|
||||
* Invokes {@link IInputContext#performPrivateCommand(String, Bundle)}.
|
||||
*
|
||||
* @param action {@code action} parameter to be passed.
|
||||
* @param data {@code data} parameter to be passed.
|
||||
@@ -489,9 +462,8 @@ public final class IInputContextInvoker {
|
||||
*/
|
||||
@AnyThread
|
||||
public boolean performPrivateCommand(String action, Bundle data) {
|
||||
final InputConnectionCommand command = Commands.performPrivateCommand(action, data);
|
||||
try {
|
||||
mIInputContext.doEdit(command);
|
||||
mIInputContext.performPrivateCommand(action, data);
|
||||
return true;
|
||||
} catch (RemoteException e) {
|
||||
return false;
|
||||
@@ -499,7 +471,7 @@ public final class IInputContextInvoker {
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements {@link android.view.inputmethod.InputConnection#requestCursorUpdates(int)}.
|
||||
* Invokes {@link IInputContext#requestCursorUpdates(int, IIntResultCallback)}.
|
||||
*
|
||||
* @param cursorUpdateMode {@code cursorUpdateMode} parameter to be passed.
|
||||
* @return {@link Completable.Boolean} that can be used to retrieve the invocation result.
|
||||
@@ -509,10 +481,8 @@ public final class IInputContextInvoker {
|
||||
@NonNull
|
||||
public Completable.Boolean requestCursorUpdates(int cursorUpdateMode) {
|
||||
final Completable.Boolean value = Completable.createBoolean();
|
||||
final InputConnectionCommand command =
|
||||
Commands.requestCursorUpdates(cursorUpdateMode, value);
|
||||
try {
|
||||
mIInputContext.doEdit(command);
|
||||
mIInputContext.requestCursorUpdates(cursorUpdateMode, ResultCallbacks.of(value));
|
||||
} catch (RemoteException e) {
|
||||
value.onError(ThrowableHolder.of(e));
|
||||
}
|
||||
@@ -520,8 +490,8 @@ public final class IInputContextInvoker {
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements {@link android.view.inputmethod.InputConnection#commitContent(InputContentInfo,
|
||||
* int, Bundle)}.
|
||||
* Invokes
|
||||
* {@link IInputContext#commitContent(InputContentInfo, int, Bundle, IIntResultCallback)}.
|
||||
*
|
||||
* @param inputContentInfo {@code inputContentInfo} parameter to be passed.
|
||||
* @param flags {@code flags} parameter to be passed.
|
||||
@@ -534,10 +504,8 @@ public final class IInputContextInvoker {
|
||||
public Completable.Boolean commitContent(InputContentInfo inputContentInfo, int flags,
|
||||
Bundle opts) {
|
||||
final Completable.Boolean value = Completable.createBoolean();
|
||||
final InputConnectionCommand command =
|
||||
Commands.commitContent(inputContentInfo, flags, opts, value);
|
||||
try {
|
||||
mIInputContext.doEdit(command);
|
||||
mIInputContext.commitContent(inputContentInfo, flags, opts, ResultCallbacks.of(value));
|
||||
} catch (RemoteException e) {
|
||||
value.onError(ThrowableHolder.of(e));
|
||||
}
|
||||
@@ -545,7 +513,7 @@ public final class IInputContextInvoker {
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements {@link android.view.inputmethod.InputConnection#setImeConsumesInput(boolean)}.
|
||||
* Invokes {@link IInputContext#setImeConsumesInput(boolean)}.
|
||||
*
|
||||
* @param imeConsumesInput {@code imeConsumesInput} parameter to be passed.
|
||||
* @return {@code true} if the invocation is completed without {@link RemoteException}.
|
||||
@@ -553,341 +521,11 @@ public final class IInputContextInvoker {
|
||||
*/
|
||||
@AnyThread
|
||||
public boolean setImeConsumesInput(boolean imeConsumesInput) {
|
||||
final InputConnectionCommand command = Commands.setImeConsumesInput(imeConsumesInput);
|
||||
try {
|
||||
mIInputContext.doEdit(command);
|
||||
mIInputContext.setImeConsumesInput(imeConsumesInput);
|
||||
return true;
|
||||
} catch (RemoteException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the data packing rules from {@link android.view.inputmethod.InputConnection} API
|
||||
* params into {@link InputConnectionCommand} fields.
|
||||
*
|
||||
* Rules need to be in sync with {@link com.android.internal.view.IInputConnectionWrapper} and
|
||||
* {@link InputMethodDebug#dumpInputConnectionCommand(InputConnectionCommand)}.
|
||||
*/
|
||||
private static final class Commands {
|
||||
/**
|
||||
* Not intended to be instantiated.
|
||||
*/
|
||||
private Commands() { }
|
||||
|
||||
@AnyThread
|
||||
@NonNull
|
||||
static InputConnectionCommand getTextAfterCursor(int n, int flags,
|
||||
@NonNull Completable.CharSequence returnValue) {
|
||||
return InputConnectionCommand.create(
|
||||
InputConnectionCommandType.GET_TEXT_AFTER_CURSOR,
|
||||
n,
|
||||
0,
|
||||
flags,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
InputConnectionCommand.ParcelableType.NULL,
|
||||
null,
|
||||
returnValue);
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
@NonNull
|
||||
static InputConnectionCommand getTextBeforeCursor(int n, int flags,
|
||||
@NonNull Completable.CharSequence returnValue) {
|
||||
return InputConnectionCommand.create(
|
||||
InputConnectionCommandType.GET_TEXT_BEFORE_CURSOR,
|
||||
n,
|
||||
0,
|
||||
flags,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
InputConnectionCommand.ParcelableType.NULL,
|
||||
null,
|
||||
returnValue);
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
@NonNull
|
||||
static InputConnectionCommand getSelectedText(int flags,
|
||||
@NonNull Completable.CharSequence returnValue) {
|
||||
return InputConnectionCommand.create(
|
||||
InputConnectionCommandType.GET_SELECTED_TEXT,
|
||||
0,
|
||||
0,
|
||||
flags,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
InputConnectionCommand.ParcelableType.NULL,
|
||||
null,
|
||||
returnValue);
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
@NonNull
|
||||
static InputConnectionCommand getSurroundingText(int beforeLength, int afterLength,
|
||||
int flags, @NonNull Completable.SurroundingText returnValue) {
|
||||
return InputConnectionCommand.create(
|
||||
InputConnectionCommandType.GET_SURROUNDING_TEXT,
|
||||
beforeLength,
|
||||
afterLength,
|
||||
flags,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
InputConnectionCommand.ParcelableType.NULL,
|
||||
null,
|
||||
returnValue);
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
@NonNull
|
||||
static InputConnectionCommand getCursorCapsMode(int reqModes,
|
||||
@NonNull Completable.Int returnValue) {
|
||||
return InputConnectionCommand.create(
|
||||
InputConnectionCommandType.GET_CURSOR_CAPS_MODE,
|
||||
reqModes,
|
||||
0,
|
||||
0,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
InputConnectionCommand.ParcelableType.NULL,
|
||||
null,
|
||||
returnValue);
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
@NonNull
|
||||
static InputConnectionCommand getExtractedText(@Nullable ExtractedTextRequest request,
|
||||
int flags, @NonNull Completable.ExtractedText returnValue) {
|
||||
return InputConnectionCommand.create(
|
||||
InputConnectionCommandType.GET_EXTRACTED_TEXT,
|
||||
0,
|
||||
0,
|
||||
flags,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
InputConnectionCommand.ParcelableType.EXTRACTED_TEXT_REQUEST,
|
||||
request,
|
||||
returnValue);
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
@NonNull
|
||||
static InputConnectionCommand commitText(@Nullable CharSequence text,
|
||||
int newCursorPosition) {
|
||||
return InputConnectionCommand.create(
|
||||
InputConnectionCommandType.COMMIT_TEXT,
|
||||
newCursorPosition,
|
||||
0,
|
||||
0,
|
||||
text);
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
@NonNull
|
||||
static InputConnectionCommand commitCompletion(@Nullable CompletionInfo text) {
|
||||
return InputConnectionCommand.create(
|
||||
InputConnectionCommandType.COMMIT_COMPLETION,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
InputConnectionCommand.ParcelableType.COMPLETION_INFO,
|
||||
text);
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
@NonNull
|
||||
static InputConnectionCommand commitCorrection(@Nullable CorrectionInfo correctionInfo) {
|
||||
return InputConnectionCommand.create(
|
||||
InputConnectionCommandType.COMMIT_CORRECTION,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
InputConnectionCommand.ParcelableType.CORRECTION_INFO,
|
||||
correctionInfo);
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
@NonNull
|
||||
static InputConnectionCommand setSelection(int start, int end) {
|
||||
return InputConnectionCommand.create(
|
||||
InputConnectionCommandType.SET_SELECTION,
|
||||
start,
|
||||
end);
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
@NonNull
|
||||
static InputConnectionCommand performEditorAction(int actionCode) {
|
||||
return InputConnectionCommand.create(
|
||||
InputConnectionCommandType.PERFORM_EDITOR_ACTION,
|
||||
actionCode);
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
@NonNull
|
||||
static InputConnectionCommand performContextMenuAction(int id) {
|
||||
return InputConnectionCommand.create(
|
||||
InputConnectionCommandType.PERFORM_CONTEXT_MENU_ACTION,
|
||||
id);
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
@NonNull
|
||||
static InputConnectionCommand setComposingRegion(int start, int end) {
|
||||
return InputConnectionCommand.create(
|
||||
InputConnectionCommandType.SET_COMPOSING_REGION,
|
||||
start,
|
||||
end);
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
@NonNull
|
||||
static InputConnectionCommand setComposingText(@Nullable CharSequence text,
|
||||
int newCursorPosition) {
|
||||
return InputConnectionCommand.create(
|
||||
InputConnectionCommandType.SET_COMPOSING_TEXT,
|
||||
newCursorPosition,
|
||||
0,
|
||||
0,
|
||||
text);
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
@NonNull
|
||||
static InputConnectionCommand finishComposingText() {
|
||||
return InputConnectionCommand.create(
|
||||
InputConnectionCommandType.FINISH_COMPOSING_TEXT);
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
@NonNull
|
||||
static InputConnectionCommand beginBatchEdit() {
|
||||
return InputConnectionCommand.create(
|
||||
InputConnectionCommandType.BEGIN_BATCH_EDIT);
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
@NonNull
|
||||
static InputConnectionCommand endBatchEdit() {
|
||||
return InputConnectionCommand.create(
|
||||
InputConnectionCommandType.END_BATCH_EDIT);
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
@NonNull
|
||||
static InputConnectionCommand sendKeyEvent(@Nullable KeyEvent event) {
|
||||
return InputConnectionCommand.create(
|
||||
InputConnectionCommandType.SEND_KEY_EVENT,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
InputConnectionCommand.ParcelableType.KEY_EVENT,
|
||||
event);
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
@NonNull
|
||||
static InputConnectionCommand clearMetaKeyStates(int states) {
|
||||
return InputConnectionCommand.create(
|
||||
InputConnectionCommandType.CLEAR_META_KEY_STATES,
|
||||
states);
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
@NonNull
|
||||
static InputConnectionCommand deleteSurroundingText(int beforeLength, int afterLength) {
|
||||
return InputConnectionCommand.create(
|
||||
InputConnectionCommandType.DELETE_SURROUNDING_TEXT,
|
||||
beforeLength,
|
||||
afterLength);
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
@NonNull
|
||||
static InputConnectionCommand deleteSurroundingTextInCodePoints(int beforeLength,
|
||||
int afterLength) {
|
||||
return InputConnectionCommand.create(
|
||||
InputConnectionCommandType.DELETE_SURROUNDING_TEXT_IN_CODE_POINTS,
|
||||
beforeLength,
|
||||
afterLength);
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
@NonNull
|
||||
static InputConnectionCommand performSpellCheck() {
|
||||
return InputConnectionCommand.create(InputConnectionCommandType.PERFORM_SPELL_CHECK);
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
@NonNull
|
||||
static InputConnectionCommand performPrivateCommand(@Nullable String action,
|
||||
@Nullable Bundle data) {
|
||||
return InputConnectionCommand.create(
|
||||
InputConnectionCommandType.PERFORM_PRIVATE_COMMAND,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
null,
|
||||
action,
|
||||
data);
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
@NonNull
|
||||
static InputConnectionCommand requestCursorUpdates(int cursorUpdateMode,
|
||||
@NonNull Completable.Boolean returnValue) {
|
||||
return InputConnectionCommand.create(
|
||||
InputConnectionCommandType.REQUEST_CURSOR_UPDATES,
|
||||
cursorUpdateMode,
|
||||
0,
|
||||
0,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
InputConnectionCommand.ParcelableType.NULL,
|
||||
null,
|
||||
returnValue);
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
@NonNull
|
||||
static InputConnectionCommand commitContent(@Nullable InputContentInfo inputContentInfo,
|
||||
int flags, @Nullable Bundle opts, @NonNull Completable.Boolean returnValue) {
|
||||
return InputConnectionCommand.create(
|
||||
InputConnectionCommandType.COMMIT_CONTENT,
|
||||
0,
|
||||
0,
|
||||
flags,
|
||||
null,
|
||||
null,
|
||||
opts,
|
||||
InputConnectionCommand.ParcelableType.INPUT_CONTENT_INFO,
|
||||
inputContentInfo,
|
||||
returnValue);
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
@NonNull
|
||||
static InputConnectionCommand setImeConsumesInput(boolean imeConsumesInput) {
|
||||
return InputConnectionCommand.create(
|
||||
InputConnectionCommandType.SET_IME_CONSUMES_INPUT,
|
||||
imeConsumesInput ? 1 : 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.internal.inputmethod;
|
||||
|
||||
parcelable InputConnectionCommand;
|
||||
@@ -1,460 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.internal.inputmethod;
|
||||
|
||||
import static java.lang.annotation.RetentionPolicy.SOURCE;
|
||||
|
||||
import android.annotation.AnyThread;
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.IntRange;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.inputmethod.CompletionInfo;
|
||||
import android.view.inputmethod.CorrectionInfo;
|
||||
import android.view.inputmethod.ExtractedTextRequest;
|
||||
import android.view.inputmethod.InputContentInfo;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
|
||||
/**
|
||||
* Defines the command message to be used for IMEs to remotely invoke
|
||||
* {@link android.view.inputmethod.InputConnection} APIs in the IME client process then receive
|
||||
* results.
|
||||
*/
|
||||
public final class InputConnectionCommand implements Parcelable {
|
||||
private static final String TAG = "InputConnectionCommand";
|
||||
|
||||
@Retention(SOURCE)
|
||||
@IntDef(value = {
|
||||
ResultCallbackType.NULL,
|
||||
ResultCallbackType.BOOLEAN,
|
||||
ResultCallbackType.INT,
|
||||
ResultCallbackType.CHAR_SEQUENCE,
|
||||
ResultCallbackType.EXTRACTED_TEXT,
|
||||
ResultCallbackType.SURROUNDING_TEXT,
|
||||
})
|
||||
@interface ResultCallbackType {
|
||||
int NULL = 0;
|
||||
int BOOLEAN = 1;
|
||||
int INT = 2;
|
||||
int CHAR_SEQUENCE = 3;
|
||||
int EXTRACTED_TEXT = 4;
|
||||
int SURROUNDING_TEXT = 5;
|
||||
}
|
||||
|
||||
@Retention(SOURCE)
|
||||
@IntDef(value = {
|
||||
ParcelableType.NULL,
|
||||
ParcelableType.EXTRACTED_TEXT_REQUEST,
|
||||
ParcelableType.COMPLETION_INFO,
|
||||
ParcelableType.CORRECTION_INFO,
|
||||
ParcelableType.KEY_EVENT,
|
||||
ParcelableType.INPUT_CONTENT_INFO,
|
||||
})
|
||||
@interface ParcelableType {
|
||||
int NULL = 0;
|
||||
int EXTRACTED_TEXT_REQUEST = 1;
|
||||
int COMPLETION_INFO = 2;
|
||||
int CORRECTION_INFO = 3;
|
||||
int KEY_EVENT = 4;
|
||||
int INPUT_CONTENT_INFO = 5;
|
||||
}
|
||||
|
||||
@Retention(SOURCE)
|
||||
@IntDef(flag = true, value = {
|
||||
FieldMask.INT_ARG0,
|
||||
FieldMask.INT_ARG1,
|
||||
FieldMask.FLAGS,
|
||||
FieldMask.CHAR_SEQUENCE,
|
||||
FieldMask.STRING,
|
||||
FieldMask.BUNDLE,
|
||||
FieldMask.PARCELABLE,
|
||||
FieldMask.CALLBACK,
|
||||
})
|
||||
@interface FieldMask {
|
||||
int INT_ARG0 = 1 << 0;
|
||||
int INT_ARG1 = 1 << 1;
|
||||
int FLAGS = 1 << 2;
|
||||
int CHAR_SEQUENCE = 1 << 3;
|
||||
int STRING = 1 << 4;
|
||||
int BUNDLE = 1 << 5;
|
||||
int PARCELABLE = 1 << 6;
|
||||
int CALLBACK = 1 << 7;
|
||||
}
|
||||
|
||||
@IntRange(from = InputConnectionCommandType.FIRST_COMMAND,
|
||||
to = InputConnectionCommandType.LAST_COMMAND)
|
||||
@InputConnectionCommandType
|
||||
public final int mCommandType;
|
||||
public final int mIntArg0;
|
||||
public final int mIntArg1;
|
||||
public final int mFlags;
|
||||
public final CharSequence mCharSequence;
|
||||
public final String mString;
|
||||
public final Bundle mBundle;
|
||||
@ParcelableType
|
||||
public final int mParcelableType;
|
||||
public final Parcelable mParcelable;
|
||||
@ResultCallbackType
|
||||
public final int mResultCallbackType;
|
||||
public final IBinder mResultCallback;
|
||||
|
||||
private InputConnectionCommand(
|
||||
@IntRange(
|
||||
from = InputConnectionCommandType.FIRST_COMMAND,
|
||||
to = InputConnectionCommandType.LAST_COMMAND)
|
||||
@InputConnectionCommandType int type, int intArg0, int intArg1, int flags,
|
||||
@Nullable CharSequence charSequence, @Nullable String string, @Nullable Bundle bundle,
|
||||
@ParcelableType int parcelableType, @Nullable Parcelable parcelable,
|
||||
@ResultCallbackType int resultCallbackType, @Nullable IBinder resultCallback) {
|
||||
if (type < InputConnectionCommandType.FIRST_COMMAND
|
||||
|| InputConnectionCommandType.LAST_COMMAND < type) {
|
||||
throw new IllegalArgumentException("Unknown type=" + type);
|
||||
}
|
||||
mCommandType = type;
|
||||
mIntArg0 = intArg0;
|
||||
mIntArg1 = intArg1;
|
||||
mFlags = flags;
|
||||
mCharSequence = charSequence;
|
||||
mString = string;
|
||||
mBundle = bundle;
|
||||
mParcelableType = parcelableType;
|
||||
mParcelable = parcelable;
|
||||
mResultCallbackType = resultCallbackType;
|
||||
mResultCallback = resultCallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates {@link InputConnectionCommand} with the given {@link InputConnectionCommandType}.
|
||||
*
|
||||
* @param type {@link InputConnectionCommandType} to be set.
|
||||
* @return An {@link InputConnectionCommand} that is initialized with {@code type}.
|
||||
*/
|
||||
@NonNull
|
||||
public static InputConnectionCommand create(
|
||||
@IntRange(
|
||||
from = InputConnectionCommandType.FIRST_COMMAND,
|
||||
to = InputConnectionCommandType.LAST_COMMAND)
|
||||
@InputConnectionCommandType int type) {
|
||||
return create(type, 0);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
static InputConnectionCommand create(
|
||||
@IntRange(
|
||||
from = InputConnectionCommandType.FIRST_COMMAND,
|
||||
to = InputConnectionCommandType.LAST_COMMAND)
|
||||
@InputConnectionCommandType int type, int intArg0) {
|
||||
return create(type, intArg0, 0);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
static InputConnectionCommand create(
|
||||
@IntRange(
|
||||
from = InputConnectionCommandType.FIRST_COMMAND,
|
||||
to = InputConnectionCommandType.LAST_COMMAND)
|
||||
@InputConnectionCommandType int type, int intArg0, int intArg1) {
|
||||
return create(type, intArg0, intArg1, 0, null);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
static InputConnectionCommand create(
|
||||
@IntRange(
|
||||
from = InputConnectionCommandType.FIRST_COMMAND,
|
||||
to = InputConnectionCommandType.LAST_COMMAND)
|
||||
@InputConnectionCommandType int type, int intArg0,
|
||||
int intArg1, int flags, @Nullable CharSequence charSequence) {
|
||||
return create(type, intArg0, intArg1, flags, charSequence, null, null);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
static InputConnectionCommand create(
|
||||
@IntRange(
|
||||
from = InputConnectionCommandType.FIRST_COMMAND,
|
||||
to = InputConnectionCommandType.LAST_COMMAND)
|
||||
@InputConnectionCommandType int type,
|
||||
int intArg0, int intArg1, int flags, @Nullable CharSequence charSequence,
|
||||
@Nullable String string, @Nullable Bundle bundle) {
|
||||
return create(type, intArg0, intArg1, flags, charSequence, string,
|
||||
bundle, ParcelableType.NULL, null);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
static InputConnectionCommand create(
|
||||
@IntRange(
|
||||
from = InputConnectionCommandType.FIRST_COMMAND,
|
||||
to = InputConnectionCommandType.LAST_COMMAND)
|
||||
@InputConnectionCommandType int type,
|
||||
int intArg0, int intArg1, int flags, @Nullable CharSequence charSequence,
|
||||
@Nullable String string, @Nullable Bundle bundle,
|
||||
@ParcelableType int parcelableType, @Nullable Parcelable parcelable) {
|
||||
return new InputConnectionCommand(type, intArg0, intArg1, flags, charSequence, string,
|
||||
bundle, parcelableType, parcelable, ResultCallbackType.NULL, null);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
static InputConnectionCommand create(
|
||||
@IntRange(
|
||||
from = InputConnectionCommandType.FIRST_COMMAND,
|
||||
to = InputConnectionCommandType.LAST_COMMAND)
|
||||
@InputConnectionCommandType int type,
|
||||
int intArg0, int intArg1, int flags, @Nullable CharSequence charSequence,
|
||||
@Nullable String string, @Nullable Bundle bundle,
|
||||
@ParcelableType int parcelableType, @Nullable Parcelable parcelable,
|
||||
@NonNull Completable.Boolean returnValue) {
|
||||
return new InputConnectionCommand(type, intArg0, intArg1, flags, charSequence, string,
|
||||
bundle, parcelableType, parcelable,
|
||||
ResultCallbackType.BOOLEAN, ResultCallbacks.of(returnValue));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
static InputConnectionCommand create(
|
||||
@IntRange(
|
||||
from = InputConnectionCommandType.FIRST_COMMAND,
|
||||
to = InputConnectionCommandType.LAST_COMMAND)
|
||||
@InputConnectionCommandType int type,
|
||||
int intArg0, int intArg1, int flags, @Nullable CharSequence charSequence,
|
||||
@Nullable String string, @Nullable Bundle bundle,
|
||||
@ParcelableType int parcelableType, @Nullable Parcelable parcelable,
|
||||
@NonNull Completable.Int returnValue) {
|
||||
return new InputConnectionCommand(type, intArg0, intArg1, flags, charSequence, string,
|
||||
bundle, parcelableType, parcelable,
|
||||
ResultCallbackType.INT, ResultCallbacks.of(returnValue));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
static InputConnectionCommand create(
|
||||
@IntRange(
|
||||
from = InputConnectionCommandType.FIRST_COMMAND,
|
||||
to = InputConnectionCommandType.LAST_COMMAND)
|
||||
@InputConnectionCommandType int type,
|
||||
int intArg0, int intArg1, int flags, @Nullable CharSequence charSequence,
|
||||
@Nullable String string, @Nullable Bundle bundle,
|
||||
@ParcelableType int parcelableType, @Nullable Parcelable parcelable,
|
||||
@NonNull Completable.CharSequence returnValue) {
|
||||
return new InputConnectionCommand(type, intArg0, intArg1, flags, charSequence, string,
|
||||
bundle, parcelableType, parcelable,
|
||||
ResultCallbackType.CHAR_SEQUENCE, ResultCallbacks.of(returnValue));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
static InputConnectionCommand create(
|
||||
@IntRange(
|
||||
from = InputConnectionCommandType.FIRST_COMMAND,
|
||||
to = InputConnectionCommandType.LAST_COMMAND)
|
||||
@InputConnectionCommandType int type,
|
||||
int intArg0, int intArg1, int flags, @Nullable CharSequence charSequence,
|
||||
@Nullable String string, @Nullable Bundle bundle,
|
||||
@ParcelableType int parcelableType, @Nullable Parcelable parcelable,
|
||||
@NonNull Completable.ExtractedText returnValue) {
|
||||
return new InputConnectionCommand(type, intArg0, intArg1, flags, charSequence, string,
|
||||
bundle, parcelableType, parcelable,
|
||||
ResultCallbackType.EXTRACTED_TEXT, ResultCallbacks.of(returnValue));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
static InputConnectionCommand create(
|
||||
@IntRange(
|
||||
from = InputConnectionCommandType.FIRST_COMMAND,
|
||||
to = InputConnectionCommandType.LAST_COMMAND)
|
||||
@InputConnectionCommandType int type,
|
||||
int intArg0, int intArg1, int flags, @Nullable CharSequence charSequence,
|
||||
@Nullable String string, @Nullable Bundle bundle,
|
||||
@ParcelableType int parcelableType, @Nullable Parcelable parcelable,
|
||||
@NonNull Completable.SurroundingText returnValue) {
|
||||
return new InputConnectionCommand(type, intArg0, intArg1, flags, charSequence, string,
|
||||
bundle, parcelableType, parcelable,
|
||||
ResultCallbackType.SURROUNDING_TEXT, ResultCallbacks.of(returnValue));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@AnyThread
|
||||
@Override
|
||||
public int describeContents() {
|
||||
int result = 0;
|
||||
if (mBundle != null) {
|
||||
result |= mBundle.describeContents();
|
||||
}
|
||||
if (mParcelable != null) {
|
||||
result |= mParcelable.describeContents();
|
||||
}
|
||||
// Here we assume other objects will never contain FDs to be parcelled.
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@AnyThread
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeInt(mCommandType);
|
||||
|
||||
@FieldMask final int fieldMask = getFieldMask();
|
||||
dest.writeInt(fieldMask);
|
||||
if ((fieldMask & FieldMask.INT_ARG0) != 0) {
|
||||
dest.writeInt(mIntArg0);
|
||||
}
|
||||
if ((fieldMask & FieldMask.INT_ARG1) != 0) {
|
||||
dest.writeInt(mIntArg1);
|
||||
}
|
||||
if ((fieldMask & FieldMask.FLAGS) != 0) {
|
||||
dest.writeInt(mFlags);
|
||||
}
|
||||
if ((fieldMask & FieldMask.CHAR_SEQUENCE) != 0) {
|
||||
TextUtils.writeToParcel(mCharSequence, dest, flags);
|
||||
}
|
||||
if ((fieldMask & FieldMask.STRING) != 0) {
|
||||
dest.writeString(mString);
|
||||
}
|
||||
if ((fieldMask & FieldMask.BUNDLE) != 0) {
|
||||
dest.writeBundle(mBundle);
|
||||
}
|
||||
if ((fieldMask & FieldMask.PARCELABLE) != 0) {
|
||||
dest.writeInt(mParcelableType);
|
||||
dest.writeTypedObject(mParcelable, flags);
|
||||
}
|
||||
if ((fieldMask & FieldMask.CALLBACK) != 0) {
|
||||
dest.writeInt(mResultCallbackType);
|
||||
dest.writeStrongBinder(mResultCallback);
|
||||
}
|
||||
}
|
||||
|
||||
@FieldMask
|
||||
@AnyThread
|
||||
private int getFieldMask() {
|
||||
return (mIntArg0 != 0 ? FieldMask.INT_ARG0 : 0)
|
||||
| (mIntArg1 != 0 ? FieldMask.INT_ARG1 : 0)
|
||||
| (mFlags != 0 ? FieldMask.FLAGS : 0)
|
||||
| (mCharSequence != null ? FieldMask.CHAR_SEQUENCE : 0)
|
||||
| (mString != null ? FieldMask.STRING : 0)
|
||||
| (mBundle != null ? FieldMask.BUNDLE : 0)
|
||||
| (mParcelableType != ParcelableType.NULL ? FieldMask.PARCELABLE : 0)
|
||||
| (mResultCallbackType != ResultCallbackType.NULL ? FieldMask.CALLBACK : 0);
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
@Nullable
|
||||
private static InputConnectionCommand createFromParcel(@NonNull Parcel source) {
|
||||
final int type = source.readInt();
|
||||
if (type < InputConnectionCommandType.FIRST_COMMAND
|
||||
|| InputConnectionCommandType.LAST_COMMAND < type) {
|
||||
Log.e(TAG, "Invalid InputConnectionCommand type=" + type);
|
||||
return null;
|
||||
}
|
||||
|
||||
@FieldMask final int fieldMask = source.readInt();
|
||||
final int intArg0 = (fieldMask & FieldMask.INT_ARG0) != 0 ? source.readInt() : 0;
|
||||
final int intArg1 = (fieldMask & FieldMask.INT_ARG1) != 0 ? source.readInt() : 0;
|
||||
final int flags = (fieldMask & FieldMask.FLAGS) != 0 ? source.readInt() : 0;
|
||||
final CharSequence charSequence = (fieldMask & FieldMask.CHAR_SEQUENCE) != 0
|
||||
? TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source) : null;
|
||||
final String string = (fieldMask & FieldMask.STRING) != 0 ? source.readString() : null;
|
||||
final Bundle bundle = (fieldMask & FieldMask.BUNDLE) != 0 ? source.readBundle() : null;
|
||||
|
||||
@ParcelableType final int parcelableType;
|
||||
final Parcelable parcelable;
|
||||
if ((fieldMask & FieldMask.PARCELABLE) != 0) {
|
||||
parcelableType = source.readInt();
|
||||
switch (parcelableType) {
|
||||
case ParcelableType.NULL:
|
||||
Log.e(TAG, "Unexpected ParcelableType=NULL");
|
||||
return null;
|
||||
case ParcelableType.EXTRACTED_TEXT_REQUEST:
|
||||
parcelable = source.readTypedObject(ExtractedTextRequest.CREATOR);
|
||||
break;
|
||||
case ParcelableType.COMPLETION_INFO:
|
||||
parcelable = source.readTypedObject(CompletionInfo.CREATOR);
|
||||
break;
|
||||
case ParcelableType.CORRECTION_INFO:
|
||||
parcelable = source.readTypedObject(CorrectionInfo.CREATOR);
|
||||
break;
|
||||
case ParcelableType.KEY_EVENT:
|
||||
parcelable = source.readTypedObject(KeyEvent.CREATOR);
|
||||
break;
|
||||
case ParcelableType.INPUT_CONTENT_INFO:
|
||||
parcelable = source.readTypedObject(InputContentInfo.CREATOR);
|
||||
break;
|
||||
default:
|
||||
Log.e(TAG, "Unknown ParcelableType=" + parcelableType);
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
parcelableType = ParcelableType.NULL;
|
||||
parcelable = null;
|
||||
}
|
||||
@ResultCallbackType final int resultCallbackType;
|
||||
final IBinder resultCallback;
|
||||
if ((fieldMask & FieldMask.CALLBACK) != 0) {
|
||||
resultCallbackType = source.readInt();
|
||||
switch (resultCallbackType) {
|
||||
case ResultCallbackType.NULL:
|
||||
Log.e(TAG, "Unexpected ResultCallbackType=NULL");
|
||||
return null;
|
||||
case ResultCallbackType.BOOLEAN:
|
||||
case ResultCallbackType.INT:
|
||||
case ResultCallbackType.CHAR_SEQUENCE:
|
||||
case ResultCallbackType.EXTRACTED_TEXT:
|
||||
case ResultCallbackType.SURROUNDING_TEXT:
|
||||
resultCallback = source.readStrongBinder();
|
||||
break;
|
||||
default:
|
||||
Log.e(TAG, "Unknown ResultCallbackType=" + resultCallbackType);
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
resultCallbackType = ResultCallbackType.NULL;
|
||||
resultCallback = null;
|
||||
}
|
||||
return new InputConnectionCommand(type, intArg0, intArg1, flags, charSequence, string,
|
||||
bundle, parcelableType, parcelable, resultCallbackType, resultCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to make this class parcelable.
|
||||
*/
|
||||
public static final Parcelable.Creator<InputConnectionCommand> CREATOR =
|
||||
new Parcelable.Creator<InputConnectionCommand>() {
|
||||
@AnyThread
|
||||
@Nullable
|
||||
@Override
|
||||
public InputConnectionCommand createFromParcel(Parcel source) {
|
||||
try {
|
||||
return InputConnectionCommand.createFromParcel(source);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Returning null due to exception.", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
@NonNull
|
||||
@Override
|
||||
public InputConnectionCommand[] newArray(int size) {
|
||||
return new InputConnectionCommand[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.internal.inputmethod;
|
||||
|
||||
import static java.lang.annotation.RetentionPolicy.SOURCE;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
|
||||
@Retention(SOURCE)
|
||||
@IntDef(value = {
|
||||
InputConnectionCommandType.BEGIN_BATCH_EDIT,
|
||||
InputConnectionCommandType.CLEAR_META_KEY_STATES,
|
||||
InputConnectionCommandType.COMMIT_COMPLETION,
|
||||
InputConnectionCommandType.COMMIT_CONTENT,
|
||||
InputConnectionCommandType.COMMIT_CORRECTION,
|
||||
InputConnectionCommandType.COMMIT_TEXT,
|
||||
InputConnectionCommandType.DELETE_SURROUNDING_TEXT,
|
||||
InputConnectionCommandType.DELETE_SURROUNDING_TEXT_IN_CODE_POINTS,
|
||||
InputConnectionCommandType.END_BATCH_EDIT,
|
||||
InputConnectionCommandType.FINISH_COMPOSING_TEXT,
|
||||
InputConnectionCommandType.GET_CURSOR_CAPS_MODE,
|
||||
InputConnectionCommandType.GET_EXTRACTED_TEXT,
|
||||
InputConnectionCommandType.GET_SELECTED_TEXT,
|
||||
InputConnectionCommandType.GET_SURROUNDING_TEXT,
|
||||
InputConnectionCommandType.GET_TEXT_AFTER_CURSOR,
|
||||
InputConnectionCommandType.GET_TEXT_BEFORE_CURSOR,
|
||||
InputConnectionCommandType.PERFORM_CONTEXT_MENU_ACTION,
|
||||
InputConnectionCommandType.PERFORM_EDITOR_ACTION,
|
||||
InputConnectionCommandType.PERFORM_SPELL_CHECK,
|
||||
InputConnectionCommandType.REQUEST_CURSOR_UPDATES,
|
||||
InputConnectionCommandType.SEND_KEY_EVENT,
|
||||
InputConnectionCommandType.SET_COMPOSING_REGION,
|
||||
InputConnectionCommandType.SET_COMPOSING_TEXT,
|
||||
InputConnectionCommandType.SET_IME_CONSUMES_INPUT,
|
||||
InputConnectionCommandType.SET_SELECTION,
|
||||
})
|
||||
public @interface InputConnectionCommandType {
|
||||
int FIRST_COMMAND = 1;
|
||||
|
||||
int BEGIN_BATCH_EDIT = FIRST_COMMAND;
|
||||
int CLEAR_META_KEY_STATES = 2;
|
||||
int COMMIT_COMPLETION = 3;
|
||||
int COMMIT_CONTENT = 4;
|
||||
int COMMIT_CORRECTION = 5;
|
||||
int COMMIT_TEXT = 6;
|
||||
int DELETE_SURROUNDING_TEXT = 7;
|
||||
int DELETE_SURROUNDING_TEXT_IN_CODE_POINTS = 8;
|
||||
int END_BATCH_EDIT = 9;
|
||||
int FINISH_COMPOSING_TEXT = 10;
|
||||
int GET_CURSOR_CAPS_MODE = 11;
|
||||
int GET_EXTRACTED_TEXT = 12;
|
||||
int GET_SELECTED_TEXT = 13;
|
||||
int GET_SURROUNDING_TEXT = 14;
|
||||
int GET_TEXT_AFTER_CURSOR = 15;
|
||||
int GET_TEXT_BEFORE_CURSOR = 16;
|
||||
int PERFORM_CONTEXT_MENU_ACTION = 17;
|
||||
int PERFORM_EDITOR_ACTION = 18;
|
||||
int PERFORM_SPELL_CHECK = 19;
|
||||
int PERFORM_PRIVATE_COMMAND = 20;
|
||||
int REQUEST_CURSOR_UPDATES = 21;
|
||||
int SEND_KEY_EVENT = 22;
|
||||
int SET_COMPOSING_REGION = 23;
|
||||
int SET_COMPOSING_TEXT = 24;
|
||||
int SET_IME_CONSUMES_INPUT = 25;
|
||||
int SET_SELECTION = 26;
|
||||
|
||||
int LAST_COMMAND = SET_SELECTION;
|
||||
}
|
||||
@@ -18,7 +18,6 @@ package com.android.internal.inputmethod;
|
||||
|
||||
import android.annotation.AnyThread;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.view.WindowManager;
|
||||
import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
|
||||
|
||||
@@ -242,133 +241,6 @@ public final class InputMethodDebug {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts {@link InputConnectionCommandType} to human readable {@link String}.
|
||||
*/
|
||||
public static String inputConnectionCommandTypeToString(@InputConnectionCommandType int type) {
|
||||
switch (type) {
|
||||
case InputConnectionCommandType.BEGIN_BATCH_EDIT:
|
||||
return "beginBatchEdit";
|
||||
case InputConnectionCommandType.CLEAR_META_KEY_STATES:
|
||||
return "clearMetaKeyStates";
|
||||
case InputConnectionCommandType.COMMIT_COMPLETION:
|
||||
return "commitCompletion";
|
||||
case InputConnectionCommandType.COMMIT_CONTENT:
|
||||
return "commitContent";
|
||||
case InputConnectionCommandType.COMMIT_CORRECTION:
|
||||
return "commitCorrection";
|
||||
case InputConnectionCommandType.COMMIT_TEXT:
|
||||
return "commitText";
|
||||
case InputConnectionCommandType.DELETE_SURROUNDING_TEXT:
|
||||
return "deleteSurroundingText";
|
||||
case InputConnectionCommandType.DELETE_SURROUNDING_TEXT_IN_CODE_POINTS:
|
||||
return "deleteSurroundingTextInCodePoints";
|
||||
case InputConnectionCommandType.END_BATCH_EDIT:
|
||||
return "endBatchEdit";
|
||||
case InputConnectionCommandType.FINISH_COMPOSING_TEXT:
|
||||
return "finishComposingText";
|
||||
case InputConnectionCommandType.GET_CURSOR_CAPS_MODE:
|
||||
return "getCursorCapsMode";
|
||||
case InputConnectionCommandType.GET_EXTRACTED_TEXT:
|
||||
return "getExtractedText";
|
||||
case InputConnectionCommandType.GET_SELECTED_TEXT:
|
||||
return "getSelectedText";
|
||||
case InputConnectionCommandType.GET_SURROUNDING_TEXT:
|
||||
return "getSurroundingText";
|
||||
case InputConnectionCommandType.GET_TEXT_AFTER_CURSOR:
|
||||
return "getTextAfterCursor";
|
||||
case InputConnectionCommandType.GET_TEXT_BEFORE_CURSOR:
|
||||
return "getTextBeforeCursor";
|
||||
case InputConnectionCommandType.PERFORM_CONTEXT_MENU_ACTION:
|
||||
return "performContextMenuAction";
|
||||
case InputConnectionCommandType.PERFORM_EDITOR_ACTION:
|
||||
return "performEditorAction";
|
||||
case InputConnectionCommandType.PERFORM_SPELL_CHECK:
|
||||
return "performSpellCheck";
|
||||
case InputConnectionCommandType.REQUEST_CURSOR_UPDATES:
|
||||
return "requestCursorUpdates";
|
||||
case InputConnectionCommandType.SEND_KEY_EVENT:
|
||||
return "sendKeyEvent";
|
||||
case InputConnectionCommandType.SET_COMPOSING_REGION:
|
||||
return "setComposingRegion";
|
||||
case InputConnectionCommandType.SET_COMPOSING_TEXT:
|
||||
return "setComposingText";
|
||||
case InputConnectionCommandType.SET_IME_CONSUMES_INPUT:
|
||||
return "setImeConsumesInput";
|
||||
case InputConnectionCommandType.SET_SELECTION:
|
||||
return "setSelection";
|
||||
default:
|
||||
return "Unknown=" + type;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts {@link InputConnectionCommand} to human readable {@link String}.
|
||||
*/
|
||||
@NonNull
|
||||
public static String dumpInputConnectionCommand(@Nullable InputConnectionCommand command) {
|
||||
if (command == null) {
|
||||
return "null";
|
||||
}
|
||||
switch (command.mCommandType) {
|
||||
case InputConnectionCommandType.BEGIN_BATCH_EDIT:
|
||||
return "beginBatchEdit()";
|
||||
case InputConnectionCommandType.CLEAR_META_KEY_STATES:
|
||||
return "clearMetaKeyStates(" + command.mIntArg0 + ")";
|
||||
case InputConnectionCommandType.COMMIT_COMPLETION:
|
||||
return "commitCompletion(" + command.mParcelable + ")";
|
||||
case InputConnectionCommandType.COMMIT_CONTENT:
|
||||
return "commitContent(" + command.mParcelable + ", " + command.mFlags + ", "
|
||||
+ command.mBundle + ")";
|
||||
case InputConnectionCommandType.COMMIT_CORRECTION:
|
||||
return "commitCorrection(" + command.mParcelable + ")";
|
||||
case InputConnectionCommandType.COMMIT_TEXT:
|
||||
return "commitText(" + command.mCharSequence + ", " + command.mIntArg0 + ")";
|
||||
case InputConnectionCommandType.DELETE_SURROUNDING_TEXT:
|
||||
return "deleteSurroundingText(" + command.mIntArg0 + ", " + command.mIntArg1 + ")";
|
||||
case InputConnectionCommandType.DELETE_SURROUNDING_TEXT_IN_CODE_POINTS:
|
||||
return "deleteSurroundingTextInCodePoints(" + command.mIntArg0 + ", "
|
||||
+ command.mIntArg1 + ")";
|
||||
case InputConnectionCommandType.END_BATCH_EDIT:
|
||||
return "endBatchEdit()";
|
||||
case InputConnectionCommandType.FINISH_COMPOSING_TEXT:
|
||||
return "finishComposingText()";
|
||||
case InputConnectionCommandType.GET_CURSOR_CAPS_MODE:
|
||||
return "getCursorCapsMode(" + command.mIntArg0 + ")";
|
||||
case InputConnectionCommandType.GET_EXTRACTED_TEXT:
|
||||
return "getExtractedText(" + command.mParcelable + ", " + command.mFlags + ")";
|
||||
case InputConnectionCommandType.GET_SELECTED_TEXT:
|
||||
return "getSelectedText(" + command.mFlags + ")";
|
||||
case InputConnectionCommandType.GET_SURROUNDING_TEXT:
|
||||
return "getSurroundingText(" + command.mIntArg0 + ", " + command.mIntArg1 + ", "
|
||||
+ command.mFlags + ")";
|
||||
case InputConnectionCommandType.GET_TEXT_AFTER_CURSOR:
|
||||
return "getTextAfterCursor(" + command.mIntArg0 + ", " + command.mFlags + ")";
|
||||
case InputConnectionCommandType.GET_TEXT_BEFORE_CURSOR:
|
||||
return "getTextBeforeCursor(" + command.mIntArg0 + ", " + command.mFlags + ")";
|
||||
case InputConnectionCommandType.PERFORM_CONTEXT_MENU_ACTION:
|
||||
return "performContextMenuAction(" + command.mIntArg0 + ")";
|
||||
case InputConnectionCommandType.PERFORM_EDITOR_ACTION:
|
||||
return "performEditorAction(" + command.mIntArg0 + ")";
|
||||
case InputConnectionCommandType.PERFORM_SPELL_CHECK:
|
||||
return "performSpellCheck()";
|
||||
case InputConnectionCommandType.REQUEST_CURSOR_UPDATES:
|
||||
return "requestCursorUpdates(" + command.mIntArg0 + ")";
|
||||
case InputConnectionCommandType.SEND_KEY_EVENT:
|
||||
return "sendKeyEvent(" + command.mParcelable + ")";
|
||||
case InputConnectionCommandType.SET_COMPOSING_REGION:
|
||||
return "setComposingRegion(" + command.mIntArg0 + ", " + command.mIntArg1 + ")";
|
||||
case InputConnectionCommandType.SET_COMPOSING_TEXT:
|
||||
return "setComposingText(" + command.mCharSequence + ", " + command.mIntArg0 + ")";
|
||||
case InputConnectionCommandType.SET_IME_CONSUMES_INPUT:
|
||||
return "setImeConsumesInput(" + (command.mIntArg0 != 0) + ")";
|
||||
case InputConnectionCommandType.SET_SELECTION:
|
||||
return "setSelection(" + command.mIntArg0 + ", " + command.mIntArg1 + ")";
|
||||
default:
|
||||
return "unknown(type=" + command.mCommandType + ")";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a fixed size string of the object.
|
||||
* TODO(b/151575861): Take & return with StringBuilder to make more memory efficient.
|
||||
|
||||
@@ -16,14 +16,13 @@
|
||||
|
||||
package com.android.internal.view;
|
||||
|
||||
import android.annotation.AnyThread;
|
||||
import android.annotation.BinderThread;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.RemoteException;
|
||||
import android.os.Trace;
|
||||
import android.util.Log;
|
||||
import android.util.proto.ProtoOutputStream;
|
||||
@@ -42,12 +41,14 @@ import android.view.inputmethod.InputMethodManager;
|
||||
import android.view.inputmethod.SurroundingText;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.inputmethod.CallbackUtils;
|
||||
import com.android.internal.inputmethod.IBooleanResultCallback;
|
||||
import com.android.internal.inputmethod.ICharSequenceResultCallback;
|
||||
import com.android.internal.inputmethod.IExtractedTextResultCallback;
|
||||
import com.android.internal.inputmethod.IIntResultCallback;
|
||||
import com.android.internal.inputmethod.ISurroundingTextResultCallback;
|
||||
import com.android.internal.inputmethod.ImeTracing;
|
||||
import com.android.internal.inputmethod.InputConnectionCommand;
|
||||
import com.android.internal.inputmethod.InputConnectionCommandType;
|
||||
import com.android.internal.inputmethod.InputConnectionProtoDumper;
|
||||
import com.android.internal.inputmethod.InputMethodDebug;
|
||||
import com.android.internal.os.SomeArgs;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
@@ -55,8 +56,34 @@ public final class IInputConnectionWrapper extends IInputContext.Stub {
|
||||
private static final String TAG = "IInputConnectionWrapper";
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private static final int DO_EDIT = 10;
|
||||
private static final int DO_CLOSE_CONNECTION = 20;
|
||||
private static final int DO_GET_TEXT_AFTER_CURSOR = 10;
|
||||
private static final int DO_GET_TEXT_BEFORE_CURSOR = 20;
|
||||
private static final int DO_GET_SELECTED_TEXT = 25;
|
||||
private static final int DO_GET_CURSOR_CAPS_MODE = 30;
|
||||
private static final int DO_GET_EXTRACTED_TEXT = 40;
|
||||
private static final int DO_COMMIT_TEXT = 50;
|
||||
private static final int DO_COMMIT_COMPLETION = 55;
|
||||
private static final int DO_COMMIT_CORRECTION = 56;
|
||||
private static final int DO_SET_SELECTION = 57;
|
||||
private static final int DO_PERFORM_EDITOR_ACTION = 58;
|
||||
private static final int DO_PERFORM_CONTEXT_MENU_ACTION = 59;
|
||||
private static final int DO_SET_COMPOSING_TEXT = 60;
|
||||
private static final int DO_SET_COMPOSING_REGION = 63;
|
||||
private static final int DO_FINISH_COMPOSING_TEXT = 65;
|
||||
private static final int DO_SEND_KEY_EVENT = 70;
|
||||
private static final int DO_DELETE_SURROUNDING_TEXT = 80;
|
||||
private static final int DO_DELETE_SURROUNDING_TEXT_IN_CODE_POINTS = 81;
|
||||
private static final int DO_BEGIN_BATCH_EDIT = 90;
|
||||
private static final int DO_END_BATCH_EDIT = 95;
|
||||
private static final int DO_PERFORM_SPELL_CHECK = 110;
|
||||
private static final int DO_PERFORM_PRIVATE_COMMAND = 120;
|
||||
private static final int DO_CLEAR_META_KEY_STATES = 130;
|
||||
private static final int DO_REQUEST_CURSOR_UPDATES = 140;
|
||||
private static final int DO_CLOSE_CONNECTION = 150;
|
||||
private static final int DO_COMMIT_CONTENT = 160;
|
||||
private static final int DO_GET_SURROUNDING_TEXT = 41;
|
||||
private static final int DO_SET_IME_CONSUMES_INPUT = 170;
|
||||
|
||||
|
||||
@GuardedBy("mLock")
|
||||
@Nullable
|
||||
@@ -120,7 +147,7 @@ public final class IInputConnectionWrapper extends IInputContext.Stub {
|
||||
// reportFinish() will take effect.
|
||||
return;
|
||||
}
|
||||
dispatchMessage(mH.obtainMessage(DO_CLOSE_CONNECTION));
|
||||
closeConnection();
|
||||
|
||||
// Notify the app that the InputConnection was closed.
|
||||
final View servedView = mServedView.get();
|
||||
@@ -165,33 +192,146 @@ public final class IInputConnectionWrapper extends IInputContext.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
@BinderThread
|
||||
@Override
|
||||
public void doEdit(@Nullable InputConnectionCommand command) {
|
||||
if (command == null) {
|
||||
// As long as everything is working as expected, we should never see any null object
|
||||
// here. If we are seeing null object, it means that either the sender or
|
||||
// InputConnectionCommand.CREATOR#createFromParcel() returned null for whatever
|
||||
// unexpected reasons. Note that InputConnectionCommand.CREATOR#createFromParcel() does
|
||||
// some data verifications. Hence failing to pass the verification is one of the
|
||||
// reasons to see null here.
|
||||
Log.w(TAG, "Ignoring invalid InputConnectionCommand.");
|
||||
return;
|
||||
}
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "incoming: " + InputMethodDebug.dumpInputConnectionCommand(command));
|
||||
}
|
||||
dispatchMessage(mH.obtainMessage(DO_EDIT, command));
|
||||
public void getTextAfterCursor(int length, int flags, ICharSequenceResultCallback callback) {
|
||||
dispatchMessage(mH.obtainMessage(DO_GET_TEXT_AFTER_CURSOR, length, flags, callback));
|
||||
}
|
||||
|
||||
public void getTextBeforeCursor(int length, int flags, ICharSequenceResultCallback callback) {
|
||||
dispatchMessage(mH.obtainMessage(DO_GET_TEXT_BEFORE_CURSOR, length, flags, callback));
|
||||
}
|
||||
|
||||
public void getSelectedText(int flags, ICharSequenceResultCallback callback) {
|
||||
dispatchMessage(mH.obtainMessage(DO_GET_SELECTED_TEXT, flags, 0 /* unused */, callback));
|
||||
}
|
||||
|
||||
/**
|
||||
* Exposed for {@link InputMethodManager} to trigger
|
||||
* {@link InputConnection#finishComposingText()}.
|
||||
* Dispatches the request for retrieving surrounding text.
|
||||
*
|
||||
* <p>See {@link InputConnection#getSurroundingText(int, int, int)}.
|
||||
*/
|
||||
@AnyThread
|
||||
public void getSurroundingText(int beforeLength, int afterLength, int flags,
|
||||
ISurroundingTextResultCallback callback) {
|
||||
final SomeArgs args = SomeArgs.obtain();
|
||||
args.arg1 = beforeLength;
|
||||
args.arg2 = afterLength;
|
||||
args.arg3 = flags;
|
||||
args.arg4 = callback;
|
||||
dispatchMessage(mH.obtainMessage(DO_GET_SURROUNDING_TEXT, flags, 0 /* unused */, args));
|
||||
}
|
||||
|
||||
public void getCursorCapsMode(int reqModes, IIntResultCallback callback) {
|
||||
dispatchMessage(
|
||||
mH.obtainMessage(DO_GET_CURSOR_CAPS_MODE, reqModes, 0 /* unused */, callback));
|
||||
}
|
||||
|
||||
public void getExtractedText(ExtractedTextRequest request, int flags,
|
||||
IExtractedTextResultCallback callback) {
|
||||
final SomeArgs args = SomeArgs.obtain();
|
||||
args.arg1 = request;
|
||||
args.arg2 = callback;
|
||||
dispatchMessage(mH.obtainMessage(DO_GET_EXTRACTED_TEXT, flags, 0 /* unused */, args));
|
||||
}
|
||||
|
||||
public void commitText(CharSequence text, int newCursorPosition) {
|
||||
dispatchMessage(obtainMessageIO(DO_COMMIT_TEXT, newCursorPosition, text));
|
||||
}
|
||||
|
||||
public void commitCompletion(CompletionInfo text) {
|
||||
dispatchMessage(obtainMessageO(DO_COMMIT_COMPLETION, text));
|
||||
}
|
||||
|
||||
public void commitCorrection(CorrectionInfo info) {
|
||||
dispatchMessage(obtainMessageO(DO_COMMIT_CORRECTION, info));
|
||||
}
|
||||
|
||||
public void setSelection(int start, int end) {
|
||||
dispatchMessage(obtainMessageII(DO_SET_SELECTION, start, end));
|
||||
}
|
||||
|
||||
public void performEditorAction(int id) {
|
||||
dispatchMessage(obtainMessageII(DO_PERFORM_EDITOR_ACTION, id, 0));
|
||||
}
|
||||
|
||||
public void performContextMenuAction(int id) {
|
||||
dispatchMessage(obtainMessageII(DO_PERFORM_CONTEXT_MENU_ACTION, id, 0));
|
||||
}
|
||||
|
||||
public void setComposingRegion(int start, int end) {
|
||||
dispatchMessage(obtainMessageII(DO_SET_COMPOSING_REGION, start, end));
|
||||
}
|
||||
|
||||
public void setComposingText(CharSequence text, int newCursorPosition) {
|
||||
dispatchMessage(obtainMessageIO(DO_SET_COMPOSING_TEXT, newCursorPosition, text));
|
||||
}
|
||||
|
||||
public void finishComposingText() {
|
||||
dispatchMessage(mH.obtainMessage(DO_EDIT, InputConnectionCommand.create(
|
||||
InputConnectionCommandType.FINISH_COMPOSING_TEXT)));
|
||||
dispatchMessage(obtainMessage(DO_FINISH_COMPOSING_TEXT));
|
||||
}
|
||||
|
||||
public void sendKeyEvent(KeyEvent event) {
|
||||
dispatchMessage(obtainMessageO(DO_SEND_KEY_EVENT, event));
|
||||
}
|
||||
|
||||
public void clearMetaKeyStates(int states) {
|
||||
dispatchMessage(obtainMessageII(DO_CLEAR_META_KEY_STATES, states, 0));
|
||||
}
|
||||
|
||||
public void deleteSurroundingText(int beforeLength, int afterLength) {
|
||||
dispatchMessage(obtainMessageII(DO_DELETE_SURROUNDING_TEXT,
|
||||
beforeLength, afterLength));
|
||||
}
|
||||
|
||||
public void deleteSurroundingTextInCodePoints(int beforeLength, int afterLength) {
|
||||
dispatchMessage(obtainMessageII(DO_DELETE_SURROUNDING_TEXT_IN_CODE_POINTS,
|
||||
beforeLength, afterLength));
|
||||
}
|
||||
|
||||
public void beginBatchEdit() {
|
||||
dispatchMessage(obtainMessage(DO_BEGIN_BATCH_EDIT));
|
||||
}
|
||||
|
||||
public void endBatchEdit() {
|
||||
dispatchMessage(obtainMessage(DO_END_BATCH_EDIT));
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches the request for performing spell check.
|
||||
*
|
||||
* @see InputConnection#performSpellCheck()
|
||||
*/
|
||||
public void performSpellCheck() {
|
||||
dispatchMessage(obtainMessage(DO_PERFORM_SPELL_CHECK));
|
||||
}
|
||||
|
||||
public void performPrivateCommand(String action, Bundle data) {
|
||||
dispatchMessage(obtainMessageOO(DO_PERFORM_PRIVATE_COMMAND, action, data));
|
||||
}
|
||||
|
||||
public void requestCursorUpdates(int cursorUpdateMode, IBooleanResultCallback callback) {
|
||||
dispatchMessage(mH.obtainMessage(DO_REQUEST_CURSOR_UPDATES, cursorUpdateMode,
|
||||
0 /* unused */, callback));
|
||||
}
|
||||
|
||||
public void closeConnection() {
|
||||
dispatchMessage(obtainMessage(DO_CLOSE_CONNECTION));
|
||||
}
|
||||
|
||||
public void commitContent(InputContentInfo inputContentInfo, int flags, Bundle opts,
|
||||
IBooleanResultCallback callback) {
|
||||
final SomeArgs args = SomeArgs.obtain();
|
||||
args.arg1 = inputContentInfo;
|
||||
args.arg2 = opts;
|
||||
args.arg3 = callback;
|
||||
dispatchMessage(mH.obtainMessage(DO_COMMIT_CONTENT, flags, 0 /* unused */, args));
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches the request for setting ime consumes input.
|
||||
*
|
||||
* <p>See {@link InputConnection#setImeConsumesInput(boolean)}.
|
||||
*/
|
||||
public void setImeConsumesInput(boolean imeConsumesInput) {
|
||||
dispatchMessage(obtainMessageB(DO_SET_IME_CONSUMES_INPUT, imeConsumesInput));
|
||||
}
|
||||
|
||||
void dispatchMessage(Message msg) {
|
||||
@@ -207,131 +347,108 @@ public final class IInputConnectionWrapper extends IInputContext.Stub {
|
||||
mH.sendMessage(msg);
|
||||
}
|
||||
|
||||
private void executeMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case DO_EDIT:
|
||||
doEditMain((InputConnectionCommand) msg.obj);
|
||||
break;
|
||||
case DO_CLOSE_CONNECTION:
|
||||
// Note that we do not need to worry about race condition here, because 1) mFinished
|
||||
// is updated only inside this block, and 2) the code here is running on a Handler
|
||||
// hence we assume multiple DO_CLOSE_CONNECTION messages will not be handled at the
|
||||
// same time.
|
||||
if (isFinished()) {
|
||||
return;
|
||||
}
|
||||
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#closeConnection");
|
||||
try {
|
||||
InputConnection ic = getInputConnection();
|
||||
// Note we do NOT check isActive() here, because this is safe
|
||||
// for an IME to call at any time, and we need to allow it
|
||||
// through to clean up our state after the IME has switched to
|
||||
// another client.
|
||||
if (ic == null) {
|
||||
return;
|
||||
}
|
||||
@MissingMethodFlags final int missingMethods =
|
||||
InputConnectionInspector.getMissingMethodFlags(ic);
|
||||
if ((missingMethods & MissingMethodFlags.CLOSE_CONNECTION) == 0) {
|
||||
ic.closeConnection();
|
||||
}
|
||||
} finally {
|
||||
synchronized (mLock) {
|
||||
mInputConnection = null;
|
||||
mFinished = true;
|
||||
}
|
||||
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void doEditMain(@NonNull InputConnectionCommand command) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "handling: " + InputMethodDebug.dumpInputConnectionCommand(command));
|
||||
}
|
||||
void executeMessage(Message msg) {
|
||||
byte[] icProto;
|
||||
switch (command.mCommandType) {
|
||||
case InputConnectionCommandType.GET_TEXT_AFTER_CURSOR: {
|
||||
switch (msg.what) {
|
||||
case DO_GET_TEXT_AFTER_CURSOR: {
|
||||
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getTextAfterCursor");
|
||||
try {
|
||||
final int n = command.mIntArg0;
|
||||
final int flags = command.mFlags;
|
||||
final ICharSequenceResultCallback callback =
|
||||
(ICharSequenceResultCallback) msg.obj;
|
||||
final InputConnection ic = getInputConnection();
|
||||
final CharSequence result;
|
||||
if (ic == null || !isActive()) {
|
||||
Log.w(TAG, "getTextAfterCursor on inactive InputConnection");
|
||||
result = null;
|
||||
} else {
|
||||
result = ic.getTextAfterCursor(n, flags);
|
||||
result = ic.getTextAfterCursor(msg.arg1, msg.arg2);
|
||||
}
|
||||
if (ImeTracing.getInstance().isEnabled()) {
|
||||
icProto = InputConnectionProtoDumper.buildGetTextAfterCursorProto(n, flags,
|
||||
result);
|
||||
icProto = InputConnectionProtoDumper.buildGetTextAfterCursorProto(msg.arg1,
|
||||
msg.arg2, result);
|
||||
ImeTracing.getInstance().triggerClientDump(
|
||||
TAG + "#getTextAfterCursor", mParentInputMethodManager, icProto);
|
||||
}
|
||||
CallbackUtils.onResult(command, result, TAG);
|
||||
try {
|
||||
callback.onResult(result);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Failed to return the result to getTextAfterCursor()."
|
||||
+ " result=" + result, e);
|
||||
}
|
||||
} finally {
|
||||
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case InputConnectionCommandType.GET_TEXT_BEFORE_CURSOR: {
|
||||
case DO_GET_TEXT_BEFORE_CURSOR: {
|
||||
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getTextBeforeCursor");
|
||||
try {
|
||||
final int n = command.mIntArg0;
|
||||
final int flags = command.mFlags;
|
||||
final ICharSequenceResultCallback callback =
|
||||
(ICharSequenceResultCallback) msg.obj;
|
||||
final InputConnection ic = getInputConnection();
|
||||
final CharSequence result;
|
||||
if (ic == null || !isActive()) {
|
||||
Log.w(TAG, "getTextBeforeCursor on inactive InputConnection");
|
||||
result = null;
|
||||
} else {
|
||||
result = ic.getTextBeforeCursor(n, flags);
|
||||
result = ic.getTextBeforeCursor(msg.arg1, msg.arg2);
|
||||
}
|
||||
if (ImeTracing.getInstance().isEnabled()) {
|
||||
icProto = InputConnectionProtoDumper.buildGetTextBeforeCursorProto(n, flags,
|
||||
result);
|
||||
icProto = InputConnectionProtoDumper.buildGetTextBeforeCursorProto(msg.arg1,
|
||||
msg.arg2, result);
|
||||
ImeTracing.getInstance().triggerClientDump(
|
||||
TAG + "#getTextBeforeCursor", mParentInputMethodManager, icProto);
|
||||
}
|
||||
CallbackUtils.onResult(command, result, TAG);
|
||||
try {
|
||||
callback.onResult(result);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Failed to return the result to getTextBeforeCursor()."
|
||||
+ " result=" + result, e);
|
||||
}
|
||||
} finally {
|
||||
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case InputConnectionCommandType.GET_SELECTED_TEXT: {
|
||||
case DO_GET_SELECTED_TEXT: {
|
||||
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getSelectedText");
|
||||
try {
|
||||
final int flags = command.mFlags;
|
||||
final ICharSequenceResultCallback callback =
|
||||
(ICharSequenceResultCallback) msg.obj;
|
||||
final InputConnection ic = getInputConnection();
|
||||
final CharSequence result;
|
||||
if (ic == null || !isActive()) {
|
||||
Log.w(TAG, "getSelectedText on inactive InputConnection");
|
||||
result = null;
|
||||
} else {
|
||||
result = ic.getSelectedText(flags);
|
||||
result = ic.getSelectedText(msg.arg1);
|
||||
}
|
||||
if (ImeTracing.getInstance().isEnabled()) {
|
||||
icProto = InputConnectionProtoDumper.buildGetSelectedTextProto(flags,
|
||||
icProto = InputConnectionProtoDumper.buildGetSelectedTextProto(msg.arg1,
|
||||
result);
|
||||
ImeTracing.getInstance().triggerClientDump(
|
||||
TAG + "#getSelectedText", mParentInputMethodManager, icProto);
|
||||
}
|
||||
CallbackUtils.onResult(command, result, TAG);
|
||||
try {
|
||||
callback.onResult(result);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Failed to return the result to getSelectedText()."
|
||||
+ " result=" + result, e);
|
||||
}
|
||||
} finally {
|
||||
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case InputConnectionCommandType.GET_SURROUNDING_TEXT: {
|
||||
case DO_GET_SURROUNDING_TEXT: {
|
||||
final SomeArgs args = (SomeArgs) msg.obj;
|
||||
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getSurroundingText");
|
||||
try {
|
||||
final int beforeLength = command.mIntArg0;
|
||||
final int afterLength = command.mIntArg1;
|
||||
final int flags = command.mFlags;
|
||||
int beforeLength = (int) args.arg1;
|
||||
int afterLength = (int) args.arg2;
|
||||
int flags = (int) args.arg3;
|
||||
final ISurroundingTextResultCallback callback =
|
||||
(ISurroundingTextResultCallback) args.arg4;
|
||||
final InputConnection ic = getInputConnection();
|
||||
final SurroundingText result;
|
||||
if (ic == null || !isActive()) {
|
||||
@@ -346,186 +463,193 @@ public final class IInputConnectionWrapper extends IInputContext.Stub {
|
||||
ImeTracing.getInstance().triggerClientDump(
|
||||
TAG + "#getSurroundingText", mParentInputMethodManager, icProto);
|
||||
}
|
||||
CallbackUtils.onResult(command, result, TAG);
|
||||
try {
|
||||
callback.onResult(result);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Failed to return the result to getSurroundingText()."
|
||||
+ " result=" + result, e);
|
||||
}
|
||||
} finally {
|
||||
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
|
||||
args.recycle();
|
||||
}
|
||||
return;
|
||||
}
|
||||
case InputConnectionCommandType.GET_CURSOR_CAPS_MODE: {
|
||||
case DO_GET_CURSOR_CAPS_MODE: {
|
||||
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getCursorCapsMode");
|
||||
try {
|
||||
final int reqModes = command.mIntArg0;
|
||||
final IIntResultCallback callback = (IIntResultCallback) msg.obj;
|
||||
final InputConnection ic = getInputConnection();
|
||||
final int result;
|
||||
if (ic == null || !isActive()) {
|
||||
Log.w(TAG, "getCursorCapsMode on inactive InputConnection");
|
||||
result = 0;
|
||||
} else {
|
||||
result = ic.getCursorCapsMode(reqModes);
|
||||
result = ic.getCursorCapsMode(msg.arg1);
|
||||
}
|
||||
if (ImeTracing.getInstance().isEnabled()) {
|
||||
icProto = InputConnectionProtoDumper.buildGetCursorCapsModeProto(reqModes,
|
||||
icProto = InputConnectionProtoDumper.buildGetCursorCapsModeProto(msg.arg1,
|
||||
result);
|
||||
ImeTracing.getInstance().triggerClientDump(
|
||||
TAG + "#getCursorCapsMode", mParentInputMethodManager, icProto);
|
||||
}
|
||||
CallbackUtils.onResult(command, result, TAG);
|
||||
try {
|
||||
callback.onResult(result);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Failed to return the result to getCursorCapsMode()."
|
||||
+ " result=" + result, e);
|
||||
}
|
||||
} finally {
|
||||
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case InputConnectionCommandType.GET_EXTRACTED_TEXT: {
|
||||
case DO_GET_EXTRACTED_TEXT: {
|
||||
final SomeArgs args = (SomeArgs) msg.obj;
|
||||
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getExtractedText");
|
||||
try {
|
||||
final ExtractedTextRequest request = (ExtractedTextRequest) command.mParcelable;
|
||||
final int flags = command.mFlags;
|
||||
final ExtractedTextRequest request = (ExtractedTextRequest) args.arg1;
|
||||
final IExtractedTextResultCallback callback =
|
||||
(IExtractedTextResultCallback) args.arg2;
|
||||
final InputConnection ic = getInputConnection();
|
||||
final ExtractedText result;
|
||||
if (ic == null || !isActive()) {
|
||||
Log.w(TAG, "getExtractedText on inactive InputConnection");
|
||||
result = null;
|
||||
} else {
|
||||
result = ic.getExtractedText(request, flags);
|
||||
result = ic.getExtractedText(request, msg.arg1);
|
||||
}
|
||||
if (ImeTracing.getInstance().isEnabled()) {
|
||||
icProto = InputConnectionProtoDumper.buildGetExtractedTextProto(request,
|
||||
flags, result);
|
||||
msg.arg1, result);
|
||||
ImeTracing.getInstance().triggerClientDump(
|
||||
TAG + "#getExtractedText", mParentInputMethodManager, icProto);
|
||||
}
|
||||
CallbackUtils.onResult(command, result, TAG);
|
||||
try {
|
||||
callback.onResult(result);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Failed to return the result to getExtractedText()."
|
||||
+ " result=" + result, e);
|
||||
}
|
||||
} finally {
|
||||
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
|
||||
args.recycle();
|
||||
}
|
||||
return;
|
||||
}
|
||||
case InputConnectionCommandType.COMMIT_TEXT: {
|
||||
case DO_COMMIT_TEXT: {
|
||||
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#commitText");
|
||||
try {
|
||||
final CharSequence text = command.mCharSequence;
|
||||
final int newCursorPosition = command.mIntArg0;
|
||||
InputConnection ic = getInputConnection();
|
||||
if (ic == null || !isActive()) {
|
||||
Log.w(TAG, "commitText on inactive InputConnection");
|
||||
return;
|
||||
}
|
||||
ic.commitText(text, newCursorPosition);
|
||||
ic.commitText((CharSequence) msg.obj, msg.arg1);
|
||||
} finally {
|
||||
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case InputConnectionCommandType.SET_SELECTION: {
|
||||
case DO_SET_SELECTION: {
|
||||
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#setSelection");
|
||||
try {
|
||||
final int start = command.mIntArg0;
|
||||
final int end = command.mIntArg1;
|
||||
InputConnection ic = getInputConnection();
|
||||
if (ic == null || !isActive()) {
|
||||
Log.w(TAG, "setSelection on inactive InputConnection");
|
||||
return;
|
||||
}
|
||||
ic.setSelection(start, end);
|
||||
ic.setSelection(msg.arg1, msg.arg2);
|
||||
} finally {
|
||||
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case InputConnectionCommandType.PERFORM_EDITOR_ACTION: {
|
||||
case DO_PERFORM_EDITOR_ACTION: {
|
||||
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#performEditorAction");
|
||||
try {
|
||||
final int editorAction = command.mIntArg0;
|
||||
InputConnection ic = getInputConnection();
|
||||
if (ic == null || !isActive()) {
|
||||
Log.w(TAG, "performEditorAction on inactive InputConnection");
|
||||
return;
|
||||
}
|
||||
ic.performEditorAction(editorAction);
|
||||
ic.performEditorAction(msg.arg1);
|
||||
} finally {
|
||||
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case InputConnectionCommandType.PERFORM_CONTEXT_MENU_ACTION: {
|
||||
case DO_PERFORM_CONTEXT_MENU_ACTION: {
|
||||
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#performContextMenuAction");
|
||||
try {
|
||||
final int id = command.mIntArg0;
|
||||
InputConnection ic = getInputConnection();
|
||||
if (ic == null || !isActive()) {
|
||||
Log.w(TAG, "performContextMenuAction on inactive InputConnection");
|
||||
return;
|
||||
}
|
||||
ic.performContextMenuAction(id);
|
||||
ic.performContextMenuAction(msg.arg1);
|
||||
} finally {
|
||||
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case InputConnectionCommandType.COMMIT_COMPLETION: {
|
||||
case DO_COMMIT_COMPLETION: {
|
||||
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#commitCompletion");
|
||||
try {
|
||||
final CompletionInfo text = (CompletionInfo) command.mParcelable;
|
||||
InputConnection ic = getInputConnection();
|
||||
if (ic == null || !isActive()) {
|
||||
Log.w(TAG, "commitCompletion on inactive InputConnection");
|
||||
return;
|
||||
}
|
||||
ic.commitCompletion(text);
|
||||
ic.commitCompletion((CompletionInfo) msg.obj);
|
||||
} finally {
|
||||
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case InputConnectionCommandType.COMMIT_CORRECTION: {
|
||||
case DO_COMMIT_CORRECTION: {
|
||||
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#commitCorrection");
|
||||
try {
|
||||
final CorrectionInfo correctionInfo = (CorrectionInfo) command.mParcelable;
|
||||
InputConnection ic = getInputConnection();
|
||||
if (ic == null || !isActive()) {
|
||||
Log.w(TAG, "commitCorrection on inactive InputConnection");
|
||||
return;
|
||||
}
|
||||
ic.commitCorrection(correctionInfo);
|
||||
ic.commitCorrection((CorrectionInfo) msg.obj);
|
||||
} finally {
|
||||
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case InputConnectionCommandType.SET_COMPOSING_TEXT: {
|
||||
case DO_SET_COMPOSING_TEXT: {
|
||||
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#setComposingText");
|
||||
try {
|
||||
final CharSequence text = command.mCharSequence;
|
||||
final int newCursorPosition = command.mIntArg0;
|
||||
InputConnection ic = getInputConnection();
|
||||
if (ic == null || !isActive()) {
|
||||
Log.w(TAG, "setComposingText on inactive InputConnection");
|
||||
return;
|
||||
}
|
||||
ic.setComposingText(text, newCursorPosition);
|
||||
ic.setComposingText((CharSequence) msg.obj, msg.arg1);
|
||||
} finally {
|
||||
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case InputConnectionCommandType.SET_COMPOSING_REGION: {
|
||||
case DO_SET_COMPOSING_REGION: {
|
||||
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#setComposingRegion");
|
||||
try {
|
||||
final int start = command.mIntArg0;
|
||||
final int end = command.mIntArg1;
|
||||
InputConnection ic = getInputConnection();
|
||||
if (ic == null || !isActive()) {
|
||||
Log.w(TAG, "setComposingRegion on inactive InputConnection");
|
||||
return;
|
||||
}
|
||||
ic.setComposingRegion(start, end);
|
||||
ic.setComposingRegion(msg.arg1, msg.arg2);
|
||||
} finally {
|
||||
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case InputConnectionCommandType.FINISH_COMPOSING_TEXT: {
|
||||
case DO_FINISH_COMPOSING_TEXT: {
|
||||
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#finishComposingText");
|
||||
try {
|
||||
if (isFinished()) {
|
||||
@@ -551,70 +675,64 @@ public final class IInputConnectionWrapper extends IInputContext.Stub {
|
||||
}
|
||||
return;
|
||||
}
|
||||
case InputConnectionCommandType.SEND_KEY_EVENT: {
|
||||
case DO_SEND_KEY_EVENT: {
|
||||
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#sendKeyEvent");
|
||||
try {
|
||||
final KeyEvent event = (KeyEvent) command.mParcelable;
|
||||
InputConnection ic = getInputConnection();
|
||||
if (ic == null || !isActive()) {
|
||||
Log.w(TAG, "sendKeyEvent on inactive InputConnection");
|
||||
return;
|
||||
}
|
||||
ic.sendKeyEvent(event);
|
||||
ic.sendKeyEvent((KeyEvent) msg.obj);
|
||||
} finally {
|
||||
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case InputConnectionCommandType.CLEAR_META_KEY_STATES: {
|
||||
case DO_CLEAR_META_KEY_STATES: {
|
||||
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#clearMetaKeyStates");
|
||||
try {
|
||||
final int states = command.mIntArg0;
|
||||
InputConnection ic = getInputConnection();
|
||||
if (ic == null || !isActive()) {
|
||||
Log.w(TAG, "clearMetaKeyStates on inactive InputConnection");
|
||||
return;
|
||||
}
|
||||
ic.clearMetaKeyStates(states);
|
||||
ic.clearMetaKeyStates(msg.arg1);
|
||||
} finally {
|
||||
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case InputConnectionCommandType.DELETE_SURROUNDING_TEXT: {
|
||||
case DO_DELETE_SURROUNDING_TEXT: {
|
||||
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#deleteSurroundingText");
|
||||
try {
|
||||
final int beforeLength = command.mIntArg0;
|
||||
final int afterLength = command.mIntArg1;
|
||||
InputConnection ic = getInputConnection();
|
||||
if (ic == null || !isActive()) {
|
||||
Log.w(TAG, "deleteSurroundingText on inactive InputConnection");
|
||||
return;
|
||||
}
|
||||
ic.deleteSurroundingText(beforeLength, afterLength);
|
||||
ic.deleteSurroundingText(msg.arg1, msg.arg2);
|
||||
} finally {
|
||||
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case InputConnectionCommandType.DELETE_SURROUNDING_TEXT_IN_CODE_POINTS: {
|
||||
case DO_DELETE_SURROUNDING_TEXT_IN_CODE_POINTS: {
|
||||
Trace.traceBegin(Trace.TRACE_TAG_INPUT,
|
||||
"InputConnection#deleteSurroundingTextInCodePoints");
|
||||
try {
|
||||
final int beforeLength = command.mIntArg0;
|
||||
final int afterLength = command.mIntArg1;
|
||||
InputConnection ic = getInputConnection();
|
||||
if (ic == null || !isActive()) {
|
||||
Log.w(TAG, "deleteSurroundingTextInCodePoints on inactive InputConnection");
|
||||
return;
|
||||
}
|
||||
ic.deleteSurroundingTextInCodePoints(beforeLength, afterLength);
|
||||
ic.deleteSurroundingTextInCodePoints(msg.arg1, msg.arg2);
|
||||
} finally {
|
||||
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case InputConnectionCommandType.BEGIN_BATCH_EDIT: {
|
||||
case DO_BEGIN_BATCH_EDIT: {
|
||||
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#beginBatchEdit");
|
||||
try {
|
||||
InputConnection ic = getInputConnection();
|
||||
@@ -628,7 +746,7 @@ public final class IInputConnectionWrapper extends IInputContext.Stub {
|
||||
}
|
||||
return;
|
||||
}
|
||||
case InputConnectionCommandType.END_BATCH_EDIT: {
|
||||
case DO_END_BATCH_EDIT: {
|
||||
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#endBatchEdit");
|
||||
try {
|
||||
InputConnection ic = getInputConnection();
|
||||
@@ -642,7 +760,7 @@ public final class IInputConnectionWrapper extends IInputContext.Stub {
|
||||
}
|
||||
return;
|
||||
}
|
||||
case InputConnectionCommandType.PERFORM_SPELL_CHECK: {
|
||||
case DO_PERFORM_SPELL_CHECK: {
|
||||
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#performSpellCheck");
|
||||
try {
|
||||
InputConnection ic = getInputConnection();
|
||||
@@ -656,11 +774,12 @@ public final class IInputConnectionWrapper extends IInputContext.Stub {
|
||||
}
|
||||
return;
|
||||
}
|
||||
case InputConnectionCommandType.PERFORM_PRIVATE_COMMAND: {
|
||||
case DO_PERFORM_PRIVATE_COMMAND: {
|
||||
final SomeArgs args = (SomeArgs) msg.obj;
|
||||
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#performPrivateCommand");
|
||||
try {
|
||||
final String action = command.mString;
|
||||
final Bundle data = command.mBundle;
|
||||
final String action = (String) args.arg1;
|
||||
final Bundle data = (Bundle) args.arg2;
|
||||
InputConnection ic = getInputConnection();
|
||||
if (ic == null || !isActive()) {
|
||||
Log.w(TAG, "performPrivateCommand on inactive InputConnection");
|
||||
@@ -669,71 +788,142 @@ public final class IInputConnectionWrapper extends IInputContext.Stub {
|
||||
ic.performPrivateCommand(action, data);
|
||||
} finally {
|
||||
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
|
||||
args.recycle();
|
||||
}
|
||||
return;
|
||||
}
|
||||
case InputConnectionCommandType.REQUEST_CURSOR_UPDATES: {
|
||||
case DO_REQUEST_CURSOR_UPDATES: {
|
||||
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#requestCursorUpdates");
|
||||
try {
|
||||
final int cursorUpdateMode = command.mIntArg0;
|
||||
final IBooleanResultCallback callback = (IBooleanResultCallback) msg.obj;
|
||||
final InputConnection ic = getInputConnection();
|
||||
final boolean result;
|
||||
if (ic == null || !isActive()) {
|
||||
Log.w(TAG, "requestCursorAnchorInfo on inactive InputConnection");
|
||||
result = false;
|
||||
} else {
|
||||
result = ic.requestCursorUpdates(cursorUpdateMode);
|
||||
result = ic.requestCursorUpdates(msg.arg1);
|
||||
}
|
||||
try {
|
||||
callback.onResult(result);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Failed to return the result to requestCursorUpdates()."
|
||||
+ " result=" + result, e);
|
||||
}
|
||||
CallbackUtils.onResult(command, result, TAG);
|
||||
} finally {
|
||||
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case InputConnectionCommandType.COMMIT_CONTENT: {
|
||||
case DO_CLOSE_CONNECTION: {
|
||||
// Note that we do not need to worry about race condition here, because 1) mFinished
|
||||
// is updated only inside this block, and 2) the code here is running on a Handler
|
||||
// hence we assume multiple DO_CLOSE_CONNECTION messages will not be handled at the
|
||||
// same time.
|
||||
if (isFinished()) {
|
||||
return;
|
||||
}
|
||||
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#closeConnection");
|
||||
try {
|
||||
InputConnection ic = getInputConnection();
|
||||
// Note we do NOT check isActive() here, because this is safe
|
||||
// for an IME to call at any time, and we need to allow it
|
||||
// through to clean up our state after the IME has switched to
|
||||
// another client.
|
||||
if (ic == null) {
|
||||
return;
|
||||
}
|
||||
@MissingMethodFlags
|
||||
final int missingMethods = InputConnectionInspector.getMissingMethodFlags(ic);
|
||||
if ((missingMethods & MissingMethodFlags.CLOSE_CONNECTION) == 0) {
|
||||
ic.closeConnection();
|
||||
}
|
||||
} finally {
|
||||
synchronized (mLock) {
|
||||
mInputConnection = null;
|
||||
mFinished = true;
|
||||
}
|
||||
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case DO_COMMIT_CONTENT: {
|
||||
final int flags = msg.arg1;
|
||||
SomeArgs args = (SomeArgs) msg.obj;
|
||||
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#commitContent");
|
||||
try {
|
||||
final InputContentInfo inputContentInfo =
|
||||
(InputContentInfo) command.mParcelable;
|
||||
final int flags = command.mFlags;
|
||||
final Bundle opts = command.mBundle;
|
||||
final IBooleanResultCallback callback = (IBooleanResultCallback) args.arg3;
|
||||
final InputConnection ic = getInputConnection();
|
||||
final boolean result;
|
||||
if (ic == null || !isActive()) {
|
||||
Log.w(TAG, "commitContent on inactive InputConnection");
|
||||
result = false;
|
||||
} else {
|
||||
final InputContentInfo inputContentInfo = (InputContentInfo) args.arg1;
|
||||
if (inputContentInfo == null || !inputContentInfo.validate()) {
|
||||
Log.w(TAG, "commitContent with invalid inputContentInfo="
|
||||
+ inputContentInfo);
|
||||
result = false;
|
||||
} else {
|
||||
result = ic.commitContent(inputContentInfo, flags, opts);
|
||||
result = ic.commitContent(inputContentInfo, flags, (Bundle) args.arg2);
|
||||
}
|
||||
}
|
||||
CallbackUtils.onResult(command, result, TAG);
|
||||
try {
|
||||
callback.onResult(result);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Failed to return the result to commitContent()."
|
||||
+ " result=" + result, e);
|
||||
}
|
||||
} finally {
|
||||
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
|
||||
args.recycle();
|
||||
}
|
||||
return;
|
||||
}
|
||||
case InputConnectionCommandType.SET_IME_CONSUMES_INPUT: {
|
||||
case DO_SET_IME_CONSUMES_INPUT: {
|
||||
Trace.traceBegin(Trace.TRACE_TAG_INPUT,
|
||||
"InputConnection#setImeConsumesInput");
|
||||
try {
|
||||
final boolean imeConsumesInput = (command.mIntArg0 != 0);
|
||||
InputConnection ic = getInputConnection();
|
||||
if (ic == null || !isActive()) {
|
||||
Log.w(TAG,
|
||||
"setImeConsumesInput on inactive InputConnection");
|
||||
return;
|
||||
}
|
||||
ic.setImeConsumesInput(imeConsumesInput);
|
||||
ic.setImeConsumesInput(msg.arg1 == 1);
|
||||
} finally {
|
||||
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
Log.w(TAG, "Unhandled message code: " + msg.what);
|
||||
}
|
||||
|
||||
Message obtainMessage(int what) {
|
||||
return mH.obtainMessage(what);
|
||||
}
|
||||
|
||||
Message obtainMessageII(int what, int arg1, int arg2) {
|
||||
return mH.obtainMessage(what, arg1, arg2);
|
||||
}
|
||||
|
||||
Message obtainMessageO(int what, Object arg1) {
|
||||
return mH.obtainMessage(what, 0, 0, arg1);
|
||||
}
|
||||
|
||||
Message obtainMessageIO(int what, int arg1, Object arg2) {
|
||||
return mH.obtainMessage(what, arg1, 0, arg2);
|
||||
}
|
||||
|
||||
Message obtainMessageOO(int what, Object arg1, Object arg2) {
|
||||
final SomeArgs args = SomeArgs.obtain();
|
||||
args.arg1 = arg1;
|
||||
args.arg2 = arg2;
|
||||
return mH.obtainMessage(what, 0, 0, args);
|
||||
}
|
||||
|
||||
Message obtainMessageB(int what, boolean arg1) {
|
||||
return mH.obtainMessage(what, arg1 ? 1 : 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,13 +16,76 @@
|
||||
|
||||
package com.android.internal.view;
|
||||
|
||||
import com.android.internal.inputmethod.InputConnectionCommand;
|
||||
import android.os.Bundle;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.inputmethod.CompletionInfo;
|
||||
import android.view.inputmethod.CorrectionInfo;
|
||||
import android.view.inputmethod.ExtractedTextRequest;
|
||||
import android.view.inputmethod.InputContentInfo;
|
||||
|
||||
import com.android.internal.inputmethod.IBooleanResultCallback;
|
||||
import com.android.internal.inputmethod.ICharSequenceResultCallback;
|
||||
import com.android.internal.inputmethod.IExtractedTextResultCallback;
|
||||
import com.android.internal.inputmethod.IIntResultCallback;
|
||||
import com.android.internal.inputmethod.ISurroundingTextResultCallback;
|
||||
|
||||
/**
|
||||
* Interface from an input method to the application, allowing it to perform
|
||||
* edits on the current input field and other interactions with the application.
|
||||
* {@hide}
|
||||
*/
|
||||
oneway interface IInputContext {
|
||||
void doEdit(in InputConnectionCommand command);
|
||||
oneway interface IInputContext {
|
||||
void getTextBeforeCursor(int length, int flags, ICharSequenceResultCallback callback);
|
||||
|
||||
void getTextAfterCursor(int length, int flags, ICharSequenceResultCallback callback);
|
||||
|
||||
void getCursorCapsMode(int reqModes, IIntResultCallback callback);
|
||||
|
||||
void getExtractedText(in ExtractedTextRequest request, int flags,
|
||||
IExtractedTextResultCallback callback);
|
||||
|
||||
void deleteSurroundingText(int beforeLength, int afterLength);
|
||||
void deleteSurroundingTextInCodePoints(int beforeLength, int afterLength);
|
||||
|
||||
void setComposingText(CharSequence text, int newCursorPosition);
|
||||
|
||||
void finishComposingText();
|
||||
|
||||
void commitText(CharSequence text, int newCursorPosition);
|
||||
|
||||
void commitCompletion(in CompletionInfo completion);
|
||||
|
||||
void commitCorrection(in CorrectionInfo correction);
|
||||
|
||||
void setSelection(int start, int end);
|
||||
|
||||
void performEditorAction(int actionCode);
|
||||
|
||||
void performContextMenuAction(int id);
|
||||
|
||||
void beginBatchEdit();
|
||||
|
||||
void endBatchEdit();
|
||||
|
||||
void sendKeyEvent(in KeyEvent event);
|
||||
|
||||
void clearMetaKeyStates(int states);
|
||||
|
||||
void performSpellCheck();
|
||||
|
||||
void performPrivateCommand(String action, in Bundle data);
|
||||
|
||||
void setComposingRegion(int start, int end);
|
||||
|
||||
void getSelectedText(int flags, ICharSequenceResultCallback callback);
|
||||
|
||||
void requestCursorUpdates(int cursorUpdateMode, IBooleanResultCallback callback);
|
||||
|
||||
void commitContent(in InputContentInfo inputContentInfo, int flags, in Bundle opts,
|
||||
IBooleanResultCallback callback);
|
||||
|
||||
void getSurroundingText(int beforeLength, int afterLength, int flags,
|
||||
ISurroundingTextResultCallback callback);
|
||||
|
||||
void setImeConsumesInput(boolean imeConsumesInput);
|
||||
}
|
||||
|
||||
@@ -73,13 +73,4 @@ public class InputMethodDebugTest {
|
||||
InputMethodDebug.softInputDisplayReasonToString(
|
||||
SoftInputShowHideReason.HIDE_REMOVE_CLIENT));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDumpInputConnectionCommand() {
|
||||
// TODO: add more tests
|
||||
assertEquals("null", InputMethodDebug.dumpInputConnectionCommand(null));
|
||||
assertEquals("endBatchEdit()",
|
||||
InputMethodDebug.dumpInputConnectionCommand(
|
||||
InputConnectionCommand.create(InputConnectionCommandType.END_BATCH_EDIT)));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user