My Sample app is working well with the earlier version(before Android M) but getting crash while performing compression after being fetched from internal storage since height and width is coming -1.
Bitmap bmp = BitmapFactory.decodeFile(filePath, options);
int actualHeight = options.outHeight;
int actualWidth = options.outWidth;
After doing some research, I come to the conclusion that the the file is getting corrupted at the time of clicking an image in Android N & M, may be since I'm saving the images as a temporary file not sure.
The following code I'm using for clicking an image:
public void takePhoto() {
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
File f = null;
try {
f = setUpPhotoFile();
mCurrentPhotoPath = f.getAbsolutePath();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, FileProvider.getUriForFile(ctx.getContext(),"com.example.fileprovider", f);
}
else{
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(f));
}
} catch (IOException e) {
e.printStackTrace();
f = null;
mCurrentPhotoPath = null;
}
ctx.startActivityForResult(cameraIntent, CAMERA_PIC_REQUEST);
}
fileprovider.xml
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path name="images" path="Pictures/AIADMK/"/>
</paths>
manifest.xml
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.example.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/fileprovider" />
</provider>
The below is the crash error:
java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/emulated/0/Pictures/AIADMK/IMG_20170428_122804_1986080142.jpg
at android.support.v4.content.FileProvider$SimplePathStrategy.getUriForFile(FileProvider.java:711)
at android.support.v4.content.FileProvider.getUriForFile(FileProvider.java:400)
at helper.ImageHelper.takePhoto(ImageHelper.java:108)
at helper.ImageHelper$1.onClick(ImageHelper.java:73)
at com.android.internal.app.AlertController$AlertParams$3.onItemClick(AlertController.java:1134)
at android.widget.AdapterView.performItemClick(AdapterView.java:315)
at android.widget.AbsListView.performItemClick(AbsListView.java:1193)
at android.widget.AbsListView$PerformClick.run(AbsListView.java:3231)
at android.widget.AbsListView$3.run(AbsListView.java:4207)
at android.os.Handler.handleCallback(Handler.java:815)
at android.os.Handler.dispatchMessage(Handler.java:104)
at android.os.Looper.loop(Looper.java:207)
at android.app.ActivityThread.main(ActivityThread.java:5769)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:789)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:679)
Where am I going wrong?
Add required permissions check before requesting to camera
and in addition
For Android N,
add this code in onCreate() method of your Application class.
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.N) {
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());
}
No need to specify provider or path with this.
Note-Using provider is still the best way to do same task.
hope it help someone !
check permission for marshmallow
if (Build.VERSION.SDK_INT >= 23 &&
(ContextCompat.checkSelfPermission(yourActivityContext, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED)) {
ActivityCompat.requestPermissions(yourActivityContext, new String[]{Manifest.permission.CAMERA}, 2//requestCode);
} else {
selectImage();
}
And override onRequestPermissionsResult of Activity
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case 2: //same request code you provided in code above
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
selectImage();
}
break;
}
}
Check for permission for API 23 and above refer this
http://www.coderzheaven.com/2016/07/29/simple-example-on-using-camera-access-permission-in-android-marshmallow/
Check your onActivityResult() is it give you output in bitmap or uri.
3.If you are getting output in uri convert it into bitmap.
The issue is the latest version of Android because in Android M & N we have to use FileProvider in order to persist the file and for earlier version we can use Uri.fromFile(f).
I do have to change my fileprovider.xml as listed below:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<external-path name="myexternalimages" path="Pictures/AIADMK" />
</paths>
Related
I want to open the camera, save the photo and pass it to an ImageView. However, I am able to take the photo but I cannot confirm the photo creation. I can also cancel or retake the photo but not confirm.
This is the related code that I used. It doesn't even get to onActivityResult when pressing the confirm button.
camera_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.CAMERA) == PackageManager.PERMISSION_DENIED){
requestPermissions(new String[]{ Manifest.permission.CAMERA }, CAMERA_CODE);
}else{
OpenCamera();
}
}
});
private void OpenCamera(){
File file = new File(DbHelper.ImageFolder.getPath() + File.separator + NewImageFileName());
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
Uri uri = FileProvider.getUriForFile(this, getApplicationContext().getPackageName() + ".provider", file);
image_path = uri.getPath();
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivityForResult(intent, CAMERA_CODE);
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (grantResults.length == 0 || grantResults[0] == PackageManager.PERMISSION_DENIED)
return;
switch (requestCode){
case CAMERA_CODE:
OpenCamera();
break;
case GALLERY_CODE:
OpenGallery();
break;
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode != RESULT_OK) return;
Bitmap image = null;
switch (requestCode){
case CAMERA_CODE:
image = BitmapFactory.decodeFile(image_path);
break;
case GALLERY_CODE:
try {
image = MediaStore.Images.Media.getBitmap(getContentResolver(), data.getData());
image_path = NewImageFileName();
// Then saves to local
} catch (IOException e) {
e.printStackTrace();
}
break;
default:
return;
}
food_image.setImageBitmap(image);
}
My cell phone is OnePlus 7 Pro. My code works on another phone I borrowed. I wonder if my code is wrong (or it needs some code to handle compatibility) or there is something wrong with the device. On the emulator (Pixel 3 XL), it keeps taking photos and there is no confirm.
My project is here.
Code posted is here.
---Update---
It seems there is something wrong with other settings. Now it keeps processing the image. And my emulator doesn't get the image set.
The main problem of mine is I forgot to check the permission of writing memory as saving the picture taken requires it:
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) {
requestPermissions(new String[]{ Manifest.permission.WRITE_EXTERNAL_STORAGE }, WRITE_STORAGE);
Adding this properly would make my camera work.
My source code is here.
You are using "OnePlus 7 Pro" to run your app
and it's OS is Android 9.0 (Pie).
If you target to run your application that OS is upper then N you need some file sharing setting
1.Specify the FileProvider
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapp">
<application
...>
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.example.myapp.fileprovider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/filepaths" />
</provider>
...
</application>
</manifest>
2.Specify sharable directories in res/xml/filepaths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="my_images" path="Android/data/com.example.package.name/files/Pictures" />
</paths>
Change some code in on onActivityResult
//*******
Bitmap image = null;
switch (requestCode){
case CAMERA_CODE:
Bundle extras = data.getExtras();
image = (Bitmap) extras.get("data");
break;
//*****
Android Developer Code Link for file sharing provider setting
Android Developer Code Link how to Take Photos
I can successfully run intent sharing a cap screen (bitmap) from a file location "file:///sdcard/temporary_file.jpg". But now i am stuck at saving the bitmap to that location.
I included the following in manifests
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Also this function to check permission:
#Override
public void onRequestPermissionsResult(int requestCode,
String[] permissions, int[] grantResults) {
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// do your stuff
} else {
Toast.makeText(iv_ScoreBoard.this, "GET_ACCOUNTS Denied",
Toast.LENGTH_SHORT).show();
}
break;
default:
super.onRequestPermissionsResult(requestCode, permissions,
grantResults);
}
}
Onclick Sharing button:
View rootView = getWindow().getDecorView().findViewById(android.R.id.content);
Bitmap bitmaptest = getScreenShot(rootView);
Intent share = new Intent(Intent.ACTION_SEND);
share.putExtra(Intent.EXTRA_TEXT, "#Share from App \"XXYY\"");
share.setType("image/jpeg");
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
bitmaptest.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
File f = new File(Environment.getExternalStorageDirectory() + File.separator + "temporary_file.jpg");
try {
f.createNewFile();
FileOutputStream fo = new FileOutputStream(f);
fo.write(bytes.toByteArray());
} catch (IOException e) {
e.printStackTrace();
}
share.putExtra(Intent.EXTRA_STREAM, Uri.parse("file:///sdcard/temporary_file.jpg"));
startActivity(Intent.createChooser(share, "Share Image"));
return true;
getScreenShot(View view)
public static Bitmap getScreenShot(View view) {
View screenView = view.getRootView();
screenView.setDrawingCacheEnabled(true);
Bitmap bitmap = Bitmap.createBitmap(screenView.getDrawingCache());
screenView.setDrawingCacheEnabled(false);
return bitmap;
}
It produces a black screen cap as a picture when share button is clicked...
No file is created, no error is found.
When sharing a file to another application you need to provide Uri permissions.
To do that you first have to create a provider in your Manifest, like this:
<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>
#xml/provider_paths will look like this:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="SavedImages" path="Android/data/com.yourpackagename.yourappname/files/SavedImages/"/>
</paths>
You will have to create the above in your res->xml folder I called mine provider_paths.xml
If you do not have a xml folder, create one.
then when you share your file you should provide the permissions:
Uri imageUri;
Intent share = new Intent(Intent.ACTION_SEND);
if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
imageUri = Uri.parse("file:///sdcard/temporary_file.jpg");
}else {
File newFile = new File(Environment.getExternalStorageDirectory() + File.separator + "temporary_file.jpg");
imageUri = FileProvider.getUriForFile(getContext(), getContext().getPackageName() + ".provider", newFile);
share.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
share.setType("image/jpeg");
share.putExtra(Intent.EXTRA_STREAM, imageUri);
share(Intent.createChooser(share, "Share image using"));
I honestly do not think your issue is regarding runtime permissions. If it was you would get a crash and the file would not be created. As you stated in your question It produces a black screen cap as a picture when share button is clicked... No file is created, no error is found..
When not providing Uri permissions, other other hand, will most likely produce a Uri exposed exception.
The file will still be created, but it would be empty. Like you are experiencing.
You are not requesting/checking permissions at least in the code provided by you in the question.
Your code only implements onRequestPermissionResult, which is called to notify you the results once you have requested the permissions.
You must request permission.
Implement following in your activity.
final int requestCode1 = 100;//this is the constant which you pass while requesting permission.
// this code helps you to identify which permission was requested in onPermissionResultReceived, in case you are dealing with more than one permission groups.
....
onCreate(){
... // your code goes here
...
#Override
public void onClick(View view){
if (ContextCompat.checkSelfPermission(thisActivity,
Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
// Permission is not granted
// request permission
ActivityCompat.requestPermissions(iv_ScoreBoard.this, new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, requestCode1);
} else{
//permission granted
takeScreenShot();
}
Your onRequestPermissionsResult
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case requestCode1:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// do your stuff
takeScreenShot();
} else {
Toast.makeText(iv_ScoreBoard.this, "Permission Denied",
Toast.LENGTH_SHORT).show();
}
break;
default:
super.onRequestPermissionsResult(requestCode, permissions,
grantResults);
}
}
Add above code in onCreate or just before performing the action that requires these permission.
Refer - https://developer.android.com/training/permissions/requesting#java
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 5 years ago.
Improve this question
I am try take a photo and save in Android. I have read this tutorial take photo simple android training
In the tutorial i see that we get Uri by
FileProvider.getUriForFile()
Uri photoURI = FileProvider.getUriForFile(this,"com.example.android.fileprovider",photoFile);
but when i click button download example and download demo from there, the code in this example create Uri by
Uri.fromFile()
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(f));
I have seen that compileSdkVersion of example is 25 but my project use
compileSdkVersion 26
so if i use Uri.fromFile() my project get error (no error if we change compileSdkVersion of my project 26 to 25, but i think i should not do that)
So my question is How we can Take Photo with FileProvider and compileSdkVersion >= 26.
A great way of taking and storing pictures in android is to use the EasyImage library. EasyImage allows you to easily capture images from the gallery, camera or documents without creating lots of boilerplate.
Have a look at the EasyImage android link.
Basic usage is as follows, for advance usage please refer the link above.
To directly open the camera:
EasyImage.openCamera(Fragment fragment, int type);
In your onActivityResult() you can again use EasyImage and use it's handleActivityResult() method to override it's two methods onImagePickerError() and onImagesPicked() to do the relevant work.
I have created an example take photo with Content provider and compileSdkVersion 26. I put my code here for anyone need
private void dispatchTakePictureIntent() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// Ensure that there's a camera activity to handle the intent
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
// Create the File where the photo should go
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException ex) {
ex.printStackTrace();
}
// Continue only if the File was successfully created
if (photoFile != null) {
Uri photoURI = FileProvider.getUriForFile(
this,
"com.funny.fileprovider",
photoFile);
Log.d("=DEBUG=",photoURI.toString());
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
NewNoteActivity.this.grantUriPermission("com.example.funny.stickynote",photoURI, FLAG_GRANT_READ_URI_PERMISSION);
NewNoteActivity.this.grantUriPermission("com.example.funny.stickynote",photoURI, FLAG_GRANT_WRITE_URI_PERMISSION);
takePictureIntent.setFlags(FLAG_GRANT_READ_URI_PERMISSION);
takePictureIntent.setFlags(FLAG_GRANT_WRITE_URI_PERMISSION);
//takePictureIntent.setData(photoURI);
NewNoteActivity.this.setResult(RESULT_OK, takePictureIntent);
PackageManager packageManager = getPackageManager();
//if (takePictureIntent.resolveActivity(packageManager) != null) {
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
//}
}
}
}
When receive the result
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(moreOptionDialog.isShowing()==true)
{
moreOptionDialog.dismiss();
}
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK)
{
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
Bitmap imageBitmap = BitmapFactory.decodeFile(currentPhotoPath, bmOptions);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
(int)getResources().getDimension(R.dimen.image_note_size),
(int)getResources().getDimension(R.dimen.image_note_size)
);
lp.setMargins(
(int)getResources().getDimension(R.dimen.image_note_margin),
(int)getResources().getDimension(R.dimen.image_note_margin),
(int)getResources().getDimension(R.dimen.image_note_margin),
(int)getResources().getDimension(R.dimen.image_note_margin)
);
// Do other work with full size photo saved in mLocationForPhotos
ImageView imageView = new ImageView(this);
//imageView.setBackgroundColor(ContextCompat.getColor(NewNoteActivity.this, R.color.blue));
imageView.setLayoutParams(
new ViewGroup.LayoutParams(lp)
);
imageView.setScaleType(ImageView.ScaleType.FIT_XY);
imageView.setImageBitmap(imageBitmap);
imageListAreaLinearLayout.addView(imageView, lp);
}
}
in the manifest.xml
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.funny.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths"></meta-data>
</provider>
file_paths
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-files-path name="pic" path="Pictures" />
</paths>
I have implemented device camera functionality in my Android app. It's working well and good in all devices I've tested it out. Now I received a crash report from a user who is using Pixel XL.
Is there any change in Pixel XL for fetching the bitmap from onActivityResult?
My code:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
if (requestCode == AppConstants.ACTION_REQUEST_CAMERA && resultCode == Activity.RESULT_OK) {
if(data != null) {
if(data.getData()!=null) {
try {
if (bitmap != null) {
bitmap.recycle();
}
InputStream stream = getContentResolver().openInputStream(data.getData());
bitmap = BitmapFactory.decodeStream(stream);
stream.close();
setCircularBitmap(bitmap);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
} else {
bitmap = (Bitmap) data.getExtras().get("data");
setCircularBitmap(bitmap);
}
} else {
LogUtils.debug("path",initialURI.getEncodedPath());
bitmap = getBitmapFromUri(initialURI);
setCircularBitmap(bitmap);
Toast.makeText(EditProfileActivity.this, "path " + initialURI.getEncodedPath(), Toast.LENGTH_SHORT).show();
}
isProfileImageUpdated = true;
super.onActivityResult(requestCode, resultCode, data);
} else if (requestCode == AppConstants.ACTION_REQUEST_GALLERY && resultCode == Activity.RESULT_OK) {
if(data != null) {
Uri selectedImage = data.getData();
bitmap = getBitmapFromUri(selectedImage);
setCircularBitmap(bitmap);
} else {
LogUtils.debug("path", "Gallery Data null");
}
isProfileImageUpdated = true;
super.onActivityResult(requestCode, resultCode, data);
}
}
The first condition is for device camera, and the second is for Gallery. And I have implemented runtime permissions too.
Got crash in this line:
bitmap = (Bitmap) data.getExtras().get("data");
Anything I'm missing out for Pixel XL? Didn't find any post pointing out to Pixel XL.
EDIT:
Crash Report:
java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=1025, result=-1, data=Intent { }} to activity {com.paramsolutions.leadshare/com.paramsolutions.leadshare.activity.EditProfileActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object android.os.BaseBundle.get(java.lang.String)' on a null object reference
at android.app.ActivityThread.deliverResults(ActivityThread.java:4089)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:4132)
at android.app.ActivityThread.-wrap20(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1533)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object android.os.BaseBundle.get(java.lang.String)' on a null object reference
at com.paramsolutions.leadshare.activity.EditProfileActivity.onActivityResult(EditProfileActivity.java:323)
at android.app.Activity.dispatchActivityResult(Activity.java:6932)
at android.app.ActivityThread.deliverResults(ActivityThread.java:4085)
The line number points to the above-mentioned line, and I've Moto G4 Plus, which is also 7.0. I don't have that issue. Anything different in Pixel XL?
Does the app crashes for all the Android 7.0 devices.
If your targetSdkVersion is 24 or higher, we have to use FileProvider class to give access to the particular file or folder to make them accessible for other apps.
Steps to replace file:// uri with content:// uri:
Add this to your manifest
<?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>
then create a provider_paths.xml file in xml folder under res folder. Folder may be needed to create if it doesn't exist. The content of the file is shown below. It describes that we would like to share access to the External Storage at root folder (path=".") with the name external_files.
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_files" path="."/>
</paths>
The final step is to change the line of code below in
Uri photoURI = Uri.fromFile(createImageFile());
to
Uri photoURI = FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName() + ".provider", createImageFile());
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()?
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
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 !
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
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
Use File Provider it will help you