Context:
I am developing an app that implements a custom input method (a custom keyboard). It builds fine, and I can enable and switch over to the keyboard manually, but every time I launch the app from Android Studio, it becomes disabled and deselected, then I have to dig through the settings again, etc.
I know there are commands to re-enable it using ADB:
adb -d shell ime enable com.example.app/.services.Keyboard
and
adb -d shell ime set com.example.app/.services.Keyboard
I'd like to run these between the app install and app launch, but I can't figure out where exactly to configure this.
I've tried:
Adding a custom Gradle task
I added this to my build.gradle.kts
afterEvaluate {
tasks.register("enableKB", Exec::class) {
val adbPath = android.sdkDirectory.resolve("platform-tools/adb").toString()
commandLine(
adbPath,
"-d",
"shell",
"ime enable com.example.app/.services.Keyboard"
)
commandLine(
adbPath,
"-d",
"shell",
"ime set com.example.app/.services.Keyboard"
)
}
tasks.named("installDebug").configure {
finalizedBy("enableKB")
}
}
This does nothing (I don't think the installDebug
task is ever called)
If I add it as a Before Launch
step in the App configuration, it gets to the second command (where it sets the keyboard) and fails with Unknown input method com.example.app/.services.Keyboard cannot be selected for user #0
. It seems the first command is run, but the keyboard was ever set either.
Adding an extra run configuration
I tried adding a shell script in the Android Studio run configuration with the App run as a prerequisite, but the App run is blocking.
What I think:
I think I need to have the ADB commands after the app install, since installing the app seems to reset the state of the input methods. It just seems that the run configuration does the install/launch all in one big step, and I am unsure where to add these commands, or if there is a better way entirely.
I figured it out. There are a couple steps.
First, the commandLine
tasks need to be called separately.
tasks.register("enableKB", Exec::class) {
val adbPath = android.sdkDirectory.resolve("platform-tools/adb").toString()
commandLine(
adbPath,
"-d",
"shell",
"ime enable com.example.app/.services.Keyboard"
)
}
tasks.register("setKB", Exec::class) {
val adbPath = android.sdkDirectory.resolve("platform-tools/adb").toString()
commandLine(
adbPath,
"-d",
"shell",
"ime set com.example.app/.services.Keyboard"
)
dependsOn("enableKB")
}
Then, the app needs to be started manually (I'll explain in a sec.) This can be hooked at the end of installDebug
tasks.register("startDebug", Exec::class) {
val adbPath = android.sdkDirectory.resolve("platform-tools/adb").toString()
commandLine(
adbPath,
"-d",
"shell",
"am start -n com.example.app/com.example.app.main.MainActivity"
)
dependsOn("setKB")
}
afterEvaluate {
tasks.named("installDebug").configure {
finalizedBy("startDebug")
}
}
Then the App Configuration needs to be changed. The Installation and Launch options need to be disabled since they somehow interfere with the command to set the keyboard.
Gradle Aware Make
must also be removed; it interferes with the custom build steps. The installDebug
(or some other task) can be manually selected as a Before Launch step.
Why did I even use the Android App configuration when I could have just used a Gradle Task one? Because I needed logcat to be attached automatically.
This is the best I could figure out right now. I had better explanations of my findings but SO went down half way through my answer and I lost half of it.