From 6430454bf669419d6cdc82aa8d7ff54f77ccdc0e Mon Sep 17 00:00:00 2001 From: Alexandre Jacinto Date: Thu, 26 Mar 2026 15:18:53 -0400 Subject: [PATCH 1/3] fix: properly ask for gallery permissions --- .../plugins/camera/CameraPlugin.kt | 2 +- .../plugins/camera/IonCameraFlow.kt | 41 +++++++++++++++++-- 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/android/src/main/java/com/capacitorjs/plugins/camera/CameraPlugin.kt b/android/src/main/java/com/capacitorjs/plugins/camera/CameraPlugin.kt index e7515f1..1968efe 100644 --- a/android/src/main/java/com/capacitorjs/plugins/camera/CameraPlugin.kt +++ b/android/src/main/java/com/capacitorjs/plugins/camera/CameraPlugin.kt @@ -160,7 +160,7 @@ class CameraPlugin : Plugin() { */ @PermissionCallback private fun ionCameraPermissionsCallback(call: PluginCall) { - ionFlow.handleCameraPermissionsCallback(call) + ionFlow.handlePermissionsCallback(call) } override fun requestPermissionForAliases( diff --git a/android/src/main/java/com/capacitorjs/plugins/camera/IonCameraFlow.kt b/android/src/main/java/com/capacitorjs/plugins/camera/IonCameraFlow.kt index 15d91e5..9023bc5 100644 --- a/android/src/main/java/com/capacitorjs/plugins/camera/IonCameraFlow.kt +++ b/android/src/main/java/com/capacitorjs/plugins/camera/IonCameraFlow.kt @@ -320,6 +320,8 @@ class IonCameraFlow( } private fun openGallery(call: PluginCall) { + if (!checkGalleryPermissions(call)) return + val manager = galleryManager ?: run { sendError(IONCAMRError.CONTEXT_ERROR) return @@ -984,13 +986,46 @@ class IonCameraFlow( return true } - fun handleCameraPermissionsCallback(call: PluginCall) { - if (permissionHelper.getPermissionState(CAMERA) != PermissionState.GRANTED) { + private fun checkGalleryPermissions(call: PluginCall): Boolean { + // Android 10+ does not require storage permissions to use the system gallery picker + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + return true + } + val needGalleryPerms = permissionHelper.isPermissionDeclared(SAVE_GALLERY) + val hasGalleryPerms = !needGalleryPerms || permissionHelper.getPermissionState(SAVE_GALLERY) == PermissionState.GRANTED + if (!hasGalleryPerms) { + permissionHelper.requestPermissionForAlias(SAVE_GALLERY, call, "ionCameraPermissionsCallback") + return false + } + return true + } + + fun handlePermissionsCallback(call: PluginCall) { + // chooseFromGallery does not require CAMERA permission + if (call.methodName != "chooseFromGallery" && + permissionHelper.getPermissionState(CAMERA) != PermissionState.GRANTED) { sendError(IONCAMRError.CAMERA_PERMISSION_DENIED_ERROR) return } - when (call.getMethodName()) { + // On Android <= 9, SAVE_GALLERY (READ/WRITE_EXTERNAL_STORAGE) is required: + // - for takePhoto/recordVideo when saveToGallery is true + // - always for chooseFromGallery (READ_EXTERNAL_STORAGE is needed to access the gallery) + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { + val needsGalleryPerm = when (call.methodName) { + "takePhoto" -> cameraSettings?.saveToGallery ?: false + "recordVideo" -> videoParameters?.saveToGallery ?: false + "chooseFromGallery" -> true + else -> false + } + val galleryPermDeclared = permissionHelper.isPermissionDeclared(SAVE_GALLERY) + if (needsGalleryPerm && galleryPermDeclared && permissionHelper.getPermissionState(SAVE_GALLERY) != PermissionState.GRANTED) { + sendError(IONCAMRError.GALLERY_PERMISSION_DENIED_ERROR) + return + } + } + + when (call.methodName) { "takePhoto" -> openCamera(call) "recordVideo" -> openRecordVideo(call) "chooseFromGallery" -> openGallery(call) From fc61c0e0c631b9e0f4302715286725ebd7e9e578 Mon Sep 17 00:00:00 2001 From: Alexandre Jacinto Date: Thu, 26 Mar 2026 17:26:17 -0400 Subject: [PATCH 2/3] chore: update errors --- .../java/com/capacitorjs/plugins/camera/IonCameraFlow.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/android/src/main/java/com/capacitorjs/plugins/camera/IonCameraFlow.kt b/android/src/main/java/com/capacitorjs/plugins/camera/IonCameraFlow.kt index 9023bc5..64400d2 100644 --- a/android/src/main/java/com/capacitorjs/plugins/camera/IonCameraFlow.kt +++ b/android/src/main/java/com/capacitorjs/plugins/camera/IonCameraFlow.kt @@ -294,7 +294,7 @@ class IonCameraFlow( sendError(it) } } catch (ex: Exception) { - sendError(IONCAMRError.VIDEO_CAPTURE_NOT_SUPPORTED_ERROR) + sendError(IONCAMRError.CAPTURE_VIDEO_ERROR) } } } @@ -542,7 +542,7 @@ class IonCameraFlow( processResultEditFromGallery(intent) } else { lastEditUri = null - sendError(IONCAMRError.EDIT_OPERATION_CANCELLED_ERROR) + sendError(IONCAMRError.EDIT_CANCELLED_ERROR) } } else -> sendError(IONCAMRError.EDIT_IMAGE_ERROR) @@ -575,7 +575,7 @@ class IonCameraFlow( private fun handleEditResult(result: ActivityResult) { when (result.resultCode) { Activity.RESULT_OK -> processResultFromEdit(result) - Activity.RESULT_CANCELED -> sendError(IONCAMRError.EDIT_OPERATION_CANCELLED_ERROR) + Activity.RESULT_CANCELED -> sendError(IONCAMRError.EDIT_CANCELLED_ERROR) else -> sendError(IONCAMRError.EDIT_IMAGE_ERROR) } } @@ -700,7 +700,7 @@ class IonCameraFlow( processResult(intent) } else { lastEditUri = null - sendError(IONCAMRError.EDIT_OPERATION_CANCELLED_ERROR) + sendError(IONCAMRError.EDIT_CANCELLED_ERROR) } } else -> sendError(IONCAMRError.EDIT_IMAGE_ERROR) From 4240ed8516443ebf68c9e01b45102b1966319235 Mon Sep 17 00:00:00 2001 From: Alexandre Jacinto Date: Fri, 27 Mar 2026 09:37:14 -0400 Subject: [PATCH 3/3] fix: use proper error --- .../main/java/com/capacitorjs/plugins/camera/IonCameraFlow.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/src/main/java/com/capacitorjs/plugins/camera/IonCameraFlow.kt b/android/src/main/java/com/capacitorjs/plugins/camera/IonCameraFlow.kt index 64400d2..7517744 100644 --- a/android/src/main/java/com/capacitorjs/plugins/camera/IonCameraFlow.kt +++ b/android/src/main/java/com/capacitorjs/plugins/camera/IonCameraFlow.kt @@ -268,7 +268,7 @@ class IonCameraFlow( currentCall = call manager.takePhoto(activity, settings.encodingType, cameraLauncher) } catch (ex: Exception) { - sendError(IONCAMRError.FAILED_TO_CAPTURE_IMAGE_ERROR) + sendError(IONCAMRError.TAKE_PHOTO_ERROR) } } }