Part 2: Building a custom image keyboard on Android
A picture is worth a thousand words
The other parts of this series can be found here: Part 1, Part 3.
People love to communicate through imagery. Be that pictures, emojis or gifs. On Android, it used to be the case that custom keyboards (called ‘soft keyboards’) could only send Unicode emoji to apps. Rich content could only be sent via janky workarounds like the clipboard. This all changed in Android 7.1 (API level 25). Included in the Android SDK was the Commit Content API which provided a universal way to send rich content directly to the text input in an app. The API is also backwards compatible (using the Compat library) so devices running Android versions as early as 3.2 (API level 13) could implement it.
How
The Commit content API consists of two parts. One for the receiver (like Whatsapp) and one for the sender (us!)
The following steps describe the steps to add an image in an app:
- When a user taps on a text field, the editor (e.g. WhatsApp) sends a list of supported mime types that it accepts. These could be jpg. png, gif.
- The sender app then displays a list of supported content.
- The user clicks on the image that they want to send and it is inserted into the editor.
Simple.
The first part of this series covered the react native side of things. This part will cover creating our simple image keyboard, this will cover the use of the Commit content API and will lay the groundwork for our second part where we will create a proper image keyboard. This will be much more about programmatically creating layouts and using all the assets available.
Open the project we created from the first part, let’s create our ImageKeyboard.java class, place this in the same place as your MainActivity.java file. Because there is a fair amount of boilerplate and I want to keep these posts reasonably short I have provided a class with the main structure already written. This can be found here. You will need to import all the required libraries but this can easily be done by pressing option + enter and selecting import class.
Before we get to the meat of the code lets have a quick skim over the contents of the class.
Our ImageKeyboard class extends InputMethodService
. This gives us access to some lifecycle methods needed to detect MIME types and display the keyboard.
isCommitContentSupported
is a helper method allowing us to check what MIME types the receiver app supports. This then allows us to display only supported content.
doCommitContent
is the money shot of this file as it performs the act of actually adding the image to the editor.
validatePackageName
is a helper method to validate the package name.
onCreate
, onCreateInputView
and onStartInputView
will be discussed later as this is where the bulk of the code for this tutorial will go.
getFileForResource
is a helper method which gets needed resource for the editor using the File API and FileProvider API. These are needed to allow us to securely share content between apps.
The Android documentation is excellent and the File API and FileProvider API can be found here.
While we are talking about the sharing of content (images) there are a few other files we need to create/amend.
First, let’s create a new XML resource. You may need to create the xml directory in the res directory. Name the file file_paths and enter the following code
This simply creates a path for the files to be securely stored ready for the FileProvider API to access.
Next, open the AndroidManifest.xml file in within the application tags paste the following:
Make sure you change the string in the android:authorities
parameter to match that of the AUTHORITY
variable in the ImageKeyboard.java
file. This snippet makes use of the file_paths.xml file we just created to give the app permission to provide content from there.
Apart from the 3 methods mentioned above the rest should not really need to be touched.
This being an image keyboard we obviously need some images. I am just using an image from google and storing them in the app/res/raw directory. Make sure you have an image in that directory.
onCreate
Let’s start with the onCreate
method. All we are doing here is assigning the file that we are going to add to the editor. We are using the File API to get the path of the images directory (that we just created). Then passing that to the getFileForResource
method to get the secure file ready for the editor. We will make this more dynamic in the second part but this will suffice for now.
onStartInputView
This method is only called once when the custom keyboard is started. This is where we check what MIME types are supported and act accordingly. Here we are just informing the user by displaying a toast.
onCreateInputView
The final step is to actually display the contents of the keyboard. In this post, we are keeping it very simple. But there are still a few steps to get it working.
First, let's finish the onCreateInputView
method. This method takes a layout file to generate the button for our keyboard.
https://gist.github.com/jim-at-jibba/b026ccb4938cfb62184037b0d426c941
We still need to create the XML file that holders our keyboard’s layout. In the res/layout folder, create the keybard_layout.xml file and add the following to it:
This layout file is pretty straightforward. We wrap a button in a relative layout with height and width constraints that match its parents. We then give the button a fixed width and height and position it. We also provide the button with the context of our class meaning the android:onClick
method can come from our ImageKeyboard class. The last thing we need to do is to create the addImage
click handler in our class.
Currently, all this method does is call the doCommitContent
method with the globally available image that was generated in the onCreate
method.
To get our keyboard to show in the keyboard menu in the settings we need to update the AndroidManifest.xml file again adding a service property. This just provided the intent of our service.
Open the file and add the following, placing it above the provider
tag:
Your AndroidManifest.xml should look like this:
We also need to create one last file. In the res/xml folder create a method.xml resource file and add this to the file:
And that is it. It does not take much to create a custom image keyboard. Granted it is very simple but the principles are the same. In the next part, we will programmatically generate the layout making into a much more real-world application.
The source code for this tutorial can be found here.
The other parts of this series can be found here: Part 1, Part 3