feat(learn,todo,meditate): dictate through the phone's voice input app (ADR 0038, D18)

On Android the microphone now opens the app handling
RECOGNIZE_SPEECH (FUTO Voice Input, Google's), the default the person
chose in Android, and puts the text it returns where the cursor stood,
as Dictation does; cancelled, nothing. Only where none is installed, or
it can't be opened, does speech_to_text listen in line as before.

halkyon_app: VoiceInputApp (one listen, an answer once closed) on the
channel app.halkyon/voice_input, which DeviceSpeechInput asks first at
every listen, answering SpeechStart.finished so that Dictation doesn't
listen again; speech_to_text isn't touched on that route, so our app
asks for no microphone. SpeechInput.listen and Dictation.start take the
prompt the voice input app shows (the field's hint).

Each app: VoiceInput.kt (queryIntentActivities, startActivityForResult,
the first of EXTRA_RESULTS) attached in MainActivity, which hands it
activity results, and RECOGNIZE_SPEECH among the manifest's queries.
The privacy pages of Learn and Meditate say so.

Our own Whisper and Meditate's dream recordings are dropped (D18).

Whats-New: The microphone now dictates through your phone's voice input app, such as FUTO Voice Input.
Whats-New-De: Das Mikrofon diktiert jetzt über die Spracheingabe-App deines Telefons, etwa FUTO Voice Input.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
Tizian 「ティツィアーン」 2026-11-07 23:45:20 +01:00
commit c36bd83c6a
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64

View file

@ -406,6 +406,31 @@ void main() {
expect(find.byTooltip('Search'), findsOneWidget);
});
testWidgets('with a voice input app installed, the microphone opens it, '
'and what it returns goes into the field, once; cancelled, nothing '
"(Meditate's ADR 0038, D18)", (tester) async {
speech.app = true;
await showApp(tester);
await unfold(tester);
await tester.tap(find.byTooltip('Speak your question'));
await tester.pump();
expect(speech.appOpen, isTrue);
expect(speech.listening, isFalse, reason: 'nothing else listens');
expect(speech.prompts, ['Speak your question']);
speech.cancel();
await tester.pumpAndSettle();
expect(find.byTooltip('Speak your question'), findsOneWidget);
await tester.tap(find.byTooltip('Speak your question'));
await tester.pump();
speech.answer('what does 火 mean');
await tester.pumpAndSettle();
expect(find.text('what does 火 mean'), findsOneWidget);
expect(speech.languages, hasLength(2), reason: 'once a tap');
expect(find.byTooltip('Search'), findsOneWidget);
});
testWidgets('says so where no speech recognition is installed, and how '
'to get one, never stuck listening (GrapheneOS, 4 Nov 2026)', (
tester,