I've got to fix our App for Android N due to the FileProvider changes. I've basically read all about this topic for the last ours, but no solution found did work out for me.
Here's our prior code which starts downloads from our app, stores them in the Download
folder and calls an ACTION_VIEW
intent as soons as the DownloadManager
tells he's finished downloading:
BroadcastReceiver onComplete = new BroadcastReceiver() {
public void onReceive(Context ctxt, Intent intent) {
Log.d(TAG, "Download commplete");
// Check for our download
long referenceId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
if (mDownloadReference == referenceId) {
DownloadManager.Query query = new DownloadManager.Query();
query.setFilterById(mDownloadReference);
Cursor c = mDownloadManager.query(query);
if (c.moveToFirst()) {
int columnIndex = c.getColumnIndex(DownloadManager.COLUMN_STATUS);
if (DownloadManager.STATUS_SUCCESSFUL == c.getInt(columnIndex)) {
String localUri = c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
String fileExtension = MimeTypeMap.getFileExtensionFromUrl(localUri);
String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(fileExtension);
if (mimeType != null) {
Intent openFileIntent = new Intent(Intent.ACTION_VIEW);
openFileIntent.setDataAndTypeAndNormalize(Uri.parse(localUri), mimeType);
openFileIntent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
try {
mAcme.startActivity(openFileIntent);
}
catch (ActivityNotFoundException e) {
// Ignore if no activity was found.
}
}
}
}
}
}
};
This works on Android M, but breaks on N due to the popular FileUriExposedException
. I've now tried to fix this by using the FileProvider
, but I cannot get it to work. It's breaking when I try to get the content URI:
Failed to find configured root that contains /file:/storage/emulated/0/Download/test.pdf
The localUri
returned from the DownloadManager
for the file is:
file:///storage/emulated/0/Download/test.pdf
The Environment.getExternalStorageDirectory()
returns /storage/emulated/0
and this is the code for the conversion:
File file = new File(localUri);
Log.d(TAG, localUri + " - " + Environment.getExternalStorageDirectory());
Uri contentUri = FileProvider.getUriForFile(ctxt, "my.file.provider", file);
From AndroidManifest.xml
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="my.file.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"/>
</provider>
The file_paths.xml
:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_path" path="." />
</paths>
And I've tried all values I could find in that xml file. :(
Thanks to @greenaps I was able to solve the issue. The local URI retrieved from the DownlodManager
was prefixed with file://
. This has to be dropped for the new FileProvider
:
if (localUri.substring(0, 7).matches("file://")) {
localUri = localUri.substring(7);
}
File file = new File(localUri);