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()
?
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
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
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
Done! FileProvider is now declared and be ready to use.
The final step is to change the line of code below in MainActivity.java
to
And .... done ! Your application should now work perfectly fine on any Android version including Android Nougat. Cheers !
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()
methodChange this line
to
Hope this will help you to solve your issue.
For more go to - Setting Up File Sharing - Offical documentation
Use File Provider it will help you
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
you need to use this snippet:
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:
3- pay attention to
android:resource="@xml/file_paths"
you need to create an xml file with same namefile_paths
under yourres/xml/
folder and put this in it:on couple of other snippets on the web, and the documentation itself, it says you need to write this
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