New Image File From URI Does Not Exist - android

So I'm using the Android Crop library (https://github.com/jdamcd/android-crop) to allow a user to take a picture and then crop it.
I need to create two files: one that contains the original image from the camera and one that contains the cropped image. I do this by defining two Files and two URI's that I then pass into the Android Crop library:
// Camera file.
Calendar calendar = Calendar.getInstance();
cameraCaptureFile = new File(getExternalCacheDir(), "camera-capture-" + calendar.getTime().getTime() + ".tmp");
cameraCaptureUri = FileProvider.getUriForFile(this, getPackageName() + ".provider", cameraCaptureFile);
grantUriPermission(getPackageName(), cameraCaptureUri, FLAG_GRANT_WRITE_URI_PERMISSION & FLAG_GRANT_READ_URI_PERMISSION);
// Cropped file.
croppedFile = new File(getExternalCacheDir(), "cropped.png");
croppedFileUri = FileProvider.getUriForFile(this, getPackageName() + ".provider", croppedFile);
grantUriPermission(getPackageName(), croppedFileUri, FLAG_GRANT_WRITE_URI_PERMISSION & FLAG_GRANT_READ_URI_PERMISSION);
// Start cropping library.
Crop.of(cameraCaptureUri, croppedFileUri)
// Cropping complete lets get our cropped file.
File croppedPng = new File(croppedFileUri.getPath());
The problem is that croppedPng.exists() always returns false; however, when I go into the device storage browser and navigation to Android/data/com.mycompany/cache both the original and cropped files are there as expected.
I'm not quite sure what to make of this since my app was able to create the two files but then it cannot read them? Does not make sense.
Just for completion here are my other configurations related to this problem:
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>
AndroidManifest.xml
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.mycompany.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_paths"/>
</provider>

Related

How to share Videos to any app using Intent?

Issue: What happens is after sharing the video when i launch the app to check the shared video it shows me error of "Unable to import" and "The video is no longer available".
Android Version: Oreo(8.0)
Code: I am trying with the following code to share videos with other apps using intent:
Intent share = new Intent(Intent.ACTION_SEND);
share.setType("video/*");
share.putExtra(Intent.EXTRA_SUBJECT, "abc");
share.putExtra(Intent.EXTRA_TITLE, "abcd");
File imageFileToShare = new File(Environment.getExternalStorageDirectory() + "/mygallery/" + "airp.mp4");
Uri uri = FileProvider.getUriForFile(Main2Activity.this, "abc.dcf.fileprovider", imageFileToShare);
share.putExtra(Intent.EXTRA_STREAM, uri);
share.setPackage("com.abc.in");
startActivity(Intent.createChooser(share, "Message"));
The above code is working fine to share Images but its not working to share videos.
What i have tried: I have tried by sharing various file types like 3gp, mkv, mp4 but nothing is working out and I have also went through various similar questions but no solution is working in case of videos.
Please help me with this issue and also if there is any alternate way to do so?
You can add this to your OnCreate
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());
If that doesn't work for you,
Add Provider to Manifest by doing 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>
Remember to use android:name="androidx.core.content.FileProvider" if you're using androidx
Create a file in xml directory (res/xml) and name 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>
Replace
Uri uri = FileProvider.getUriForFile(Main2Activity.this, "abc.dcf.fileprovider", imageFileToShare);
with this
Uri uri = FileProvider.getUriForFile(Main2Activity.this, BuildConfig.APPLICATION_ID + ".provider",imageFileToShare);

Passing file to other apps on a Huawai tablet with API level 24

My App is creating a PDF and passes it to other Apps to be displayed elsewhere. I create the file in internal storage to have to ask the user for less permissions.
I create my intent via:
Intent viewIntent = new Intent(Intent.ActionView);
Java.IO.File document = new Java.IO.File(filePath);
Android.Net.Uri contentUri = FileProvider.GetUriForFile(
_context,
_context.PackageName + ".provider",
document);
viewIntent.SetDataAndType(contentUri, GetMimeType(document));
viewIntent.SetFlags(ActivityFlags.NewTask);
viewIntent.AddFlags(ActivityFlags.GrantReadUriPermission);
viewIntent.AddFlags(ActivityFlags.ClearTask);
viewIntent.AddFlags(ActivityFlags.GrantPersistableUriPermission);
viewIntent.AddFlags(ActivityFlags.GrantPrefixUriPermission);
viewIntent.AddFlags(ActivityFlags.GrantWriteUriPermission);
Intent chooser = Intent.CreateChooser(viewIntent, "");
chooser.SetFlags(ActivityFlags.NewTask);
chooser.AddFlags(ActivityFlags.GrantReadUriPermission);
chooser.AddFlags(ActivityFlags.ClearTask);
chooser.AddFlags(ActivityFlags.GrantPersistableUriPermission);
chooser.AddFlags(ActivityFlags.GrantPrefixUriPermission);
chooser.AddFlags(ActivityFlags.GrantWriteUriPermission);
_context.StartActivity(viewIntent);
On the Google Pixel 3 XL where I test, I can open a PDF without any issues.
When I do the same on a Huawei tablet with API level 24, sometimes everything works but at other times Adobe Acrobat shows an error: This file could not be accessed. Check the location or the network and try again.
The behavior isn't deterministic, sometimes I get the error but other times everything works fine.
In the Application node of your Android Manifest make sure you've added a FileProvider definition:
<provider android:name="android.support.v4.content.FileProvider" android:authorities="${applicationId}.FileProvider" android:exported="false" android:grantUriPermissions="true">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="#xml/provider_paths" />
</provider>
Add a Resources/xml/provider_paths file with the contents:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_files" path="."/>
</paths>
You can restrict this later if needed. However, for my use case I put files in external storage, which I share from. You need to adjust this accordingly where you are sharing from.
I.e. if you are sharing the file from internal app storage you will need to add a files-path definition there too.
Then when sharing a file you simply do:
var packageName = context.ApplicationInfo.PackageName;
var fileProviderName = $"{packageName}.FileProvider";
var intent = new Intent(Intent.ActionSend);
intent.AddFlags(ActivityFlags.GrantReadUriPermission);
intent.SetType("image/*"); // change mime type if wanting to open in other app
intent.PutExtra(Intent.ExtraStream,
FileProvider.GetUriForFile(context, fileProviderName, new Java.IO.File(filePath)));
StartActivity(intent);
That should be enough, works fine every time for me for sharing images to another app. I don't think you need the flags for your chooser Intent, only for the inner viewIntent. Also the GrantReadUriPermission should be the only thing needed if you are providing flags.

Flutter share image intent

I am trying to share an image via classic Intent. I have added the following items:
file_paths.xml:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<files-path name="my_images" path="." />
</paths>
Manifest:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.example.android.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths" />
</provider>
And finally MainActivity.java:
private void shareFile(String fileName) {
Intent share = new Intent(Intent.ACTION_SEND);
Uri uri = FileProvider.getUriForFile(this, "com.example.android.fileprovider", new File(this.getApplicationInfo().dataDir + "/app_flutter/userphotos", fileName));
share.setData(uri);
share.setType("image/png");
share.putExtra(Intent.EXTRA_STREAM, uri);
share.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(Intent.createChooser(share, "Share"));
}
The problem I am facing is that image I am trying to share has the following path:
/data/user/0/shoedrobe.innovativeproposals.com.shoedrobe/app_flutter/userphotos/receipt20181101094430.jpg
However the FileProvider is trying to access it from here:
java.lang.IllegalArgumentException: Failed to find configured root
that contains
/data/data/shoedrobe.innovativeproposals.com.shoedrobe/app_flutter/userphotos/receipt20181101094430.jpg
For saving images I am using package path_provider and I am saving items under
getApplicationDocumentsDirectory(), which in Android is AppData directory.
I am not sure why FileProvider decided suddenly to go from /data/user/0/ to /data/data/ folder, therefore any help or tips regarding this matter would be highly appreciated.
Update:
I have updated the code as per recommendations and replaced the Uri under MainActivity.java with the following line:
Uri uri = FileProvider.getUriForFile(this, "com.example.android.fileprovider", new File(this.getDir("flutter", Context.MODE_PRIVATE).getPath() + "/app_flutter/userphotos", path));
Nonetheless, the problem still persists (same exception that file is supposed to be under /data/data/<package> instead of /data/user/0. I have also tried to add additional persmissions to my AndroidManifest:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
but it did not work as well. Could the problem lie with my file_paths.xml file?
In the end, none of the proposed solutions did not work; neither using extenal-path, nor the other solution.
The way how I managed in the end to share file was to actually copy it to a temporary (cache) directory first (in flutter path_provider it's getTemporaryDirectory()) and update file_paths.xml to following:
<cache-path name="image" path="."/>
and finally under MainActivity.java:
Uri uri = FileProvider.getUriForFile(this, "com.example.android.fileprovider", new File(this.getCacheDir(), path));
Under the hood, Flutter's getApplicationDocumentsDirectory() is using getDir() instead of dataDir, which could be different.
From the Android documentation on getDataDir(), which is equivalent to this.getApplicationInfo().dataDir:
Returns the absolute path to the directory on the filesystem where all private files belonging to this app are stored. Apps should not use this path directly; they should instead use getFilesDir(), getCacheDir(), getDir(String, int), or other storage APIs on this class.
The returned path may change over time if the calling app is moved to an adopted storage device, so only relative paths should be persisted.
Therefore, to ensure consistency between the directory used for saving images by Flutter and the directory used to retrieve the files via FileProvider, the getUriForFile line in MainActivity.java could be modified like this:
FileProvider.getUriForFile(this, "com.example.android.fileprovider", new File(<your application context>.getDir("flutter", Context.MODE_PRIVATE).getPath() + "/app_flutter/userphotos", fileName));
... replacing <your application context> with the variable storing your application's context, if any.

How to open files (from SD-Card) in gallery

I save paths of different jpg. files in a database. These images are partly in the internal memory and partly in the external memory (SD-card).
Now I want to open the pictures in the gallery.
To open images from the internal memory I use the FileProvider, I proceed as follows:
String path = "/storage/emulated/0/Pictures/Meetings/IMG_Testmeeting20180809_225414.jpg";
File image = new File(path);
Uri uri = FileProvider.getUriForFile(getContext(), "com.meetings.martin.provider",image);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(uri, "image/*");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
getContext().startActivity(intent);
This is my FileProvider in the AndroidManifest.xml:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.meetings.martin.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths">
</meta-data>
</provider>
This is content of the file_paths.xml:
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="my_images" path="." />
</paths>
This works perfectly..
..but , if I want to open an image, which is located on the SD card, I get the following error message:
Failed to find configured root that contains <path>
I've often read that the FileProvider can not access files on the SD card. But how can I then turn the path into a Uri and open it in the gallery?
I solved it.
I added following line to the path file:
<root-path name="external_files" path="/storage/" />

File provider - Files not accessible even in the own app

I am implementing a File Provider, followed the doc carefully but unable to use the files in the app itself or share any file.
Added manifest, created xml file for dir sharing, generating content uri, granting uri permission, tried sharing files with cache, external, internal dir but nothing is working.
Searched the net but found nothing which is missing in the code.
Below is the code:
Manifest:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="package.widget.fileprovider"
android:exported="false"
android:grantUriPermissions="true" >
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/filepaths" />
</provider>
filepaths.xml
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<cache-path name="widgetDoc" path="."/>
</paths>
GetUri:
private Uri getFileUri(Context context, String name){
File newFile = new File(context.getCacheDir() + File.separator + StorageUtil.INTERNAL_DIR, name);
Uri contentUri = FileProvider.getUriForFile(context, "package.widget.fileprovider", newFile);
return contentUri;
}
Code to access pdf file:
Intent target = new Intent(Intent.ACTION_VIEW);
Uri uri = getFileUri(getApplicationContext(), file);
target.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
target.setDataAndType(uri,"application/pdf");
Intent intent = Intent.createChooser(target, "Choose Pdf Viewer...");
startActivity(intent);
Code to access image:
imageview.setImageURI(getFileUri(getApplicationContext(), file));
Kindly help me out where I am going wrong, not even able to use these files in my own app too.
Thanks in advance.
I need to show these image files in a widget and now if am accessing the image files from the widget then it is giving IllegalArgumentException: Failed to find configured root however it is working fine with activity
Ideally, use setImageViewBitmap(), and make sure that your image is small (under 1MB in heap space, such as less than 512x512).
While the RemoteViews can accept a Uri, you have good way of associating Intent.FLAG_GRANT_READ_URI_PERMISSION with a RemoteViews for the purposes of populating an ImageView. And, you cannot export your FileProvider, as FileProvider does not allow that.
You can attempt to identify the user's chosen home screen and use grantUriPermission() to grant the home screen access to this Uri, but I would expect that solution to be fragile.

Categories

Resources