I am writing an Android application using Xamarin that has a custom activity view used to capture images using the API Camera. This job works fine on all the devices I tested, however some users reported an application crash completely when trying to take a picture. It was quickly obvious that all these users used Samsung phones, and unfortunately, I do not have one test for testing.
Fortunately, I managed to grab the exception and stack trace, but I don't understand what might cause this problem. Exception, stack trace and problematic code below.
This is a fairly simple job with full-screen camera viewing, a flash switch, and a capture button. It uses its own CameraHelperclass to configure and interact with the API Camera. The camera is configured and the preview is displayed by the method OnSurfaceTextureAvailablebefore the user can interact and launch the method TakePicture.
Exception stack trace
java.lang.RuntimeException: takePicture failed
android.hardware.Camera.native_takePicture(Native Method):0
android.hardware.Camera.takePicture(Camera.java:1523):0
android.hardware.Camera.takePicture(Camera.java:1468):0
md5efa7d89b8a471e1a97a183b83296df21.CameraHelper.n_onAutoFocus(Native Method):0
md5efa7d89b8a471e1a97a183b83296df21.CameraHelper.onAutoFocus(CameraHelper.java:39):0
Methods in CameraHelper
public void OnSurfaceTextureAvailable(object sender, TextureView.SurfaceTextureAvailableEventArgs e)
{
try
{
_camera = Camera.Open(_cameraInt);
}
catch (Exception ex)
{
_callback.OnInitializationFailed(ex);
return;
}
var orientation = GetDisplayOrientation();
_camera.SetDisplayOrientation(orientation);
var cameraParameters = _camera.GetParameters();
if (cameraParameters.SupportedFocusModes != null && cameraParameters.SupportedFocusModes.Contains(Camera.Parameters.FocusModeContinuousPicture))
cameraParameters.FocusMode = Camera.Parameters.FocusModeContinuousPicture;
if (cameraParameters.SupportedFlashModes != null && cameraParameters.SupportedFlashModes.Contains(Camera.Parameters.FlashModeAuto))
{
cameraParameters.FlashMode = Camera.Parameters.FlashModeAuto;
HasFlash = true;
}
cameraParameters.JpegQuality = JPEG_QUALITY;
var pictureSize = GetIdealPictureSize(cameraParameters.SupportedPictureSizes, MAX_MEGAPIXELS);
_imageWidth = pictureSize.Width;
_imageHeight = pictureSize.Height;
cameraParameters.SetPictureSize(pictureSize.Width, pictureSize.Height);
var previewSize = GetIdealPreviewSize(cameraParameters.SupportedPreviewSizes, _previewTexture.Height, _previewTexture.Width);
cameraParameters.SetPreviewSize(previewSize.Width, previewSize.Height);
_camera.SetParameters(cameraParameters);
_camera.SetPreviewTexture(_previewTexture.SurfaceTexture);
_camera.StartPreview();
UpdatePreviewTextureMatrix();
EventHandler<TextureView.SurfaceTextureUpdatedEventArgs> h = null;
_previewTexture.SurfaceTextureUpdated += h = (s, e2) =>
{
_previewTexture.SurfaceTextureUpdated -= h;
_callback.OnCameraPreviewReady();
_ready = true;
};
}
public void TakePicture()
{
if (!_ready || _busy)
{
var e = new Exception("Camera not ready");
OnTakePictureFailed(e);
return;
}
_busy = true;
_camera.AutoFocus(this);
}
public void OnAutoFocus(bool success, Camera camera)
{
try
{
_camera.TakePicture(null, null, this);
}
catch (Exception e)
{
OnTakePictureFailed(e);
}
}
public void OnPictureTaken(byte[] data, Camera camera)
{
_busy = false;
var rotation = GetPictureRotation();
_callback.OnPictureTaken(data, rotation, _imageWidth, _imageHeight);
}
private void OnTakePictureFailed(Exception e)
{
_busy = false;
_callback.OnTakePictureFailed(e);
}
The camera is available, and the preview is displayed without problems, and the exception applies only to Samsung devices.