feat(app): Hintergrund-Wake als Schalter (default aus)

Punkt 2: das Wake-Wort triggerte nur im Vordergrund — eine bewusste JS-Zeile
verwarf jede Hintergrund-Erkennung (native Erkennung + Foreground-Service
liefen längst durch). Jetzt hinter Einstellung 'Auch bei gesperrtem Bildschirm
zuhören' (default aus, mehr Fehltrigger möglich). Greift live via
setBgWakeEnabled.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-08-16 11:19:06 +02:00
co-authored by Claude Opus 4.8
parent a15b8ce51a
commit 54dc4498e5
2 changed files with 66 additions and 5 deletions
+39 -5
View File
@@ -65,6 +65,28 @@ export async function saveWakeThreshold(v: number): Promise<void> {
await AsyncStorage.setItem(WAKE_THRESHOLD_STORAGE_KEY, String(v));
}
// Hintergrund-Wake: darf das Wake-Wort auch triggern, wenn die App im
// Hintergrund / der Bildschirm gesperrt ist? Default AUS — im Hintergrund
// sind die meisten „Trigger" Fehlalarme (TV, Husten, AudioFocus-Spikes).
// AN = auch bei gesperrtem Bildschirm zuhoeren. Die native Erkennung laeuft
// ohnehin durch (Foreground-Service + Wake-Locks) — dieser Schalter oeffnet
// nur das JS-Gate in onWakeDetected.
export const BG_WAKE_STORAGE_KEY = 'aria_bg_wake_enabled';
export async function loadBgWakeEnabled(): Promise<boolean> {
try {
return (await AsyncStorage.getItem(BG_WAKE_STORAGE_KEY)) === 'true';
} catch {
return false;
}
}
export async function saveBgWakeEnabled(enabled: boolean): Promise<void> {
try {
await AsyncStorage.setItem(BG_WAKE_STORAGE_KEY, String(enabled));
} catch {}
}
/** Verfuegbare Wake-Words — entsprechen den .onnx Dateien in
* android/app/src/main/assets/openwakeword/. Custom-Keywords (eigenes
* Training via openwakeword Notebook) muessen aktuell als Asset eingebaut
@@ -133,6 +155,10 @@ class WakeWordService {
* Hintergrund-Detections sind quasi immer false-positives (TV, Husten,
* AudioFocus-Switch beim Wechsel zu Musik etc.). */
private inBackground: boolean = false;
/** Wenn true: Wake-Wort triggert auch im Hintergrund / bei gesperrtem
* Bildschirm. Default false. Wird beim Arm aus AsyncStorage geladen und
* bei Aenderung in den Einstellungen via setBgWakeEnabled() aktualisiert. */
private bgWakeEnabled: boolean = false;
/** Re-Entry-Guard fuer onWakeDetected: native kann mehrere
* WakeWordDetected-Events emitten BEVOR OpenWakeWord.stop() in JS
* resolved (Bridge-Queue + Doze-Backlog). Mit dem Flag wird das zweite
@@ -214,7 +240,8 @@ class WakeWordService {
this.initInProgress = (async () => {
try {
const threshold = await loadWakeThreshold();
console.log('[WakeWord] init mit threshold=%s', threshold);
this.bgWakeEnabled = await loadBgWakeEnabled();
console.log('[WakeWord] init mit threshold=%s, bgWake=%s', threshold, this.bgWakeEnabled);
await OpenWakeWord.init(this.keyword, threshold, DEFAULT_PATIENCE, DEFAULT_DEBOUNCE_MS);
// Subscribe nur einmal
if (!this.eventSub) {
@@ -311,7 +338,14 @@ class WakeWordService {
* was als „Wake-Word" reinkommt ist Husten/TV/AudioFocus-Switch. */
setBackground(): void {
this.inBackground = true;
console.log('[WakeWord] App im Hintergrund — Detections gesperrt');
console.log('[WakeWord] App im Hintergrund — Detections %s',
this.bgWakeEnabled ? 'AKTIV (Hintergrund-Wake an)' : 'gesperrt');
}
/** Hintergrund-Wake ein/aus schalten (aus den Einstellungen). */
setBgWakeEnabled(enabled: boolean): void {
this.bgWakeEnabled = enabled;
console.log('[WakeWord] Hintergrund-Wake = %s', enabled);
}
/** App im Vordergrund: Detections wieder freigeben, plus kurzer Cooldown
@@ -326,9 +360,9 @@ class WakeWordService {
/** Wake-Word getriggert: Native-Modul pausieren, Konversation starten. */
private async onWakeDetected(): Promise<void> {
if (this.inBackground) {
console.log('[WakeWord] Trigger ignoriert (App im Hintergrund)');
import('./logger').then(m => m.reportAppDebug('wake.detect', 'ignored: app in background')).catch(()=>{});
if (this.inBackground && !this.bgWakeEnabled) {
console.log('[WakeWord] Trigger ignoriert (App im Hintergrund, Hintergrund-Wake aus)');
import('./logger').then(m => m.reportAppDebug('wake.detect', 'ignored: app in background (bg-wake off)')).catch(()=>{});
return;
}
// Re-Entry-Guard: blocken wenn ein Detection-Zyklus schon laeuft.