Add bitmap safety in onCaptureSuccess callback

Track the current bitmap through the decode→rotate→effect pipeline
with a nullable variable. On exception, the in-flight bitmap is
recycled in the catch block to prevent native memory leaks. Errors
are now logged with Log.e and a proper companion TAG.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Ole-Morten Duesund 2026-02-27 15:20:57 +01:00
commit f0249fcd64

View file

@ -5,6 +5,7 @@ import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Matrix
import android.location.Location
import android.util.Log
import androidx.camera.core.ImageCapture
import androidx.camera.core.ImageCaptureException
import androidx.camera.core.ImageProxy
@ -28,6 +29,10 @@ class ImageCaptureHandler(
private val photoSaver: PhotoSaver
) {
companion object {
private const val TAG = "ImageCaptureHandler"
}
/**
* Holds the processed bitmap ready for saving, produced inside the
* camera callback (synchronous CPU work) and consumed afterwards
@ -58,26 +63,30 @@ class ImageCaptureHandler(
executor,
object : ImageCapture.OnImageCapturedCallback() {
override fun onCaptureSuccess(imageProxy: ImageProxy) {
var currentBitmap: Bitmap? = null
try {
val imageRotation = imageProxy.imageInfo.rotationDegrees
var bitmap = imageProxyToBitmap(imageProxy)
currentBitmap = imageProxyToBitmap(imageProxy)
imageProxy.close()
if (bitmap == null) {
if (currentBitmap == null) {
continuation.resume(
SaveResult.Error("Failed to convert image") as Any
)
return
}
bitmap = rotateBitmap(bitmap, imageRotation, isFrontCamera)
currentBitmap = rotateBitmap(currentBitmap, imageRotation, isFrontCamera)
val processedBitmap = applyTiltShiftEffect(bitmap, blurParams)
bitmap.recycle()
val processedBitmap = applyTiltShiftEffect(currentBitmap, blurParams)
currentBitmap.recycle()
currentBitmap = null
continuation.resume(ProcessedCapture(processedBitmap))
} catch (e: Exception) {
Log.e(TAG, "Image processing failed", e)
currentBitmap?.recycle()
continuation.resume(
SaveResult.Error("Capture failed: ${e.message}", e) as Any
)