Android : How to write camera intent in android nougat

28,357

Solution 1

Hey please follow this thread as a reference. It will show you how to use File Provider when you set your targetSDK as 24 and change following. In your private static Uri getImageFileUri() method

Change this line

return Uri.fromFile(image);

to

FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName() + ".provider", createImageFile());

Hope this will help you to solve your issue.
For more go to - Setting Up File Sharing - Offical documentation

Solution 2

Try this its not the intent that create the problem once you take the picture and save to the sd card and getting back the uri is different in Nougat....

It is quite easy to implement FileProvider on your application. First you need to add a FileProvider tag in AndroidManifest.xml under tag like below: AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    ...
    <application
        ...
        <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="${applicationId}.provider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/provider_paths"/>
        </provider>
    </application>
</manifest>

And then create a provider_paths.xml file in xml folder under res folder. Folder may be needed to create if it doesn't exist.

res/xml/provider_paths.xml

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="external_files" path="."/>
</paths>

Done! FileProvider is now declared and be ready to use.

The final step is to change the line of code below in MainActivity.java

Uri photoURI = Uri.fromFile(createImageFile());

to

Uri photoURI = FileProvider.getUriForFile(MainActivity.this,
            BuildConfig.APPLICATION_ID + ".provider",
            createImageFile());

And .... done ! Your application should now work perfectly fine on any Android version including Android Nougat. Cheers !

Solution 3

Well it is Android's job to make developers life a living hell with each update :)

googlers, here is a step by step guide for developers who (like the question) have used the samples in Android documentations;

1- in the part you have used

Uri.fromFile(image)

you need to use this snippet:

Uri photoURI = FileProvider.getUriForFile(mContext,
                        "com.sample.test.fileprovider",
                        image);

of course it is needless to say that you have to change com.sample.test to your package name.

2- now you need to declare your provider in your AndroidManifest.xml to do so, under Application tag, paste this tag:

<provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="com.sample.test.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />

3- pay attention to android:resource="@xml/file_paths" you need to create an xml file with same name file_paths under your res/xml/ folder and put this in it:

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="pictures"/>
</paths>

on couple of other snippets on the web, and the documentation itself, it says you need to write this

<external-path name="my_images" path="Android/data/com.example.package.name/files/Pictures" />

instead of ours, it is actually depend on your code, if you create your File using Environment.getExternalStorageDirectory().getPath() you do not need it, but if you followed exactly like the docs, you need to stick to the docs

Solution 4

Here fixed your camera intent problem in 7.0 version,

file:// is not allowed(Android N) to attach with Intent anymore or it will throw FileUriExposedException which may cause your app crash immediately called.

Please check full detail of problems & solution.

Soltution

Share:
28,357
KJEjava48
Author by

KJEjava48

Updated on July 05, 2022

Comments

  • KJEjava48
    KJEjava48 almost 2 years

    In my android application I have to take images using the camera when a button is clicked. It is working perfectly in all Android versions except Android 7 (Nougat). When I choose the camera option, the app is exiting even if the permissions are granted. I think the problem is in the camera-calling Intent. Below is my code.

    camera = (ImageView) dialog.findViewById(R.id.camera);
    
    camera.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            clickCamera();
            dialog.dismiss();
        }
    });
    
    private void clickCamera() { // 1 for icon and 2 for attachment
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(MainActivity.this, new String[] { Manifest.permission.CAMERA }, MY_REQUEST_CODE);
        } else {
            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(MainActivity.this, new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE }, MY_REQUEST_CODE_STORAGE);
            } else {
                currentImageUri = getImageFileUri();
                Intent intentPicture = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                intentPicture.putExtra(MediaStore.EXTRA_OUTPUT, currentImageUri); // set the image file name
                // start the image capture Intent
                startActivityForResult(intentPicture, REQUEST_CAMERA);  // 1 for REQUEST_CAMERA (icon) and 2 for REQUEST_CAMERA_ATT (attachment)
            }
        }
    }
    
    private static Uri getImageFileUri(){
        // Create a storage directory for the images
        // To be safe(r), you should check that the SD card is mounted
        // using Environment.getExternalStorageState() before doing this
    
        imagePath = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "MyProject");
        if (!imagePath.exists()) {
            if (!imagePath.mkdirs()) {
                return null;
            } else {
                // create new folder
            }
        }
    
        // Create an image file name
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
        File image = new File(imagePath, "MyProject_" + timeStamp + ".jpg");
    
        if (!image.exists()) {
            try {
                image.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        // Create an File Uri
        return Uri.fromFile(image);
    }
    
    
    @Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
        switch (requestCode) {
            case MY_REQUEST_CODE: {
                // If request is cancelled, the result arrays are empty.
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    // permission was granted, yay! Do the
                    // contacts-related task you need to do.
                    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                        ActivityCompat.requestPermissions(MainActivity.this, new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE }, MY_REQUEST_CODE_STORAGE);
                    } else {
                        currentImageUri = getImageFileUri();
                        Intent intentPicture = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                        intentPicture.putExtra(MediaStore.EXTRA_OUTPUT, currentImageUri); // set the image file name
                        // start the image capture Intent
                        startActivityForResult(intentPicture, REQUEST_CAMERA);
                    }
                } else {
                    // permission denied, boo! Disable the
                    // functionality that depends on this permission.
                    Toast.makeText(this, "Doesn't have permission... ", Toast.LENGTH_SHORT).show();
                }
                return;
            }
            case MY_REQUEST_CODE_STORAGE: {
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    currentImageUri = getImageFileUri();
                    Intent intentPicture = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                    intentPicture.putExtra(MediaStore.EXTRA_OUTPUT, currentImageUri); // set the image file name
                    // start the image capture Intent
                    startActivityForResult(intentPicture, REQUEST_CAMERA);
                } else {
                    // permission denied, boo! Disable the
                    // functionality that depends on this permission.
                    Toast.makeText(this, "Doesn't have permission...", Toast.LENGTH_SHORT).show();
                }
                return;
            }
        }
    }
    

    What is the problem here for Nougat? Is it because of the Uri returned by getImageFileUri()?

  • Paresh P.
    Paresh P. about 7 years
    This must be a comment. Hold on until you get enough reputation to comment.
  • android_griezmann
    android_griezmann about 7 years
    Yes indeed! For all android versions.
  • KJEjava48
    KJEjava48 about 7 years
    what is this createImageFile() here?
  • android_griezmann
    android_griezmann about 7 years
    createImageFile() is FILE which you want to create on SDCard, in your case you should pass File image.
  • KJEjava48
    KJEjava48 about 7 years
    getting this error when i try ur solution java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.XmlResourceParser android.content.pm.ProviderInfo.loadXmlMetaData(android.cont‌​ent.pm.PackageManage‌​r, java.lang.String)' on a null object reference
  • KJEjava48
    KJEjava48 about 7 years
    @ Does i need to define FileProvider in AndroidManifest as in ur documentaion link??
  • android_griezmann
    android_griezmann about 7 years
    yes you have to follow the steps given in this thread
  • KJEjava48
    KJEjava48 about 7 years
    Now camera is functioning but getting this error java.io.FileNotFoundException: /external_files/Pictures/MyProject/MyProject_20170330_123131‌​.jpg: open failed: ENOENT (No such file or directory) ,because of that i cant catch the image that i have taken
  • KJEjava48
    KJEjava48 about 7 years
    I can see the taken image in folder /sdcard/PICTURES/MyProject/ folder
  • android_griezmann
    android_griezmann about 7 years
  • KJEjava48
    KJEjava48 about 7 years
    does i need to change external_files to sdcard??
  • KJEjava48
    KJEjava48 about 7 years
    @G T Does the external-path name "external_files" will work with every devices??Also is there any requirement for the line intentPicture.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION‌​) with the camera intent
  • greenapps
    greenapps about 7 years
    No. This is ok as answer. And of course we will post answers when posting comments is made impossible for some silly reason.
  • g7pro
    g7pro about 7 years
    @KJEjava48 till date am still working with the same external_files and also i havn't mentioned anything more along with the intent too
  • g7pro
    g7pro about 7 years
    still got issue?
  • KJEjava48
    KJEjava48 about 7 years
    Ur solution is wrking
  • KJEjava48
    KJEjava48 about 7 years
    i have already upvoted ur answer..android_griezmann also given the same answer b4 u, that's why i have marked his answer right.Thank's for ur effort for the answer with complete code.
  • g7pro
    g7pro about 7 years
    Sure i didn't coome to see that in the first place
  • Omer Waqas Khan
    Omer Waqas Khan almost 7 years
    In your solution, can you please define "createImageFile()" method
  • Vishal Gadhiya
    Vishal Gadhiya almost 7 years
    createImageFile() means , last captured image convert in file.like File file = new File("Captured image uri")
  • Aditya Patil
    Aditya Patil over 4 years
    replace android.support.v4.content.FileProvider to androidx.core.content.FileProvider