Edition 34

Simulating Hardware Keys And Key Events On Android

When we use our phones we're not always just interacting with UI elements inside an app. Mobile devices, particularly Android devices, have an array of physical buttons and keys that often play a role in modulating device state or navigating through apps. It's important to test the use of these keys in your app, but sometimes it's just plain convenient to be able to use them.

Luckily, Appium gives you direct access to these special functions via the Android KeyEvent library, made available to Appium users with the pressKey methods. What are KeyEvents? They're Android system events triggered when users press various keys or buttons, and come in three parts:

  1. The keycode of the pressed key
  2. Any meta state information (meta states correspond to meta keys being pressed, such as ALT or CTRL)
  3. Any flags (flags are set by the system, such as whether the key event originated from the soft keyboard)

Appium enables us to actually generate KeyEvents, making the system (and thus any apps under test) believe that a user actually triggered the events. We can construct KeyEvents with each of the three components above (keycode, metastate, and flag). In most cases, we don't need to worry about the metastate or flag, but of course this will depend on what your app is listening for.

In the simplest case, we can simply call the pressKey method (which exists only on AndroidDriver of course, since KeyEvents are specific to Android:

driver.pressKey(keyEvent);

But how do we construct the keyEvent parameter? It must be of type KeyEvent, and at a minimum we have to provide a keycode, which is an integer (represented as the AndroidKey enum for the Java client). So let's say we wanted to simulate a click of the hardware "Back" button on some Android devices. We can simply write:

driver.pressKey(new KeyEvent(AndroidKey.BACK));

And the device will behave as though we've triggered the "Back" button! Though it wouldn't make sense in this case, we could also have added a metastate to the KeyEvent:

new KeyEvent(AndroidKey.BACK)
    .withMetaModifier(KeyEventMetaModifier.SHIFT_ON);

What if we want to power off the device? We'll need more than pressKey since it's required to hold the power button for a long time. We could instead try the appropriately-named longPressKey method:

driver.longPressKey(new KeyEvent(AndroidKey.POWER));

And that's all there is to it! The real magic lies in seeing everything you have access to using the KeyEvent interface. To see the full list of possible keycodes, simply visit the Android KeyEvent docs and scroll down through the huge list of constants. You've got everything from alphanumeric keys to media controls. I'm sure some of you will find some interesting uses for this API that the rest of us never considered! Be sure to let me know if you do.