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:
Yohei Yukawa
2021-07-30 09:07:36 -07:00
parent da04fd9eb8
commit 7eec13b458
9 changed files with 487 additions and 1439 deletions

View File

@@ -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);
}
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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;

View File

@@ -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];
}
};
}

View File

@@ -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;
}

View File

@@ -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.

View File

@@ -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);
}
}

View File

@@ -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);
}

View File

@@ -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)));
}
}