Input

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.

  1. Create a new driver instance using the InputDriver.Builder.
  2. Register the driver with the UserDriverManager.

    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 mDriver;
    
    @Override
    public void onCreate() {
        super.onCreate();
    
            // Create a new driver instance
            mDriver = new InputDriver.Builder()
                    .setName(DRIVER_NAME)
                    .setSupportedKeys(new int[] {KEY_CODE})
                    .build();
    
            // Register with the framework
            UserDriverManager manager = UserDriverManager.getInstance();
            manager.registerInputDriver(mDriver);
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
    }
    
  3. When a hardware event occurs, construct a new InputDriverEvent for each state change with the current key code and input action.

  4. Inject the events into the driver with the emit() method.

    public class ButtonDriverService extends Service {
        ...
    
        // A state change has occurred
        private void triggerEvent(boolean pressed) {
            InputDriverEvent event = new InputDriverEvent();
            event.setKeyPressed(KEY_CODE, pressed);
    
            mDriver.emit(event);
        }
    }
    
  5. Unregister the driver when key events are not longer required.

    public class ButtonDriverService extends Service {
        ...
    
        @Override
        public void onDestroy() {
            super.onDestroy();
    
            UserDriverManager manager = UserDriverManager.getInstance();
            manager.unregisterInputDriver(mDriver);
        }
    }
    

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.

  1. Create a new driver instance using the InputDriver.Builder.
  2. Register the driver with the UserDriverManager.

    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 mDriver;
    
    @Override
    public void onCreate() {
        super.onCreate();
    
            mDriver = 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(mDriver);
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
    }
    
  3. When a hardware event occurs, construct a new InputDriverEvent and inject it into the driver with the emit() method.

    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);
    
            mDriver.emit(event);
        }
    }
    
  4. Unregister the driver when pointer events are not longer required.

    public class TouchpadDriverService extends Service {
        ...
    
        @Override
        public void onDestroy() {
            super.onDestroy();
    
            UserDriverManager manager = UserDriverManager.getInstance();
            manager.unregisterInputDriver(mDriver);
        }
    }
    

If your input device emits multiple input events rapidly, consider re-using the same InputDriverEvent object to avoid multiple object allocations.

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);
    mDriver.emit(inputEvent);
}

See also

  1. Button Driver sample
  2. Handling Keyboard Actions
  3. Handling Controller Actions
  4. Using Touch Gestures

See Handling Controller Actions for more details on how Android handles input events from external source devices.