Chapters

Hide chapters

Android Accessibility by Tutorials

Second Edition · Android 12 · Kotlin 1.6 · Android Studio Chipmunk

Before You Begin

Section 0: 4 chapters
Show chapters Hide chapters

Section I: Android Accessibility by Tutorials

Section 1: 13 chapters
Show chapters Hide chapters

Section II: Appendix

Section 2: 1 chapter
Show chapters Hide chapters

5. Perceivable — Time-Based Media & Cues
Written by Victoria Gonda

Heads up... You’re accessing parts of this content for free, with some sections shown as zzqynfjaw text.

Heads up... You’re accessing parts of this content for free, with some sections shown as zdvijcnyw text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

Video, audio, animation and instructions are vital parts of your app’s experience. But for those who live with certain conditions, these media types may not be useful, or even perceivable. In order to build an accessible app, you’ll need to make adjustments to your app’s design to make these kinds of media accessible to all.

In this chapter, you’ll delve deeper into the concept of perceivability, specifically how to make time-based media useful to different people. You’ll also learn best practices for giving your users cues they can use to navigate your app with the help of assistive technologies.

Displaying Time-Based Media

As you might expect, time-based media is anything that, well, takes place over time. The obvious examples are video and audio; they start at a particular time, and then they end later. Animations also fall into this category. There is only one way to consume these media types.

That thought brings you to the prevailing WCAG guideline for this chapter:

Guideline 1.2 Time-based Media Provide alternatives for time-based media.

There are many ways you can provide these types of media. For prerecorded audio, you can have on-screen captions. If you have a video, you can include an audio track or text alternative that contains the same information. When you’re animating an instruction, you can also provide an audio or text description.

In some cases, you can make time-based media completely optional, allowing the user to skip it. Be careful with optional settings though — you don’t want to prevent people from accessing content that might be valuable.

Think about the guideline’s success criteria, which specify a heuristic that these elements need equivalent alternatives, for example, text, captions, or other form factors.

Consider this criterion:

Success Criterion 1.2.3 Audio Description or Media Alternative (Prerecorded): An alternative for time-based media or audio description of the prerecorded video content is provided for synchronized media, except when the media is a media alternative for text and is clearly labeled as such.

Level A

Taco Tuesday has some significant issues where time-based media is not accessible, especially in the onboarding flow. Once again, you’ll improve the app so that you can learn.

Open up the project you used in previous chapters or use the starter project from this chapter’s materials.

Improving the Onboarding Flow

Think about the many ways you could design the onboarding process for Taco Tuesday:

Heads up... You’re accessing parts of this content for free, with some sections shown as gsciqqmug text.

Heads up... You’re accessing parts of this content for free, with some sections shown as krpetzwar text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

Exploring the Onboarding

If you don’t see the onboarding flow, go to Settings and select Show on-boarding. Then close and reopen the app. You can do this anytime you want to see onboarding again.

Show on-boarding in settings.
Tcis eg-ciatfasy ek mokserwb.

//  val sharedPref = PreferenceManager.getDefaultSharedPreferences(this)
//  val showOnboarding = sharedPref.getBoolean("onboarding", true)
//  if (showOnboarding) {
   OnboardingActivity.startActivity(this)
//   finish()
//  }
Screenshots of onboarding views.
Zvpuasrbudc ak ojriipbetf ruawv.

Removing Auto-Advance

To make Taco Tuesday’s onboarding flow more friendly, you’ll remove the auto-advance feature and add controls.

Heads up... You’re accessing parts of this content for free, with some sections shown as bgrispgax text.

Heads up... You’re accessing parts of this content for free, with some sections shown as fxlicfpiq text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now
lifecycleScope.launch(Dispatchers.IO) {
 val options = resources.getStringArray(R.array.pop_up_options)
 while (isActive) {
  delay(5000) // 5 seconds

  withContext(Dispatchers.Main) {
   if (binding.onboardingPager.currentItem == NUM_PAGES - 1) {
    MainActivity.startActivity(this@OnboardingActivity)
    this.cancel()
   } else {
    binding.onboardingPager.currentItem++
   }
  }
 }
}

Adding Controls

In this section, you’ll implement logic that gives your user a straightforward way to advance to the next page. First, you’ll add the layout for a Next button.

<com.google.android.material.button.MaterialButton
  android:id="@+id/onboarding_next_button"
  style="@style/Widget.MaterialComponents.Button.TextButton"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:padding="@dimen/space_normal"
  android:text="@string/onboarding_next"
  android:textColor="?colorOnPrimary"
  app:layout_constraintBottom_toBottomOf="parent"
  app:layout_constraintEnd_toEndOf="parent" />
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintBottom_toTopOf="@id/onboarding_next_button"

Heads up... You’re accessing parts of this content for free, with some sections shown as jvxebwbel text.

Heads up... You’re accessing parts of this content for free, with some sections shown as rzdojvwut text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now
Next button.
Peyd nesbiv.

binding.onboardingNextButton.setOnClickListener {
 if (binding.onboardingPager.currentItem == NUM_PAGES - 1) {
  MainActivity.startActivity(this)
 } else {
  binding.onboardingPager.currentItem =
    binding.onboardingPager.currentItem + 1
 }
}
<com.google.android.material.button.MaterialButton
  android:id="@+id/onboarding_back_button"
  style="@style/Widget.MaterialComponents.Button.TextButton"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:padding="@dimen/space_normal"
  android:text="@string/onboarding_back"
  android:textColor="?colorOnPrimary"
  app:layout_constraintBottom_toBottomOf="parent"
  app:layout_constraintStart_toStartOf="parent" />
binding.onboardingBackButton.setOnClickListener {
 binding.onboardingPager.currentItem =
   binding.onboardingPager.currentItem - 1
}

Heads up... You’re accessing parts of this content for free, with some sections shown as ffpekvfiq text.

Heads up... You’re accessing parts of this content for free, with some sections shown as cxzogmmik text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now
binding.onboardingPager.registerOnPageChangeCallback(
    object : ViewPager2.OnPageChangeCallback() {
      override fun onPageSelected(position: Int) {
        binding.onboardingNextButton.text =
            if (position == NUM_PAGES - 1) {
              getString(R.string.onboarding_done)
            } else {
              getString(R.string.onboarding_next)
            }
        binding.onboardingBackButton.visibility =
            if (position == 0) {
              View.GONE
            } else {
              View.VISIBLE
            }
      }
    }
)
Screenshots of all button states.
Bxpaedcvewk ot oxv finbar bfoqaj.

Giving Cues

Another important part of onboarding is what you’re saying. How do you make sure your instructions are meaningful? For example, if you’re describing a button’s color, what does that mean for a person who doesn’t perceive color? This brings you to the second criterion you’ll explore in this chapter:

Heads up... You’re accessing parts of this content for free, with some sections shown as njlejxtyg text.

Heads up... You’re accessing parts of this content for free, with some sections shown as vvdigjkyg text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now
Grayscale buttons.
Cqimncoxa suygikh.

Improving Cues in Onboarding

There are several things you’ll do to improve the onboarding flow’s cues. You’ll start by making the button descriptions more clear and more friendly to those who rely on screen readers.

Clarifying the Instructions

The instructions are defined in strings.xml, and each entry is prepended with onboarding_ for ease when searching.

Heads up... You’re accessing parts of this content for free, with some sections shown as qbhiqkvuv text.

Heads up... You’re accessing parts of this content for free, with some sections shown as nrbawfgas text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now
Icon buttons on the detail screen.
Olos toqhilt ak bjo zediuz skqaah.

Heads up... You’re accessing parts of this content for free, with some sections shown as tdraxntis text.

Heads up... You’re accessing parts of this content for free, with some sections shown as gvhodjfyc text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

Adding Text to the Button

No button should be without some kind of description, so you’ll add some text to this button to make its purpose clear.

com.google.android.material.button.MaterialButton
android:src="@drawable/ic_baseline_thumb_up_24"
android:text="@string/shared_try_it"
app:icon="@drawable/ic_baseline_thumb_up_24"
Try it button.
Jnp ib vopfid.

Modifying the Button State

This button changes state depending on if the recipe is currently saved or not. This means you need logic to update the text and icon, depending on the button’s state.

recipeDetailTryDiscardButton.setImageDrawable(
 ResourcesCompat.getDrawable(resources,
  R.drawable.ic_baseline_thumb_down_24,
  requireContext().theme))
recipeDetailTryDiscardButton.text =
  getString(R.string.shared_discard)
recipeDetailTryDiscardButton.icon =
  ResourcesCompat.getDrawable(resources,
    R.drawable.ic_baseline_thumb_down_24,
    requireContext().theme)

Heads up... You’re accessing parts of this content for free, with some sections shown as gzbihpqix text.

Heads up... You’re accessing parts of this content for free, with some sections shown as tvqilczot text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now
recipeDetailTryDiscardButton.setImageDrawable(
 ResourcesCompat.getDrawable(resources,
  R.drawable.ic_baseline_thumb_up_24,
  requireContext().theme))
recipeDetailTryDiscardButton.text =
  getString(R.string.shared_try_it)
recipeDetailTryDiscardButton.icon =
  ResourcesCompat.getDrawable(resources,
   R.drawable.ic_baseline_thumb_up_24,
   requireContext().theme)
Updated buttons on the detail screen.
Iscedut fovyofl ud fve podeux hdxuaf.

Adding State-Specific Instructions

Now you can add instructions for this button to your onboarding. You’ll need to add a new page just for these instructions.

<string name="onboarding_details">Manage your recipes using the \"Try it\" and \"Discard\" buttons on the detail view.</string>
<string name="onboarding_details_description">Thumbs-up icon</string>

Heads up... You’re accessing parts of this content for free, with some sections shown as smkihwgav text.

Heads up... You’re accessing parts of this content for free, with some sections shown as zkbapvcic text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now
OnboardingItem(
  R.drawable.onboarding_details,
  R.string.onboarding_details,
  R.string.onboarding_details_description
),
private val NUM_PAGES: Int
 get() = pages.size
Screenshot of new onboarding page.
Cntuemmcib oq kil avzoecbabj qata.

Key Points

  • Time-based media such as video, audio and animations, must be accompanied by alternatives.
  • Alternatives to visual media can be text or audio, and alternatives to audio can be equivalent visuals.
  • Users must be able to control media that’s important for them to understand. You need to provide a way for them to go back and revisit something
  • Sensory characteristics such as shape, color, size, visual location, orientation or sound should not be the only ways you give instructions.

Where to Go From Here?

Time-based media is a broad topic, in part, because there are many ways to use time-based media in an app.

Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.
© 2025 Kodeco Inc.

You’re accessing parts of this content for free, with some sections shown as vshahwrym text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now