Edition 120

Setting Accelerometer Data for the Android Emulator

Animated GIF of Android accelerometer

Part of what makes our mobile devices so powerful is the array of sensors they contain. One of those sensors is called an accelerometer. It basically measures the acceleration of the device in three dimensions (referred to as x, y, and z to denote left/right, back/forth, and up/down). This feature can be used for any number of applications, from counting steps to controlling video games. Take a look at the screen recording at the top of this post. An Android emulator is displayed here, and I'm opening an app which is designed to detect vibrations in any dimension, using the device's accelerometer. To actually make things happen with the virtual accelerometer, I'm opening up the advanced emulator controls, and then fiddling around with acceleration values in each of the 3 possible dimensions. You can see, when I do this, that the vibration app is "detecting" these changes, and drawing them as a sort of timeline or graph.

How would you test this kinds of app using Appium? Well, you could build a robot to jiggle a device physically and trigger it as part of your Appium script. That would be the "highest-fidelity" sort of automated testing we could imagine. One step more synthetic, and one step easier, would be to somehow inject accelerometer data into the device, to make it believe the device is being moved around. And this is something we can do with Appium. Unfortunately, this feature currently works only on Android, and it currently works only on virtual devices (emulators). While Google allows you to set a mock location provider to spoof geolocation, the same does not appear to be possible for the accelerometer. But as long as your app can run on an emulator, you should be good to go with the strategy outlined here.

Emulator Commands

The way that Appium provides access to setting accelerometer data is via something called the Emulator Console. This is a special server hosted by the emulator that you can attach to using the telnet command. Once connected, you have access to a whole suite of advanced emulator controls, that can be run from the command line. It's basically all the same things you could do from the emulator UI, but totally scriptable. As of Appium 1.18.0, there is a mobile command available that wraps up all this business with telnet into one easy interface:

driver.executeScript("mobile: execEmuConsoleCommand", ImmutableMap.of("command", command));

In this example, the variable command would be the string that would be sent as an emulator console command. Here are some examples of what you could put in command:

  • ping - check whether the device is responding
  • rotate - rotate the device
  • geo fix <long> <lat> <sat> - set the fake geolocation of the device

But the type of command we care about for this post would be something like this:

sensor set acceleration <x>:<y>:<z>

(Where x, y, and z are positive or negative accelerations in meters per second squared.)

One other thing to remember is that to use this mobile: execEmuConsoleCommand feature, you need to make sure to start the Appium server with a special security flag, otherwise the feature won't work. This is to prevent random Appium users from messing with emulators on a system that might host multiple sessions from multiple users. To disable this security for this feature, run Appium as follows:

appium --allow-insecure=emulator_console

An example

All that's left is to put this knowledge to good use! I'm going to write a simple test with the Vibration Analysis app. I'm referencing a local version of it in my capabilities, so you'll want to download an APK and adjust the source code to reference your local copy if you're following along. But capabilities aside, what I want to do is trigger a series of accelerations in all dimensions for a device, such that it eases in and out of those accelerations. The simplest way I thought of to do this was to use the Math.sin function to define a few points along a curve. We take those points as the acceleration values, with the end result that the device accelerates in the positive direction and then in the negative direction, as if we were moving the device in a smoothly angled arc.

The logic is as follows:

  1. Define the number of steps we want in the arc.
  2. For each step, get a position on a sine curve for that step, and multiply it by a number so that we get values between -MAX and MAX
  3. Construct an emulator console command using the calculated value for this step
  4. Run the Appium command with the emulator console command as an argument
  5. Sleep for some number of milliseconds to "cool down" in between each acceleration change

That's it! Let's check it out in code:

public void testAccelerometer() throws Exception {
    int numIterations = 10;
    int multiplier = 5;
    for (int i = 0; i <= numIterations; i++) {
        Double val = Math.sin((Math.PI / numIterations) * i) * multiplier;
        String command = "sensor set acceleration " + val + ":" + val + ":" + val;
        driver.executeScript("mobile: execEmuConsoleCommand", ImmutableMap.of("command", command));

When I run this, I notice the Vibration Analysis timeline showing exactly the intended kind of accelerations taking place, drawing a sort of sine curve! This is a sort of fake example in that I can't think of something right now for which I'd want to move the device in an angled curve like this, but it shows how it's possible to encode arbitrary sets of accelerations as Appium commands. It might be quite difficult, but there would certainly be a way to encode even the acceleration changes used to control games! Your only limitation is how fast Appium can send the acceleration commands to the device. Let me know if you try this with any more real-world or more complicated scenarios! And of course, you can always check out this edition's code sample in the context of a working project here.