Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
1 of 3 tasks
diachedelic opened this issue Apr 18, 2024 · 3 comments
Closed
1 of 3 tasks

Comments

@diachedelic
Copy link
Contributor

diachedelic commented Apr 18, 2024

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

  • iOS
  • Android
  • Web

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:

private void showMediaCaptureOrFilePicker(ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams, boolean isVideo) {
// TODO: add support for video capture on Android M and older
// On Android M and lower the VIDEO_CAPTURE_INTENT (e.g.: intent.getData())
// returns a file:// URI instead of the expected content:// URI.
// So we disable it for now because it requires a bit more work
boolean isVideoCaptureSupported = android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N;
boolean shown = false;
if (isVideo && isVideoCaptureSupported) {
shown = showVideoCapturePicker(filePathCallback);
} else {
shown = showImageCapturePicker(filePathCallback);
}
if (!shown) {
Logger.warn(Logger.tags("FileChooser"), "Media capture intent could not be launched. Falling back to default file picker.");
showFilePicker(filePathCallback, fileChooserParams);
}
}

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:

private boolean showImageCapturePicker(final ValueCallback<Uri[]> filePathCallback) {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (takePictureIntent.resolveActivity(bridge.getActivity().getPackageManager()) == null) {
return false;
}

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
Copy link
Contributor Author

Seems related to react-native-webview/react-native-webview#3300.

@jcesarmobile
Copy link
Member

please, provide a full app, not a code snippet

@jcesarmobile jcesarmobile added the needs reply needs reply from the user label Apr 18, 2024
@ionitron-bot ionitron-bot bot removed the triage label Apr 18, 2024
@Ionitron
Copy link
Collaborator

Ionitron commented May 4, 2024

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 馃挋

@Ionitron Ionitron closed this as completed May 4, 2024
@Ionitron Ionitron removed the needs reply needs reply from the user label May 4, 2024
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

No branches or pull requests

3 participants