Posted on November 26, 2020 | Guille
There are countless tutorials and example code for building an Android keyboard, but all of them use Java and the deprecated KeyboardView and Keyboard classes from android.inputmethodservice
. If you’re building an Android keyboard in 2020 you want to be using Kotlin and designing your own layout from scratch.
Why Kotlin?
According to the official Android documentation:
If you’re looking to build an Android app, we recommend starting with Kotlin to take advantage of its best-in-class features.
I’m not going to go into what those best-in-class features are. Suffice it to say that Kotlin is not only the official recommendation, it is also the fourth most loved programming language according to Stack Overflow.
Why a custom layout?
The KeyboardView and Keyboard classes that are included in android.inputmethodservice
have been deprecated in API level 29, and for good reason: they create the entire view programmatically, and directly extend the View class for the base layout. Again according to the official Android documentation:
Declaring your UI in XML allows you to separate the presentation of your app from the code that controls its behavior. Using XML files also makes it easy to provide different layouts for different screen sizes and orientations.
Using XML for declaring the UI also gives you access to the Layout Inspector tool in Android Studio, which is very handy for visualizing the UI and modifying it graphically. As for which layout to use, there’s also an explicit recommendation in the official Android documentation:
The best way to create a responsive layout for different screen sizes is to use ConstraintLayout as the base layout in your UI.
Hopefully you are now convinced that you should be using Kotlin, declaring your UI in XML, and using ConstraintLayout. Well good luck finding a tutorial or example code with these prerequisites. When we started development of our T16Fling keyboard we found nothing of the sort, so we created this tutorial to help the next person who finds themselves in this predicament.
1. Create the project
An Android keyboard (technically an Input Method Editor) doesn’t require any Activity, since it works as a service. Therefore, when creating the new project in Android Studio select the “No Activity” template. You can add a Settings Activity later on if you want to allow the user to modify the keyboard’s configuration.
The first thing to do is create a new Kotlin Class that extends InputMethodService, since this is what is called when the keyboard is opened:
class MyKeyboard : InputMethodService() {
}
All the code that has to do with setting up the keyboard will eventually go in there.
The next step is to define the input method. In the “res” directory, create a new Android Resource Directory of type “xml” (appropriately named “xml”) and in it create a new XML Resource File named “method”. This file should contain the following:
<input-method xmlns:android="http://schemas.android.com/apk/res/android">
<subtype android:languageTag="en" android:imeSubtypeMode="keyboard" />
</input-method>
Right now there is only one subtype for English, but you could add other subtypes for different languages here.
Now you must declare the service so that Android can identify it and offer it as a Virtual Keyboard in the system settings. To do this just add the following lines in the AndroidManifest.xml under the “application” tag:
<service android:name="my.packagename.MyKeyboard" android:label="@string/app_name" android:permission="android.permission.BIND_INPUT_METHOD">
<intent-filter>
<action android:name="android.view.InputMethod" />
</intent-filter>
<meta-data android:name="android.view.im" android:resource="@xml/method" />
</service>
You shouldn’t have any compilation errors now, so go ahead and run the app in the emulator or a physical device. When you run it the app should install correctly, but there will be a launch error saying that the Default Activity was not found. That’s predictable since the project was created from the “No Activity” template, but for some reason Android Studio still tries to launch a Default Activity. Just edit the Run Configuration and select “Nothing” on the Launch option to get rid of this message.
To select the new keyboard on the device, go to Settings -> System -> Language & input -> Virtual keyboard -> Manage keyboards and activate it. If you try to use it you will see that nothing is displayed when you open the keyboard on a text input, so it’s pretty useless at the moment.
2. Create the layout
It’s time to start building the actual keyboard, and that requires a layout. In the “res” directory, create a new Android Resource Directory of type “layout” (appropriately named “layout”) and in it create a new Layout Resource File named “input” with root element androidx.constraintlayout.widget.ConstraintLayout
. Once created, Android Studio will complain that the ConstraintLayout class was not found, and suggest that you add the dependency to your build.gradle. Go ahead and do that.
With the empty layout created, edit your InputMethodService (the MyKeyboard class you created in the previous step) and add this inside:
override fun onCreateInputView(): View {
return layoutInflater.inflate(R.layout.input, null)
}
The onCreateInputView()
method is run when the system asks your keyboard to draw its view, and this line is simply telling it to create the view by inflating the layout found in layout/input.xml
.
3. Add event handlers
We’re not going to go into how to build your layout because that is just regular Android development and depends a lot on the type of keyboard you are trying to build. For simplicity’s sake let’s say your keyboard is for accepting EULAs and its layout is made up of just two Buttons: one with label “YES” which outputs “y” and another with label “NO” which outputs “n”. In your InputMethodService you could use a Kotlin scope function such as apply
after the inflation and set your click listeners here:
return layoutInflater.inflate(R.layout.input, null).apply {
findViewById<Button>(R.id.btnYes).setOnClickListener {
this@MyKeyboard.sendDownUpKeyEvents(KeyEvent.KEYCODE_Y)
}
findViewById<Button>(R.id.btnNo).setOnClickListener {
this@MyKeyboard.sendDownUpKeyEvents(KeyEvent.KEYCODE_N)
}
}
Now when you run your app you should see that clicking on the buttons will in fact output the “y” and “n” characters to the text input. You have a working keyboard!
4. Next steps
This tutorial is not to be seen as a complete guide for creating a powerful Android keyboard, it is only the basic building blocks to get you started. From here you can do several things to improve on this keyboard and make it more complete:
- Create your own Key view (could extend Button, or ImageButton) and keep the event handling logic there (maybe use GestureDetector to handle long presses or double taps).
- Instead of just sending KeyEvents, use InputConnection to manipulate the text in the text input more precisely (get and set selected text, commit text, delete text, etc.).
- Add layout subtypes for different languages.
- Handle different types of inputs (numeric, password, multi-line, etc.) by reading the EditorInfo in your InputMethodService’s onStartInputView
- Show word suggestions or corrections by adding a Candidates View
T16Fling
If you want to see the code for a more complex keyboard that uses the fling gesture to determine the character to send to the text input check out our T16Fling keyboard.