althaus althaus - 12 days ago 13
Android Question

Open downloaded file on Android N using FileProvider

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. :(

Answer

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);