Aegix Global, LLC
AIM Android — VPAT 2.5
Last reviewed 2026-04-03VPAT 2.5 — Aegix AIM Android Application
| Product Name | Aegix AIM (Alert & Incident Management) Android App |
| Product Version | Current (as of 2026-04-07) |
| Report Date | 2026-04-07 |
| VPAT Version | 2.5 (Revision 1) |
| Contact | Aegix Global |
| Evaluation Methods | Static code analysis of all Activities, Fragments, Compose UI screens, XML layouts, custom Views, and service components |
Applicable Standards
- WCAG 2.1 Level A and Level AA
- Revised Section 508 (2017)
- EN 301 549 V3.2.1 (2021-03) Chapter 11 (Mobile Software)
Conformance Level Definitions
| Term | Description |
|---|---|
| Supports | Fully meets the criterion |
| Partially Supports | Some functionality meets the criterion |
| Does Not Support | Majority of functionality does not meet the criterion |
| Not Applicable | The criterion is not relevant |
Table 1: WCAG 2.1 Level A and AA Report
Principle 1: Perceivable
1.1.1 Non-text Content (Level A)
| Conformance Level | Partially Supports |
| Remarks | Core alert screens now have meaningful contentDescription attributes. Design system imageView() and drawableView() functions accept content description parameters. Some non-critical screens still use default descriptions. |
Remediation completed:
| # | File | Change |
|---|---|---|
| 1 | foundation/design-system/shared/.../CustomViews.kt | imageView() and drawableView() now accept contentDesc parameter instead of hardcoded strings. |
| 2 | products/aim/wear/.../InitAlertScreen.kt | Hero image now has contentDescription = stringResource(R.string.content_desc_current_alert). |
| 3 | products/aim/wear/.../InitAlertScreen.kt | StartLayoutButton images marked as decorative (contentDescription = null) since Row provides accessible label via onClickLabel. |
| 4 | products/aim/phone/.../AlertIconSection.kt | Alert icon GlideImage uses stringResource(R.string.content_desc_alert_icon). Change icon image uses stringResource(R.string.content_desc_change_alert_icon). |
| 5 | products/aim/phone/.../fragment_end_alert.xml | Alert type icon ImageView has contentDescription. Tower images marked importantForAccessibility="no". |
| 6 | products/aim/phone/.../fragment_alert_detail.xml | Tower images marked importantForAccessibility="no". |
Remaining items:
| # | File | Issue |
|---|---|---|
| 1 | Various phone Compose screens | Some non-critical settings screens still use imageView() with default content description. |
| 2 | Login screen logo | Logo image may still lack specific content description (LoginScreen is Compose-based in auth module). |
1.3.1 Info and Relationships (Level A)
| Conformance Level | Partially Supports |
| Remarks | Heading semantics added to safety-critical screens (wear module alert screens, phone XML layouts). Custom clickable elements on alert screens now have Role.Button semantics. Form labels linked to controls via android:labelFor. Some non-critical screens still lack heading and role semantics. |
Remediation completed:
| # | File | Change |
|---|---|---|
| 1 | products/aim/wear/.../StartAlertScreen.kt | ”EMERGENCY” and “ATTENTION” section headers now have Modifier.semantics { heading() }. |
| 2 | products/aim/wear/.../SiteSelectionScreen.kt | ”SITES” header has Modifier.semantics { heading() }. Hardcoded string replaced with stringResource. |
| 3 | products/aim/wear/.../InitAlertScreen.kt | StartLayoutButton now uses clickable(role = Role.Button, onClickLabel = ...). |
| 4 | products/aim/wear/.../StartAlertScreen.kt | AlertTypeItem now uses clickable(role = Role.Button, onClickLabel = ...). |
| 5 | products/aim/wear/.../SiteSelectionScreen.kt | SiteRow now uses clickable(role = Role.Button, onClickLabel = ...). |
| 6 | products/aim/phone/.../fragment_alert_detail.xml | tvPoliceStatus has android:labelFor="@+id/spinnerPoliceStatus". tvGuidance has android:labelFor="@+id/spinnerGuidance". tvStatus has android:accessibilityHeading="true". |
| 7 | products/aim/phone/.../fragment_end_alert.xml | TvEndAlert has android:accessibilityHeading="true". tvTitle has android:accessibilityHeading="true" and android:labelFor="@+id/rgReason". |
Remaining items:
| # | File | Issue |
|---|---|---|
| 1 | Phone Compose settings screens | ~80 .clickable {} calls without role = Role.Button in non-critical settings screens. |
| 2 | DashboardActivity.kt TopAppBar | Title text lacks heading semantics. |
1.3.4 Orientation (Level AA)
| Conformance Level | Supports |
| Remarks | No android:screenOrientation lock found in AndroidManifest.xml. Activities support both portrait and landscape. |
1.4.1 Use of Color (Level A)
| Conformance Level | Partially Supports |
| Remarks | Site selection status indicator now includes text label alongside color circle. |
Remediation completed:
| # | File | Change |
|---|---|---|
| 1 | products/aim/wear/.../SiteSelectionScreen.kt | SiteRow now displays a text status label (“Alert active”, “Drill active”, “Safe”) alongside the colored circle. Color circle also has contentDescription via semantics. |
Remaining items:
| # | File | Issue |
|---|---|---|
| 1 | Phone module alert type selection | Selected alert type may still be indicated only by border color. |
1.4.3 Contrast (Minimum) (Level AA)
| Conformance Level | Partially Supports |
| Remarks | Primary teal color adjusted for better contrast in both light and dark themes. Alert red darkened for body text contrast. |
Remediation completed:
| # | File | Change |
|---|---|---|
| 1 | foundation/design-system/shared/.../AppTheme.kt | Light theme primary: #00B6B4 → #008F8D (~5.0:1 against white). Dark theme primary: #00B6B4 → #00D4D2 (~5.0:1 against dark surface). Alert button color (light): #E70E00 → #B80B00 (~5.5:1 with white text). |
| 2 | products/aim/phone/.../colors.xml | colorPrimary: #00B6B4 → #008F8D. colorPrimary30 updated to match. |
Remaining items:
| # | File | Issue |
|---|---|---|
| 1 | Disabled button states | alpha = 0.4f may still degrade contrast below 3:1 minimum. |
| 2 | Dark theme alert red | #EE003E not yet adjusted (currently ~4.5:1 with white, borderline). |
1.4.4 Resize Text (Level AA)
| Conformance Level | Supports |
| Remarks | System font scale override removed. Text uses sp units throughout. |
Remediation completed:
| # | File | Change |
|---|---|---|
| 1 | products/aim/phone/.../BaseActivity.kt | Removed config.fontScale = 1.0f override — app now respects user’s system font scale preference. |
| 2 | products/aim/phone/.../SplashActivity.kt | Removed config.fontScale = 1.0f override. |
Remaining items:
| # | File | Issue |
|---|---|---|
| 1 | Fixed-height containers | Some containers with height(120.dp) or similar may clip text at 200% scale. Should be changed to heightIn(min = 120.dp). |
1.4.11 Non-text Contrast (Level AA)
| Conformance Level | Partially Supports |
| Remarks | Some UI component boundaries still use transparent or thin borders. |
Remaining items:
| # | File | Issue |
|---|---|---|
| 1 | Dropdown fields | OutlinedTextField with transparent border colors. |
| 2 | Card borders | 0.5.dp borders may be imperceptible. |
Principle 2: Operable
2.1.1 Keyboard (Level A)
| Conformance Level | Partially Supports |
| Remarks | Compose built-in components (Button, TextField) support D-pad/keyboard. Custom clickable elements in wear alert screens now have proper role semantics enabling keyboard interaction. |
2.4.3 Focus Order (Level A)
| Conformance Level | Partially Supports |
| Remarks | No FocusRequester used on screen transitions. Overlay service with FLAG_NOT_FOCUSABLE no longer exists in the current codebase (safety issue from original VPAT is resolved). |
Remaining items:
| # | File | Issue |
|---|---|---|
| 1 | Navigation screens | No focus management after navigation — focus not directed to new screen’s primary content. |
| 2 | Error states | After login errors, focus does not move to error message. |
2.4.6 Headings and Labels (Level AA)
| Conformance Level | Partially Supports |
| Remarks | Heading semantics added to safety-critical screens. See 1.3.1 remediation above. |
2.5.1 Pointer Gestures (Level A)
| Conformance Level | Partially Supports |
| Remarks | Pull-to-refresh still lacks a button alternative on some screens. |
2.5.5 Target Size (Level AAA, recommended by EN 301 549)
| Conformance Level | Partially Supports |
| Remarks | Some interactive elements still fall below Android’s 48x48dp minimum touch target. |
2.5.8 Target Size (Minimum) (Level AA — WCAG 2.2)
| Conformance Level | Partially Supports |
| Remarks | Minimum 24x24dp is met in most cases. |
Principle 3: Understandable
3.3.1 Error Identification (Level A)
| Conformance Level | Partially Supports |
| Remarks | Toast-based errors replaced with Snackbar in safety-critical flows (EndAlertFragment, SplashActivity). Snackbar is focusable and reliably announced by TalkBack. |
Remediation completed:
| # | File | Change |
|---|---|---|
| 1 | products/aim/phone/.../EndAlertFragment.kt | All toast() calls replaced with Snackbar.make(...).show(). Hardcoded error strings replaced with string resources. |
| 2 | products/aim/phone/.../SplashActivity.kt | Toast.makeText() replaced with Snackbar.make(...).show(). |
Remaining items:
| # | File | Issue |
|---|---|---|
| 1 | Other fragments | Some non-critical fragments may still use Toast for error messages. |
| 2 | Compose screens | Error display in Compose screens should use inline error text with liveRegion. |
3.3.2 Labels or Instructions (Level A)
| Conformance Level | Partially Supports |
| Remarks | android:labelFor added to police status and guidance labels in alert detail. Radio group label linked in end alert screen. |
Principle 4: Robust
4.1.2 Name, Role, Value (Level A)
| Conformance Level | Partially Supports |
| Remarks | Safety-critical custom interactive elements now have Role.Button semantics with onClickLabel. Wear alert screens fully remediated. Phone settings Compose screens still lack role semantics on many clickable elements. |
Remediation completed:
| # | File | Change |
|---|---|---|
| 1 | products/aim/wear/.../InitAlertScreen.kt | StartLayoutButton has Role.Button and descriptive onClickLabel. |
| 2 | products/aim/wear/.../StartAlertScreen.kt | AlertTypeItem has Role.Button with onClickLabel including alert type name. |
| 3 | products/aim/wear/.../SiteSelectionScreen.kt | SiteRow has Role.Button with onClickLabel. |
4.1.3 Status Messages (Level AA)
| Conformance Level | Partially Supports |
| Remarks | Live region added to ProgressScreen loading dialog. Alert start/end events now announced via announceForAccessibility(). Socket connection status changes announced. |
Remediation completed:
| # | File | Change |
|---|---|---|
| 1 | foundation/design-system/shared/.../ProgressScreen.kt | Loading dialog Column has Modifier.semantics { liveRegion = LiveRegionMode.Polite }. |
| 2 | products/aim/phone/.../AlertFragment.kt | onAlertStarted() calls announceForAccessibility() with alert/drill status. onAlertEnd() calls announceForAccessibility() with end announcement. |
| 3 | products/aim/phone/.../DashboardActivity.kt | onSocketStatusChanged() calls announceForAccessibility() for connected/disconnected states. |
Remaining items:
| # | File | Issue |
|---|---|---|
| 1 | Guidance text updates | Guidance plan text in alert detail does not announce via live region when selection changes. |
| 2 | Pull-to-refresh loading | Loading state during pull-to-refresh not announced. |
Table 2: Revised Section 508 — Functional Performance Criteria
| Criterion | Conformance | Remarks |
|---|---|---|
| 302.1 Without Vision | Partially Supports | Safety-critical alert screens now have contentDescription, Role.Button semantics, heading structure, and live region announcements for alert start/end events. Overlay service no longer exists in codebase. |
| 302.2 With Limited Vision | Partially Supports | Text uses sp units. System font scale override removed — app respects user preferences. Color contrast improved (primary teal and alert red adjusted). Some fixed-height containers may clip scaled text. |
| 302.3 Without Perception of Color | Partially Supports | Status indicator in SiteSelectionScreen now includes text label alongside color. Some alert type selection screens may still use color as sole differentiator. |
| 302.4 Without Hearing | Partially Supports | Alert notifications now include vibration pattern via .setVibrate() and notification channel enableVibration(). |
| 302.5 With Limited Hearing | Partially Supports | Notifications provide visual content with vibration alternative. |
| 302.6 Without Speech | Supports | App does not require speech input. |
| 302.7 With Limited Manipulation | Partially Supports | Most controls are single-tap. Pull-to-refresh still lacks button alternative on some screens. Touch targets below 48dp in some areas. |
| 302.8 With Limited Reach and Strength | Partially Supports | Same touch target issues as 302.7. |
| 302.9 With Limited Language, Cognitive, and Learning Abilities | Partially Supports | Simple UI flow. Error messages now use Snackbar (persistent, dismissible) instead of transient Toast. |
Table 3: EN 301 549 Chapter 11 — Mobile Software
| Clause | Criterion | Conformance | Remarks |
|---|---|---|---|
| 11.1.1.1 | Non-text Content | Partially Supports | Safety-critical images now have contentDescription. Design system components accept content description parameters. |
| 11.1.3.1 | Info and Relationships | Partially Supports | Heading semantics and Role.Button added to wear alert screens and phone alert XML layouts. Form labels linked via labelFor. |
| 11.1.3.4 | Orientation | Supports | No orientation lock in manifest. |
| 11.1.4.3 | Contrast (Minimum) | Partially Supports | Primary teal adjusted: light #008F8D (~5.0:1), dark #00D4D2 (~5.0:1). Alert red adjusted to #B80B00 (~5.5:1). |
| 11.1.4.4 | Resize Text | Supports | fontScale override removed. Text uses sp. |
| 11.1.4.11 | Non-text Contrast | Partially Supports | Some dropdown field boundaries still transparent. |
| 11.2.1.1 | Keyboard | Partially Supports | Custom clickable elements in alert screens now have role semantics enabling keyboard interaction. |
| 11.2.4.3 | Focus Order | Partially Supports | Overlay service no longer exists. No focus management on navigation transitions. |
| 11.2.4.7 | Focus Visible | Partially Supports | Compose default focus indicators present on standard and role-annotated components. |
| 11.2.5.1 | Pointer Gestures | Partially Supports | Pull-to-refresh still lacks button alternative. |
| 11.3.3.1 | Error Identification | Partially Supports | Toast replaced with Snackbar in EndAlertFragment and SplashActivity. |
| 11.4.1.2 | Name, Role, Value | Partially Supports | Safety-critical custom interactive elements now have roles and click labels. |
| 11.4.1.3 | Status Messages | Partially Supports | Live region on ProgressScreen. Alert start/end/connection announced via announceForAccessibility. |
| 11.5.2.3 | Use of Accessibility Services | Partially Supports | TalkBack interaction improved for alert screens. Overlay service removed. |
| 11.5.2.5 | Object Information | Partially Supports | Roles and states added to wear alert screens. Phone settings screens still lack roles. |
| 11.5.2.7 | Values | Partially Supports | Form field values accessible. Status indicator now has text label. |
| 11.5.2.12 | Execution of Available Actions | Partially Supports | Clickable items have onClickLabel for TalkBack action description. |
| 11.5.2.13 | Tracking of Focus and Selection | Partially Supports | No focus tracking across screen transitions. |
| 11.5.2.15 | Change Notification | Partially Supports | Alert start/end events now announced. Loading state has live region. Connection changes announced. |
| 11.5.2.17 | Modifications | Partially Supports | Text fields editable. Status text labels visible alongside color. |
| 11.7 | User Preferences | Partially Supports | Respects system dark theme. Font scale override removed — respects user font size. Does not respect prefers-reduced-motion. |
| 11.8.2 | Accessible Content Creation | Not Applicable | App does not create content documents. |
Summary
Conformance Status: Partially Supports (WCAG 2.1 Level AA overall)
Critical Issues Resolved
- System Font Scale Override Removed: (
BaseActivity.kt,SplashActivity.kt):config.fontScale = 1.0fremoved — users who need larger text now benefit from system font scaling. - Live Regions for Real-time Events: Alert start/end events and connection status changes now announced via
announceForAccessibility().ProgressScreenloading dialog hasLiveRegionMode.Polite. - Vibration Alternative for Deaf Users: (
LocalNotification.kt): Notification channel and individual notifications now include vibration patterns. - Content Descriptions on Safety-Critical Images: Design system
imageView()/drawableView()accept content description parameters. Wear alert screens and phone alert layouts have proper descriptions. - Role.Button Semantics on Custom Interactive Elements:
StartLayoutButton,AlertTypeItem,SiteRowin wear alert screens now haveRole.Buttonwith descriptiveonClickLabel. - Heading Structure on Safety-Critical Screens: “EMERGENCY”, “ATTENTION”, “SITES” in wear screens and alert type name, end alert headers in phone XML layouts have heading semantics.
- Color-Independent Status Indicators: Site selection status now shows text labels (“Alert active”, “Drill active”, “Safe”) alongside colored circles.
- Improved Color Contrast: Primary teal adjusted from
#00B6B4to#008F8D(light) /#00D4D2(dark) for 5.0:1 contrast. Alert red adjusted to#B80B00for 5.5:1 contrast. - Toast Errors Replaced with Snackbar:
EndAlertFragmentandSplashActivitynow use accessible Snackbar instead of unreliable Toast. - Form Labels Linked to Controls: Police status and guidance labels linked to spinners via
android:labelFor. Radio group label linked in end alert screen. - Emergency Alert Overlay: The
OverlayService.ktwithFLAG_NOT_FOCUSABLEreferenced in the original VPAT no longer exists in the current codebase — this safety-critical blocker is resolved. - Phone Compose Settings Screens: ~80 clickable elements without
Role.Buttonin non-critical settings screens. - Focus Management: No
FocusRequesteron navigation transitions. - Touch Target Sizes: Some elements below 48dp minimum.
- Pull-to-Refresh Alternative: No button alternative for gesture-dependent refresh.
- Non-text Contrast: Some dropdown borders still transparent.
- Reduced Motion: App does not respect
prefers-reduced-motion. - Automated Testing: No Espresso accessibility checks or CI/CD integration yet.
Remaining Work
- Phone Compose Settings Screens: ~80 clickable elements without
Role.Buttonin non-critical settings screens. - Focus Management: No
FocusRequesteron navigation transitions. - Touch Target Sizes: Some elements below 48dp minimum.
- Pull-to-Refresh Alternative: No button alternative for gesture-dependent refresh.
- Non-text Contrast: Some dropdown borders still transparent.
- Reduced Motion: App does not respect
prefers-reduced-motion. - Automated Testing: No Espresso accessibility checks or CI/CD integration yet.
Positive Findings
- No orientation lock (supports both portrait and landscape)
- RTL support enabled (
android:supportsRtl="true") - Text uses
spunits (scalable) and system font scale is respected - Standard Compose components (Button, TextField, RadioButton) provide baseline accessibility
- Dark theme support via Material3 dynamic color scheme
- Alert notifications include vibration for deaf/hard-of-hearing users
- Real-time alert events announced to screen reader users