Skip to content

fix(MainActivity): grant WebView audio capture after RECORD_AUDIO grant (#63) - #93

Open
jim-daf wants to merge 1 commit into
woheller69:masterfrom
jim-daf:fix/issue-63-voice-input
Open

jim-daf wants to merge 1 commit into
woheller69:masterfrom
jim-daf:fix/issue-63-voice-input

Conversation

@jim-daf

@jim-daf jim-daf commented Apr 26, 2026

Copy link
Copy Markdown
Contributor

Forward the OS mic grant to the WebView (refs #63)

Resolves #63

What is happening

Issue #63 reports voice input not working on Huawei WebView with MicroG. Two real bugs in onPermissionRequest cause this even when the OS mic permission is granted:

  1. The check only looks at request.getResources()[0]. Some WebView builds (Huawei in particular) request capture alongside other resources or in a different order, so the equality check at index 0 fails and the request falls through to request.deny().
  2. When RECORD_AUDIO is not yet granted at the OS level, requestPermissions(...) is called but the PermissionRequest is dropped on the floor. After the user grants the mic in the dialog, onRequestPermissionsResult only shows a toast. The original PermissionRequest is never granted, so the WebView still thinks the page was denied. The TODO comment in the original source already calls this out.

The fix

Scan all resources for audio capture and cache the request:

boolean wantsAudio = false;
for (String r : request.getResources()) {
    if (android.webkit.PermissionRequest.RESOURCE_AUDIO_CAPTURE.equals(r)) {
        wantsAudio = true;
        break;
    }
}
if (!wantsAudio) {
    request.deny();
    return;
}
if (checkSelfPermission(Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED) {
    request.grant(new String[]{android.webkit.PermissionRequest.RESOURCE_AUDIO_CAPTURE});
    return;
}
pendingAudioPermissionRequest = request;
requestPermissions(new String[]{Manifest.permission.RECORD_AUDIO}, 123);

Then in onRequestPermissionsResult:

if (pendingAudioPermissionRequest != null) {
    if (granted) {
        pendingAudioPermissionRequest.grant(
                new String[]{android.webkit.PermissionRequest.RESOURCE_AUDIO_CAPTURE});
    } else {
        pendingAudioPermissionRequest.deny();
    }
    pendingAudioPermissionRequest = null;
}

Why this fixes the Huawei + MicroG case

The OP confirmed three things:

  • the page does call into the WebView (the mic button appears)
  • the OS mic permission was granted manually
  • voice works in Chrome on the same device

That rules out the page itself, the mic hardware, and the OS layer. What is left is the bridge between the WebView's PermissionRequest and Activity.onRequestPermissionsResult, which is exactly what this PR repairs.

The Huawei WebView angle is a side note. The first bug (index-0 only check) is what hits Huawei WebView specifically because its PermissionRequest resource ordering differs from AOSP. The second bug (not forwarding the grant) hits everyone the first time they grant the mic.

Files changed

  • app/src/main/java/org/woheller69/gptassist/MainActivity.java

…granted (woheller69#63)

The previous onPermissionRequest only matched RESOURCE_AUDIO_CAPTURE
at index 0 of request.getResources() and never forwarded the OS
RECORD_AUDIO grant back to the WebView, so on Huawei WebView and
other builds the mic was effectively never granted, causing the
voice button to do nothing as reported in woheller69#63.

Now the resource array is scanned for RESOURCE_AUDIO_CAPTURE and
the PermissionRequest is cached so onRequestPermissionsResult can
call request.grant once the user answers the dialog.
@jim-daf
jim-daf marked this pull request as ready for review April 26, 2026 10:04
Copilot AI review requested due to automatic review settings April 26, 2026 10:04

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes WebView microphone permission handling so that RECORD_AUDIO grants at the OS level are correctly forwarded back to the originating WebView PermissionRequest, addressing voice input failures (notably reported on Huawei WebView).

Changes:

  • Scan the full PermissionRequest.getResources() array for RESOURCE_AUDIO_CAPTURE instead of only checking index 0.
  • Cache the pending WebView PermissionRequest when OS mic permission is not yet granted, and grant/deny it in onRequestPermissionsResult.
  • Add comments clarifying the rationale (Issue #63).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +205 to +207
if (checkSelfPermission(Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED) {
request.grant(new String[]{android.webkit.PermissionRequest.RESOURCE_AUDIO_CAPTURE});
return;

Copilot AI Apr 26, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

onPermissionRequest auto-grants microphone capture based solely on the OS RECORD_AUDIO permission. When the app is in unrestricted browsing mode, this means any origin loaded in the WebView can get mic access without a per-site/user confirmation. Consider additionally gating the grant by request.getOrigin() (e.g., only allowlisted hosts / only when restricted is true) or showing an explicit confirmation dialog before calling request.grant(...).

Copilot uses AI. Check for mistakes.
Comment on lines +209 to +212
// Cache the request so we can grant it after the OS
// dialog returns, then ask for RECORD_AUDIO.
pendingAudioPermissionRequest = request;
requestPermissions(new String[]{Manifest.permission.RECORD_AUDIO}, 123);

Copilot AI Apr 26, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pendingAudioPermissionRequest is overwritten unconditionally. If the WebView triggers another onPermissionRequest before the user responds to the OS prompt, the earlier PermissionRequest will never be granted/denied (and you may trigger multiple OS prompts). Consider either denying any existing pending request before overwriting it, or short-circuiting when one is already pending.

Copilot uses AI. Check for mistakes.
// Cache the request so we can grant it after the OS
// dialog returns, then ask for RECORD_AUDIO.
pendingAudioPermissionRequest = request;
requestPermissions(new String[]{Manifest.permission.RECORD_AUDIO}, 123);

Copilot AI Apr 26, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Request code 123 is a magic number used in both requestPermissions(...) and onRequestPermissionsResult. Defining a named static final int constant (similar to FILE_CHOOSER_REQUEST_CODE) would make this easier to maintain and reduces the chance of collisions with future permission requests.

Copilot uses AI. Check for mistakes.
@woheller69

Copy link
Copy Markdown
Owner

I cannot test if this fixes the issue. On all my devices it is working anyway.
You can upload an apk (rename to zip) in issue #63.
If other users confirm that this is working I will merge it.

@jim-daf

jim-daf commented Apr 26, 2026

Copy link
Copy Markdown
Contributor Author

@woheller69 Built a debug APK from this branch and posted it (both .apk and a renamed .zip) on issue #63 for testing:

https://github.com/jim-daf/gptAssist/releases/tag/pr93-debug

(comment: #63 (comment))

It's debug-signed, so it's only useful for the affected users to confirm the fix. Obviously a real release build would have to come from your signing key.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Voice input not working on Huawei WebView

3 participants