Questo documento traccia le fasi del refactoring modulare dell’IME fisica di Pastiera, con l’obiettivo di ridurre il “god class” PhysicalKeyboardInputMethodService, migliorare il riuso e facilitare futuri test automatizzati. Ogni fase è stata pensata per essere behaviour-preserving e accompagnata da build/test lato utente.
Extract KeyMappingLoader, layout managers, and variation map loading into data/ classes with interfaces.
Keep current JSON/schema untouched; service keeps using same loaders via new wrappers.
Create ModifierStateController that owns shift/ctrl/alt states and sync helpers; replace direct properties with delegation while keeping public behavior identical.
Wrap NavModeHandler into NavModeController to manage latch state, notifications, and entry/exit rules.
Centralize detection of numeric/password/restricted fields and shouldDisableSmartFeatures computation to reduce duplication.
Move SYM page state, variation activation, and auto-close logic into SymLayoutController, exposing intents like onSymKey, onVariationRequested, onSymMappingResolved.
Implement CandidatesBarController to replace empty CandidatesViewManager, and KeyboardVisibilityController to manage view creation/show/hide; service calls these instead of direct UI mutations.
Add router that decides between nav-mode handling, launcher shortcuts, text input flow, and delegates to controllers; service’s onKeyDown/Up/LongPress/Motion delegate to router.
Move autocorrect undo, double-space period, auto-capitalization triggers, and backspace handling into TextInputController + AutoCorrectionManager, preserving sequence and preference checks.
Rename to PastieraImeService (or keep name) and limit it to lifecycle wiring, dependency setup, and delegating events to controllers; ensure settings listener and broadcasts are reattached without logic change.
Remove dead/unused artifacts (e.g., empty CandidatesViewManager) once replacements are wired.
Run regression checks (same unit/UI tests) after each step to confirm behavior parity.
- ✅ Dati e repository: i loader JSON e i repository (
data/) sono usati da servizio, schermate e manager (fase 1). - ✅ Controller core:
ModifierStateController,NavModeController,SymLayoutController,TextInputController,AutoCorrectionManagereInputContextStatesono cablati nel servizio (fasi 2–5). - ✅ UI status bar:
StatusBarControllerconLedStatusView/VariationBarViewgestisce modalità FULL e CANDIDATES (fase 6). ⚠️ Variazioni/SYM:variationsMap,lastInsertedChar,availableVariationse le istanze diStatusBarControllervivono ancora inPhysicalKeyboardInputMethodService.⚠️ Gestione viste IME:onCreateInputView,onCreateCandidatesView,onEvaluateInputViewShowneensureInputViewCreatedsono logica ad-hoc del servizio; manca unKeyboardVisibilityController.⚠️ Instradamento eventi:onKeyDown/Up/LongPressè una god function >700 righe; non c’è ancora unInputEventRouter.- ⏳ Snellimento servizio: la classe principale resta >1.700 righe; rename/estrazione a
PastieraImeServicenon ancora eseguiti.
Obiettivo: isolare accesso a JSON/layout/variations dal servizio IME.
- Nuove classi:
data/layout/LayoutMappingRepository,JsonLayoutLoader,LayoutFileStoredata/variation/VariationRepositorydata/mappings/KeyMappingLoader(spostato fuori dainputmethod)
- Principali cambiamenti:
PhysicalKeyboardInputMethodServiceora carica layout, nav-mode mappings e variazioni tramite i repository (nessuna logica JSON nel servizio).KeyboardLayoutSettingsScreen,NavModeSettingsScreen,SettingsManageraggiornati a usare i nuovi moduli.AltSymManagereAutoCorrectorcontinuano a funzionare ma consumano le nuove API.
- Testing suggerito: cambio layout, import/export JSON, long-press/auto-correct con keyboard fisica.
Obiettivo: centralizzare stato Shift/Ctrl/Alt e nav-mode per ridurre duplicazione e accoppiamento.
-
core/ModifierStateController- Mantiene gli stati
Shift/Ctrl/Alt(pressed/latch/one-shot/physically pressed) e sincronizza automaticamente conAutoCapitalizeHelper. - Espone snapshot per la Status Bar e funzioni
handleShift/Ctrl/AltKeyDown/Up.
- Mantiene gli stati
-
core/NavModeController- Incapsula NavModeHandler, latch state & notifiche.
- Decide se una key è nav-mode, gestisce DPAD mapping e conserva la latched-state tra servizi/UI.
-
PhysicalKeyboardInputMethodService- Ridotto ai wiring: delega key handling a
ModifierStateControllereNavModeController. - Status bar aggiornata via snapshot, niente più accesso diretto ai campi
ShiftState/CtrlState.
- Ridotto ai wiring: delega key handling a
-
Testing suggerito: double-tap shift/caps lock, ctrl latch + nav mode (fuori da text field), alt latch/one-shot, status bar LED.
Obiettivo: isolare tutta la logica SYM (pagine emoji/simboli, auto-close, restore, UI data).
-
core/SymLayoutController- Gestisce
symPage, persistenza, restore daSettingsManager, auto-close rules e snapshot per UI. - Espone
handleKeyWhenActiveconSymKeyResultper distinguereCONSUME,CALL_SUPER,NOT_HANDLED. - Fornisce
emojiMapText()ecurrentSymMappings()per StatusBar/Candidates.
- Gestisce
-
Priorità Alt/Ctrl (correzioni successive)
- Alt: chiude sempre SYM all’attivazione per permettere agli Alt mappings di funzionare subito.
- Ctrl: bypassa la griglia SYM; con latch/pressed, i Ctrl shortcuts (es. DPAD, copy/paste) hanno precedenza, mantenendo SYM aperto finché Ctrl resta attivo.
- Inserimento SYM via tastiera fisica chiude il layout quando auto-close è attivo; gli inserimenti via touchscreen lo lasciano aperto.
-
UI: la Status Bar riceve ora
emojiMapText/symMappingsdirettamente dal controller, mantenendo il layout LED coerente fra input e candidates view. -
Testing suggerito:
- Cycle SYM (0→emoji→symbols) e verifica persistenza/restore.
- Inserisci simboli via tastiera con Alt/Ctrl attivi: Alt deve chiudere SYM, Ctrl non deve inserire simboli.
- Inserisci gli stessi simboli via touchscreen: SYM resta aperto.
- Verifica auto-close su Back/Enter/Alt e dopo commit fisico (quando l’opzione è abilitata).
Obiettivo: spostare auto-correct, double-space, auto-cap e undo fuori dal servizio e in controller dedicati.
-
core/TextInputController- Gestisce double-space→“. ”, auto-cap dopo punteggiatura e Enter; usa
ModifierStateControllerper lo Shift one-shot e centralizza il timing (50 ms) nell’AutoCapitalizeHelper.
- Gestisce double-space→“. ”, auto-cap dopo punteggiatura e Enter; usa
-
core/AutoCorrectionManager- Incapsula undo via Backspace, correzioni su spazio/punteggiatura e accettazione/clear dei reject su altri tasti.
-
PhysicalKeyboardInputMethodService- Deleghe per oltre 200 righe di logica text pipeline; ora richiama solo i metodi dei controller e aggiorna la status bar via callback.
-
Auto-cap delay
- Il servizio non passa più
delayMspersonalizzati: la tempistica è centralizzata nell’helper (default 50 ms) così futuri tweak richiedono una modifica sola.
- Il servizio non passa più
-
Testing suggerito:
- Digita una parola autocorretta e premi Backspace subito → deve ripristinare la parola originale.
- Double-space produce “. ”, abilita Shift one-shot e non introduce ritardi percepibili.
- Auto-correction/accept/reset continua a funzionare su spazio/punteggiatura e altri tasti.
- Campi con smart features disabilitate ignorano tutte le funzioni sopra.
Obiettivo: avere un’unica fonte di verità per lo stato del campo attivo (editable/numeric/password/restricted) e per il flag shouldDisableSmartFeatures.
-
core/InputContextState- Nuovo snapshot immutabile creato da
EditorInfoche esponeisEditable,isReallyEditable,isNumericFielde il motivo di restrizione (password/URI/email/filter). - Fornisce helper
shouldDisableSmartFeaturescosì il servizio non ricalcola più manualmente le bitmask dell’inputType. isNumericFieldconsidera siaTYPE_CLASS_NUMBERsiaTYPE_CLASS_PHONE, quindi anche i campi telefono applicano subito le mappature Alt.
- Nuovo snapshot immutabile creato da
-
PhysicalKeyboardInputMethodService- Sostituiti i campi
isNumericFieldeshouldDisableSmartFeaturescon getter che leggono dallo snapshot. - Rimossi
checkFieldEditabilitye la vecchia funzioneshouldDisableSmartFeatures(info), ora la logica sta tutta inInputContextState. - Introdotta
enforceSmartFeatureDisabledState()per applicare/hide candidates e variazioni in modo coerente sia in restart sia in start “fresh”.
- Sostituiti i campi
-
Testing suggerito:
- Campi password/URI/email/filter devono disattivare status LED delle variazioni e non mostrare candidates.
- Campi numerici devono continuare a committare i caratteri Alt direttamente (nessun crash in long-press).
- Passare rapidamente da un campo testo “normale” a uno password non deve lasciare stato sporco nella status bar.
Obiettivo: separare la Status Bar in componenti modulari per riuso (anche nella sola visuale candidates) e ridurre il codice monolitico.
-
inputmethod/ui/LedStatusView- Incapsula la creazione/aggiornamento degli indicatori Shift/SYM/Ctrl/Alt.
StatusBarControllerdelega ora gli update dei LED allo snapshot, evitando duplicazioni di colore/stato.
-
inputmethod/ui/VariationBarView- Gestisce variazioni, overlay swipe, microfono e pulsante Settings con animazioni dedicate.
- Espone callback per
onVariationSelected/onCursorMovede lancia direttamenteSpeechRecognitionActivity/SettingsActivity.
-
StatusBarController- Supporta il nuovo
Mode(FULLvsCANDIDATES_ONLY). PhysicalKeyboardInputMethodServiceusaMode.CANDIDATES_ONLYper la sola candidates view: vengono mostrati solo i LED e, quando richiesto, il layout SYM (nessuna barra variazioni/microfono).- Il service continua a delegare gli snapshot, ma con una classe >300 righe più corta e priva di logica duplicata per variazioni/LED.
- Supporta il nuovo
-
Testing suggerito:
- Modalità completa: variazioni + microfono continuano a reagire a swipe/click; aprire i Settings e avviare il microfono.
- Modalità “solo candidates” (disabilitando la tastiera virtuale dall’IME selector): verificare che compaiano solo LED e griglia SYM quando attivata.
- Toggle rapido SYM ↔ variazioni in entrambe le modalità per individuare glitch di animazione.
7A. UI surface controllers
- Estrarre
CandidatesBarController(rimpiazzainputmethod/CandidatesViewManager.kt) per possederevariationsMap, stato SYM e aggiornare le dueStatusBarController. - Introdurre
KeyboardVisibilityControllerche gestisce creazione e visibilità delle viste IME (onCreateInputView,onCreateCandidatesView,onEvaluateInputViewShown,ensureInputViewCreated,setCandidatesViewShown,requestShowSelf). 7B. Input Event Router - Implementare
InputEventRouter(nuovo pacchettoinputmethod/events/) per smistareonKeyDown/Up/LongPress/Motiontra nav-mode, shortcut launcher, text pipeline, SYM/Alt e fallback al sistema. 7C. Service slim down & cleanup - Rinominare o confermare
PastieraImeService, lasciandolo limitato al lifecycle wiring e ai listener. - Rimuovere artefatti morti (
CandidatesViewManager, duplicazioni) e assicurare che i nuovi controller espongano hook per test/regressioni.
Ogni fase continuerà a essere accompagnata da assembleDebug e test manuali suggeriti per garantire parità funzionale.
- Cambio layout fisico, import/export JSON.
- Shift/Ctrl/Alt double-tap + status bar LED.
- Nav mode (fuori campo testo) con DPAD + ritorno in campo testo.
- SYM: toggle, auto-close, Alt priority, Ctrl shortcuts while SYM is open.
- Long-press Alt/SYM e Alt+Space.
- Inserimento touch vs fisico per emoji/simboli.
Con questa struttura modulare, le prossime fasi potranno concentrarsi su UI e text pipeline senza toccare nuovamente il servizio principale, riducendo il rischio di regressioni.