ArturS
ArturS

Reputation: 753

Fatal Exception - Camera is being used after Camera.release() was called HTC ONE M9

I was checking if my surfaceView project is working fine so I've tried it on my wives Galaxy s7 G930F and it worked just fine, when I've tried to run in on my HTC ONE M9 and it didn't even move at all, crashing all the time. It's strange issue, the both phone runs on android 6. While trying to run i was attached a log:

 E/AndroidRuntime: FATAL EXCEPTION: main
              Process: com.example.arturs.androidmirrorapplicationv2, PID: 15974
              java.lang.RuntimeException: Camera is being used after Camera.release() was called
                  at android.hardware.Camera.setPreviewSurface(Native Method)
                  at android.hardware.Camera.setPreviewDisplay(Camera.java:923)
                  at com.example.arturs.androidmirrorapplicationv2.CameraView.surfaceCreated(CameraView.java:46)
                  at android.view.SurfaceView.updateWindow(SurfaceView.java:582)
                  at android.view.SurfaceView$3.onPreDraw(SurfaceView.java:177)
                  at android.view.ViewTreeObserver.dispatchOnPreDraw(ViewTreeObserver.java:944)
                  at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2152)
                  at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1174)
                  at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6241)
                  at android.view.Choreographer$CallbackRecord.run(Choreographer.java:873)
                  at android.view.Choreographer.doCallbacks(Choreographer.java:676)
                  at android.view.Choreographer.doFrame(Choreographer.java:606)
                  at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:859)
                  at android.os.Handler.handleCallback(Handler.java:739)
                  at android.os.Handler.dispatchMessage(Handler.java:95)
                  at android.os.Looper.loop(Looper.java:168)
Disconnected from the target VM, address: 'localhost:8602', transport: 'socket'
                      at android.app.ActivityThread.main(ActivityThread.java:5845)
                      at java.lang.reflect.Method.invoke(Native Method)

And the rest of my code looks like that above: MainActivity class

import android.content.pm.PackageManager;
import android.hardware.Camera;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;

public class MainActivity extends AppCompatActivity {

private Camera mCamera;
private CameraView mCameraView;
private static final String TAG = "MainActivity";

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
}


@Override
protected void onResume(){
    super.onResume();


    try{
        if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED)
            //pyta użytkownika o autoryzację - potrzebne w androidzie => 6.0 tzw. run permission
            ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.CAMERA}, 50);
        else

        mCamera = openFrontFacingCamera();
        mCameraView = new CameraView(this, mCamera);
        setContentView(mCameraView);
    } catch (Exception e){
        finish();
    }
}

@Override
protected void onPause(){
    if(mCamera != null){
        mCamera.release();
        mCamera = null;
    }
    super.onPause();
}


public Camera openFrontFacingCamera() {



    int cameraCount = 0;
    Camera cam = null;
    Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
    cameraCount = Camera.getNumberOfCameras();
    for (int camIdx = 0; camIdx < cameraCount; camIdx++) {
        Camera.getCameraInfo(camIdx, cameraInfo);
        if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
            try {
                cam = Camera.open(camIdx);
            } catch (RuntimeException e) {
                Log.e(TAG, "Camera failed to open: " + e.getLocalizedMessage());
            }
        }
    }

    return cam;
    }
}

CameraView class

import android.content.Context;
import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.Surface;
import android.view.Display;
import android.view.WindowManager;
import java.io.IOException;
import java.util.List;


public class CameraView extends SurfaceView implements SurfaceHolder.Callback{


private Camera mCamera;
private View mView;
private WindowManager display;
private Context mContext;
private static final String cameraPreview = "CameraView";
private static final String APP_CLASS = "APP_CLASS";
private static final String Bug = "Bug";

public CameraView(Context context, Camera mCamera) {
    super(context);

    mContext = context;

    this.mCamera = mCamera;
    mCamera.setDisplayOrientation(90);

    SurfaceHolder holder = getHolder();
    holder.addCallback(this);
    holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

}


@Override
public void surfaceCreated(SurfaceHolder holder) {
    try{
        mCamera.setPreviewDisplay(holder);
        mCamera.startPreview();
    } catch (IOException e) {
        Log.e(cameraPreview, "The failure of the camera settings");
    }
}


@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    Camera.Parameters params = mCamera.getParameters();
    List<Camera.Size> sizes = params.getSupportedPreviewSizes();
    Camera.Size optionalSize = getOptimalPreviewSize(sizes, width, height);
    params.setPreviewSize(optionalSize.width, optionalSize.height);
    mCamera.setParameters(params);

    boolean isPreviewRunning = true;

    if (isPreviewRunning)
    {
        mCamera.stopPreview();
    }

    Parameters parameters = mCamera.getParameters();
    Display display = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
    width = display.getWidth();
    height = display.getHeight();

    if(display.getRotation() == Surface.ROTATION_0)
    {
        parameters.setPreviewSize(height, width);
        mCamera.setDisplayOrientation(90);
    }

    if(display.getRotation() == Surface.ROTATION_90)
    {
        parameters.setPreviewSize(width, height);
        mCamera.setDisplayOrientation(0);
    }

    if(display.getRotation() == Surface.ROTATION_180)
    {
        parameters.setPreviewSize(height, width);
        mCamera.setDisplayOrientation(270);
    }

    if(display.getRotation() == Surface.ROTATION_270)
    {
        parameters.setPreviewSize(width, height);
        mCamera.setDisplayOrientation(180);
    }

    try{
    mCamera.setParameters(parameters);
    previewCamera(holder);
    mCamera.startPreview();}
    catch(Exception e){
        Log.e(Bug, "setting Parameters Failed" + e.getLocalizedMessage());

    }
}

public void previewCamera(SurfaceHolder holder)
{
    try
    {
        mCamera.setPreviewDisplay(holder);
        mCamera.startPreview();
        boolean isPreviewRunning = true;
    }
    catch(Exception e)
    {
        Log.d(APP_CLASS, "Cannot start preview", e);
    }
}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
    mCamera.release();
    mCamera = null;
}

private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {

    final double ASPECT_TOLERANCE = 0.1;
    double targetRatio=(double)h / w;

    if (sizes == null) return null;

    Camera.Size optimalSize = null;
    double minDiff = Double.MAX_VALUE;

    int targetHeight = h;

    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) {
            optimalSize = size;
            minDiff = Math.abs(size.height - targetHeight);
        }
    }

    if (optimalSize == null) {
        minDiff = Double.MAX_VALUE;
        for (Camera.Size size : sizes) {
            if (Math.abs(size.height - targetHeight) < minDiff) {
                optimalSize = size;
                minDiff = Math.abs(size.height - targetHeight);
            }
        }
    }
    return optimalSize;


 }

}

I would be thankful for all kind of advices, which can lead me to solving this issue.

Upvotes: 1

Views: 2845

Answers (1)

ArturS
ArturS

Reputation: 753

I've already figured it out :) so the MainActivity class should look like this now

    package com.example.arturs.androidmirrorapplicationv2;

import android.app.Activity;
import android.hardware.Camera;
import android.os.Bundle;
import android.util.Log;

public class MainActivity extends Activity {

private CameraView mCameraView;
private Camera mCamera;
private static final String TAG = " => Main Activity: ";

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mCamera = openFrontFacingCamera();
    setContentView(R.layout.activity_main);

}


@Override
protected void onResume() {
    super.onResume();

//
//            if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED)
//                //pyta użytkownika o autoryzację - potrzebne w androidzie => 6.0 tzw. run permission
//                ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.CAMERA}, 50);
//            else

            Log.d(TAG, " -> OnResume");
        try {
            mCamera = openFrontFacingCamera();
            if (mCamera != null) {
                mCameraView = new CameraView(this, mCamera);
                setContentView(mCameraView);
            } else {
                Log.d(TAG, " = Camera == NULL");
            }

        } catch (Exception e) {
            e.printStackTrace();
            finish();
        }

        Log.d(TAG, " <- OnResume");


}

@Override
protected void onPause(){
    Log.d(TAG, " -> onPause");
    if(mCamera != null){
        mCamera.release();
        mCamera = null;
    }
    super.onPause();
    Log.d(TAG, " <- onPause");
}


public Camera openFrontFacingCamera() {

//        if (mCamera != null) {
//            mCamera.release();
//            mCamera = null;}

    int cameraCount = 0;
    Camera cam = null;
    Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
    cameraCount = Camera.getNumberOfCameras();
    for (int camIdx = 0; camIdx < cameraCount; camIdx++) {
        Camera.getCameraInfo(camIdx, cameraInfo);
        Log.d(TAG, "Camera Info: "+cameraInfo.facing);
        if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
            try {
                return Camera.open(camIdx);
            } catch (RuntimeException e) {
                Log.e(TAG, "Camera failed to open: " + e.getLocalizedMessage());
            }
        }
    }

    return null;
}
}

And the class CameraView should look like this one above, corrected

    package com.example.arturs.androidmirrorapplicationv2;

import android.content.Context;
import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.Surface;
import android.view.Display;
import android.view.WindowManager;
import java.io.IOException;
import java.util.List;


public class CameraView extends SurfaceView implements SurfaceHolder.Callback{


private Camera mCamera;
private View mView;
private WindowManager display;
private Context mContext;
private static final String cameraPreview = "CameraView";
private static final String APP_CLASS = "APP_CLASS";
private static final String Bug = "Bug";

public CameraView(Context context, Camera mCamera) {
    super(context);

    mContext = context;

    this.mCamera = mCamera;
    mCamera.setDisplayOrientation(90);

    SurfaceHolder holder = getHolder();
    holder.addCallback(this);
    holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

}


@Override
public void surfaceCreated(SurfaceHolder holder) {
    try{
        mCamera.setPreviewDisplay(holder);
        mCamera.startPreview();
    } catch (IOException e) {
        e.printStackTrace();
        Log.e(cameraPreview, "The failure of the camera settings");
    }
}


@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    Camera.Parameters params = mCamera.getParameters();
    List<Camera.Size> sizes = params.getSupportedPreviewSizes();
    Camera.Size optionalSize = getOptimalPreviewSize(sizes, width, height);
    params.setPreviewSize(optionalSize.width, optionalSize.height);
    mCamera.setParameters(params);


    Parameters parameters = mCamera.getParameters();
    Display display = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();


    if(display.getRotation() == Surface.ROTATION_0)
    {
        mCamera.setDisplayOrientation(90);
    }

    if(display.getRotation() == Surface.ROTATION_90)
    {
        mCamera.setDisplayOrientation(0);
    }

    if(display.getRotation() == Surface.ROTATION_180)
    {
        mCamera.setDisplayOrientation(270);
    }

    if(display.getRotation() == Surface.ROTATION_270)
    {
        mCamera.setDisplayOrientation(180);
    }

    try{
    mCamera.setParameters(parameters);
    previewCamera(holder);
    mCamera.startPreview();}
    catch(Exception e){
        e.printStackTrace();
        Log.e(Bug, "setting Parameters Failed" + e.getLocalizedMessage());

    }
}

public void previewCamera(SurfaceHolder holder)
{
    try
    {
        mCamera.setPreviewDisplay(holder);
        mCamera.startPreview();
        boolean isPreviewRunning = true;
    }
    catch(Exception e)
    {
        e.printStackTrace();
        Log.d(APP_CLASS, "Cannot start preview", e);
    }
}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
    mCamera.release();
    mCamera = null;
}

private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {

    final double ASPECT_TOLERANCE = 0.1;
    double targetRatio=(double)h / w;

    if (sizes == null) return null;

    Camera.Size optimalSize = null;
    double minDiff = Double.MAX_VALUE;

    int targetHeight = h;

    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) {
            optimalSize = size;
            minDiff = Math.abs(size.height - targetHeight);
        }
    }

    if (optimalSize == null) {
        minDiff = Double.MAX_VALUE;
        for (Camera.Size size : sizes) {
            if (Math.abs(size.height - targetHeight) < minDiff) {
                optimalSize = size;
                minDiff = Math.abs(size.height - targetHeight);
            }
        }
    }
    return optimalSize;
}

}

Upvotes: 1

Related Questions