SwiftFloris
SwiftFloris is a privacy-first Android keyboard, forked from FlorisBoard and pushed toward SwiftKey-class multilingual typing without the cloud. It ships under Apache-2.0, holds no INTERNET permission, and binds zero accounts.
Zero cloud processing. Zero telemetry. Zero account. All features work offline.
⚠️ SwiftKey users — your account-backed data is being deleted on 2026-05-31
Microsoft is retiring standalone SwiftKey accounts and shutting down the `data.swiftkey.com` export endpoint on 2026-05-31. After that date your non-Microsoft-account learned vocabulary, shortcuts, and clipboard sync are permanently gone.
Two no-cloud paths off SwiftKey:
- Right now (before the cutoff) — export
swiftkey-cloud.jsonfrom `data.swiftkey.com`, install SwiftFloris via the Obtainium one-tap link below, then in SwiftFloris go to Settings → Personal dictionary → Import and pick the file. SwiftFloris ingests the JSON shape directly (see v1.8.46 release notes and the migration walk-through).- If you missed the cutoff — your learned words are gone from the cloud but everything still in the on-device SwiftKey personal dictionary can still be re-typed; SwiftFloris's instant-remember overlay climbs the words back to the top of the prediction strip after a single use.
SwiftFloris never binds your data to a Microsoft (or any other vendor) account, so the next account-retirement notice that lands in your inbox won't include this app.
Samsung / Grammarly users
Galaxy users on One UI 7+ can keep SwiftFloris as the default keyboard and invoke Galaxy AI Writing Assist from Samsung's selected-text UI when they intentionally want that separate Samsung layer. Samsung documents Writing Assist availability and features in its support guide; SamMobile's One UI 7 coverage documents the keyboard-agnostic flow.
Grammarly's Android support docs say the old Grammarly Keyboard for Android is being discontinued and replaced by Grammarly for Android, which integrates with any keyboard. SwiftFloris can stay underneath as the no-network keyboard; SwiftFloris itself does not send text to Grammarly or any other service.
Highlights
| Area | What's in v1.8.170 | Privacy posture |
|---|---|---|
| Autocorrect / prediction | SCOWL 117k English dictionary, SymSpell d1+d2, bigram + trigram next-word, capitalization-aware completions, contraction handling, instant-remember user-dictionary overlay | On-device |
| Multilingual typing | Bilingual subtype presets (EN+ES / EN+FR / EN+DE), per-token Latin language identification, top-two straddle guard, sentence-local context scoring | On-device |
| Scripts | Devanagari + Bengali + Tamil + Telugu + ... (63-script transliteration coverage); RTL Arabic shaper, Persian / Urdu / Hebrew normalisers, bundled Noto Nastaliq Urdu rendering for Urdu subtype key text | On-device |
| Gesture typing | StatisticalGlideTypingClassifier over bounded EN / DE / ES / FR / IT / PT dictionaries with adaptive touch evidence |
On-device |
| Voice input | FUTO Voice Input handoff (live path), plus preview-only local Whisper/Vosk route selector and model catalog until a recognizer runtime ships | SwiftFloris itself does not record audio |
| Emoji & stickers | Emoji search/history/pinned groups with an in-keyboard pin-to-group sheet, bundled local sticker packs, and user-imported SAF sticker folders for PNG / WebP / JPEG / GIF files | Local folder URI only |
| Clipboard | Room-backed history with pinning + per-app source tag, media/provider metadata, sensitive-item gates, and startup/restore reconciliation | On-device |
| Productivity | Calendar quick-insert reads local agenda entries for today + next 7 days; task quick-insert sends selected text to user-chosen task / note apps | Calendar permission is explicit opt-in; no network |
| Themes | 21 bundled themes — SwiftKey Pure (Light/Dark + M3 Expressive), SwiftKey High Contrast (AAA), Aurora Animated, Floris Day/Night, Swift Glacier, Swift Slate, M3E Nord (light + dark), Tokyo Night, Dracula, Catppuccin Mocha; borderless variants where applicable; Snygg theme engine; per-app accent | No telemetry |
| MCP daemon bridge | AIDL bridge to user-installed MCP daemons with per-daemon enable / disable in Settings → MCP daemon bridge | Local-only binder, no network |
| Addon packs | Addon manifest/enumerator contracts, IME-startup registry reconciliation, Settings -> Addons status/rescan, trust reset/changed-certificate controls, dictionary-pack catalog details, persisted signing-certificate pins, descriptor validation, provenance reports, typed dictionary-pack catalog, and addon APK dictionary asset mounting | No-network addon rejection |
| Settings UX | Clearer empty states for selected user-dictionary languages, extension categories, language packs, filtered clipboard history, and theme-manager recovery; surfaced keyboard preview field with ready/active state feedback | Local UI only |
| Migration | Gboard / FlorisBoard / SwiftKey JSON export importer; passphrase-encrypted SwiftFloris dictionary export/import; Keyman LDML / .kmp metadata + Windows KLC + macOS hardware-keyboard imports |
All file-system based |
| Alternative layouts | Colemak / Dvorak / Workman from the FlorisBoard layout pack, plus selectable honeycomb hex layout with clipped hex keys and hex-aware hit testing | On-device |
| AI transparency | First-run AI/ML explainer plus Settings → About → AI features screen covering next-word, glide, voice, translation, and smart compose | On-device, no account, no telemetry |
| CI / build | No-network gate, repo-hygiene gate, OSV dep scan, Dependabot version review, lint baseline-drift wrapper, manual emulator settings smoke, reproducible-build toolchain pins + build-twice APK self-check, Roborazzi visual-regression hard gate with committed theme/Addons baselines, Macrobenchmark trace sections in 6 hot paths | Audit-friendly |
Distribution
SwiftFloris ships through GitHub Releases (canonical), and is targeted at F-Droid (reproducible-build verification in progress) and Obtainium for auto-updates. It is not on Google Play by design — Play forces target-SDK churn and Integrity-API tradeoffs that conflict with the no-telemetry posture.
Option A — Obtainium (recommended for auto-updates)
Obtainium tracks GitHub Releases directly and notifies you the moment a new SwiftFloris APK ships — no Play Store, no F-Droid mirror lag, no manual polling.
One-tap subscribe:
obtainium://app/{"id":"dev.patrickgold.florisboard","url":"https://github.com/SysAdminDoc/SwiftFloris","author":"SysAdminDoc","name":"SwiftFloris","preferredApkIndex":0,"additionalSettings":"{\"includePrereleases\":false,\"fallbackToOlderReleases\":true,\"trackOnly\":false,\"versionDetection\":true,\"apkFilterRegEx\":\"app-release.*\\\\.apk\"}"}
Open the link above on a device with Obtainium installed (or paste it into Obtainium's "Add app from URL" field). Obtainium will subscribe to this repository's GitHub Releases feed and auto-prompt for installs on each new tag.
Option B — GitHub Releases (manual)
- Download the latest APK from Releases.
- Install on your Android device (Android 8.0+).
- (Optional) Install FUTO Voice Input for offline dictation. SwiftFloris's in-app Whisper/Vosk catalog is preview-only until the local recognizer runtime ships.
Option C — Manual Build
git clone https://github.com/SysAdminDoc/SwiftFloris.git
cd SwiftFloris
./gradlew assembleDebug
adb install app/build/outputs/apk/debug/app-debug.apk
Enable as Default Keyboard
- Open Settings → System → Languages & input.
- Tap Virtual keyboard (or On-screen keyboard).
- Select SwiftFloris and grant permissions as prompted.
Migrating from SwiftKey
Full step-by-step paths are in `docs/MIGRATE_FROM_SWIFTKEY.md`; the headline contract — swiftkey-cloud.json ingestion through Settings → Personal dictionary → Import — landed in v1.8.46, the cumulative-byte hardening of the JSON parser in v1.8.48, the post-import confirmation + rollback in v1.8.53, the encrypted-blob export codec primitive in v1.8.54, the Settings UI encrypted export/import round-trip in v1.8.65, and the parity-roadmap reference for the 2026-05-31 cutoff lives in `docs/archive/SWIFTKEY_PARITY_ROADMAP_2026-05-17.md`.
Documentation
Project-internal docs all live in the repository:
- `ARCHITECTURE.md` — module, package, runtime, security-boundary, and CI architecture map.
- `CONTRIBUTING.md` — contributor setup, verification, privacy, and release expectations.
- `docs/MIGRATE_FROM_SWIFTKEY.md` — SwiftKey account-retirement migration paths.
- `docs/PRIVACY_AND_AI.md` — AI/ML feature transparency and local-processing disclosure.
- `docs/THREAT_MODEL.md` — privacy / security threat model and mitigations.
- `docs/SQLCIPHER_PROVIDER_MIGRATION.md` — SQLCipher crypto-provider migration triggers, OpenSSL proof-of-concept path, and 16 KB verification gates.
- `docs/REPRODUCIBLE_BUILDS.md` — pinned toolchain and F-Droid rebuild plan.
- `docs/BENCHMARKS.md` — Macrobenchmark trace sections and regression threshold contract.
- `docs/LOCAL_VERIFICATION.md` — maintainer local test/build/lint/device commands.
- `docs/REPO_HYGIENE.md` — generated-output, deleted-doc, commit-scope, and handoff rules.
- `docs/INLINE_AUTOFILL.md` — inline-autofill matrix and password-manager verification.
- `docs/TASKER_INTEGRATION.md` — Tasker intent contract.
- `docs/FONTS.md` — bundled fonts (Nastaliq + Naskh fallback).
- `docs/AUTOCORRECT_LIFECYCLE.md` — autocorrect, spacebar, punctuation, backspace, provider-notification, and QA contract.
- `docs/GESTURE_TYPING_MULTILINGUAL.md` — multilingual gesture-typing guide.
- `docs/FUTO_VOICE_INPUT_TROUBLESHOOTING.md` — FUTO Voice Input setup + recovery actions.
- `docs/VOICE_COMMANDS.md` — built-in and custom voice-command grammar reference.
- `docs/addons/dictionary-pack-spec.md` — external dictionary-pack APK descriptor and validation contract.
- `IMPROVEMENT_PLAN.md` — execution-focused quality / UX / a11y / perf / test / delivery plan.
- `ROADMAP.md` — current and historical roadmap (v5.67).
- `CHANGELOG.md` — full release history, one section per version (anchor:
#vX.Y.Z).
Architecture & Stack
Language and build
- Kotlin 2.3.21, Compose BOM 2026.05.00, Material 3 + material-kolor.
- AGP 9.2.1, Gradle 9.5.1, JDK 17.
- KSP 2.3.8, Room 2.8.4, SQLCipher 4.16.0, Tink Android 1.21.0.
- Kotest 6.1.11 unit-test runner; Roborazzi 1.60.0 and Robolectric 4.16.1 for screenshot/JVM Android regressions.
- minSdk 26 (Android 8.0); targetSdk / compileSdk 36 (Android 16, with Android 17 / API 37 behavior gates wired).
- Crowdin pipeline for translations.
- No
INTERNETpermission in the manifest (CI-enforced).
Module layout
:app — IME + Settings UI + addon facades
lib/android — Android utility extensions
lib/color — color math
lib/compose — Compose helpers
lib/kotlin — pure-Kotlin utilities
lib/snygg — Snygg theme engine
:benchmark — Macrobenchmark + adb benchmark harness (active in settings)
:lib:native — placeholder for future native add-ons (commented out)
The IME's main work lives under app/src/main/kotlin/dev/patrickgold/florisboard/ime/{keyboard,nlp,theme,ext,emoji,mcp,voice,bidi,dictionary,kenlm}.
Building
Prerequisites
# Android SDK 36 (compile/target)
# JDK 17+
# Gradle 9.5.1 (use the bundled wrapper)
Build commands
# Debug build
./gradlew assembleDebug
# Release build (unsigned)
./gradlew assembleRelease
# Clean
./gradlew clean
# Unit tests (Kotest)
./gradlew test
# Roborazzi screenshot verify (visual-regression CI)
./gradlew :app:verifyRoborazziDebug
Signed release build
./gradlew assembleRelease \
-Pandroid.injected.signing.store.file=keystore.jks \
-Pandroid.injected.signing.store.password=$STORE_PASS \
-Pandroid.injected.signing.key.alias=$KEY_ALIAS \
-Pandroid.injected.signing.key.password=$KEY_PASS
See `docs/REPRODUCIBLE_BUILDS.md` for the toolchain pins that match the published APK fingerprints.
Permissions
| Permission | Purpose | Required? |
|---|---|---|
INPUT_METHOD |
IME service binding | ✅ Yes |
VIBRATE |
Haptic feedback | Optional |
RECORD_AUDIO |
Not requested by SwiftFloris; the external voice keyboard owns microphone access | No |
BIND_NOTIFICATION_LISTENER |
App-aware smartbar features | Optional |
Privacy note: SwiftFloris does not request
INTERNET. CI validates this on every build.
Privacy & Security
Posture
- No
INTERNETpermission, no cloud sync, no account, no telemetry, no ads. - Apache-2.0 only in the main app. GPL / AGPL / Source-First code cannot be linked into
:app; it can only ship as a clearly-isolated optional addon under its own license. - No closed-source blobs. No
libjni_latinimegoogle.so-style glide binaries. Reproducible builds with toolchain pinning.
Encryption and sensitive-field handling
- Personal dictionary: SQLCipher-encrypted Room database, with the SQLCipher passphrase wrapped by Tink / AndroidKeystore.
- IME window:
FLAG_SECUREset on password fields so the keyboard is excluded from screenshots and screen-recording overlays. - Long-press popups: suppressed on every
KeyVariation.PASSWORD(Android 17 password-visibility behavior closed on the IME side as of v1.8.44). - Personalized learning: clipboard write / dictionary learn paths skip password and
IME_FLAG_NO_PERSONALIZED_LEARNINGfields. - Opt-in addon surfaces (smart-compose, translation, MCP): every invocation runs through
SensitiveFieldGuardfirst; sensitive fields short-circuit to a safe no-result. - Personal dictionary backup: excluded from cloud-backup paths; device-transfer kept.
Full posture: `docs/THREAT_MODEL.md`.
Open Source
- GitHub — Full source code available.
- Apache License 2.0 — Permissive, audit-friendly.
Multilingual support
SwiftFloris ships first-class bilingual subtype presets for SwiftKey-style EN+ES / EN+FR / EN+DE typing, plus per-token language identification over Latin-script subtypes (EN / ES / FR / DE / IT / PT). The multilingual ranker refuses to autocommit when the two strongest plausible replacement candidates come from different enrolled languages, so cross-language autocorrects stop bleeding into the wrong sentence.
For non-Latin scripts, the transliteration layer currently covers 63 scripts ranging from Devanagari, Bengali, Tamil, Telugu, Gujarati, Gurmukhi, Kannada, Malayalam, Odia, Sinhala (Indic) through Khmer, Burmese, Lao, Thai, Tibetan, Mongolian, Javanese, Sundanese (Brahmic) into Arabic with FE70-FEFC connected-form shaping, Persian / Urdu / Hebrew normalisers, and historical scripts such as Phoenician, Imperial Aramaic, Avestan, and 20th-century constructed alphabets (Adlam, N'Ko, Cherokee, Vai, Bassa Vah, Mende Kikakui, Pahawh Hmong, Nyiakeng Puachue Hmong, Wancho, Medefaidrin).
Inline translation has the cache + language detector + sentence tokenizer + language-pack manager + router shipped on the IME side; the Bergamot WASM runtime addon is the outstanding piece tracked as L2.1a in the roadmap.
MCP daemon bridge
SwiftFloris is the first FOSS Android keyboard to ship an end-to-end MCP (Model Context Protocol) daemon bridge. It binds local-only to MCP daemons advertised by other apps on the device (no network, no cloud), surfaces them in Settings → MCP daemon bridge, and lets users enable / disable individual daemons. The bridge is opt-in by construction: tool invocations route through the same SensitiveFieldGuard as smart-compose and translation, so password fields cannot trigger remote tool calls.
The full bridge spans IMcpDaemon.aidl (Binder surface), AndroidMcpClient (JSON envelope translation), McpServiceConnectionManager (per-daemon bind lifecycle), McpAndroidDiscoverer (PackageManager discovery), McpDispatchRouter (registry → guard → tool → response), and the Settings screen that lists bound daemons + per-daemon switches.
Tasker integration
SwiftFloris exposes a Tasker intent contract for INSERT_TEXT / INSERT_CLIP / SWITCH_LAYOUT / TRIGGER_VOICE actions. See `docs/TASKER_INTEGRATION.md`.
Performance and benchmarks
Six Macrobenchmark trace sections are emitted from production code paths:
swiftfloris.ime.firstRender(FlorisImeService.onCreateInputView)swiftfloris.nlp.suggest(LatinLanguageProvider.suggest)swiftfloris.smartbar.candidates.recompose(CandidatesRowbody)swiftfloris.theme.switch(ThemeManager.updateActiveTheme)swiftfloris.dict.load(loadSpecificDictionary)swiftfloris.nlp.symspell.build(lazy index init)
Real device-number collection is tracked in `docs/BENCHMARKS.md`. Current SM-S938B / Android 16 baselines record am start -W first-render medians of TotalTime 31.0 ms and WaitTime 34.0 ms, benchmark-only swiftfloris.ime.firstRenderMs median 18.335469 ms, cold provider-direct swiftfloris.nlp.firstSuggestionMs median 1878.616249 ms for teh, dictionary cold-load / preload medians of 757.353333 ms / 772.080625 ms with lazy SymSpell d1/d2 index medians of 500.230156 ms / 532.298281 ms, candidate-row warm-typing recomposition median body / max / total of 0.326563 ms / 0.770365 ms / 4.069529 ms, theme-switch median body / max / total of 18.541197 ms / 19.587708 ms / 57.505571 ms with 0.2808075 ms cached warm switches, and backup/restore default-archive medians of 12.653698 ms backup create / 9.874167 ms restore total with 3/3 sections restored. The repository deliberately does not publish hand-wavy latency tables; numbers go in the benchmark doc with the device, OS build, and trace section or log marker that produced them.
Testing
- Unit tests: Kotest, run with
./gradlew test. Last reported HEAD: 998+ tests (post-v1.8.40), expanding with each release. The v1.8.47 hardening pass added defensive tests around dictionary import limits, voice-model atomic install, theme asset traversal, and quick-action serializer fallback. - Visual regression: Roborazzi 1.60.0, plugin alias active. CI runs
:app:verifyRoborazziDebugon every push / PR as a hard gate, backed by committed baselines for the maintainer chip, SwiftKey High Contrast, Aurora Animated, and Settings -> Addons surfaces. - Macrobenchmark:
:benchmarkis wired for AndroidX trace/frame runs, and the adb harness scripts record repeatable IME first-render, first-suggestion, dictionary-load, candidate-row recomposition, theme-switch, and backup/restore baselines. - No-network gate: CI verifies the absence of
INTERNETpermission on every build. - Lint drift: CI lint runs through
scripts/run-lint-debug-with-baseline-check.sh, which fails stale baseline entries instead of leaving them as console-only noise. - Emulator smoke: The manual
Android Emulator Smokeworkflow builds the debug APK, launches the Settings app on an emulator, and uploads logcat for crash triage. - Repo hygiene gate: CI runs
scripts/check-no-root-crash-logs.shso rooths_err_pid*.log/replay_pid*.logfiles cannot be committed, andscripts/check-repo-hygiene.shrejects tracked generated build/report output.
Recent releases
The full release stream lives in `CHANGELOG.md` and on GitHub Releases.
- v1.8.170 (2026-05-18) — Keyboard preview field polish: settings preview fields now sit on a distinct bottom surface, expose ready/active feedback, preserve bottom-bar traversal, and use coroutine-safe feedback when Android cannot open the IME picker. (notes)
- v1.8.169 (2026-05-18) — Empty-state UX polish: selected dictionary-language views, extension categories, language packs, filtered clipboard history, and the theme manager now explain blank states and route users toward add/import/filter-clear/recovery actions. (notes)
- v1.8.168 (2026-05-18) — Addon scan progress: Addons Settings now shows a shared progress card while installed packages and dictionary-pack metadata are rescanned, and the touched preference state read uses the current
collectAsStateAPI. (notes) - v1.8.167 (2026-05-18) — Theme and extension destructive confirmations: draft file deletes plus theme rule/property deletes now require explicit confirmation and explain that installed extensions/themes remain unchanged until save. (notes)
- v1.8.166 (2026-05-18) — Repo hygiene closure: CI now runs a repo-hygiene script, generated build/report output is guarded, legacy deleted markdown decisions are documented, and commit-scope/final-handoff rules are pinned. (notes)
- v1.8.165 (2026-05-18) — CI quality gates: Android CI lint now fails stale baseline drift, Dependabot reviews Gradle and Actions updates weekly, a manual emulator settings-launch smoke exists, and local verification commands are documented. (notes)
- v1.8.164 (2026-05-18) — Backup/restore baseline: benchmark-only representative archive generation measures preference plus keyboard/theme backup creation and merge restore timings under
docs/benchmark-results/. (notes) - v1.8.163 (2026-05-18) — Theme-switch baseline: benchmark-only direct switch markers and an adb harness measure SwiftKey Pure / M3E theme swaps while the benchmark IME is visible, including cold and cached timings under
docs/benchmark-results/. (notes) - v1.8.162 (2026-05-18) — Candidate row recomposition baseline: benchmark-only smartbar log markers and an adb harness measure warm typing recomposition counts/durations plus paired NLP suggestion timing under
docs/benchmark-results/. (notes) - v1.8.161 (2026-05-18) — Dictionary load/preload baseline: a benchmark-only activity preloads the Latin dictionary, forces lazy SymSpell d1/d2 index construction with an invalid probe token, and records SM-S938B / Android 16 numbers under
docs/benchmark-results/. (notes) - v1.8.160 (2026-05-18) — First suggestion latency baseline: a benchmark-only activity invokes the Latin suggestion provider against a real
EditorContentsnapshot and records cold provider-direct SM-S938B / Android 16 numbers underdocs/benchmark-results/. (notes) - v1.8.159 (2026-05-18) — IME first-render benchmark baseline:
:benchmarkis active again, a benchmark-only input activity drives cold IME view creation, and SM-S938B / Android 16 first-render numbers are committed underdocs/benchmark-results/. (notes) - v1.8.158 (2026-05-18) — Accessibility manual QA notes: contributor and accessibility docs now list TalkBack traversal, key-label, candidate-row, font-scale, non-color-state, and theme/layout checks. (notes)
- v1.8.157 (2026-05-18) — Non-color state indicators: shared success/progress/neutral cards and extension-import row icons make readiness, progress, cancellation, and completion visible without relying on color alone. (notes)
- v1.8.156 (2026-05-18) — Theme contrast audit: bundled keyboard/candidate/dialog styles and settings warning/error/dialog palettes now have selector-level AA coverage; low-contrast enter-key variants and card secondary text were tightened. (notes)
- v1.8.155 (2026-05-18) — Dynamic font scaling: compact settings metadata, links, extension component headings, and theme-rule key previews now expand wrapping room or preview size at high font scale. (notes)
- v1.8.154 (2026-05-18) — Keyboard key accessibility: semantic key targets now follow the real touch hitbox, expose an accessibility click action, and label common clipboard, voice, mode, layout, and smartbar-control keys explicitly. (notes)
- v1.8.153 (2026-05-18) — Candidate and smartbar TalkBack labels: prediction-strip candidates now announce suggestion type, position, and text, while quick actions use a stable display-name/tooltip fallback policy. (notes)
- v1.8.152 (2026-05-18) — Settings focus order: the shared settings scaffold now gives TalkBack and keyboard traversal a stable app bar -> content -> bottom actions -> floating action order. (notes)
- v1.8.151 (2026-05-18) — Dictionary transfer busy states: user dictionary import/export now shows explicit progress cards, runs transfer work off the main thread, and blocks duplicate transfer/navigation/menu/entry actions while busy. (notes)
- v1.8.150 (2026-05-18) — Trust-state recovery microcopy: backup, restore, extension, language-pack, archive-file, and manual dictionary failure cards now state what stayed unchanged and provide a retry/recovery path with the technical detail. (notes)
- v1.8.149 (2026-05-18) — Dictionary entry trust states: manual add/update/delete now show progress/result cards, run DAO writes off the main thread, refresh affected suggestion overlays, and block duplicate entry actions while work is running. (notes)
- v1.8.148 (2026-05-18) — Extension archive file trust states: archive file import/rename/delete now show progress/result cards, do file work off the main thread, and block duplicate actions while work is running. (notes)
- v1.8.147 (2026-05-18) — Theme extension trust states: theme editing now shows save progress/failure cards, confirms component removal with draft-state feedback, and installed extension deletion now shows progress/failure cards while blocking duplicate actions. (notes)
- v1.8.146 (2026-05-18) — Language pack trust states: extension import now shows file-reading/importing/cancel/failure states plus new/update/skipped counts, and language pack deletion now shows progress/success/failure cards while blocking duplicate actions. (notes)
- v1.8.145 (2026-05-18) — Restore flow trust states: erase restores now require confirmation and show recovery-copy guidance, restore progress/cancellation/failure/partial-failure states stay visible, and section-level restore summaries prevent missing archive sections from silently erasing local data. (notes)
- v1.8.144 (2026-05-18) — Backup flow trust states: backup progress, cancellation, share-sheet handoff, failure, and sensitive-clipboard exclusion now surface as explicit cards, with
BackupFlowNoticepolicy coverage. (notes) - v1.8.143 (2026-05-18) — Autocorrect lifecycle contract:
docs/AUTOCORRECT_LIFECYCLE.mdnow defines spacebar, punctuation, backspace, hardware, glide-delete, provider-notification, manual QA, and regression-test contracts; accepted provider notifications now wait for successful editor commits. (notes) - v1.8.142 (2026-05-18) — Theme rule edit policy extraction:
ThemeRuleEditPolicynow owns add-rule selection validation, selector toggling, and key-code attribute parsing/replacement decisions for the theme editor. (notes) - v1.8.141 (2026-05-18) — Punctuation flush policy extraction:
KeyboardAutoCommitFlushPolicynow owns software non-letter autocorrect flush decisions for media mode, alphabetic keys, punctuation, numeric keys, and numeric/phone layouts. (notes) - v1.8.140 (2026-05-18) — Candidate auto-commit policy extraction:
CandidateAutoCommitPolicynow owns shortcut, phrase repair, active-strip, immediate fallback, quick-prediction, and rejected-correction gating decisions with focused JVM coverage. (notes) - v1.8.139 (2026-05-18) — Dependency warning review: Gradle is checksum-pinned to 9.5.1, Navigation Compose is on 2.9.8, and JUnit Vintage is centralized at 6.0.3 after official-release review, clearing the dependency-version lint warnings. (notes)
- v1.8.138 (2026-05-18) — Conservative unused-resource cleanup: obsolete launcher/branding resources and dead legacy color tokens were removed after manifest/code/asset/test/dynamic lookup review, reducing lint from 289 warnings / 1 hint to 245 warnings / 1 hint. (notes)
- v1.8.137 (2026-05-18) — Theme editor validation tests: theme component metadata now validates through
ThemeComponentMetaValidationPolicy, with JVM coverage for valid apply normalization, invalid fields, duplicate IDs, and blank stylesheet fallback. (notes) - v1.8.136 (2026-05-18) — Subtype editor validation tests: editable subtype drafts now validate through
SubtypeEditorValidationPolicy, with JVM coverage for default add-state missing fields, complete draft building, select-placeholder rejection, and edit-state preservation. (notes) - v1.8.135 (2026-05-18) — Language pack import/update tests: extension import readiness now lives in
ExtensionImportPolicy, with JVM coverage for new installs, user-installed updates, bundled-core rejection, corrupted metadata, wrong extension type, unsupported files, and import button enablement. (notes) - v1.8.134 (2026-05-18) — Backup/restore policy tests: validation and operation-state decisions now live in
BackupRestorePolicy, with JVM coverage for backup success/cancellation/failure, invalid archives, restore enablement, and partial-failure classification. (notes) - v1.8.133 (2026-05-18) — Incognito suggestion privacy policy tests: app-declared no-learning override, dynamic toggle availability, committed-word learning, and touch-decoder evidence gates now have focused JVM coverage. (notes)
- v1.8.132 (2026-05-18) — Glide typing delete policy tests: immediate backspace word-delete escalation now lives in the editor input policy and is covered for enabled, disabled, inactive phantom-space, and explicit word-delete paths. (notes)
- v1.8.131 (2026-05-18) — Spacing lifecycle state tests: auto-space and phantom-space state transitions now have focused JVM coverage for one-update grace, composing-region visibility, and candidate-for-revert cleanup. (notes)
- v1.8.130 (2026-05-18) — Hardware keyboard input policy tests: hardware keydown/keyup routing now has focused JVM coverage for space, enter, delete pass-through, shift, mapped letters, mapped punctuation, and mapped punctuation flushing pending autocorrect before commit. (notes)
- v1.8.129 (2026-05-18) — Editor input behavior policy extraction: autocorrect spacebar commits, rejected-correction protection, punctuation auto-spacing, phantom spacing, double-space period, and sentence-capitalization gates now have focused JVM coverage through a pure policy class. (notes)
- v1.8.128 (2026-05-18) — Nastaliq Urdu font bundle: the official OFL-1.1 Noto Nastaliq Urdu TTF is now committed as an APK asset, Urdu subtype key labels and hints route Arabic-script text through it, and asset/license tests pin the bundle. (notes)
- v1.8.127 (2026-05-18) — Emoji pinned-group sheet: long-pressing emoji can now pin them to named groups, and pinned-group chips commit the saved emoji sequence from the palette. (notes)
- v1.8.126 (2026-05-18) — Addons dictionary catalog polish: Settings -> Addons now lists mounted dictionary packs with language, word count, dataset license, source, descriptor rejections, and updated install guidance. (notes)
- v1.8.125 (2026-05-18) — Addons dictionary asset mounting: enrolled dictionary-pack APK assets now feed the Latin dictionary store through
PackageManager#getResourcesForApplication(...), merge with bundled baselines, and reload when the live addon registry generation changes. (notes) - v1.8.124 (2026-05-18) — Addons trust controls: Settings -> Addons can now reset all saved signing-certificate pins or trust a changed certificate after confirmation and rescan; the pin codec gained targeted package removal and the Addons Roborazzi baseline was refreshed. (notes)
- v1.8.123 (2026-05-18) — Roborazzi baseline hard gate: committed screenshot baselines for the maintainer chip, SwiftKey High Contrast, Aurora Animated, and Settings -> Addons surfaces; CI now fails on visual-regression drift instead of using
continue-on-error. (notes) - v1.8.104 – v1.8.122 (2026-05-17/18) — seventh-pass audit closure and follow-up slices: app-declared
IME_FLAG_NO_PERSONALIZED_LEARNINGandEXTRA_IS_SENSITIVEprivacy flags are honoured, voice handoff refuses sensitive fields, checks every external voice IME's microphone grant, exposes a durable Listening state, and now gates the in-app Whisper/Vosk route selector and model catalog behind a preview-only local-runtime flag; dangerous voice remove commands were tightened, the voice setup activity is non-exported with a validated setup-intent contract, clipboard backup/clear-all leaks were closed, provider-backed clipboard media clones now cap image/video bytes, image preview decode rejects oversized dimensions before allocation, automatic clipboard history eviction now closes provider-backed media before deleting rows, sensitive clipboard text no longer feeds pin-popup description URL/email/phone classification, startup reconciliation removes missing-file history rows plus unreferenced provider files / metadata rows, media restore recreates provider metadata for restored image/video clips, failed foreign media URI clones no longer create phantom history entries, clipboard history maintenance no longer sorts or evicts on Main, the dead parallel Tink clipboard-history store has been removed so the Room-backed manager is the only live storage path, and the KenLM mmap reader now rejects header/pre-body offsets instead of aliasing them to trie-body bytes. (latest notes) - v1.8.85 – v1.8.103 (2026-05-17) — cross-subsystem hardening pass + 18 single-feature follow-up releases. v1.8.85 was an explicit AGENTS.md §6 one-time deviation that closed eleven privacy / security / reliability gaps (merged-manifest
verifyNoInternetPermission, Android 12+data_extraction_rules.xml, atomicZipUtils.unzip, thread-safeHardwareKeyboardRuntimeMapper, sticker decoder OOM, sticker MIME spoof, addon enumerator size category-error,verify-reproducible-apk.shpayload-manifest pass criterion, CI workflow permissions,pull_request_targetinjection, AltGr); v1.8.86 – v1.8.102 then returned to per-PR scope and closed eleven of twelve F-roster items (FLAG_SECURE on numeric PIN + passphrase dialog, legacy-passphrase recovery, ZipUtils abort policy, SAF lost-grant UX, addon spec docs alignment, LDMLshift=semantics, fastlane script hardening, SHA-pinned floating action tags,release.ymlkeystore hygiene,verifyDataExtractionRulesbuild gate, sticker LRU + folder cap,HardwareKeyEntry.longPressAlternates); v1.8.103 closes the documentation half (README + PROJECT_CONTEXT version refresh, master index of the session's commits). The remaining F11 Roborazzi baseline item closed in v1.8.123. (master index) - v1.8.84 (2026-05-17) — Settings → Addons status surface: users can inspect accepted/rejected addon APKs, manually rescan through the startup reconciliation path, and review package/license/version/size/signing-fingerprint details. (notes)
- v1.8.83 (2026-05-17) — Addon registry startup wiring: the IME now scans installed addon manifests at startup, reconciles them through persisted signing pins, publishes a process-wide registry, and cleans malformed stored pin lines. (notes)
- v1.8.82 (2026-05-17) — Addon signing-pin persistence:
AddonSigningPinSetsafely parses/encodes addon package fingerprint pins andprefs.addon.signingCertPinsgives the registry a durable trust store consumed by v1.8.83 startup wiring and v1.8.84 Settings status UI. (notes) - v1.8.81 (2026-05-17) — Addon catalog foundation:
AddonRegistrynow reconciles live addon state with signing-certificate pins, andDictionaryPackCatalogvalidates dictionary-pack descriptors plus provenance before Settings/Addons UI and asset mounting land. (notes) - v1.8.80 (2026-05-17) — SQLCipher provider migration plan: documented the current LibTomCrypt-based Android Community AAR state, OpenSSL proof-of-concept path, migration triggers, 16 KB page-size gates, and rollback rules without changing the runtime dependency. (notes)
- v1.8.79 (2026-05-17) — Honeycomb hex layout wire-up: the bundled honeycomb character layout is registered for subtype selection, routed through
TextKeyboardLayoutStyle.Honeycomb, clipped toHoneycombHexShape, and hit-tested against the actual hex instead of rectangular bounding boxes. (notes) - v1.8.78 (2026-05-17) — Keyman
.kmppackage import foundation: safe ZIP/package parser forkmp.json, keyboard/language/example metadata, LDML-in-package extraction, lexical-model classification, compiled-engine-required classification, and unsafe entry skipping. (notes) - v1.8.77 (2026-05-17) — User-imported sticker folder: Settings → Emoji & stickers can persist a local SAF folder URI, enumerate supported image files into an Imported sticker pack, preview them in the sticker grid, and commit them through the existing rich-content provider path. (notes)
- v1.8.76 (2026-05-17) — Hardware-keyboard runtime mapping: imported layouts can bind to Android hardware
deviceIdvalues, resolveKeyEventscan/key codes through KLC/macOS fallbacks, and commit mapped printable characters throughKeyboardManager. (notes) - v1.8.75 (2026-05-17) — Hardware-keyboard import: added an XXE-hardened macOS
.keylayoutXML parser that normalizes key maps, modifier maps, and action-backed dead keys intoHardwareKeyboardLayout. (notes) - v1.8.74 (2026-05-17) — Bump-batch C: Android Gradle Plugin
9.0.0→9.2.1and Compose BOM2026.03.01→2026.05.00; R8 keepattributes audit required no rule changes. (notes) - v1.8.73 (2026-05-17) — Repo hygiene: local root JVM crash/replay logs moved to
.ai/local-crash-logs/2026-05-16/, and CI now rejects committed rooths_err_pid*.log/replay_pid*.logfiles. (notes) - v1.8.72 (2026-05-17) — Roadmap correction: HeliBoard / NLnet open-glide integration is now treated as an additive future track, while SwiftFloris's shipped
StatisticalGlideTypingClassifierremains the production glide path until a permissive open library and dataset are actually available. (notes) - v1.8.71 (2026-05-17) — Bump-batch B: Roborazzi
1.55.0→1.60.0and Robolectric4.14.1→4.16.1; no app code, permissions, or runtime behavior changed. (notes) - v1.8.70 (2026-05-17) — README migration-window follow-up: Samsung / Grammarly keyboard-workflow callouts, Galaxy AI Writing Assist compatibility note for One UI 7+, Grammarly Keyboard replacement note, and release-front-door refresh. (notes)
- v1.8.69 (2026-05-17) — Bump-batch A: coroutines
1.11.0, KSP2.3.8, ZXing3.5.4, and AboutLibraries14.2.0; beta AboutLibraries15.0.0-b01intentionally skipped. (notes) - v1.8.68 (2026-05-17) — N7.6 Tink / AndroidKeystore migration: removed AndroidX Security Crypto, added shared Tink encrypted-preference wrapper, migrated SQLCipher passphrase and legacy clipboard-history payloads one time when old keysets remain readable. (notes)
- v1.8.67 (2026-05-17) — N12.5 reproducible-build self-verification CI: new build-twice release APK workflow plus
scripts/verify-reproducible-apk.shclean-worktree byte comparison and drift manifests. (notes) - v1.8.66 (2026-05-17) — N8.7 Article 50 transparency surface: first-run Review local AI features setup step, reopenable Settings → About → AI features in this keyboard screen, docs links, and catalog test coverage for next-word / glide / voice / translation / smart-compose disclosures. (notes)
- v1.8.65 (2026-05-17) — Phase A3 Settings wiring: Export encrypted passphrase dialog +
.sfexpcreate-document flow, direct encrypt-then-write personal-dictionary export,SFEXP1import sniffing, passphrase decrypt, andDictionaryImporter/rollback-summary routing for decrypted SwiftFloris combined-list files. (notes) - v1.8.64 (2026-05-17) — Phase D1: calendar quick-insert (
QuickAction.InsertCalendarEvent) reads localCalendarContract.Instancesentries for today + next 7 days, opens an IME-local agenda picker, and inserts the selected event title + date/time.READ_CALENDARis requested only after explicit tap. (notes) - v1.8.63 (2026-05-17) — Phase C3: bundled SwiftKey High Contrast (AAA) and Aurora Animated themes, with Snygg stylesheet tests and a reduced-motion-aware GenericShape aurora background. (notes)
- v1.8.62 (2026-05-17) — Phase C1: split-keyboard renderer wire-up with gutter-aware layout, viability gating, and touch-hit suppression inside the gutter. (notes)
- v1.8.61 (2026-05-17) — Phase B2: quick-prediction-insert threshold tuning with a configurable weighted-confidence floor and aligned plain-space suppression. (notes)
- v1.8.60 (2026-05-17) — Phase B1: multilingual cold-start sentence/phrase priors plus top-1,000 Zipf seed overlays for CS/DE/ES/FR/IT/PT. (notes)
- v1.8.59 (2026-05-17) — Phase D3: Typing Stats now shows current-week accepted corrections versus last week, backed by bounded weekly metadata in
CorrectionOutcomePriors. (notes) - v1.8.58 (2026-05-17) — Phase D2: generic task-creation quick action (
QuickAction.InsertTask). On-device replacement for SwiftKey's Microsoft-To-Do tile viaIntent.ACTION_SENDchooser; works with Tasks.org / OpenTasks / Google Tasks / Joplin / Notion / Markor.SensitiveFieldGuardgate. (notes) - v1.8.57 (2026-05-17) — Phase C2: SwiftKey "Modes → Arrow keys" parity via new
BottomRowPreset.Navigation(← ↑ space ↓ → enter). (notes) - v1.8.56 (2026-05-17) — Phase B4: same-sentence language-switch hardening via geometric-decay weighted blend in
TrailingContextLanguageBlend. (notes) - v1.8.55 (2026-05-17) — Phase B3: shared-spelling bilingual handling — sub-floor
0.30confidence on one-locale candidates overwriting shared typed words. (notes) - v1.8.54 (2026-05-17) — Phase A3 codec primitive: encrypted-blob personal-dictionary export envelope (AES-256-GCM + PBKDF2-HMAC-SHA-256 at OWASP-2025's 600 000 iterations). (notes)
- v1.8.53 (2026-05-17) — Phase A2: post-import confirmation + rollback dialog + wired
DictionaryImporterinto Settings UI. (notes) - v1.8.52 (2026-05-17) — SwiftKey migration outreach push: README banner + opening pitch lead with the 2026-05-31 cutoff, badge promoted, parity-roadmap permalink linked. (notes)
- v1.8.51 (2026-05-17) — N14.3 + N14.4 Compose BOM + Gradle wrapper dependency-pin audits. New audit-log table in
docs/DEPENDENCY_TRIAGE.md. (notes) - v1.8.50 (2026-05-17) — N17.1 emoji-picker crash triage; root-caused to
Paint.hasGlyph("")and closed with three defensive filters. (notes) - v1.8.49 (2026-05-17) — N15.3 Smart Edit voice REMOVE_ITEM_FROM_LIST: new parameterised voice-command type that excises a named item from the dictated buffer mid-stream. (notes)
- v1.8.48 (2026-05-17) — Adversarial-input + lifecycle hardening pass across the SwiftKey JSON importer, MCP daemon bridge, IME service teardown, voice-model install, ZIP extraction, and DB cursor handling. (notes)
- v1.8.47 (2026-05-16) — N1.4 FUTO swipe-trace replay and benchmark harness. (notes)
- v1.8.46 (2026-05-16) — SwiftKey
swiftkey-cloud.jsonimport parser ahead of the 2026-05-31 account retirement. NewDictionaryImportFormat.JSON+ tolerantparseSwiftKeyJson. (notes) - v1.8.45 (2026-05-16) — Android 17 IME-visibility restore across configuration changes. (notes)
- v1.8.44 (2026-05-16) — Long-press popup guard on password fields (
KeyVariation.PASSWORD). (notes) - v1.8.43 (2026-05-16) — Roborazzi plugin unblocked at 1.55.0; visual-regression CI step added. (notes)
- v1.8.42 (2026-05-16) — Kotlin 2.3.20 → 2.3.21 bug-fix bump. (notes)
- v1.8.41 (2026-05-16) — Auto-return to letter keyboard after apostrophe in symbols panel. (notes)
- v1.8.40 (2026-05-16) — Per-daemon enable / disable for the MCP bridge in Settings. (notes)
- v1.8.35–v1.8.39 — Full MCP daemon bridge: AIDL surface, AndroidMcpClient, per-daemon bind lifecycle, discoverer, IME-startup wire-up, Settings UI.
- v1.8.34 — Macrobenchmark trace instrumentation across six production hot paths.
- v1.8.31–v1.8.33, v1.8.79 — Honeycomb hex renderer foundation (
HoneycombHexShape+HoneycombHexButton+HoneycombKeyboardRow+HoneycombLayoutLoader) and productionTextKeyboardLayoutwire-up. - v1.8.0–v1.8.30 — Smart-compose / inline-translation router stack, KenLM reader pipeline, 63-script transliteration build-out, addon scaffold sweep, SwiftKey-parity slices.
- v1.7.x — Multilingual hot-switch, bigram + trigram next-word, adaptive touch, SymSpell d1+d2, Flow Through Space, encrypted personal dictionary.
- v1.6.0 — Personal-learning dictionary + 117k SCOWL English + SwiftKey design tokens.
- v1.5.0 — FUTO Voice Input integration (replacing Google Speech Recognizer).
See `ROADMAP.md` §3 for the full reconciled version table back to v1.1.0.
Contributing
SwiftFloris welcomes focused contributions in themes, dictionary packs,
transliteration tables, performance work, bug fixes, accessibility, and docs.
Before opening a PR, read `CONTRIBUTING.md` and keep the
base-app invariants intact: no network permission, no telemetry, no account
binding, Apache-2.0-compatible :app code, and no closed-source blobs.
Troubleshooting
Gesture typing not working?
See Multilingual Gesture Typing. Gesture typing currently uses the bounded statistical engine for EN / DE / ES / FR / IT / PT; the neural / open-glide path is gated on the HeliBoard NLnet release.
Voice input unavailable?
See FUTO Voice Input Troubleshooting. SwiftFloris does not record audio itself; live dictation hands off to the user-installed FUTO Voice Input app or another enabled external voice keyboard. The in-app Whisper/Vosk catalog is preview-only until the local recognizer runtime ships.
Keyboard crashes on emoji insertion?
Root-caused in v1.8.50 (ROADMAP §6 N17.1, release notes, GitHub issue #1). The trigger was Paint.hasGlyph("") aborting the palette render whenever an empty-value Emoji reached the initial filter pass. Three defensive filters landed at the palette, history-mapping, and asset-loader layers. If you still see this on v1.8.50+ please attach the device model, Android build, ROM, and a logcat capture to the issue.
Theme changes not applying?
Force-close the keyboard via Settings → Apps → SwiftFloris → Force stop, then re-open a text field. If a theme imported from an extension package fails, check Settings → Extensions for the asset's status — the asset resolver canonicalises paths and rejects anything outside the loaded theme directory.
License
Copyright 2026 SwiftFloris Contributors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Acknowledgments
- FlorisBoard — Solid IME architecture and Snygg theme engine.
- FUTO — Privacy-first voice input, available as a separate app.
- SCOWL — English word list.
- Bergamot, librime, KenLM, LiteRT-LM — Open-source language stacks that the addon scaffolds target.
- HeliBoard, AnySoftKeyboard, Unexpected Keyboard, Thumb-Key, fcitx5-android, Trime, OpenBoard — Adjacent open-source keyboards that this project learns from.
- Jetpack Compose and Material Design 3 — Modern Android UI.
Status
🚀 Active development. Current release: v1.8.170 (2026-05-18). Migration window for SwiftKey users closes 2026-05-31 — 13 days from this release.
Quick Links
| Resource | Link |
|---|---|
| GitHub | https://github.com/SysAdminDoc/SwiftFloris |
| Issues | https://github.com/SysAdminDoc/SwiftFloris/issues |
| Releases | https://github.com/SysAdminDoc/SwiftFloris/releases |
| Roadmap | ROADMAP.md |
| SwiftKey migration | docs/MIGRATE_FROM_SWIFTKEY.md |
| Privacy and AI | docs/PRIVACY_AND_AI.md |
| Threat model | docs/THREAT_MODEL.md |
| FUTO Voice | https://voiceinput.futo.org/ |
| FlorisBoard upstream | https://github.com/florisboard/florisboard |
Made for privacy and offline-first computing.