javaandroidandroid-cameraandroid-4.2-jelly-beanandroid-6.0.1-marshmallow

Camera.open works on Android 4.2.2, but fails on 6.0.1


I have 2 devices to test my app : an Acer v370 running Android 4.2.2, and a Samsung Galaxy S6 on 6.0.1

The app works fine on the Acer, but crashes instantly on the S6. I'm using _camera = Camera.open(0); and debugging says it crashes at this point.

The error I get is :

09-15 11:24:33.491 15284-15284/com.user.qrReader E/AndroidRuntime: FATAL EXCEPTION: main
  Process: com.user.qrReader, PID: 15284
  java.lang.RuntimeException: Unable to resume activity {com.user.qrReader/com.user.qrReader.MainActivity}:
  java.lang.RuntimeException: Fail to connect to camera service
      at android.app.ActivityThread.performResumeActivity(ActivityThread.java:4156)
      at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:4250)
      at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3361)
      at android.app.ActivityThread.access$1100(ActivityThread.java:222)
      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1795)
      at android.os.Handler.dispatchMessage(Handler.java:102)
      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)
  Caused by: java.lang.RuntimeException: Fail to connect to camera service
      at android.hardware.Camera.<init>(Camera.java:568)
      at android.hardware.Camera.open(Camera.java:405)
      at com.user.qrReader.CameraPreview.openCamera(CameraPreview.java:206)
      at com.user.qrReader.CameraPreview.captureStart(CameraPreview.java:288)
      at com.user.qrReader.QRReaderAppManager.onResume(QRReaderAppManager.java:208)
      at com.user.qrReader.MainActivity.onResume(MainActivity.java:187)
      at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1286)
      at android.app.Activity.performResume(Activity.java:6987)
      at android.app.ActivityThread.performResumeActivity(ActivityThread.java:4145)
      at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:4250) 
      at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3361) 
      at android.app.ActivityThread.access$1100(ActivityThread.java:222) 
      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1795) 
      at android.os.Handler.dispatchMessage(Handler.java:102) 
      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)

Here are the permissions in my manifest :

<uses-feature android:name="android.hardware.camera" android:required="true" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-permission android:name="android.permission.CAMERA" />

I can't use camera2 because I have to keep the app compatible for at least android 4, and I don't know which direction to go. It must be something related to the new android but I can't find what. Any thoughts ?

EDIT : You can also do it manually, once the apk is installed, by going to settings>applications>application manager>{my app}>permissions> allow camera. Of course it's terrible and useless if you have the solution but it helped me for a bit while I was debugging so I'll leave it here. Thank you for your answers.


Solution

  • For Checking permission I created a separate class as below:

      public class MarshMallowPermission {
    
        public static final int RECORD_PERMISSION_REQUEST_CODE = 1;
        public static final int EXTERNAL_STORAGE_PERMISSION_REQUEST_CODE = 2;
        public static final int CAMERA_PERMISSION_REQUEST_CODE = 3;
        Activity activity;
    
        public MarshMallowPermission(Activity activity) {
            this.activity = activity;
        }
    
        public boolean checkPermissionForRecord(){
            int result = ContextCompat.checkSelfPermission(activity, Manifest.permission.RECORD_AUDIO);
            if (result == PackageManager.PERMISSION_GRANTED){
                return true;
            } else {
                return false;
            }
        }
    
        public boolean checkPermissionForExternalStorage(){
            int result = ContextCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
            if (result == PackageManager.PERMISSION_GRANTED){
                return true;
            } else {
                return false;
            }
        }
    
        public boolean checkPermissionForCamera(){
            int result = ContextCompat.checkSelfPermission(activity, Manifest.permission.CAMERA);
            if (result == PackageManager.PERMISSION_GRANTED){
                return true;
            } else {
                return false;
            }
        }
    
        public void requestPermissionForRecord(){
            if (ActivityCompat.shouldShowRequestPermissionRationale(activity, Manifest.permission.RECORD_AUDIO)){
               Toast.makeText(activity, "Microphone permission needed for recording. Please allow in App Settings for additional functionality.", Toast.LENGTH_LONG).show();
            } else {
                ActivityCompat.requestPermissions(activity,new String[]{Manifest.permission.RECORD_AUDIO},RECORD_PERMISSION_REQUEST_CODE);
            }
        }
    
        public void requestPermissionForExternalStorage(){
            if (ActivityCompat.shouldShowRequestPermissionRationale(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE)){
                Toast.makeText(activity, "External Storage permission needed. Please allow in App Settings for additional functionality.", Toast.LENGTH_LONG).show();
            } else {
                ActivityCompat.requestPermissions(activity,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},EXTERNAL_STORAGE_PERMISSION_REQUEST_CODE);
            }
        }
    
        public void requestPermissionForCamera(){
            if (ActivityCompat.shouldShowRequestPermissionRationale(activity, Manifest.permission.CAMERA)){
                Toast.makeText(activity, "Camera permission needed. Please allow in App Settings for additional functionality.", Toast.LENGTH_LONG).show();
            } else {
                ActivityCompat.requestPermissions(activity,new String[]{Manifest.permission.CAMERA},CAMERA_PERMISSION_REQUEST_CODE);
            }
        }
    }
    

    Then, for getting

    MarshMallowPermission marshMallowPermission = new MarshMallowPermission(this);
    
    
    public void getPhotoFromCamera() {
    
        if (!marshMallowPermission.checkPermissionForCamera()) {
            marshMallowPermission.requestPermissionForCamera();
        } else {
            if (!marshMallowPermission.checkPermissionForExternalStorage()) {
                marshMallowPermission.requestPermissionForExternalStorage();
            } else {
                Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                File mediaStorageDir = new File(
                        Environment.getExternalStorageDirectory()
                                + File.separator
                                + getString(R.string.directory_name_corp_chat)
                                + File.separator
                                + getString(R.string.directory_name_images)
                );
    
                if (!mediaStorageDir.exists()) {
                    mediaStorageDir.mkdirs();
                }
    
                String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss",
                        Locale.getDefault()).format(new Date());
                try {
                    mediaFile = File.createTempFile(
                            "IMG_" + timeStamp,  /* prefix */
                            ".jpg",         /* suffix */
                            mediaStorageDir      /* directory */
                    );
                    takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(mediaFile));
                    startActivityForResult(takePictureIntent, PICK_FROM_CAMERA);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }