I am trying to build an IME (input method editor) for Android. I know that I have to create a class that extends InputMethodService, to have access to the getCurrentInputConnection method. My understanding is that this returns me to the currently focused text field or null if there isn't.
Then I know I have to do something like this:
val focusedTextField = currentInputConnection ?: return
The problem is that I always get null as a result. My theory is that the Text Editor (currently focused Text Field) doesn't recognize my app as an IME or maybe "doesn't realize" that it is being focused. So maybe I have to provide more information. I already checked the manifest where I declare the service and provide the metadata and everything seems to be correct. The res/xml/method.xml file is correct.
this is the manifest file. I have been told that since android 11 we have to ask for location permission to use services
<service
android:name=".IMEService"
android:label="Amazing Keyboard"
android:foregroundServiceType="location"
android:permission="android.permission.BIND_INPUT_METHOD"
android:exported="true">
<intent-filter>
<action android:name="android.view.InputMethod" />
</intent-filter>
<meta-data
android:name="android.view.im"
android:resource="@xml/method" />
</service>
This is the method file
<?xml version="1.0" encoding="utf-8"?>
<input-method xmlns:android="http://schemas.android.com/apk/res/android"
android:settingsActivity="com.example.amazingkeyboard.MainActivity">
<subtype
android:name = "my app"
android:label="English (U.S)"
android:imeSubtypeLocale="en_US"
android:imeSubtypeMode="keyboard"/>
</input-method>
This is what I am doing, I am using jetpack compose, but that is not the problem, because I already tried to return an xml view and I always have the error
class IMEService : InputMethodService(), LifecycleOwner,
ViewModelStoreOwner, SavedStateRegistryOwner {
fun sendText(text : CharSequence, newCursorPosition : Int) {
val focusedTextField = currentInputConnection ?: return //always returns null
focusedTextField.commitText(text, newCursorPosition)
}
...
}
This is where I call the method
val connection = IMEService()
@Composable fun TestKey(modifier: Modifier = Modifier) {
Key(
modifier = modifier .clickable {
connection.sendText(unicodeToString(0x1F436), 1)
}...
when I remove the validation. As I said above, the problem is that I always get null. Obviously if I do the validation, there will be no error, but I can't send either (because I always have null)
// val focusedTextField = currentInputConnection ?: return
val focusedTextField = currentInputConnection
I have this error.
java.lang.NullPointerException:
Attempt to invoke interface method 'boolean android.view.inputmethod.InputConnection.commitText(java.lang.CharSequence, int)' on a null object reference
at com.chrrissoft.amazingkeyboard.IMEService.sendText(IMEService.kt:21)
at com.chrrissoft.amazingkeyboard.composables.GeneralKeysKt$TestKey$1.invoke(generalKeys.kt:32)
at com.chrrissoft.amazingkeyboard.composables.GeneralKeysKt$TestKey$1.invoke(generalKeys.kt:31)
Here is the complete project, in case you want to review it.