Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
- Android framework integration tests covering IME discovery, `PROCESS_TEXT` exposure and end-to-end `SpellCheckerService` requests.
- End-to-end IME instrumentation covering Android IME selection, a real editable `InputConnection` and selected-text replacement.
- Opt-in real-engine performance characterization for cold start, sentence analysis and paragraph analysis.
- Reproducible Android application compatibility matrix with a helper for collecting device, Android and application-version metadata.

### Changed

Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ Manual development tests have successfully applied real Grammalecte corrections
- Samsung Notes;
- Firefox text fields.

Compatibility testing is still ongoing.
Compatibility testing is documented in the reproducible [compatibility matrix](docs/compatibility.md), including application versions, Android environment details and the integration path tested.

## Architecture

Expand Down Expand Up @@ -236,6 +236,7 @@ See [`CONTRIBUTING.md`](CONTRIBUTING.md) for development setup, project conventi
- [`THIRD_PARTY_NOTICES.md`](THIRD_PARTY_NOTICES.md)
- [`docs/architecture.md`](docs/architecture.md)
- [`docs/testing.md`](docs/testing.md)
- [`docs/compatibility.md`](docs/compatibility.md)
- [`docs/release.md`](docs/release.md)
- [`docs/adr/`](docs/adr/)

Expand Down
8 changes: 4 additions & 4 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ Exit criterion: an installable APK performs local French spelling and grammar co
- [x] Validate SMS editing
- [x] Identify applications that bypass the Android spell-checker framework
- [x] Add an end-to-end Android framework test for `SpellCheckerService`
- [ ] Build and publish a reproducible compatibility matrix
- [ ] Test additional messaging and mail applications
- [ ] Test additional Chromium/WebView editors
- [x] Build and publish a reproducible compatibility matrix
- [x] Test additional messaging and mail applications
- [x] Test additional Chromium/WebView editors

### PROCESS_TEXT fallback

Expand Down Expand Up @@ -93,7 +93,7 @@ Exit criterion: correction remains usable in common editable applications even w
- [ ] Explain the three correction modes in-app
- [ ] Improve accessibility of the application UI
- [ ] Review all user-facing French strings
- [ ] Add compatibility documentation
- [x] Add compatibility documentation
- [ ] Add performance regression tests
- [ ] Add memory/runtime stress tests

Expand Down
127 changes: 127 additions & 0 deletions docs/compatibility.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
# Android application compatibility

This document records reproducible compatibility tests for the Android
integration paths exposed by Grammalecte Android.

The matrix is intentionally based on observed behavior for specific versions.
A successful result for one application version, Android version or vendor ROM
must not be assumed to apply to every environment.

## Integration paths

The project exposes three correction paths:

- **SpellCheckerService** — native Android spell-checker integration;
- **PROCESS_TEXT** — explicit correction of selected text;
- **IME / InputConnection** — selected-text correction through the Grammalecte input method.

## Standard test fixture

Use synthetic text only.

Spelling fixture:

> Je vais au magazin.

Expected relevant correction:

> Je vais au magasin.

Grammar fixture:

> Je suis aller au magasin hier.

Expected relevant correction:

> Je suis allé au magasin hier.

The purpose of the compatibility matrix is to validate Android integration,
not to exhaustively validate Grammalecte's linguistic behavior.

## Result values

- ✅ Works
- ❌ Does not work
- ⚠️ Partial or application-specific behavior
- — Not tested

## Recorded test environments

### Samsung Galaxy S21

| Field | Value |
| --- | --- |
| Manufacturer | Samsung |
| Model | SM-G998B |
| Android | 15 |
| API | 35 |
| Build ID | AP3A.240905.015.A2 |
| Security patch | 2026-01-01 |
| Android System WebView | 154.0.8037.57 (803705703) |

## Compatibility matrix

| Device / Android | Application | Version (code) | Grammalecte build | SpellCheckerService | PROCESS_TEXT | IME / InputConnection | Notes |
| --- | --- | --- | --- | :---: | :---: | :---: | --- |
| SM-G998B / Android 15 | Samsung Notes | 4.4.45.37 (444537000) | `6c0dde2` | ❌ | ⚠️ | ⚠️ | Grammalecte was explicitly selected as the system spell checker, but Samsung Notes exposed no native suggestion UI; PROCESS_TEXT falls back to the clipboard instead of replacing the selection; IME replacement succeeds, but Samsung Notes keeps a stale red underline even after focus changes and further text edits. |
| SM-G998B / Android 15 | Firefox | 157.0 (2016186455) | `6c0dde2` | ❌ | ⚠️ | ✅ | Grammalecte was explicitly selected as the system spell checker, but Firefox did not invoke native spell-checker UI for the tested field; PROCESS_TEXT copies corrected text to the clipboard without replacing the source selection automatically; IME replacement works correctly. |
| SM-G998B / Android 15 | Samsung Messages | 16.0.10.49 (1601000049) | `6c0dde2` | ❌ | ⚠️ | ✅ | Grammalecte SpellCheckerService was explicitly selected but no native suggestion UI was exposed; PROCESS_TEXT appends corrected text after the original selection instead of replacing it; IME replacement works correctly. |
| SM-G998B / Android 15 | Chrome | 131.0.6778.260 (677826031) | `6c0dde2` | ❌ | ⚠️ | ✅ | Grammalecte was explicitly selected as the system spell checker, but the tested Chromium textarea exposed no native spell-checker UI; PROCESS_TEXT copies corrected text to the clipboard without replacing the source selection automatically; IME replacement works correctly. |
| SM-G998B / Android 15 | Android System WebView | 154.0.8037.57 (803705703) | `c69af20` | ❌ | ⚠️ | ⚠️ | The local WebView textarea showed no native spell-checker feedback; PROCESS_TEXT opens Grammalecte and produces corrected text, but WebView does not apply the returned replacement; the IME can analyze and commit corrected text successfully, but switching input methods causes WebView to lose focus/selection and requires the editor to be focused and the text selected again. |
| SM-G998B / Android 15 | Proton Mail | 7.11.9 (18324) | `5f724dd` | ❌ | ❌ | ✅ | Grammalecte was explicitly selected as the system spell checker, but the composer exposed no native spell-checker UI; the PROCESS_TEXT action was not offered for the tested selection; IME replacement works correctly, including text selected after the Grammalecte IME is already open. |
| SM-G998B / Android 15 | K-9 Mail | 23.1 (39045) | `5f724dd` | ⚠️ | ❌ | ⚠️ | Grammalecte is invoked by the editor and marks the misspelling, but K-9 exposes no usable native suggestion action when the marked word is tapped; PROCESS_TEXT is not offered; IME replacement works when text is selected before switching to Grammalecte, but a selection made after the IME is already open does not trigger a refresh. |
| SM-G998B / Android 15 | WhatsApp | 2.26.38.73 (263807322) | `5f724dd` | ⚠️ | ✅ | ⚠️ | Grammalecte is invoked and the misspelling is underlined, but WhatsApp exposes no usable native suggestion action when the marked word is tapped; PROCESS_TEXT replaces the selected text correctly; IME replacement works when text is selected before switching to Grammalecte, but a selection made after the IME is already open does not trigger a refresh. |

## Test procedure

### SpellCheckerService

1. Select Grammalecte Android as the system spell checker.
2. Open an editable field in the target application.
3. Enter the spelling fixture.
4. Verify whether Android invokes Grammalecte and exposes the expected correction.
5. Record the result without assuming that another editor in the same application behaves identically.

### PROCESS_TEXT

1. Enter the spelling fixture.
2. Select the complete text.
3. Open Android's text-selection actions.
4. Check whether **Corriger avec Grammalecte** is offered.
5. Apply the correction.
6. Record whether corrected text is returned to the source application or whether only the clipboard fallback is available.

### IME / InputConnection

1. Enter the spelling fixture in an editable field.
2. Select the complete text.
3. Switch temporarily to the Grammalecte IME.
4. Verify that the selected text is visible to Grammalecte.
5. Apply the correction.
6. Verify that the source editor now contains the corrected text.
7. Return to the normal keyboard.

## Recording environment information

Use:

./tools/collect-compatibility-env.sh PACKAGE [PACKAGE...]

For multiple ADB devices, select one with:

ANDROID_SERIAL=<serial> ./tools/collect-compatibility-env.sh PACKAGE...

Record exact application versions whenever a compatibility result is added.

## Scope

A result describes only the tested combination of:

- physical device or emulator;
- Android version and vendor ROM;
- application and application version;
- editor or field tested;
- Grammalecte Android build.

Compatibility claims should identify the integration path that was actually
observed rather than infer support from another path.
93 changes: 93 additions & 0 deletions tools/collect-compatibility-env.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#!/usr/bin/env bash
set -euo pipefail

if ! command -v adb >/dev/null 2>&1; then
echo "adb introuvable." >&2
exit 1
fi

ADB=(adb)

if [[ -n "${ANDROID_SERIAL:-}" ]]; then
ADB+=(-s "$ANDROID_SERIAL")
else
mapfile -t DEVICES < <(
adb devices |
awk 'NR > 1 && $2 == "device" { print $1 }'
)

if (( ${#DEVICES[@]} == 0 )); then
echo "Aucun appareil Android disponible via ADB." >&2
exit 1
fi

if (( ${#DEVICES[@]} > 1 )); then
echo "Plusieurs appareils détectés." >&2
echo "Définis ANDROID_SERIAL avant de relancer." >&2
adb devices -l >&2
exit 1
fi

ADB+=(-s "${DEVICES[0]}")
fi

prop() {
"${ADB[@]}" shell getprop "$1" |
tr -d '\r'
}

package_row() {
local package="$1"
local info
local version_name
local version_code

if ! "${ADB[@]}" shell pm path "$package" >/dev/null 2>&1; then
printf '| %s | not installed | - |\n' "\`$package\`"
return
fi

info="$("${ADB[@]}" shell dumpsys package "$package")"

version_name="$(
sed -n \
's/^[[:space:]]*versionName=//p' \
<<<"$info" |
head -n 1
)"

version_code="$(
sed -n \
's/^[[:space:]]*versionCode=\([0-9]*\).*/\1/p' \
<<<"$info" |
head -n 1
)"

printf '| %s | %s | %s |\n' \
"\`$package\`" \
"${version_name:-unknown}" \
"${version_code:-unknown}"
}

echo "## Device environment"
echo
echo "| Field | Value |"
echo "| --- | --- |"
printf '| Manufacturer | %s |\n' "$(prop ro.product.manufacturer)"
printf '| Model | %s |\n' "$(prop ro.product.model)"
printf '| Android | %s |\n' "$(prop ro.build.version.release)"
printf '| API | %s |\n' "$(prop ro.build.version.sdk)"
printf '| Build ID | %s |\n' "$(prop ro.build.id)"
printf '| Security patch | %s |\n' "$(prop ro.build.version.security_patch)"

if (( $# > 0 )); then
echo
echo "## Application versions"
echo
echo "| Package | Version | Version code |"
echo "| --- | --- | ---: |"

for package in "$@"; do
package_row "$package"
done
fi
Loading