MyFamilyTracker
Real-time family location sharing — Firebase Realtime DB for sub-second propagation, WorkManager + ForegroundService for OS-compliant background collection, geofencing via Google Maps API.
Accessibility testing is often treated as optional. It's not — it's good engineering that serves millions of users with disabilities. Here's how to test and fix the most common accessibility issues in Android apps.
On this page
Over 1 billion people have a disability. Many of them use Android apps. If your app doesn't work with TalkBack or breaks at large font sizes, you've cut those users out.
This isn't charity. It's engineering quality. And in many markets, it's required by law.
Most teams skip all three. Start with automated static analysis — it takes 10 minutes.
Google's Accessibility Scanner is a free app that overlays your app with accessibility issues.
Install it. Run your app. Tap "Check." You'll see:
Fix everything flagged here before moving to manual testing.
Every interactive element needs a content description for TalkBack users:
// Bad — TalkBack says "unlabeled button"
IconButton(onClick = { deleteTask(task) }) {
Icon(Icons.Default.Delete, contentDescription = null) // ← null is wrong
}
// Good — TalkBack says "Delete task Buy groceries"
IconButton(
onClick = { deleteTask(task) },
modifier = Modifier.semantics {
contentDescription = "Delete task ${task.title}"
}
) {
Icon(Icons.Default.Delete, contentDescription = "Delete")
}Images that are purely decorative should have
contentDescription = nullRole.ImageinvisibleToUser()Image(
painter = painterResource(R.drawable.decorative_background),
contentDescription = null, // Decorative — screen reader skips it
modifier = Modifier.semantics { invisibleToUser() }
)The minimum touch target is 48x48dp. Small icons (16-24dp) need padding to meet the minimum:
Icon(
imageVector = Icons.Default.MoreVert,
contentDescription = "More options",
modifier = Modifier
.size(24.dp)
.padding(12.dp) // Total touch area: 48dp
.clickable { showMenu() }
)Or use
minimumInteractiveComponentSize()// Automatically ensures 48dp minimum touch target
IconButton(onClick = { showMenu() }) {
Icon(Icons.Default.MoreVert, contentDescription = "More options")
}IconButtonWCAG AA requires:
Check your color palette at contrast-ratio.com.
In your theme:
// Design system colors with contrast verified
val TextPrimary = Color(0xFFE8E8E8) // Verified 12:1 against dark background
val TextSecondary = Color(0xFF9E9E9E) // Check this — might be borderline
val Accent = Color(0xFFFFA400) // Verified 4.7:1 against dark[!WARNING] "It looks fine to me" is not a contrast check. Use a tool. Developers without color vision deficiencies regularly ship low-contrast text that's unreadable to 8% of users.
Enable TalkBack: Settings → Accessibility → TalkBack → On
Then test your critical flows:
Common TalkBack issues:
mergeDescendants = true// Group related elements into one TalkBack announcement
Row(
modifier = Modifier.semantics(mergeDescendants = true) {}
) {
Text(text = task.title)
Text(text = if (task.completed) "Completed" else "Active")
}
// TalkBack announces: "Buy groceries, Completed" as one itemTest with system font size at maximum (usually 200%):
Settings → Display → Font size → Largest
Check for:
Use
sp// Good — wraps to accommodate large text
Column {
Text(
text = task.title,
fontSize = 16.sp, // sp scales with system font
overflow = TextOverflow.Ellipsis,
maxLines = 2
)
}
// Bad — fixed height clips large text
Box(modifier = Modifier.height(40.dp)) {
Text(text = task.title, fontSize = 16.sp)
}Compose provides semantics testing:
@Test
fun `delete button has meaningful content description`() {
composeTestRule.onNodeWithContentDescription("Delete task Buy groceries")
.assertExists()
.assertHasClickAction()
}
@Test
fun `task item announces both title and status`() {
composeTestRule.onNodeWithText("Buy groceries").assertExists()
composeTestRule.onNodeWithText("Completed").assertExists()
}IconButtonSudarshan Chaudhari
AI Systems Builder / Product Engineer
Bangkok, Thailand
Solo Android developer with 13+ years in QA, building Android apps, AI automation systems, and developer tools at SudarshanTechLabs.
Related Posts
Related Apps
Real-time family location sharing — Firebase Realtime DB for sub-second propagation, WorkManager + ForegroundService for OS-compliant background collection, geofencing via Google Maps API.
Building something? Available for Android dev and QA consulting.
Work with meComments — powered by Giscus
Real-time family location sharing — Firebase Realtime DB for sub-second propagation, WorkManager + ForegroundService for OS-compliant background collection, geofencing via Google Maps API.
ReadPrivate dream journal — structured entry capture, pattern tagging, and optional Claude-powered insight generation. All data stays on-device by default.
ReadWorkout tracker — exercise logging with set/rep/weight history, goal progression, and local Room DB persistence. No account, no cloud sync required.
Read