android : camera doesn't open in marshmallow

22,186

Solution 1

So, I accomplished my task like as below:

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();
            }
        }
    }
}

Solution 2

Quoting developers.android.com:

Beginning in Android 6.0 (API level 23), users grant permissions to apps while the app is running, not when they install the app. This approach streamlines the app install process, since the user does not need to grant permissions when they install or update the app. It also gives the user more control over the app's functionality; for example, a user could choose to give a camera app access to the camera but not to the device location. The user can revoke the permissions at any time, by going to the app's Settings screen.

System permissions are divided into two categories, normal and dangerous:

  • Normal permissions do not directly risk the user's privacy. If your app lists a normal permission in its manifest, the system grants the permission automatically.

  • Dangerous permissions can give the app access to the user's confidential data. If your app lists a normal permission in its manifest, the system grants the permission automatically. If you list a dangerous permission, the user has to explicitly give approval to your app.

WRITE_EXTERNAL_STORAGE is in the Dangerous category, for this reason you need to request the permission to the user before call mediaStorageDir.mkdirs() or File.createTempFile otherwise you program crash with this exception:

W/System.err: java.io.IOException: open failed: EACCES (Permission denied)
W/System.err:     at java.io.File.createNewFile(File.java:939)
W/System.err:     at java.io.File.createTempFile(File.java:1004)
W/System.err:     at com.example.MainActivity.getPhotoFromCamera(MainActivity.java:98)
W/System.err:     at com.example.MainActivity.onCreate(MainActivity.java:48)
W/System.err:     at android.app.Activity.performCreate(Activity.java:6237)
W/System.err:     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.
W/System.err:     at android.app.ActivityThread.performLaunchActivity(ActivityThread.
W/System.err:     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476
W/System.err:     at android.app.ActivityThread.-wrap11(ActivityThread.java)
W/System.err:     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344)
W/System.err:     at android.os.Handler.dispatchMessage(Handler.java:102)
W/System.err:     at android.os.Looper.loop(Looper.java:148)
W/System.err:     at android.app.ActivityThread.main(ActivityThread.java:5417)
W/System.err:     at java.lang.reflect.Method.invoke(Native Method)
W/System.err:     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.
W/System.err:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
W/System.err: Caused by: android.system.ErrnoException: open failed: EACCES (Permission 
W/System.err:     at libcore.io.Posix.open(Native Method)
W/System.err:     at libcore.io.BlockGuardOs.open(BlockGuardOs.java:186)
W/System.err:     at java.io.File.createNewFile(File.java:932)
W/System.err:   ... 15 more
Share:
22,186

Related videos on Youtube

Chintan Soni
Author by

Chintan Soni

Hey visitor, Greetings !!! I am Chintan Soni, a Passionate, Tech savvy, Independent, Self-motivating Mobile Application Developer. Currently serving as TechLead - Android @ ARInspect. Always eager to learn new technologies. Love to help people learn with, whatever I got. Meet my brother: Yash Soni A tech-enthusiast, Gadget Freak and Apple Fanboy. Motto that LIT my life: Learn, Implement and Teach others. Github: https://github.com/iChintanSoni Medium: https://medium.com/@chintansoni My Mentor: Paresh Mayani, Pratik Patel Currently onto: Flutter Kotlin Platforms and Frameworks I have worked on: Android Native Application Development Ionic 3.x Application Development Microsoft ASP.net Web Api 2 using Entity Framework 6.1 (MSSQL Server Database 2014) Node.js (MySQL Server) Google Firebase Augmented Reality Facebook Messenger Bots And what not...!!! Follow me on: Facebook, Twitter, LinkedIn

Updated on May 05, 2020

Comments

  • Chintan Soni
    Chintan Soni about 4 years

    So, I have below code that open camera, capture the image and save it on SDCard.

    public void getPhotoFromCamera() {
        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_temp)
        );
    
        if (!mediaStorageDir.exists()) {
            mediaStorageDir.mkdirs();
        }
    
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss",
                Locale.getDefault()).format(new Date());
        try {
            mediaFile = File.createTempFile(
                    "TEMP_FULL_IMG_" + timeStamp,
                    ".jpg",
                    mediaStorageDir
            );
            takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(mediaFile));
            startActivityForResult(takePictureIntent, PICK_FROM_CAMERA);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    private void performCrop(Uri picUri) {
        try {
            Intent cropIntent = new Intent("com.android.camera.action.CROP");
            cropIntent.setDataAndType(picUri, "image/*");
            cropIntent.putExtra("crop", "true");
            cropIntent.putExtra("aspectX", 1);
            cropIntent.putExtra("aspectY", 1);
            cropIntent.putExtra("outputX", 128);
            cropIntent.putExtra("outputY", 128);
            // retrieve data on return
            cropIntent.putExtra("return-data", true);
    
            File mediaStorageDir = new File(
                    Environment.getExternalStorageDirectory()
                            + File.separator
                            + getString(R.string.directory_name_corp_chat)
                            + File.separator
                            + getString(R.string.directory_name_temp)
            );
    
            if (!mediaStorageDir.exists()) {
                mediaStorageDir.mkdirs();
            }
    
            String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss",
                    Locale.getDefault()).format(new Date());
            try {
                croppedFile = File.createTempFile(
                        "TEMP_CROPPED_IMG_" + timeStamp,
                        ".jpg",
                        mediaStorageDir
                );
                cropIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(croppedFile));
                startActivityForResult(cropIntent, PIC_CROP);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        // respond to users whose devices do not support the crop action
        catch (ActivityNotFoundException anfe) {
            // display an error message
            String errorMessage = "Whoops - your device doesn't support the crop action!";
            Toast toast = Toast.makeText(this, errorMessage, Toast.LENGTH_SHORT);
            toast.show();
        }
    }
    
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
    
        if (requestCode == PICK_FROM_CAMERA) {
            if (resultCode == RESULT_OK) {
                performCrop(Uri.fromFile(mediaFile));
            } else {
                Log.i("Camera", "result cancel. Hence, deleting file: " + mediaFile.getPath());
                Log.i("File deleted ", mediaFile.delete() + "");
            }
        }
    
        if (requestCode == PICK_FROM_GALLERY) {
            if (resultCode == RESULT_OK) {
                performCrop(data.getData());
            } else {
                Log.i("Gallery", "result cancel");
            }
        }
    
        if (requestCode == PIC_CROP) {
            if (resultCode == RESULT_OK) {
                imageView.setImageBitmap(BitmapFactory.decodeFile(croppedFile.getAbsolutePath()));
                if (mediaFile != null) {
                    Log.i("Camera", "result cancel. Hence, deleting file: " + mediaFile.getPath());
                    Log.i("File deleted ", mediaFile.delete() + "");
                }
            } else {
                if (croppedFile != null) {
                    Log.i("Camera", "result cancel. Hence, deleting file: " + croppedFile.getPath());
                    Log.i("File deleted ", croppedFile.delete() + "");
                }
                if (mediaFile != null) {
                    Log.i("Camera", "result cancel. Hence, deleting file: " + mediaFile.getPath());
                    Log.i("File deleted ", mediaFile.delete() + "");
                }
            }
        }
    }
    

    Everything works perfect as expected below Android 6.0. But it doesn't work on Android 6.0 Marshmallow. In fact it doesn't even open the camera :(

    I don't know whether I have to do something special for marshmallow. I am not getting any kind of error too, that I can post it here. Please help me out.

    Thanks.

  • Chintan Soni
    Chintan Soni over 8 years
    Thank you.. For pointing out this feature of Marshmallow.. I don't know how did I forgot it ? Anyways.. Thanks.. I am trying to give the runtime permission and will update the question soon.
  • LukeWaggoner
    LukeWaggoner over 8 years
    Dude, you freaking saved my tail. Thanks much. You are a gentleman and a scoundrel. ;)
  • Jarrett R
    Jarrett R over 8 years
    As per the guidelines it also says you can avoid asking for too many permissions by using intents to leverage other apps such as the camera to do the work. This means that the camera app would need to have the necessary permissions to take the picture and should return a result. Right? If that is the case then why is his camera not opening? I ask because I have an issue with my app where the result code is not RESULT_OK. I think it has to do with this permissions change.
  • Mattia Maestrini
    Mattia Maestrini over 8 years
    In this case the camera is not opening because the OP try to create a temp file before open the camera. If you have another issue I suggest to open a new question.
  • Mattia Maestrini
    Mattia Maestrini over 8 years
    @ChintanSoni So have you tried to give the runtime permission?
  • Chintan Soni
    Chintan Soni over 8 years
    @MattiaMaestrini Yes sir I achieved it following your suggestion. It took some time to understand the architecture behind the implementation but I did it.. Thanks for your guidance..
  • medloh
    medloh over 8 years
    I had app working on a device with Lollipop, then failed on two devices running Marshmallow. I was getting a message on startup - It seems your device does not support camera (or it is locked). I traced the error through Camera.open() all the way to Camera.cameraInitVersion() where it was returning error of not being able to access Camera service. Didn't realize coding changes were needed for now permission model on Marshmallow.
  • RushDroid
    RushDroid over 8 years
    @ChintanSoni is it Show one request Only for one time in App?
  • Carlos.V
    Carlos.V over 8 years
    what is mediaFile? is it a File ? thanks for the example!
  • Chintan Soni
    Chintan Soni over 8 years
    @Carlos.V Yes. Its file object.
  • Rajesh Gosemath
    Rajesh Gosemath over 7 years
    @ChintanSoni: how this works? Suppose for very first time the permission is not granted it goes on if statement if (!marshMallowPermission.checkPermissionForCamera()) returns false and then request for permission the code will stop here.The other part of the code wont be executed as it is return in else part.
  • Jose Gómez
    Jose Gómez over 7 years
    In addition to the code shown, your activity has to implement a onRequestPermissionsResult method, to handle the accepted permission requests. That method could call getPhotoFromCamera, for example.