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>
Related
I'm unable to store captured image in (getExternalFilesDir(Environment.DIRECTORY_PICTURES)) Android 11 device.
I have added
<uses-permissionandroid:name="android.permission.MANAGE_EXTERNAL_STORAGE"/> in manifest and all file access also. But it's not working.
if (Build.VERSION.SDK_INT >= 30) {
if (!Environment.isExternalStorageManager()) {
try {
val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION)
intent.addCategory("android.intent.category.DEFAULT")
intent.data = Uri.parse(String.format("package:%s", applicationContext.packageName))
startActivityForResult(intent, 2296)
} catch (e: Exception) {
val intent = Intent()
intent.action = Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION
startActivityForResult(intent, 2296)
}
}
}
This code is working below Android 11 device. But on Android 11 file is not creating File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES) .toString() + "/" + FolderName )
Your phone's camera doesnot have permission to write in the specified location. So to fix this, you need to use file provider and give it appropriate permissions so that the camera can write the image to your file.
To do that,
create a FileProvider. In your manifest file, add:
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths" /> // <-------- see this
</provider>
Now create a files.xml file in your res/xml folder. In it, write some code:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<cache-path
name="camera"
path="Camera/" />
<cache-path
name="cache"
path="/" />
<files-path
name="files"
path="." />
<external-path
name="external"
path="." />
<external-files-path
name="my_images"
path="/"/>
// todo: add necessary folders according to your requirements...
// also, this is an old example. Consider googling for the latest style. I'm just copying from an old project I have, and it kinda works...
</paths>
So here we are giving the FileProvider the folders that can be shared with external apps.
2. Now create a uri where you want to store the photo. in your activity:
Context applicationContext = getApplicationContext();
File root = getCachedDir(); // consider using getExternalFilesDir(Environment.DIRECTORY_PICTURES); you need to check the file_paths.xml
File capturedPhoto = new File(root, "some_photo.jpeg");
if(!photoFile.exists()) {
photoFile.mkdirs();
}
Uri photoURI = FileProvider.getUriForFile(applicationContext, applicationContext.getPackageName() + ".fileprovider", capturedPhoto);
Please note that my project needed to save picture temporarily, so I had used cachedDir. If you save photo permanently, use getExternalFilesDir(Environment.DIRECTORY_PICTURES); and modify file_paths.xml properly.
Now that we have the correct uri, we can call the camera intent:
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,photoURI);
startActivityForResult(takePictureIntent, REQUEST_CODE);
Finally, in activty result, do something:
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == REQUEST_CODE && resultCode == RESULT_OK) {
// todo: maybe show photo in an imageView
}
}
I hope this works.
Edit
If you are using this app in production, relying on android's default camera app is a bad idea. Our app previously used this way, and it works with, say, samsung's defaul camera. But a lot of our users used third party apps, such as PixArt, which doesnot save photo to our given location. So we had to implement a builtin camera using CameraX. So consider using CameraX or some other camera library.
First Thing is "android.permission.MANAGE_EXTERNAL_STORAGE" Permission has no relation with saving image.
after Android 11 google say you should do your business in your space.
that mean you cant get or save image or any file as you did before Android 11.
you can only save in Shared folder or in your application storage data/App packagename/.....
if you want to access other app files then you need "android.permission.MANAGE_EXTERNAL_STORAGE" but google say this must be app prior functionality like filemanager or virus scanner like app.
As far as your App concern you havent provide save code.
in Android 11 i am suggestion using Media Api
ContentResolver resolver = mContext.getContentResolver();
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, s);
contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg");
contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + File.separator + getResources().getString(R.string.app_name) + File.separator + "imgfolder");
contentValues.put(MediaStore.Images.Media.DATE_ADDED, System.currentTimeMillis() / 1000);
contentValues.put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis());
contentValues.put(MediaStore.MediaColumns.IS_PENDING, 1);
Uri imageUri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
fos = resolver.openOutputStream(Objects.requireNonNull(imageUri));
try {
mBitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
fos.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
contentValues.clear();
contentValues.put(MediaStore.MediaColumns.IS_PENDING, 0);
resolver.update(imageUri, contentValues, null, null);
}
this is for image file
use this code for save captured image
String mPath = Environment.getExternalStorageDirectory() + "/Print";
Bitmap tmp = BitmapFactory.decodeFile(mPath);
File imageFile = new File(mPath);
FileOutputStream outStream;
try
{
outStream = new FileOutputStream(imageFile);
try
{
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, outStream);
outStream.flush();
outStream.close();
} catch (IOException e)
{
e.printStackTrace();
}
} catch (Exception e)
{
e.printStackTrace();
}
One of the features of my app is to allow user to assign a photo of an item stored in a DB. This could be done by either taking a new photo with the in-built camera or choosing an image from the library. Then app resizes the captured image, retrieve a full size image URI and store both in a DB. Full size image URI is stored for a later use in case user wants to load a full size image with the default image viewer. Everything works fine except viewer is unable to load image from the captured image URI right after the photo is taken, but it is possible to load the same image only when it is chosen from the library.
Ok here is the code:
manifest:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.packagename.inventoryapp.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/fileprovider" />
</provider>
fileprovider.xml
<external-files-path
name="images"
path="Pictures" />
Handle the camera:
#NeedsPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
public void onLaunchCamera(){
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
photoFileName = String.valueOf(System.currentTimeMillis()) + ".jpg";
photoFile = getPhotoFileUri(photoFileName);
Uri fileProvider = FileProvider.getUriForFile(this,
ProductContract.CONTENT_AUTHORITY + ".fileprovider", photoFile);
intent.putExtra(MediaStore.EXTRA_OUTPUT, fileProvider);
if (intent.resolveActivity(getPackageManager()) != null) {
startActivityForResult(intent, CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE);
}
}
public File getPhotoFileUri(String fileName){
File mediaStorageDir = new File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), APP_TAG);
if (!mediaStorageDir.exists() && !mediaStorageDir.mkdirs()){
Log.d(APP_TAG, "failed to create directory");
}
return new File(mediaStorageDir.getPath() + File.separator + fileName);
}
onActivtiyResult (takenImage - global Bitmap variable;
mPicUri - global Uri variable):
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
/* User chose to take a new photo */
if (requestCode == CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE) {
if (resultCode == RESULT_OK) {
File takenPhotoUri = getPhotoFileUri(photoFileName);
mPicUri = FileProvider.getUriForFile
(this, ProductContract.CONTENT_AUTHORITY + ".fileprovider", photoFile);
Bitmap fullSizeImage = BitmapFactory.decodeFile(takenPhotoUri.getAbsolutePath());
takenImage = BitmapScaler.scaleToFitWidth
(fullSizeImage, mProductImageView.getWidth() / 100 * 50);
} else { // Result was a failure
Toast.makeText(this, getString(R.string.no_picture_taken),
Toast.LENGTH_SHORT).show();
}
}
/* User chose to take an an existing photo from the gallery */
else if (requestCode == PICK_PHOTO_CODE){
if (resultCode == RESULT_OK) {
mPicUri = data.getData();
try {
Bitmap fullSizeImage = MediaStore.Images.Media.getBitmap
(getContentResolver(), mPicUri);
takenImage = BitmapScaler.scaleToFitWidth
(fullSizeImage, mProductImageView.getWidth() / 100 * 60);
} catch (IOException e) {
e.printStackTrace();
}
}
}
mProductImageView.setImageBitmap(takenImage);
/* Save image and it's URi to the database */
if (takenImage != null){
ContentValues values = new ContentValues();
values.put(ProductEntry.COLUMN_IMAGE, DbBitmapUtility.getBytesArray(takenImage));
values.put(ProductEntry.COLUMN_IMAGE_URL, mPicUri.toString());
int rows = getContentResolver().update(mProductUri, values, null, null);
}
}
Open default image image viewer to load a full size image from Uri:
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(mPicUri);
startActivity(intent);
I realise that the problem is in Uri path of a captured photo. When I retrieve it in the above way I get something like:
content://com.packagename.inventoryapp.fileprovider/images/InventoryApp/1526632674426.jpg
and Image viewer is launching with the blank screen indicating it is searching for the image with no success.
I tried to get mPicUri with getAbsolutePath() method that leads to the app crashing on launching the intent with that message:
android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.intent.action.VIEW dat=/storage/emulated/0/Android/data/com.packagename.inventoryapp/files/Pictures/InventoryApp/1526635391354.jpg }
On the contrary taking image from the existing library works fine and image Uri looks like:
content://com.google.android.apps.photos.contentprovider/0/1/content%3A%2F%2Fmedia%2Fexternal%2Fimages%2Fmedia%2F2504/ORIGINAL/NONE/1872082740
So the question is it possible to somehow retrieve captured image Uri that is not app private and could be red by image viewer?
android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.intent.action.VIEW dat=/storage/emulated/0/Android/data/com.packagename.inventoryapp/files/Pictures/InventoryApp/1526635391354.jpg }
That is not a valid Uri.
A Uri has a scheme. Yours does not. Yours resembles a bare filesystem path. In principle, you could convert that to a Uri using Uri.fromFile().
However, on Android 7.0+, using such a Uri will fail with a FileUriExposedException.
Instead, use the File with FileProvider.getUriForFile(), and provide that Uri to your ACTION_VIEW Intent. Be sure to also call addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) on that Intent, to allow third-party apps to read the content identified by that Uri.
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>
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
I am following this tutorial to share tweet + image on twitter.
https://docs.fabric.io/android/twitter/compose-tweets.html
Its working perfectly to share text on twitter with success and failure response but i am not able to share image, any one guide me what mistake i am doing here?
Note: when i share image from drawable folder of app it uploads, but i have to download image from Internet and then save it on internal storage.
My commented code below of explains clearly that image is being saved on internal storage as i tested it.
public void composetweet()
{
File myDir = getFilesDir();
File savedImage = new File(myDir + "/text/","test.jpg");
/* if(savedImage.exists()){
Bitmap myBitmap = BitmapFactory.decodeFile(savedImage.getAbsolutePath());
ImageView myTestImage = (ImageView) findViewById(R.id.myimageview);
myTestImage.setImageBitmap(myBitmap);
}*/
Uri myImageUri = Uri.fromFile(savedImage);
Intent intent = new TweetComposer.Builder(this)
.text("just setting up my Fabric.")
.image(myImageUri)
.createIntent();
startActivityForResult(intent, TWEET_COMPOSER_REQUEST_CODE);
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == TWEET_COMPOSER_REQUEST_CODE) {
if(resultCode == Activity.RESULT_OK) {
// onTwitterSuccess();
} else if(resultCode == Activity.RESULT_CANCELED) {
// onTwitterCancel();
}
}
}
I have also tried:
Uri myImageUri = Uri.fromFile(savedImage);
TweetComposer.Builder builder = new TweetComposer.Builder(this)
.text("just setting up my Fabric.")
.image(myImageUri);
builder.show();
But no luck.
Any ideas?
After doing some research i found:
when you are saving data on internal storage from your app and try to pickup inside same app it will work.
But if you want to share that file created from your app in another app, internal storage will not give you permissions.
Hence i followed this solution to make that work:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.mobitsolutions.socialmediashare.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/pathfile"/>
</provider>
The image Uri should be a file Uri (i.e. file://absolute_path scheme) to a local file. For example:
File myImageFile = new File("/path/to/image");
Uri myImageUri = Uri.fromFile(myImageFile);
try to retrive image path with absolutepath also ther is one other option setting Twittercard.
https://dev.twitter.com/cards/types/app