Add comprehensive Android accessibility support following RetroArch's proven
architecture to enable screen reader functionality for visually impaired players.
The implementation uses Android's native accessibility framework (announceForAccessibility)
to integrate with TalkBack and other screen readers, providing the same accessibility
features available on Windows (Tolk) and Linux (speech-dispatcher).
## Functionality Status
✅ **Working:**
- Compiles successfully for all Android architectures
- TTS starts correctly after game data loading
- TTS interrupts speech when needed (using appropriate `force=true`)
- TTS uses Android's default text-to-speech engine
⚠️ **Known Issues (mod-related, not TTS):**
- Stats screen navigation: pressing C or equivalent button focuses on "Strength"
and prevents navigation through other attributes
- Tracking keys provide incorrect/imprecise directions, preventing proper navigation
to desired destinations
- Mod sounds (doors, chests) not playing - likely due to incorrect file paths or
Android-specific issues
See #12 for details on known issues.
## Usage Instructions
⚠️ **IMPORTANT:** To play, you must suspend the screen reader (TalkBack) after
loading the game data (.mpq). The accessibility mod takes control of TTS through
Android's native API.
## Key Technical Changes
• Added JNI bridge between C++ game code and Java accessibility APIs
• Implemented thread-safe JNIEnv caching with pthread thread-local storage
• Created native methods for screen reader detection and text-to-speech
• Fixed initialization order: nativeInitAccessibility() must be called after
super.onCreate() to ensure SDL loads the native library first
• Enabled SCREEN_READER_INTEGRATION flag in Android CMake configuration
## Technical Details
- Java Layer (DevilutionXSDLActivity.java):
• isScreenReaderEnabled(): Checks TalkBack and touch exploration state
• accessibilitySpeak(): Uses announceForAccessibility() API
- JNI Bridge (Source/platform/android/android.cpp):
• GetJNI(): Thread-safe JNIEnv retrieval with automatic thread attachment
• SpeakTextAndroid(): Calls Java accessibilitySpeak() from C++
• IsScreenReaderEnabledAndroid(): Queries TalkBack status from native code
- Platform Integration (Source/utils/screen_reader.cpp):
• Routes accessibility calls to platform-specific implementations
• Maintains consistent API across Windows, Linux, and Android
## Architecture Notes
- Follows RetroArch's accessibility implementation pattern
- Uses global JNI references for thread-safe Activity access
- Caches method IDs to avoid repeated JNI lookups
- Handles thread attachment/detachment automatically
- No external dependencies required (Android SDK only)
## Documentation
Added comprehensive technical documentation in docs/ANDROID_ACCESSIBILITY.md
Fixes startup crash caused by calling native methods before library loading.
Verified on physical device: app launches successfully, accessibility features functional.
Closes#12
```
Add comprehensive Android accessibility support following RetroArch's proven
architecture to enable screen reader functionality for visually impaired players.
The implementation uses Android's native accessibility framework (announceForAccessibility)
to integrate with TalkBack and other screen readers, providing the same accessibility
features available on Windows (Tolk) and Linux (speech-dispatcher).
## Functionality Status
✅ **Working:**
- Compiles successfully for all Android architectures
- TTS starts correctly after game data loading
- TTS interrupts speech when needed (using appropriate `force=true`)
- TTS uses Android's default text-to-speech engine
⚠️ **Known Issues (mod-related, not TTS):**
- Stats screen navigation: pressing C or equivalent button focuses on "Strength"
and prevents navigation through other attributes
- Tracking keys provide incorrect/imprecise directions, preventing proper navigation
to desired destinations
- Mod sounds (doors, chests) not playing - likely due to incorrect file paths or
Android-specific issues
See #12 for details on known issues.
## Usage Instructions
⚠️ **IMPORTANT:** To play, you must suspend the screen reader (TalkBack) after
loading the game data (.mpq). The accessibility mod takes control of TTS through
Android's native API.
## Key Technical Changes
• Added JNI bridge between C++ game code and Java accessibility APIs
• Implemented thread-safe JNIEnv caching with pthread thread-local storage
• Created native methods for screen reader detection and text-to-speech
• Fixed initialization order: nativeInitAccessibility() must be called after
super.onCreate() to ensure SDL loads the native library first
• Enabled SCREEN_READER_INTEGRATION flag in Android CMake configuration
## Technical Details
- Java Layer (DevilutionXSDLActivity.java):
• isScreenReaderEnabled(): Checks TalkBack and touch exploration state
• accessibilitySpeak(): Uses announceForAccessibility() API
- JNI Bridge (Source/platform/android/android.cpp):
• GetJNI(): Thread-safe JNIEnv retrieval with automatic thread attachment
• SpeakTextAndroid(): Calls Java accessibilitySpeak() from C++
• IsScreenReaderEnabledAndroid(): Queries TalkBack status from native code
- Platform Integration (Source/utils/screen_reader.cpp):
• Routes accessibility calls to platform-specific implementations
• Maintains consistent API across Windows, Linux, and Android
## Architecture Notes
- Follows RetroArch's accessibility implementation pattern
- Uses global JNI references for thread-safe Activity access
- Caches method IDs to avoid repeated JNI lookups
- Handles thread attachment/detachment automatically
- No external dependencies required (Android SDK only)
## Documentation
Added comprehensive technical documentation in docs/ANDROID_ACCESSIBILITY.md
Fixes startup crash caused by calling native methods before library loading.
Verified on physical device: app launches successfully, accessibility features functional.
Related files:
• CMake/Dependencies.cmake: Skip external dependencies for Android
• Source/CMakeLists.txt: Add Android-specific screen reader configuration
• android-project/app/build.gradle: Enable SCREEN_READER_INTEGRATION flag
* Fix broken catacombs wall tile
When tile 15 is followed by tile 1 below, change tile 1 to tile 8
(left corner) to fix a visual glitch in the catacombs.
* Silence fmt catch warnings and guard SaveHelper copy
Turns out, `add_custom_target`'s `DEPENDS` argument can only
refer to outputs of custom commands in the same directory (i.e. the same
CMakeLists.txt scope).
Interestingly, this worked with all generators except parallel
make, so perhaps there some ongoing work in CMake to allow
cross-directory `DEPENDS`.
Works around this limitation by moving tests to the same scope
(`CMakeLists.txt` file) as assets.
This doesn't implement full sound support but stubs out most of the
sound code under SDL3, so that we can implement it piecemeal.
Implemented here:
1. Sound device initialization.
2. SVid sound playback.
Does not add a dependency on `SDL_mixer`: SDL3 built-ins
are enough to play SVid audio.
This does not actually add SDL3 support but adds enough
CMake stuff to make the following succeed:
```bash
cmake -S. -Bbuild-sdl3 -DUSE_SDL3=ON -DDEVILUTIONX_SYSTEM_SDL3=OFF -DDEVILUTIONX_STATIC_SDL3=ON -DNOSOUND=ON
```
`NOSOUND` is needed because `SDL_audiolib` does not support SDL3.
Now that the DOS SDL supports CMake, this is a much better option that
`configure`, because it lets us easily test out local changes to SDL,
e.g.:
```bash
cmake -S. -Bbuild-dos -DCMAKE_TOOLCHAIN_FILE=CMake/platforms/djcpp.toolchain.cmake \
-DTARGET_PLATFORM="dos" -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=OFF \
-DFETCHCONTENT_SOURCE_DIR_SDL2="${HOME}/diasurgical-SDL"
```
Ubuntu 20.04 is going EOL in May.
Ubuntu 22.04 CMake is 3.22.
Debian stable CMake is 3.25.
Debian oldstable (EOL in 2026) has CMake 3.25 in bullseye-backports.
Collects transitive object library dependencies in the topological order
and adds cycle detection.
Now transitive dependencies are actually all linked.
This does not fully address the issue of most everything
being a giant library but it's a start.
Note that the libraries are OBJECT libraries, so they
may (and currently do) contain references to missing
symbols.
Also fixes the implementation of transitive dependency
support for OBJECT libraries.