14

I am using Camera2API in Android 6.0. I was done without error in Android 5.0. However, when I used my code in the Android 6.0, I have a issue. The issue is that sometime I can open the camera successfully and take picture. However, sometime the camera cannot open and it has error

java.lang.SecurityException: Lacking privileges to access camera service
    at android.hardware.camera2.utils.CameraBinderDecorator.throwOnError(CameraBinderDecorator.java:108)

I added the runtime permission as follows:

String[] PERMISSIONS = {Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.CAMERA};
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
    if(!hasAllPermissions(this, PERMISSIONS)){
        ActivityCompat.requestPermissions(this, PERMISSIONS, PERMISSION_ALL);
    }
}

public static boolean hasAllPermissions(Context context, String... permissions) {
    if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && context != null && permissions != null) {
        for (String permission : permissions) {
            if (ActivityCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) {
                return false;
            }
        }
    }
    return true;
}

This is all log

FATAL EXCEPTION: main
Process: com.example.camera2api, PID: 5376
java.lang.SecurityException: Lacking privileges to access camera service
at android.hardware.camera2.utils.CameraBinderDecorator.throwOnError(CameraBinderDecorator.java:108)
at android.hardware.camera2.utils.CameraBinderDecorator$CameraBinderDecoratorListener.onAfterInvocation(CameraBinderDecorator.java:73)
at android.hardware.camera2.utils.Decorator.invoke(Decorator.java:81)
at java.lang.reflect.Proxy.invoke(Proxy.java:393)
at $Proxy2.cancelRequest(Unknown Source)
at android.hardware.camera2.impl.CameraDeviceImpl.stopRepeating(CameraDeviceImpl.java:926)
at android.hardware.camera2.impl.CameraCaptureSessionImpl.close(CameraCaptureSessionImpl.java:378)
at android.hardware.camera2.impl.CameraCaptureSessionImpl$2.onDisconnected(CameraCaptureSessionImpl.java:514)
at android.hardware.camera2.impl.CameraDeviceImpl$7.run(CameraDeviceImpl.java:228)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:158)
at android.app.ActivityThread.main(ActivityThread.java:7229)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)

update: For someone who want to look at my full code. I upload my full code here

public class AndroidCamera extends AppCompatActivity {

private static final SparseIntArray ORIENTATIONS = new SparseIntArray();

static {
    ORIENTATIONS.append(Surface.ROTATION_0, 90);
    ORIENTATIONS.append(Surface.ROTATION_90, 0);
    ORIENTATIONS.append(Surface.ROTATION_180, 270);
    ORIENTATIONS.append(Surface.ROTATION_270, 180);
}

private static final String TAG = "Camera2App";
private String mImageFileLocation = "";
private static final int STATE_PREVIEW = 0;
private static final int STATE_WAIT_LOCK = 1;
private static final int STATE_WAITING_PRECAPTURE = 2;
/**
 * Camera state: Waiting for the exposure state to be something other than precapture.
 */
private static final int STATE_WAITING_NON_PRECAPTURE = 3;

/**
 * Camera state: Picture was taken.
 */
private static final int STATE_PICTURE_TAKEN = 4;
private int mState;
private TextureView mTextureView;
private Size mPreviewSize;

private String mCameraId;
String[] PERMISSIONS = {Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.CAMERA};
private static final int PERMISSION_ALL = 105;
private  static final int REQUEST_CAMERA_RESULT = 106;
private boolean isRegistred=false;
private int mSensorOrientation;
private TextureView.SurfaceTextureListener mSurfaceTextureListener =
        new TextureView.SurfaceTextureListener() {
            @Override
            public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
                if (!TextUtils.isEmpty(BleUtils.getCameraLens(AndroidCamera.this)))
                    setupCamera(width, height,BleUtils.getCameraLens(AndroidCamera.this));
                else
                    setupCamera(width, height,"1");
                openCamera();

            }

            @Override
            public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {

            }

            @Override
            public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
                //closeCamera();

                return false;
            }

            @Override
            public void onSurfaceTextureUpdated(SurfaceTexture surface) {

            }
        };
private Semaphore mCameraOpenCloseLock = new Semaphore(1);
private CameraDevice mCameraDevice;
private CameraDevice.StateCallback mCameraDeviceStateCallback =
        new CameraDevice.StateCallback() {
            @Override
            public void onOpened(CameraDevice camera) {
                mCameraOpenCloseLock.release();
                mCameraDevice = camera;
                //Toast.makeText(getApplicationContext(),"Camera Opened!", Toast.LENGTH_SHORT).show();
                createCameraPreviewSession();
            }

            @Override
            public void onDisconnected(CameraDevice camera) {
                camera.close();
                mCameraDevice = null;

            }

            @Override
            public void onError(CameraDevice camera, int error) {
                camera.close();
                mCameraDevice = null;

            }
        };
private CaptureRequest mPreviewCaptureRequest;
private CaptureRequest.Builder mPreviewCaptureRequestBuilder;
private CameraCaptureSession mCameraCaptureSession;
private CameraCaptureSession.CaptureCallback mSessionCaptureCallback
        = new CameraCaptureSession.CaptureCallback() {

    private void process(CaptureResult result){

        switch (mState){
            case STATE_PREVIEW:
                break;
            case STATE_WAIT_LOCK:
                Integer afState=result.get(CaptureResult.CONTROL_AF_STATE);
                if(afState==CaptureRequest.CONTROL_AF_STATE_FOCUSED_LOCKED){
                    captureStillImage();
                }
                else{
                    captureStillImage();
                }

                break;
        }


    }

    @Override
    public void onCaptureStarted(CameraCaptureSession session, CaptureRequest request, long timestamp, long frameNumber) {
        super.onCaptureStarted(session, request, timestamp, frameNumber);
    }

    @Override
    public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
        super.onCaptureCompleted(session, request, result);

        process(result);
    }

    @Override
    public void onCaptureFailed(CameraCaptureSession session, CaptureRequest request, CaptureFailure failure) {
        super.onCaptureFailed(session, request, failure);
        Handler mHandler = new Handler(getMainLooper());
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(getApplicationContext(), "Focus Lock UnSuccesful", Toast.LENGTH_SHORT).show();
            }
        });

    }
};

private HandlerThread mBackgroundThread;
private Handler mBackgroundHandler;
private static File mImageFile;
private ImageReader mImageReader;
private final ImageReader.OnImageAvailableListener mOnImageAvailableListener =
        new ImageReader.OnImageAvailableListener() {
            @Override
            public void onImageAvailable(ImageReader reader) {

                mBackgroundHandler.post(new ImageSaver(reader.acquireNextImage()));
            }
        };

private static class ImageSaver implements Runnable {


    private final Image mImage;

    private ImageSaver(Image image) {
        mImage = image;
    }

    @Override
    public void run() {

        ByteBuffer byteBuffer = mImage.getPlanes()[0].getBuffer();
        byte[] bytes = new byte[byteBuffer.remaining()];
        byteBuffer.get(bytes);

        FileOutputStream fileOutputStream = null;

        try {

            fileOutputStream = new FileOutputStream(mImageFile);
            fileOutputStream.write(bytes);

        } catch (IOException e) {
            e.printStackTrace();
        } finally {

            mImage.close();
            if (fileOutputStream != null) {
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }

    }
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.camera_activity);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
        if(!hasAllPermissions(this, PERMISSIONS)){
            ActivityCompat.requestPermissions(this, PERMISSIONS, PERMISSION_ALL);
        }
    }




    mTextureView = (TextureView) findViewById(R.id.texture);
}
public static boolean hasAllPermissions(Context context, String... permissions) {
    if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && context != null && permissions != null) {
        for (String permission : permissions) {
            if (ActivityCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) {
                return false;
            }
        }
    }
    return true;
}
@Override
public void onStart() {
    super.onStart();
    if (!EventBus.getDefault().isRegistered(this)) {
        EventBus.getDefault().register(this);
    }
}
//onStop
@Override
public void onStop() {
    super.onStop();
    EventBus.getDefault().unregister(this);
}


@Subscribe
public void onCaptureNumberReceived(OnCaptureEvent event) {
    //get the phone number value here and do something with it
    String capturecode = event.getCodeCapture();
    Log.d(TAG, capturecode);
    if (capturecode.equals("capture")) {
        try {
            mImageFile = createImageFile();

        } catch (IOException e) {
            e.printStackTrace();
        }

        lockFocus();
        MediaActionSound sound = new MediaActionSound();
        sound.play(MediaActionSound.SHUTTER_CLICK);
    }
    else if(capturecode.equals("end_capture")) {
        finish(); // call this to finish the current activity
        Intent homeIntent = new Intent(Intent.ACTION_MAIN);
        homeIntent.addCategory( Intent.CATEGORY_HOME );
        homeIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        startActivity(homeIntent);
    }

}

public void takepicture(View view) {

    try {
        mImageFile = createImageFile();
        Log.d("TAG","=====Take picture=====");

    } catch (IOException e) {
        e.printStackTrace();
    }

    lockFocus();
    MediaActionSound sound = new MediaActionSound();
    sound.play(MediaActionSound.SHUTTER_CLICK);
}

public void switch_camera(View view) {
    closeCamera();
    //swap the id of the camera to be used
    if(mCameraId == String.valueOf(Camera.CameraInfo.CAMERA_FACING_BACK)){
        mCameraId = String.valueOf(Camera.CameraInfo.CAMERA_FACING_FRONT);
    }
    else {
        mCameraId = String.valueOf(Camera.CameraInfo.CAMERA_FACING_BACK);
    }
    BleUtils.setCameraLens(this, mCameraId);
    if (mTextureView.isAvailable()) {

        setupCamera(mTextureView.getWidth(), mTextureView.getHeight(),mCameraId);
        openCamera();
    } else {
        mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
    }

}

File createImageFile() throws IOException {

    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
    String imageFileName = "BLE_" + timeStamp + "_";
    File storageDirectory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
    if(!storageDirectory.exists()){
        if(!storageDirectory.mkdirs()){
            Log.e("Dir", "Failed to create directory");
            Log.d("MAKE DIR", storageDirectory.mkdir() + "" +  storageDirectory.getParentFile() + "");
            return null;
        }
    }
    File image = File.createTempFile(imageFileName, ".jpg", storageDirectory);
    mImageFileLocation = image.getAbsolutePath();

    return image;
}

@Override
public void onResume() {
    super.onResume();
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
        if(!hasAllPermissions(this, PERMISSIONS)){
            ActivityCompat.requestPermissions(this, PERMISSIONS, PERMISSION_ALL);
        }
    }
    openBackgroundThread();
    if (mTextureView.isAvailable()) {
        if (!TextUtils.isEmpty(BleUtils.getCameraLens(AndroidCamera.this)))
            setupCamera(mTextureView.getWidth(), mTextureView.getHeight(),BleUtils.getCameraLens(AndroidCamera.this));
        else
            setupCamera(mTextureView.getWidth(), mTextureView.getHeight(),"1");
        closeCamera();
        openCamera();
    } else {
        mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
    }
}
@Override
public void onDestroy() {
    super.onDestroy();
    Log.d(TAG,"onDestroy");
}
public void onPause() {
    Log.d(TAG,"onPause");
    closeCamera();

    closeBackgroundThread();
    super.onPause();
}

private void setupCamera(int width, int height, String cameraId) {
    CameraManager cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
    try {
            CameraCharacteristics cameraCharacteristics = cameraManager.getCameraCharacteristics(cameraId);
            StreamConfigurationMap map = cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);

            Size largestImageSize = Collections.max(
                    Arrays.asList(map.getOutputSizes(ImageFormat.JPEG)),
                    new Comparator<Size>() {
                        @Override
                        public int compare(Size lhs, Size rhs) {
                            return Long.signum(lhs.getWidth() * lhs.getHeight() -
                                    rhs.getWidth() * rhs.getHeight());
                        }
                    }
            );
            mImageReader = ImageReader.newInstance(largestImageSize.getWidth(),
                    largestImageSize.getHeight(),
                    ImageFormat.JPEG,
                    1);
            mImageReader.setOnImageAvailableListener(mOnImageAvailableListener,
                    mBackgroundHandler);
            mPreviewSize = getPreferredPreviewSize(map.getOutputSizes(SurfaceTexture.class), width, height);
            mCameraId = cameraId;
            Log.d("CAMERA_ID",String.valueOf(mCameraId));
    //    }

    } catch (CameraAccessException e) {
        e.printStackTrace();
    }
}

private Size getPreferredPreviewSize(Size[] mapSizes, int width, int height) {
    List<Size> collectorSizes = new ArrayList<>();
    for (Size option : mapSizes) {
        if (width > height) {
            if (option.getWidth() > width &&
                    option.getHeight() > height) {
                collectorSizes.add(option);
            }
        } else {
            if (option.getWidth() > height &&
                    option.getHeight() > width) {
                collectorSizes.add(option);
            }
        }
    }
    if (collectorSizes.size() > 0) {
        return Collections.min(collectorSizes, new Comparator<Size>() {
            @Override
            public int compare(Size lhs, Size rhs) {
                return Long.signum(lhs.getWidth() * lhs.getHeight() - rhs.getWidth() * rhs.getHeight());
            }
        });
    }
    return mapSizes[0];

}

private void openCamera() {
    CameraManager cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
    try {
        Log.v("CAMERA", mCameraId + " " + mCameraDeviceStateCallback);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
            if(ContextCompat.checkSelfPermission(this, android.Manifest.permission.CAMERA)
                    == PackageManager.PERMISSION_GRANTED){
                cameraManager.openCamera(mCameraId, mCameraDeviceStateCallback,mBackgroundHandler);
            }
            else {
                if (shouldShowRequestPermissionRationale(android.Manifest.permission.CAMERA)){
                    Toast.makeText(this,"No Permission to use the Camera services", Toast.LENGTH_SHORT).show();
                }
                requestPermissions(new String[] {android.Manifest.permission.CAMERA},REQUEST_CAMERA_RESULT);
            }
        }
        else {
            cameraManager.openCamera(mCameraId, mCameraDeviceStateCallback, mBackgroundHandler);
        }
    } catch (CameraAccessException e) {
        e.printStackTrace();
    }


}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    switch (requestCode){
        case  REQUEST_CAMERA_RESULT:
            if (grantResults[0] != PackageManager.PERMISSION_GRANTED){
                Toast.makeText(this, "Cannot run application because camera service permission have not been granted", Toast.LENGTH_SHORT).show();
            }
            break;
        default:
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
            break;
    }
}
private void closeCamera(){
    if(mCameraCaptureSession!=null){
        mCameraCaptureSession.close();
        mCameraCaptureSession=null;
    }
    if (mCameraDevice!=null){
        mCameraDevice.close();
        mCameraDevice=null;

        if(mImageReader!=null){

            mImageReader.close();
            mImageReader=null;

        }
    }
}
private void createCameraPreviewSession(){
    try{
        SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture();
        surfaceTexture.setDefaultBufferSize(mPreviewSize.getWidth(),mPreviewSize.getHeight());
        Surface previewSurface= new Surface(surfaceTexture);
        mPreviewCaptureRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
        mPreviewCaptureRequestBuilder.addTarget(previewSurface);
        mPreviewCaptureRequestBuilder.set(CaptureRequest.JPEG_QUALITY, (byte)100);
        mCameraDevice.createCaptureSession(Arrays.asList(previewSurface,mImageReader.getSurface()),
                new CameraCaptureSession.StateCallback() {
                    @Override
                    public void onConfigured(CameraCaptureSession session) {
                        if(mCameraDevice==null){
                            return;
                        }
                        try {
                            mPreviewCaptureRequest = mPreviewCaptureRequestBuilder.build();
                            mCameraCaptureSession = session;
                            mCameraCaptureSession.setRepeatingRequest(
                                    mPreviewCaptureRequest,
                                    mSessionCaptureCallback,
                                    mBackgroundHandler
                            );

                        }catch (CameraAccessException e){
                            e.printStackTrace();
                        }

                    }

                    @Override
                    public void onConfigureFailed(CameraCaptureSession session) {
                        Handler mHandler = new Handler(getMainLooper());
                        mHandler.post(new Runnable() {
                            @Override
                            public void run() {
                                Toast.makeText(
                                        getApplicationContext(),
                                        "create camera session failed!",
                                        Toast.LENGTH_SHORT
                                ).show();
                            }
                        });

                    }
                },null);

    }catch (CameraAccessException e){
        e.printStackTrace();
    }
}

private void openBackgroundThread(){
    mBackgroundThread=new HandlerThread("Camera2 background thread");
    mBackgroundThread.start();
    mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
}
private  void closeBackgroundThread(){

    mBackgroundThread.quitSafely();
    try{

        mBackgroundThread.join();
        mBackgroundThread=null;
        mBackgroundHandler=null;

    }catch (InterruptedException e){
        e.printStackTrace();
    }

}

private void lockFocus(){
    try{

        mState=STATE_WAIT_LOCK;
        mPreviewCaptureRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
                CaptureRequest.CONTROL_AF_TRIGGER_START);
        mCameraCaptureSession.capture(mPreviewCaptureRequestBuilder.build(),
                mSessionCaptureCallback,mBackgroundHandler);

    }catch (CameraAccessException e){
        e.printStackTrace();
    }
}

private void unLockFocus(){
    try{

        mState=STATE_PREVIEW;
        mPreviewCaptureRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
                CaptureRequest.CONTROL_AF_TRIGGER_CANCEL);
        mCameraCaptureSession.capture(mPreviewCaptureRequestBuilder.build(),
                mSessionCaptureCallback,mBackgroundHandler);

    }catch (CameraAccessException e){
        e.printStackTrace();
    }
}

private void captureStillImage(){
    try {

        CaptureRequest.Builder captureStillBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
        captureStillBuilder.addTarget(mImageReader.getSurface());

        // Use the same AE and AF modes as the preview.
        captureStillBuilder.set(CaptureRequest.CONTROL_AF_MODE,
                CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
       // setAutoFlash(captureBuilder);

        // Orientation
        int rotation=0;
        //Front camera
        if(mCameraId.equals("1")) {
            rotation = this.getWindowManager().getDefaultDisplay().getRotation();
            captureStillBuilder.set(CaptureRequest.JPEG_ORIENTATION, getOrientation(rotation));
        }
        else {
            rotation = this.getWindowManager().getDefaultDisplay().getRotation();
            captureStillBuilder.set(CaptureRequest.JPEG_ORIENTATION,
                    ORIENTATIONS.get(rotation));
        }

        CameraCaptureSession.CaptureCallback captureCallback =
                new CameraCaptureSession.CaptureCallback() {
                    @Override
                    public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
                        super.onCaptureCompleted(session, request, result);

                        //Toast.makeText(getApplicationContext(),"Image Captured",Toast.LENGTH_SHORT).show();

                        unLockFocus();
                    }
                };

        mCameraCaptureSession.capture(

                captureStillBuilder.build(),captureCallback,null
        );

    }catch (CameraAccessException e){
        e.printStackTrace();
    }
}

private int getOrientation(int rotation) {
    return (ORIENTATIONS.get(rotation) + mSensorOrientation +180) % 360;
}

}

user3051460
  • 1,455
  • 22
  • 58

1 Answers1

9

setupCamera() is called right from onSurfaceTextureAvailable, which can be earlier than the permissions are granted.

What you need to do is to track whether the permissions are granted and if the surface texture available in both callbacks.

Make a single entry for checking these conditions and setting up camera

private boolean mSurfaceTextureAvailable;
private boolean mPermissionsGranted;
private boolean mCameraOpened;

private void setupCameraIfPossible() {
    if (!mCameraOpened && mSurfaceTextureAvailable && mPermissionsGranted) {
        String cameraLens = BleUtils.getCameraLens(AndroidCamera.this);
        if (TextUtils.isEmpty(cameraLens)) {
            cameraLens = "1";
        }
        setupCamera(mTextureView.getWidth(), mTextureView.getHeight(), cameraLens);
        openCamera();
    }
}

private final TextureView.SurfaceTextureListener mSurfaceTextureListener =
        new TextureView.SurfaceTextureListener() {
            @Override
            public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
                mSurfaceTextureAvailable = true;
                setupCameraIfPossible();
            }

            @Override
            public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {

            }

            @Override
            public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
                //closeCamera();
                mSurfaceTextureAvailable = false;
                return false;
            }

            @Override
            public void onSurfaceTextureUpdated(SurfaceTexture surface) {

            }
        };

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

    // Make sure the boolean flag is set. Will be true for lower SDK
    mPermissionsGranted = hasAllPermissions(this, PERMISSIONS);
    if (!mPermissionsGranted) {
        ActivityCompat.requestPermissions(this, PERMISSIONS, PERMISSION_ALL);
    }
    mTextureView = (TextureView) findViewById(R.id.texture);
}

In onResume() you don't need to check for permissions. If they will be denied while in background your Activity will get killed and you will go through onCreate() again.

Remove the code in onPause() and onResume()!

//    @Override
//    public void onResume() {
//        super.onResume();
//        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
//            if(!hasAllPermissions(this, PERMISSIONS)){
//                ActivityCompat.requestPermissions(this, PERMISSIONS, PERMISSION_ALL);
//            }
//        }
//        openBackgroundThread();
//        if (mTextureView.isAvailable()) {
//            if (!TextUtils.isEmpty(BleUtils.getCameraLens(AndroidCamera.this)))
//                setupCamera(mTextureView.getWidth(), mTextureView.getHeight(),BleUtils.getCameraLens(AndroidCamera.this));
//            else
//                setupCamera(mTextureView.getWidth(), mTextureView.getHeight(),"1");
//            closeCamera();
//            openCamera();
//        } else {
//            mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
//        }
//    }

//    public void onPause() {
//        Log.d(TAG,"onPause");
//        closeCamera();
//
//        closeBackgroundThread();
//        super.onPause();
//    }

Add this to onStart()

@Override
public void onStart() {
    super.onStart();
    openCameraIfPossible();
}

Move closing camera to onStop()

@Override
public void onStop() {
    super.onStop();
    closeCamera();
}

private void closeCamera() {
    mCameraOpened = false; // set a field indicating it is closed
    ...
}

private void openCamera() {
    ...
    mCameraOpened = true; // If successful, set a field indicating it is opened
}

Now another thing I discovered is that you must actually check for permissions in onRequestPermissionsResult() instead of using grantResults flags

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    switch (requestCode){
        case REQUEST_CAMERA_RESULT:
            mPermissionsGranted = hasAllPermissions(this, PERMISSIONS);
            setupCameraIfPossible();
            break;

        default:
            break;
    }
}
Yaroslav Mytkalyk
  • 16,950
  • 10
  • 72
  • 99
  • Thanks. I think you missing the calling function `openBackgroundThread`. Second, it still is error as above question. – user3051460 Nov 08 '16 at 10:27
  • @user3051460 yes, sorry, I missed it. Edited and added to onCreate(). Are you sure the error log is the same as above? I can't run your code because I don't have BleUtils and your layout. – Yaroslav Mytkalyk Nov 08 '16 at 10:41
  • Wait me. I will create a project and let you know – user3051460 Nov 08 '16 at 10:49
  • Finally, I got the solution. The issue is that I start the preview when screen is not ready (screen off and then turn on). To solve it, I added a timer to make a delay time. This is my code. You can contribute and provide a better solution than using timer. Thanks https://github.com/mjohn123/Camera2APIM – user3051460 Nov 08 '16 at 14:00
  • I accepted it to thankful for your help. In additions, I need to move the `openBackgroundThread` on `onResume` function instead of the `onCreate.` Let see my code for more detail – user3051460 Nov 08 '16 at 14:09
  • @user3051460 so is your problem solved or you still need assistance? – Yaroslav Mytkalyk Nov 08 '16 at 15:57
  • I solved it, But I just ask one more question. Do you think timer is good solution for ignoring the screen ready issue? – user3051460 Nov 09 '16 at 01:57
  • @user3051460 timer is a bad idea, in most time it works but there's always a possible device or situation when something can take more time than the timer is set for. Or the opposite, timer can make user wait for longer than it should. I cannot offer you a solution because I don't understand what do you mean by "screen not ready". Do you mean if you start Activity when the display is off, and turn it on after onCreate() the Camera has a problem? Or is it something else? – Yaroslav Mytkalyk Nov 09 '16 at 10:57
  • Thanks. When we turn on the camera SurfaceTexture, we have to guarantee that the screen is the state on (if the screen is off, we cannot see anything on the screen and the app may crash). The time spends to turn on my screen about 1 ~2 seconds. Hence, I used a timer (does not do anything) to wait for the screen on. That is the meaning of screen is not ready – user3051460 Nov 09 '16 at 11:52
  • Do you find any solution? I am still not solve it yet. The issue is that when screen off, and we open camera, it will crash – user3051460 Nov 21 '16 at 10:10
  • @user3051460 I thought you figured that out so I didn't bother. Now that I launched your project and tried on emulator I had E/OpenGLRenderer: GL error: Out of memory! after a while. Maybe you have a leak somewhere restarting all those activities but that's rather a topic for a new question. – Yaroslav Mytkalyk Nov 21 '16 at 12:34
  • Do you run in real device? Because emulator cannot simulate the capture function. I worked well with this project, except the `Lacking privileges to access camera service`. It came from screen on/off issue. I think that when screen lock, the texture cannot rending, I think the error is come from that – user3051460 Nov 21 '16 at 12:49
  • Closing Camera in onDestroy is a horrible idea because in that case you might lock camera and other apps won't be able to access it until your activity is destroyed – Sam Jan 08 '17 at 23:08
  • @YaroslavMytkalyk I'm doing it in onPause. I've had issues with switching apps and having issues with camera access. It's a big question whether that's overkill or not but I didn't encounter any issues with onPause one – Sam Jan 13 '17 at 08:06