Normally the android camera api with a PreviewCallback freezes the camera after a picture is taken and this can be used as an approval screen for the image taken. My problem is this is not the behavior on phones like the samsung S6 and S6 edge. those two phones continue with the live preview after the picture is taken.
The pictures taken are still good and can be used for later use but the preview isnt showing, and the way my app is set up, i have a check and an x mark for the user to approve what they just took a photo of. Instead they have this overlay for check and "x" and a live preview on the background. And this only happens on the samsung s6/s6 edge.
Any idea what can cause an issue like this on specific devices?
Code used for preview and picture taking with some logging everywhere:
class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
// SurfaceHolder
private SurfaceHolder mHolder;
// Our Camera.
private Camera mCamera;
// Parent Context.
private Context mContext;
// Camera Sizing (For rotation, orientation changes)
private Camera.Size mPreviewSize;
// List of supported preview sizes
private List<Camera.Size> mSupportedPreviewSizes;
private List<Camera.Size> mSupportPictureSizes;
// Flash modes supported by this camera
private List<String> mSupportedFlashModes;
// View holding this camera.
private View mCameraView;
public CameraPreview(Context context, Camera camera, View cameraView) {
super(context);
Log.d(TAG, "CameraPreview: ");
// Capture the context
mCameraView = cameraView;
mContext = context;
setCamera(camera);
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = getHolder();
mHolder.addCallback(this);
// mHolder.setKeepScreenOn(true);
// deprecated setting, but required on Android versions prior to 3.0
// mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
/**
* Begin the preview of the camera input.
*/
public void startCameraPreview()
{
Log.d(TAG, "startCameraPreview: ");
try{
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
}
catch(Exception e){
e.printStackTrace();
}
}
/**
* Extract supported preview and flash modes from the camera.
* @param camera
*/
private void setCamera(Camera camera)
{
// Source: http://stackoverflow.com/questions/7942378/android-camera-will-not-work-startpreview-fails
mCamera = camera;
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
mSupportPictureSizes = mCamera.getParameters().getSupportedPictureSizes();
for(Camera.Size size : mSupportedPreviewSizes){
Log.d(TAG, "supportedPreviewSizes width: " + size.width + " x " + size.height);
}
for(Camera.Size size : mSupportPictureSizes){
Log.d(TAG, "mSupportPictureSizes width: " + size.width + " x " + size.height);
}
mSupportedFlashModes = mCamera.getParameters().getSupportedFlashModes();
Camera.Parameters parameters = mCamera.getParameters();
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
// Set the camera to Auto Flash mode.
if (mSupportedFlashModes != null && mSupportedFlashModes.contains(Camera.Parameters.FLASH_MODE_AUTO)){
parameters.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);
}
mCamera.setParameters(parameters);
requestLayout();
}
/**
* The Surface has been created, now tell the camera where to draw the preview.
* @param holder
*/
public void surfaceCreated(SurfaceHolder holder) {
Log.d(TAG, "surfaceCreated: ");
try {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Dispose of the camera preview.
* @param holder
*/
public void surfaceDestroyed(SurfaceHolder holder) {
Log.d(TAG, "surfaceDestroyed: ");
if (mCamera != null){
mCamera.stopPreview();
}
}
/**
* React to surface changed events
* @param holder
* @param format
* @param w
* @param h
*/
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
// If your preview can change or rotate, take care of those events here.
// Make sure to stop the preview before resizing or reformatting it.
if (mHolder.getSurface() == null){
// preview surface does not exist
Log.d(TAG, "surfaceChanged: preview surface does not exist");
return;
}
Log.d(TAG, "surfaceChanged: start & stop preview");
// stop preview before making changes
try {
mCamera.stopPreview();
} catch (Exception e){
// ignore: tried to stop a non-existent preview
}
// set preview size and make any resize, rotate or
// reformatting changes here
// start preview with new settings
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e){
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
}
}
@Override
public SurfaceHolder getHolder() {
return super.getHolder();
}
/**
* Calculate the measurements of the layout
* @param widthMeasureSpec
* @param heightMeasureSpec
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
// Source: http://stackoverflow.com/questions/7942378/android-camera-will-not-work-startpreview-fails
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);
if (mSupportedPreviewSizes != null){
Log.d(TAG, "onMeasure: w x h: " + width + " x " + height);
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
}
}
/**
* Update the layout based on rotation and orientation changes.
* @param changed
* @param left
* @param top
* @param right
* @param bottom
*/
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom)
{
Log.d(TAG, "onLayout: ");
// Source: http://stackoverflow.com/questions/7942378/android-camera-will-not-work-startpreview-fails
if (changed) {
final int width = right - left;
final int height = bottom - top;
int previewWidth = width;
int previewHeight = height;
if (mPreviewSize != null){
Display display = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
switch (display.getRotation())
{
case Surface.ROTATION_0:
previewWidth = mPreviewSize.height;
previewHeight = mPreviewSize.width;
mCamera.setDisplayOrientation(90);
Log.d(TAG, "onLayout: rotation0");
break;
case Surface.ROTATION_90:
previewWidth = mPreviewSize.width;
previewHeight = mPreviewSize.height;
Log.d(TAG, "onLayout: rotation90");
break;
case Surface.ROTATION_180:
previewWidth = mPreviewSize.height;
previewHeight = mPreviewSize.width;
Log.d(TAG, "onLayout: rotation180");
break;
case Surface.ROTATION_270:
previewWidth = mPreviewSize.width;
previewHeight = mPreviewSize.height;
mCamera.setDisplayOrientation(180);
Log.d(TAG, "onLayout: rotation270");
break;
}
}
final int scaledChildHeight = previewHeight * width / previewWidth;
mCameraView.layout(0, height - scaledChildHeight, width, height);
}
}
private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
Log.d(TAG, "getOptimalPreviewSize: ");
final double ASPECT_TOLERANCE = 0.05;
double targetRatio = (double) w / h;
if (sizes == null) return null;
Camera.Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
// Try to find an size match aspect ratio and size
for (Camera.Size size : sizes) {
double ratio = (double) size.width / size.height;
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE){
continue;
}
if (Math.abs(size.height - targetHeight) < minDiff) {
Log.d(TAG, "getOptimalPreviewSize: found a match");
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
// Cannot find the one match the aspect ratio, ignore the requirement
if (optimalSize == null) {
Log.d(TAG, "getOptimalPreviewSize: couldn't find match");
minDiff = Double.MAX_VALUE;
for (Camera.Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
Log.d(TAG, "getOptimalPreviewSize: " + optimalSize.width + " x HEIGHT: " + optimalSize.height);
return optimalSize;
}
}
/**
* Picture Callback for handling a picture capture and saving it out to a file.
*/
private Camera.PictureCallback mPicture = new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
Camera.Parameters parameters = camera.getParameters();
Camera.Size mPictureTakenSize = parameters.getPictureSize();
System.out.println("picture taken size: " + mPictureTakenSize.width + " x " + mPictureTakenSize.height);
if(data!=null){
Log.d(TAG, "onPictureTaken: data not null, setting data to currentData");
// currentData = data;
setPictureTakenData(data);
cameraViewModel.setPreview(true);
}
else{
onProgress = false;
Log.d(TAG, "onPictureTaken: data is null");
}
}
};