How to Automate Testing of Android TV Apps Using Appium

  October 17, 2019

Android TV is a version of Google’s Android mobile operating system designed for turning TVs into smart, connected and digital streaming media players. It has a lot in common with other smart TV solutions but also possesses great features inherited from Android mobile OS. Since it can access the Google Play app store, Android developers can optimize and distribute their Android apps to the Android TV platform. That being said, testing Android TV apps is not as straightforward as testing Android mobile apps.

Differences from Automating Android Mobile Apps

When testing Android mobile apps, the typical functional tests include finding, clicking and swiping elements. And the same idea is also applicable to testing Android TV apps. But there are a few fundamental platform specifics that make Android TV app test automation more challenging.

  1. No touchscreen
  2. Using remote control
  3. No portrait orientation
  4. Navigating through TV apps isn’t as easy as through mobile apps

What Frameworks to Use for Automating Android TV App Tests

Overall the Android TV app development is quite similar to the Android mobile app development in many ways. This also applies to Android TV app testing. If you want to deliver high-quality Android TV apps, you’d also need to do comprehensive testing and follow the same QA processes as you would do for Android app testing.

As for automating Android TV app testing, you don’t need to look for a new tool, but simply use any of those widely used native frameworks for Android mobile testing on the market.

In this blog, we will talk about how to use Appium to nail down test automation for Android TV apps.

How to Use Appium for Automating Android TV App Tests

Like mentioned before, Android TV app automation differs from Android mobile app automation primarily by Android TVs not having a touchscreen. Therefore most of the time you can’t tap or click elements like on Android mobile devices.

You need to emulate remote controller usage by issuing ADB commands for example “adb shell input keyevent KEYCODE_ENTER”. And you need to know what element is currently selected/ focused.

  • Use ADB commands to simulate remote controller commands
  • Some elements can be clicked/ tapped using Appium Webdriver
  • Some elements can only be accessed by selecting it with controller (selected/focused)

Below is an example of selecting the “Most Popular” section of the menu list on Nvidia SHIELD, Nvidia Games app.

Selecting an Item from the Menu List

Functions needed to select a menu item from the list (vertical, on the left) include:

  • Get the root element for the list
  • Go through all the items in the list
  • Look for the name of the list item (e.g. “Most Popular”)
    • If found, check that it is selected or focused otherwise go down using ADB command to the next item
automate 'most popular' on android tv apps

“Most Popular” is selected/ focused

Sample code
protected void selectMenuItem(String itemName) throws Exception {

  boolean notAtMenuItem = true;
  int startTime;
  int timer;
  MobileElement menuItemRoot;
  List<MobileElement> menuItems;
  MobileElement menuItem;
  String itemText;

  startTime = (int)(System.currentTimeMillis() / 1000);
  while (notAtMenuItem)
  {
    timer = (((int)(System.currentTimeMillis() / 1000))-startTime);
    if(timer>70)
    {
      throw new Exception("selecting menu item takes too long, fail");
    }
    menuItemRoot = wd.findElement(By.id(resMenuItemsElement));
    menuItems = menuItemRoot.findElements(By.id(resMenuItemElement));

    for (int i = 0; i < menuItems.size(); i++)
    {
      menuItem = menuItems.get(i);
      itemText = menuItem.getText().toLowerCase();
      if (itemText.contains(itemName.toLowerCase()))
      {
        if (menuItem.getAttribute("selected").toLowerCase().equals("true"))
        {
          log("menu item found");
          atvPressEnter();
          notAtMenuItem = false;
          break;
        }
      }
    }
    if (notAtMenuItem)
    {
      atvGoDown();
    }
    sleep(1);
  }
}
Selecting a Game from the Games List

Below is an example of selecting the game “Tomb Raider” from the games list “Most Popular”.

Functions to select a game from the list (horizontal) include:

  • Look for the correct game list (multiple lists are visible to Appium), use xpath to find the name of the list item (“Most Popular”) and go up the hierarchy to get root element of that list item (element containing the text “Most Popular” is not a parent of elements containing game name text)
  • Go through all the items in the list
  • Look for the name of the list item (e.g. “Tomb Raider”)
    • If found, check that it is selected or focused otherwise go right using ADB command to next item
android tv automation - select Tomb Raider

“Tomb Raider” is selected/ focused

Sample Code
protected boolean selectContentItem(String menuItemName, String itemName) throws Exception {

  boolean notAtContentItem = true;
  boolean gameFound = false;
  int startTime;
  int timer;
  MobileElement contentItemRoot;
  List<MobileElement> contentItems;
  MobileElement contentItem;
  String itemText;
  String rootElementXpath =
      "//android.widget.TextView[@resource-id='com.nvidia.tegrazone3:id/row_header' and contains(translate(@text, '";

  startTime = (int)(System.currentTimeMillis() / 1000);
  while (notAtContentItem)
  {
    timer = (((int)(System.currentTimeMillis() / 1000))-startTime);
    if(timer>90)
    {
      //throw new Exception("selecting content item takes too long, fail");
      break;
    }
    contentItemRoot = wd.findElement(By.xpath(rootElementXpath
        +menuItemName.toUpperCase()+"', '"+menuItemName.toLowerCase()+"'),'"+menuItemName.toLowerCase()+"')]/../../.."));
    contentItems = contentItemRoot.findElements(By.id(resMenuItemContentElement));

    // select content item (game)
    for (int j = 0; j < contentItems.size(); j++)
    {
      contentItem = contentItems.get(j);
      itemText = contentItem.getText().toLowerCase();
      if (itemText.contains(itemName.toLowerCase()))
      {
        if (contentItem.getAttribute("selected").toLowerCase().equals("true"))
        {
          log("content item found");
          atvPressEnter();
          notAtContentItem = false;
          gameFound = true;
          break;
        }
      }
    }
    if (notAtContentItem)
    {
      atvGoRight();
    }
    sleep(1);
    }
    return gameFound;
}
Emulating a Remote Controller

The remote controller emulation is done using ADB-commands.

protected void atvADBCommand(String command) throws Exception
{
  Runtime.getRuntime().exec("adb -s "+ udid + " shell input keyevent "+command);
}
protected void atvPressEnter() throws Exception
{
  atvADBCommand("KEYCODE_ENTER");
}

Another possible problem

One of the problems of automating Android TV apps is that if you try to find an element using its text value, the element containing that text might not get focused or selected.

Element with the text “I agree and continue”, for example, does not get focused or selected even though it is selected from the visual standpoint. In this case, you need to look for its parent element and get its selected/focused value.

android tv apps automation - end user agreement

”I agree and continue” is selected with a remote controller

end user agree hierarchy

Hierarchy of that element

end user I agree element

Element is not focused / selected

end user agree root

Its parent element is focused now