Input user drivers provide an interface for apps to inject events into Android's input pipeline. With this API, apps can emulate a Human Interface Device (HID) or connect external hardware to the input system using Peripheral I/O.
Adding the required permission
Add the required permission for the user driver to your app's manifest file:
<uses-permission android:name="com.google.android.things.permission.MANAGE_INPUT_DRIVERS" />
Key events
Key events indicate a momentary press and release of an input switch. They are generally used for generic button input (e.g. volume keys, media playback keys) and the keys of a keyboard. Android represents each event as a KeyEvent instance.
- Create a new driver instance using the InputDriver.Builder.
Register the driver with the UserDriverManager.
Kotlin
import com.google.android.things.userdriver.UserDriverManager import com.google.android.things.userdriver.input.InputDriver ... // Driver parameters private const val DRIVER_NAME = "EscapeButton" private const val DRIVER_VERSION = 1 // Key code for driver to emulate private const val KEY_CODE = KeyEvent.KEYCODE_ESCAPE class ButtonDriverService : Service() { private lateinit var driver: InputDriver override fun onCreate() { super.onCreate() // Create a new driver instance driver = InputDriver.Builder() .setName(DRIVER_NAME) .setSupportedKeys(intArrayOf(KEY_CODE)) .build() // Register with the framework val manager = UserDriverManager.getInstance() manager.registerInputDriver(driver) } override fun onBind(intent: Intent?): IBinder? { return null } }
Java
import com.google.android.things.userdriver.input.InputDriver; import com.google.android.things.userdriver.UserDriverManager; ... public class ButtonDriverService extends Service { // Driver parameters private static final String DRIVER_NAME = "EscapeButton"; private static final int DRIVER_VERSION = 1; // Key code for driver to emulate private static final int KEY_CODE = KeyEvent.KEYCODE_ESCAPE; private InputDriver driver; @Override public void onCreate() { super.onCreate(); // Create a new driver instance driver = new InputDriver.Builder() .setName(DRIVER_NAME) .setSupportedKeys(new int[] {KEY_CODE}) .build(); // Register with the framework UserDriverManager manager = UserDriverManager.getInstance(); manager.registerInputDriver(driver); } @Override public IBinder onBind(Intent intent) { return null; } }
When a hardware event occurs, construct a new InputDriverEvent for each state change with the current key code and input action.
Inject the events into the driver with the emit() method.
Kotlin
class ButtonDriverService : Service() { ... // A state change has occurred private fun triggerEvent(pressed: Boolean) { val event = InputDriverEvent() event.setKeyPressed(KEY_CODE, pressed) driver.emit(event) } }
Java
public class ButtonDriverService extends Service { ... // A state change has occurred private void triggerEvent(boolean pressed) { InputDriverEvent event = new InputDriverEvent(); event.setKeyPressed(KEY_CODE, pressed); driver.emit(event); } }
Unregister the driver when key events are not longer required.
Kotlin
class ButtonDriverService : Service() { ... override fun onDestroy() { super.onDestroy() val manager = UserDriverManager.getInstance() manager.unregisterInputDriver(driver) } }
Java
public class ButtonDriverService extends Service { ... @Override public void onDestroy() { super.onDestroy(); UserDriverManager manager = UserDriverManager.getInstance(); manager.unregisterInputDriver(driver); } }
Motion events
Input drivers can also emit motion events to connect a pointing device to the framework, such as a touchpad or mouse. These devices report an absolute position value as an x/y coordinate. Each event includes an optional pressed state to indicate if the event represents a "tap" or "click" event at that location.
- Create a new driver instance using the InputDriver.Builder.
Register the driver with the UserDriverManager.
Kotlin
import com.google.android.things.userdriver.input.InputDriver ... // Driver parameters private const val DRIVER_NAME = "Touchpad" private const val DRIVER_VERSION = 1 class TouchpadDriverService : Service() { private lateinit var driver: InputDriver override fun onCreate() { super.onCreate() driver = InputDriver.Builder() .setName(DRIVER_NAME) .setAxisConfiguration(MotionEvent.AXIS_X, 0, 255, 0, 0) .setAxisConfiguration(MotionEvent.AXIS_Y, 0, 255, 0, 0) .build() val manager = UserDriverManager.getInstance() manager.registerInputDriver(driver) } override fun onBind(intent: Intent?): IBinder? { return null } }
Java
import com.google.android.things.userdriver.input.InputDriver; ... public class TouchpadDriverService extends Service { // Driver parameters private static final String DRIVER_NAME = "Touchpad"; private static final int DRIVER_VERSION = 1; private InputDriver driver; @Override public void onCreate() { super.onCreate(); driver = InputDriver.Builder() .setName(DRIVER_NAME) .setAxisConfiguration(MotionEvent.AXIS_X, 0, 255, 0, 0) .setAxisConfiguration(MotionEvent.AXIS_Y, 0, 255, 0, 0) .build(); UserDriverManager manager = UserDriverManager.getInstance(); manager.registerInputDriver(driver); } @Override public IBinder onBind(Intent intent) { return null; } }
When a hardware event occurs, construct a new InputDriverEvent and inject it into the driver with the emit() method.
Kotlin
class TouchpadDriverService : Service() { ... // A state change has occurred private fun triggerEvent(x: Int, y: Int, pressed: Boolean) { val event = InputDriverEvent().apply { setPosition(MotionEvent.AXIS_X, x) setPosition(MotionEvent.AXIS_Y, y) setContact(pressed) } driver.emit(event) } }
Java
public class TouchpadDriverService extends Service { ... // A state change has occurred private void triggerEvent(int x, int y, boolean pressed) { InputDriverEvent event = new InputDriverEvent(); event.setPosition(MotionEvent.AXIS_X, x); event.setPosition(MotionEvent.AXIS_Y, y); event.setContact(pressed); driver.emit(event); } }
Unregister the driver when pointer events are not longer required.
Kotlin
class TouchpadDriverService : Service() { ... override fun onDestroy() { super.onDestroy() val manager = UserDriverManager.getInstance() manager.unregisterInputDriver(driver) } }
Java
public class TouchpadDriverService extends Service { ... @Override public void onDestroy() { super.onDestroy(); UserDriverManager manager = UserDriverManager.getInstance(); manager.unregisterInputDriver(driver); } }
If your input device emits multiple input events rapidly, consider re-using the
same InputDriverEvent
object to avoid multiple object allocations.
Kotlin
val inputEvent = InputDriverEvent() for (keyCode in eventSet) { // Clear the event before values are set inputEvent.clear() // Set properties for the current event event.apply { setPosition(MotionEvent.AXIS_X, ...) setPosition(MotionEvent.AXIS_Y, ...) setContact(true) driver.emit(inputEvent) } }
Java
InputDriverEvent inputEvent = new InputDriverEvent(); for (int keyCode : eventSet) { // Clear the event before values are set inputEvent.clear(); // Set properties for the current event event.setPosition(MotionEvent.AXIS_X, ...); event.setPosition(MotionEvent.AXIS_Y, ...); event.setContact(true); driver.emit(inputEvent); }
See also
See Handling Controller Actions for more details on how Android handles input events from external source devices.