Skip to content

bug: #123

@glu000

Description

@glu000

Plugin version:
6.0.1

Platform(s):
Android

Current behavior:
On Android, the partialResults event is missing the last spoken word. When speaking continuously without pauses (e.g., "I have a conflict"), the partialResults events only contain all words except the last one. The last word is never received in partialResults.

Example of actual output:
partialResults: { matches: ["I"] } partialResults: { matches: ["I have"] } partialResults: { matches: ["I have a"] } // "conflict" is never received - missing!

This is reproducible 100% of the time - the last word before a pause is always missing from partialResults.

Expected behavior:
The partialResults event should include ALL spoken words, including the last word:

partialResults: { matches: ["I"] } partialResults: { matches: ["I have"] } partialResults: { matches: ["I have a"] } partialResults: { matches: ["I have a conflict"] }

Steps to reproduce:

  1. Initialize speech recognition with partialResults: true:
await SpeechRecognition.start({
  language: 'de-DE',
  maxResults: 5,
  partialResults: true,
  popup: false
});
Add a listener for partialResults:
await SpeechRecognition.addListener('partialResults', (data) => {
  console.log('partialResults:', data.matches);
});
Speak a sentence quickly without pauses, e.g., "I have a conflict"
Observe that the last word ("conflict") never appears in partialResults
Related code: Root cause in the plugin source code: In SpeechRecognition.java, the onPartialResults() method only reads RESULTS_RECOGNITION but ignores UNSTABLE_TEXT:
// Line 313-314 in SpeechRecognition.java
@Override
public void onPartialResults(Bundle partialResults) {
    ArrayList<String> matches = partialResults.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
    // ❌ Missing: android.speech.extra.UNSTABLE_TEXT is not read!
    // The last word is stored in UNSTABLE_TEXT, not in RESULTS_RECOGNITION
The same issue exists in onResults() (line 292-293). Proposed fix:
@Override
public void onPartialResults(Bundle partialResults) {
    ArrayList<String> matches = partialResults.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
    ArrayList<String> unstableMatches = partialResults.getStringArrayList("android.speech.extra.UNSTABLE_TEXT");
    
    // Combine stable and unstable results
    if (matches != null && matches.size() > 0) {
        String completeText = matches.get(0);
        if (unstableMatches != null && unstableMatches.size() > 0 && !unstableMatches.get(0).isEmpty()) {
            completeText = completeText + " " + unstableMatches.get(0);
        }
        
        ArrayList<String> combinedMatches = new ArrayList<>();
        combinedMatches.add(completeText.trim());
        
        JSArray matchesJSON = new JSArray(combinedMatches);
        
        // Continue with existing logic...
        if (matches != null && matches.size() > 0 && !previousPartialResults.equals(matchesJSON)) {
            previousPartialResults = matchesJSON;
            JSObject ret = new JSObject();
            ret.put("matches", previousPartialResults);
            notifyListeners("partialResults", ret);
        }
    }
}
Other information: This is a well-documented Android Speech Recognition behavior where the last spoken word (which Android considers "unstable" until confirmed by a pause or continuation) is stored separately in android.speech.extra.UNSTABLE_TEXT and must be explicitly read and combined with RESULTS_RECOGNITION. References:
[Stack Overflow: Android Speech Recognition - No recognition result matched](https://stackoverflow.com/questions/59977735/android-speech-recognition-no-recognition-result-matched)
[Stack Overflow: Partial results using speech recognition](https://stackoverflow.com/questions/9859184/partial-results-using-speech-recognition)
[Stack Overflow: RecognitionListener OnPartialResults vs OnResults](https://stackoverflow.com/questions/47161433/recognitionlistener-onpartialresults-vs-onresults)
Impact: This bug makes continuous speech recognition unusable on Android for real-time transcription, voice commands, or any application requiring immediate processing of spoken input. Users effectively lose the last word of every phrase, requiring them to add unnatural pauses or repeat words. Capacitor doctor:
Latest Dependencies:

  @capacitor/cli: 7.0.2
  @capacitor/core: 7.0.2
  @capacitor/android: 7.0.2
  @capacitor/ios: 7.0.2

Installed Dependencies:

  @capacitor/cli: 7.0.2
  @capacitor/core: 7.0.2
  @capacitor/android: 7.0.2
  @capacitor/ios: 7.0.2

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions