A bit of backstory (a foreword by Diane Ko)
At Airbnb, our vision is a world where anyone can belong anywhere. This includes not just our physical spaces, but our digital ones as well. We recognized that our product needed to provide a better experience for people with disabilities. Over the last few years, we started major efforts to improve the accessibility of our digital platforms across the company. We also know that accessibility is not a one-time effort; without consciously considering the needs of our entire community, efforts to provide a better experience for all users can go away with one new release. Our goal was to create a foundation of awareness, know-how, and accountability. We not only wanted people at Airbnb to know how to improve what already existed but also how to prevent creating barriers to inclusion in the first place.
When the Airbnb digital accessibility team first started, we knew that no matter how many people we had on our team, the accessibility team alone wouldn’t be able to individually review every design or code change. Additionally, the engineers on the accessibility team were web engineers, and not familiar enough with modern mobile app development to provide specific guidance in that area. We needed a way to scale, and a way to drum up support on different teams across different platforms and disciplines.
Following the lead from practices established by an existing cross-platform team, we started a partners group dedicated to accessibility. We gathered engineers and designers from across the company to regularly join us and talk about organizational issues they were facing related to accessibility and common patterns in designs and components they noticed. The partners allowed us to have a pulse on what was going on across the company as well as share what they learned from us to others on their teams.
We immediately noticed an incredible level of enthusiasm from different members of the partners’ group to help solve some of the larger issues facing the product, including people volunteering to lead accessibility efforts for our mobile apps. One such partner was Julia Fu. Following in the example of Michael Bachand, who volunteered to lead iOS accessibility, Julia set a plan for making the Android app more accessible and rallied the other Android engineers to follow her lead. This article will talk through some of the challenges and learnings from her experience.
The Airbnb Android App
The Airbnb Android app is one of the most popular apps for traveling. Millions of users use our app every day, including many with accessibility needs. The app supports many features. Travelers can explore the app to find a place to stay, an experience to try, or a restaurant to enjoy. They can book a listing, manage their trips and communicate with hosts on the go. In addition to supporting guests who are traveling, the app also provides hosts the convenience of managing their listings and connecting with guests on their mobile phones.
At Airbnb, every product team with a mobile presence owns a few features in the Android app. In general, every product team has Android, iOS, web, and backend engineers to develop features along with designers, product managers, and other cross-functional groups. This team structure has enabled teams to ship features fast and in parallel on all platforms. Additionally, some screens on the app include features from multiple teams.
Making such a complex app more accessible is a huge endeavor that involves all the Android engineers from every team in the company.
The advantages and challenges of the Android platform
Working on Android accessibility is very different from iOS and the web, and it has its own unique challenges and advantages.
Challenges
For Android, the biggest challenge is the fragmentation of Android phones and spotty support of some features across different versions.
One example of this is the ClickableSpan
.
In our app, we use Android’s ClickableSpan
for inline links. When the user activates the link, the app opens another screen.
Android provides patchy support for this view. For Android version Oreo and above, using Linkify.addLinks
can make TalkBack recognize this as a link and the user can activate it. However, this solution does not work for pre-Oreo devices. We solved this accessibility problem by creating a virtual view for ClickableSpan
and that view requests its own accessibility focus.
In situations like ClickableSpan
, we need to test different Android versions thoroughly and might have to create different solutions for versions where built-in accessibility is not supported.
Advantages
On the other hand, Android offers significant advantages in software development for accessibility. Being able to access the Android source code and TalkBack source code have helped enormously with accumulating knowledge and debugging code. For instance, we found it very handy to check out TalkBack code from GitHub, install it on a phone, and then debug accessibility issues by using the debugger or by printing out logs. The level of clarity and detail from being able to step through both the operating system code and the assistive technology code is impossible to get on the web or on iOS.
Additionally, Google proved to be a valuable source in making our app more accessible. During Google I/O this year, Google hosted office hours to help app developers with accessibility. A few Airbnb engineers attended the office hours and had the app briefly reviewed by Google accessibility engineers for feedback and got many accessibility questions answered. We also participated in Google Play’s Accessibility Pilot, in which Google Play reviewed key flows in the app and gave us feedback and guidance on fixes. This level of access to Google was enormously helpful to us.
Sharing responsibilities and ownership
At Airbnb, Android has fewer engineers than iOS or Web. However, having fewer engineers also elevates everyone’s involvement in Airbnb’s Android community. Our community culture encourages engineers to openly learn from the problems and successes of peers and promotes better communication across teams.
As a close community, many engineers will take on larger tasks to improve the Android app overall. An example of this for accessibility was the datepicker, one of the most important features in the app. Users use it to pick check-in and check-out dates when searching for or booking a listing.
This datepicker was a custom view built from scratch and is unique to Airbnb. Unfortunately, this feature had no clear engineering owner. However, because of our close Android community, one Android engineer took this challenge and volunteered to own the project. He spent a few weeks making the date picker more accessible, which greatly unblocked users from booking a listing.
Because of this amazing culture and community, we are able to turn an ownership problem into an opportunity. This close-knit community is the backbone of our Android accessibility efforts. Everyone plays an integral part not only by contributing to the features they own but also by volunteering to take on multiple initiatives, such as making shared views more accessible.
Spreading awareness and know-how through documentation and training
Engineers need to have the necessary knowledge, skills, and tools to be empowered to do their best work. Documentation and training are critical to enabling engineers to learn and participate in making the Android app more accessible.
Documentation
When we started a strong push for Android accessibility around a year ago, there was limited internal Android documentation about accessibility. Additionally, Android’s official accessibility documentation lacked detailed guidance to account for the various scenarios we encountered. To fill the gaps, we started by searching material on the internet, including blog posts, online tutorials, wikis, and more. We also sought out extra guidance from mobile experts at Deque for some of the more complex issues. Then, we synthesized the information, categorized it, and developed the initial version of our internal Android documentation.
As time went on, our engineers continued to acquire new knowledge from their work and from external resources. Our documentation expanded with each new problem solved and with new information acquired. It has evolved to be a rich knowledge repository, covering fundamental knowledge, best practices, debugging and testing tools.
Training
Within a year, the in-house training has also been created and enhanced. The classes dedicated to Android accessibility training unfold in four stages to level up all Android engineers’ knowledge and skills about accessibility.
When an Android engineer joins Airbnb, they take an accessibility class as part of the engineering bootcamp, our internal engineering onboarding process. This is the first stage in accessibility training. This beginner class covers a brief introduction to accessibility, an example of an accessible view, an overview of debugging tools, and a simple code lab. It ensures engineers know and are aware of accessibility from day one.
The next level of training is the Fundamentals Workshop. This is a one hour workshop that aims to make sure engineers know how to fix common accessibility bugs on Android. In this workshop, engineers get hands-on with accessibility features on phones, learn what is good accessibility for common views, get an in-depth overview of the debugging tools, and learn general accessibility guidelines in development.
After engineers attend the Fundamentals Workshop, the Advanced Workshop is offered to provide a “behind the scenes” deep dive on how views are made more accessible for screen readers such as TalkBack. It explains how Android, the Airbnb app, and screen readers interact with each other. It also includes a case study about ViewPager
and demonstrates code snippets from Android and TalkBack source code. Engineers then apply their knowledge with a code lab. This class deepens engineers’ understanding of accessibility, which can help them tackle more challenging accessibility bugs.
The last workshop is the Custom Views Workshop. It guides engineers to make custom views more accessible, which covers some of the most complicated code engineers need to write in order to make features more accessible.
Beyond the structured classes, tech talks are given whenever there’s some information or knowledge worth sharing to the whole Android community at Airbnb. Typical topics include new Accessibility APIs and better tools for debugging.
Having these trainings was the tipping point for Android accessibility to spread the momentum to the whole Android community at Airbnb. The Fundamentals Workshop is the essential training needed for engineers to get 90% of the accessibility violations fixed in the app. Once engineers had both the training and the documentation to build their screens in a more accessible way, we were able to make major strides in improving the app’s accessibility.
Scaling accessibility fixes with shared components
At Airbnb, we build every page with a collection of UI components. Airbnb created our Design Language System to achieve a consistent look and feel across the app. Each screen is built using reusable components.
On Android, our screens are comprised of several different components. Many of these UI components are re-used heavily across the app. This has provided us with an enormously convenient way to make the UI in the app more accessible. If we make all the components more accessible, we could accomplish 70% of the work to make the app more accessible. When we improve the accessibility for one component, it is improved in all the pages that have this component as part of the view.
In the first half of this year, we scrutinized all the UI components and improved many for accessibility. Having the UI component system saves time and frustration for designers and engineers.
Building systems to enforce accessibility requirements
In order to efficiently make the whole app more accessible, we built a few engineering systems to automate reinforcement of accessibility requirements. They are designed to systematize the accessibility requirements and minimize the level of effort for each Android engineer. One of the areas we did this was with page titles.
Technical challenges
Based on WCAG success criterion 2.4.2, each screen should have a descriptive title to provide users with information of the page content. This requirement is straightforward, but we faced a few technical challenges:
- Android lacks support for setting page titles on screens built using
Fragment
. In Android, there are two main classes to build screens:Activity
andFragment
. A screen can be built using either anActivity
directly or using aFragment
inside anActivity
. Android provides support for Activity but very limited support for Fragment. For screens built using Activity, TalkBack announces the title of the screen automatically because Activity sends an accessibility event with title information in it. For screens built withFragment
, Android only provides support in Android Pie with the newest API,setAccessibilityPaneTitle()
. Since this version of Android was only released earlier this year, very few Android users are on this version. For Airbnb’s Android app, 95% of our screens are built usingFragment
, which is the recommended practice of Android. We added support for page titles on these screens by invokingannounceForAccessibility()
to force the announcement of the page title. - Different architectures in the app post significant challenge in designing a simple page title system to accommodate all architectures. This year, our Android app moved to a new architecture called MvRx. With this architecture, even though both new and legacy screens are using
Fragment
, the code structure changed significantly enough that we can’t apply the same solution to both. The new architecture is still being adopted, so we needed to accommodate both MvRx and legacy screens.
Solution for pre-Android Pie devices
We designed the following system for providing page title for all screens:
- Create a
class
that holds all the cases of page title. The page title can be provided with a localizedString
literal, aString
resource, or aString
resource witharguments
.class PageTitle { private var text: CharSequence? = null private var stringRes: Int? = null private var args: Array? = null constructor(text: CharSequence) { this.text = text } constructor(stringRes: Int, vararg args: Any) { this.stringRes = stringRes this.args = args } fun getText(context: Context): CharSequence? = text ?: stringRes?.let { context.getString(it, args) } }
- Create a method that uses the page title. For
Activity
, assign the page title to be thetitle
ofActivity
. Android sends an accessibility event to TalkBack with the title as part of the information and triggers an announcement from Talkback about the page title. ForFragment
, ask the root view to make an announcement for the page title.fun Activity.announceForPageChange(pageName: PageTitle) { val text = pageName.getText(this) if (text != null) { if (isActivityScreen()) { title = text } else { view.announceForAccessibility(text) } } }
- Create an
interface
that requires all screens to implement it in order to provide page title.interface PageTitleHelper { val pageTitle: PageTitle }
- For
Activity
, implement thePageTitleHelper
interface to provide a page title.class ExampleActivity : PageTitleHelper { override val pageTitle: PageTitle get() = PageTitle(R.string.example_page_title) }
- For
Fragment
, due to having both LegacyFragment
and MvRxFragment
, create a parentFragment
that handles common logic, including page title. This triggers the announcement whenonResume()
is called.abstract class ParentFragment: Fragment(), PageTitleHelper { override fun onResume() { super.onResume() activity.announceForPageChange(pageTitle) } }
- For a Legacy
Fragment
, implementpageTitle
to provide the page title.class ExampleFragment: ParentFragment() { override val pageTitle: PageTitle get() = PageTitle(R.string.example_page_title) }
- For MvRx
Fragment
, implementpageTitle
. Unlike with the LegacyFragment
, the page title is part of theScreenConfig
object due to the specific architecture of MvRx.class> ExampleMvrxFragment : ParentFragment() { override val pageTitle: PageTitle get() = screenConfig.pageTitle override val screenConfig: ScreenConfig get() = ScreenConfig(pageTitle = PageTitle(R.string.example_page_title)) }
With this system, engineers only need to provide a descriptive string for the page title and the underlying code takes care of all the screen types. This descriptive string is mandatory for every screen in order to enforce the accessibility requirement.
Using existing patterns to create custom solutions
Airbnb is known for its unique style and design. But, custom designs require custom implementations. For engineering, this means we have to think harder and be more creative about seeking technical solutions to make them more accessible.
One of the custom components we have is the price slider.
The price slider is a custom view in which users can adjust the price range when searching for listings to book on Airbnb. Users can adjust the first thumb to change the minimum price and the second thumb to change the maximum price. This component was built from scratch by using custom drawing and input gesture handling.
Making this price slider more accessible was an intense exercise in problem-solving. One possible solution was to replace this component with two simple EditText
views in which user could enter maximum and minimum values. However, we wanted to be careful with a visual design change that could negatively impact users if not done well. Until we could come up with a nice design that supported this functionality, we needed a way to make the existing experience more accessible.
After intensive research, we decided to utilize the ExploreByTouchHelper
to represent this view as a collection of view-like logical items, or “virtual views.” Studying the existing Android native UI components’ accessibility revealed that the most similar existing Android native component is the SeekBar
, where a user can slide a thumb up or down in 5% increments. We borrowed the logic and created two virtual views representing the two thumbs for UI interaction. Every move of the “virtual” thumb changes 5% of the current price range. When price range is updated, an announcement is made to the user to notify them of the newest price range.
Gathering feedback with real user testing
It is hard to know whether the app provides a good experience without seeing a real user using it. In order to validate our efforts and find guidance for our future endeavors, we invited blind users to participate in paid user studies, focusing on our key flows. Real user testing provided us with many specific and valuable insights we did not have. Two of the things that we heard during user testing are features coming in Android Pie: headings and grouped navigation.
Headings
Headings not only allow the user to know which element is the heading of a section but also allow the user to jump to different parts of the screen when navigating by headings. Navigating in this manner is especially vital when the page is long with a lot of information. Heading navigation with TalkBack has been available on the web on Android for a couple of years, but TalkBack hadn’t added support for heading navigation in apps until this year. There also hadn’t been a way to programmatically set headings in Android apps. With Android Pie, we’ll be able to use the accessibilityHeading
attribute to specify which elements represent headings in the app.
Grouped navigation
During user testing, one blind user mentioned that sometimes she had to swipe so much that her finger and even her right arm would be swollen. It’s crucial that when we build screens, we should try to group elements as much as possible to reduce the number of swipes needed for screen reader users. Although grouping elements is possible in older Android versions, Android Pie introduces screenReaderFocusable
to group elements specifically for screen reader users so that it doesn’t interfere with keyboard user navigation.
Now it’s your turn
Over the course of a year, we’ve made real progress on improving Android accessibility. It’s been an incredible journey so far and we recognize there’s more we can do; we continue to learn and work to improve how our app works for our users.
None of this will happen overnight. It takes months of rigorous execution, meticulous attention to accessibility requirements, and the structure and discipline of enforcement systems. It might not be perfect the first time, or even the second time. The key is to adapt over time, learn from mistakes, and keep working to make it better. Trying to improve your Android app’s accessibility when you have a long road ahead of you can seem overwhelming and sometimes impossible at first, but we want to encourage you to make the effort to take that first step.
Krishna says:
Great write-up. It will be helpful if you can author a follow-up blog focusing on debugging accessibility issues with Talkback