testing & QA

Testing Talkback in isolation with Espresso

Android engineer. Basketball lover. Software craftsman at Novoda

You can easily detect if TalkBack is enabled when binding views. You can then change their behaviour to make interaction with elements more natural. This blogpost explains how to test this functionality.

The biggest problem with testing custom behaviour with TalkBack is time. You turn it on, navigate to the app, ensure navigation between elements works as expected, check elements have the correct content descriptions and usage hints (with different data sets) and finally turn it off. It can be difficult to unit test this behaviour as it relies heavily on Android framework classes. You could also use Espresso to run tests on real devices, but the problem still remains with the setup and running of the tests.

We noticed this problem in some of our projects, so we wrote a simple library that is able to turn TalkBack on, run Espresso tests and turn it off after each test.

System under test

So let's imagine you have a TweetView with multiple actions represented by different buttons. The TweetView hides these buttons when TalkBack is enabled, but the user can choose any of the actions from a dialog, which appears after clicking on the view.


public void bind(final Tweet tweet, final TweetActions tweetActions) {
    setContentDescription(tweet.author + ", " + tweet.summary);
    if (accessibilityServices.isSpokenFeedbackEnabled()) {
         setOnClickListener(new OnClickListener() {
            public void onClick(View v) {

On top of that, you can add custom click and long click labels.



It’s important that you test that everything behaves as expected when TalkBack is disabled. It’s worth reading our previous blogpost on testing views in isolation with Espresso to help you setup the library and add your base tests.

When TalkBack is enabled, you can test:

  • the buttons are hidden
  • action dialog appears when clicking the view
  • each action triggers its corresponding callback
  • the content description and usage hints are set correctly

Addition setup for TalkBack

Toggling TalkBack state requires the WRITE_SECURE_SETTINGS permission, so you need to grant it to your app. First, you need to install the app, then you can run this command:

adb shell pm grant $PACKAGE_NAME android.permission.WRITE_SECURE_SETTINGS

Just remember to change $PACKAGE_NAME to your own.

Once the app is installed and the permission is granted you can easily toggle TalkBack in two ways:

  • via adb by running these actions:
$ adb shell am start -a "com.novoda.espresso.ENABLE_TALKBACK"
$ adb shell am start -a "com.novoda.espresso.DISABLE_TALKBACK"
  • programmatically by starting an Intent :
Intent intent = new Intent("com.novoda.espresso.DISABLE_TALKBACK"); // or ENABLE_TALKBACK 


So let's create a TweetViewTalkBackTest in androidTest with TalkBackViewTestRule.

@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public class TweetViewTalkBackTest {
    public ViewTestRule<TweetView> viewTestRule = 
        new TalkBackViewTestRule<>(R.layout.view_tweet_view);

This first test will check if buttons are actually hidden.

public void whenBoundTweetView_thenButtonsAreHidden() {
private void bindTweetView( {
    viewTestRule.bindViewUsing(new ViewTestRule.Binder<TweetView>() {
        public void bind(TweetView view) {
            view.bind(TEST_TWEET, tweetActions);

Then you can check if clicking on a View displays the ActionDialog and has all required actions.

public void whenClicking_thenDisplaysDialogWithAllActions() {
private void checkViewsWithTextDisplayed(int... ids) {
    for (int id : ids) {

After that, you can make sure that clicking particular actions triggers the correct callback.

public void whenClickingDetails_ThenOpensDetails() {

Finally, you can test if the content description and usage hints have been set up the way you want them:

public void whenBoundTweetView_thenHasCorrectContentDescription() {
                TWEET_AUTHOR + ", " + TWEET_SUMMARY)));
public void whenBoundTweetView_thenHasCustomUsageHint() {
        .check(matches(withUsageHintOnClick("See actions")));
public void whenBoundTweetView_thenHasLongClickCustomUsageHint() {
        .check(matches(withUsageHintOnLongClick("Open details")));

And that's it 🎉 . Our QA team loves this tool, so let us know how it works for you!

Enjoyed this article? There's more...

We send out a small, valuable newsletter with the best stories, app design & development resources every month.

No spam, no giving your data away, unsubscribe anytime.

About Novoda

We plan, design, and develop the world’s most desirable software products. Our team’s expertise helps brands like Sony, Motorola, Tesco, Channel4, BBC, and News Corp build fully customized Android devices or simply make their mobile experiences the best on the market. Since 2008, our full in-house teams work from London, Liverpool, Berlin, Barcelona, and NYC.

Let’s get in contact