ionic-team / capacitor

Build cross-platform Native Progressive Web Apps for iOS, Android, and the Web ⚡️
https://capacitorjs.com
MIT License
11.24k stars 955 forks source link

[Bug]: <input capture> opens file picker instead of camera on Google Pixel running Android 14 #7411

Closed diachedelic closed 2 weeks ago

diachedelic commented 1 month ago

Capacitor Version

💊 Capacitor Doctor 💊

Latest Dependencies:

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

Installed Dependencies:

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

[success] iOS looking great! 👌 [success] Android looking great! 👌

Other API Details

No response

Platforms Affected

Current Behavior

If I select an input like

<input type="file" accept="image/*" capture>

on a Google Pixel 7a running Android 14, a file picker is shown instead of the camera. However, on a Samsung A52 running Android 14 the camera is shown as expected.

Expected Behavior

I expect the camera to show on all devices, including the Google Pixel.

Project Reproduction

https://gist.github.com/diachedelic/3970e9617d26d4629b6e38887a830555

Additional Information

I believe I have found the problem. It is in BridgeWebChromeClient.java.

This method is responsible for showing the camera, falling back to a file picker if the camera fails to open: https://github.com/ionic-team/capacitor/blob/5b2ab7c68db4e77b8b2961e927acc5a708ee260f/android/capacitor/src/main/java/com/getcapacitor/BridgeWebChromeClient.java#L345-L361

I can confirm that the shown variable is set to true on my Samsung, but false on my Google Pixel. Thus the file picker opens on the Google Pixel.

Digging deeper, the showImageCapturePicker method appears to be exiting early after failing to resolve the intent's activity: https://github.com/ionic-team/capacitor/blob/5b2ab7c68db4e77b8b2961e927acc5a708ee260f/android/capacitor/src/main/java/com/getcapacitor/BridgeWebChromeClient.java#L364-L368 The resolveActivity method returns null on the Google Pixel, but not on the Samsung.

If I remove this if statement entirely, the camera opens as expected on the Google Pixel. Same with the showVideoCapturePicker method. So it appears that the resolveActivity method is returning a false negative on the Google Pixel.

What about removing the if and expanding the try block to encompass all of the method's statements? Something like:

    private boolean showImageCapturePicker(final ValueCallback<Uri[]> filePathCallback) {
        try {
            Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            final Uri imageFileUri = createImageFileUri();
            takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageFileUri);
            activityListener =
                activityResult -> {
                    Uri[] result = null;
                    if (activityResult.getResultCode() == Activity.RESULT_OK) {
                        result = new Uri[] { imageFileUri };
                    }
                    filePathCallback.onReceiveValue(result);
                };
            activityLauncher.launch(takePictureIntent);
            return true;
        } catch (Exception ex) {
            Logger.error("Unable to create temporary media capture file: " + ex.getMessage());
            return false;
        }
    }
diachedelic commented 1 month ago

Seems related to https://github.com/react-native-webview/react-native-webview/discussions/3300.

jcesarmobile commented 1 month ago

please, provide a full app, not a code snippet

Ionitron commented 2 weeks ago

It looks like this issue didn't get the information it needed, so I'll close it for now. If I made a mistake, sorry! I am just a bot.

Have a great day! Ionitron 💙