1

My code for sending a file with an Intent doesn't work with all file sources and I could not find the solution yet:

My app is registered for opening files, so when I select a file in ES File Explorer the intent looks like this:

intent->mData->uriString=/storage/emulated/0/backups/apps/NextGenEndPoint_1.0.apk    

when selecting the same file in Asus File Manager I get following intent:

intent->mData->uriString=/file/sdcard/backups/apps/NextGenEndPoint_1.0.apk

This is my code:

        // With this path it works. Path example being sent by e.g ES File Explorer
        String fileName = "/storage/emulated/0/backups/apps/PDFViewer.apk";
        // with this path it doesn't. This path is sent by Asus File Explorer
        fileName = "/file/sdcard/backups/apps/PDFViewer.apk";
        final Intent installIntent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
        installIntent.setData(getUriForFile(context, "com.myapp.fileprovider", new File(fileName)));
        installIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION);
        context.startActivity(installIntent);

I also tried new File("/file/sdcard/backups/apps/PDFViewer.apk").exists(); what returns false.

The xml:

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
  <external-path name="external" path="/"/>      
</paths>

And the provider in the manifest:

    <provider
        android:name="android.support.v4.content.FileProvider"
        android:authorities="com.myapp.fileprovider"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_provider_paths" />
    </provider>

The exception:

 11-02 12:21:09.004: E/ACRA(9807): com.mycompany.myapp fatal error : Failed to find configured root that contains /file/sdcard/PDFViewer.apk
 11-02 12:21:09.004: E/ACRA(9807): java.lang.IllegalArgumentException: Failed to find configured root that contains /file/sdcard/PDFViewer.apk
 11-02 12:21:09.004: E/ACRA(9807):  at android.support.v4.content.FileProvider$SimplePathStrategy.getUriForFile(SourceFile:711)
 11-02 12:21:09.004: E/ACRA(9807):  at android.support.v4.content.FileProvider.getUriForFile(SourceFile:400)

What am I missing?

David
  • 3,971
  • 1
  • 26
  • 65
  • `fileName = "/file/sdcard/backups/apps/PDFViewer.apk";`. Are you sure it is not `fileName = "file:///sdcard/backups/apps/PDFViewer.apk";` ? Change to `fileName = "/sdcard/backups/apps/PDFViewer.apk";`. – greenapps Nov 02 '16 at 17:59
  • `new File(pkg)`?? What is pkg? And fileName is not used. – greenapps Nov 02 '16 at 18:01
  • the path does not include file:/// I hardcoded the string so you can see what I get, but I get those paths automatically by the file provider of those apps – David Nov 03 '16 at 09:44
  • Yes i know. So the solution is very simple. If such a path starts with "/file/" then replace it by "/" as i said before. Why didn't you try? Why didn't you react on my suggestion? – greenapps Nov 03 '16 at 10:23
  • But before doing so and before calling the intent you could use the `File` class to see if that /file/.... path exists. Or is it is some Asus 'feature'. Asus explores gets only delivered with an Asus device? – greenapps Nov 03 '16 at 10:27
  • Or use ES File Explorer to see if you can see that path delivered by Asus explorer. If so then pick that same file with ES. – greenapps Nov 03 '16 at 11:24
  • I update the questions with a few more details. But replacing "/file/" would not be a general solution or? I'm wondering why do the paths differ at first? If you open the APK with the default Android Package Installer the app gets installed, so the Package Installer can also read the file. – David Nov 03 '16 at 12:34
  • `tried new File("/file/sdcard/backups/apps/PDFViewer.apk"); what returns false.`. Impossible.That will return a File object. What do you mean exactly? And you swapped the uris of the explorers. Now you blame ES File Explorer. – greenapps Nov 03 '16 at 12:55
  • `/file/sdcard/backups/apps/NextGenEndPoint_1.0.apk`. No that is only a part of the content sheme you got. File Manager app from ASUS will deliver `content://com.asus.filemanager.OpenFileProvider/file/sdcard/backups/apps/NextGenEndPoint_1.0.apk`. You better show your code where you determine the 'path' as now you do it wrong. – greenapps Nov 03 '16 at 13:20

3 Answers3

1

In the referenced File:

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
  <external-path name="external" path="/"/>      
</paths>

use files-path instead of external-path

or

use Environment.getExternalStorageDirectory()

Chandan Rai
  • 9,879
  • 2
  • 20
  • 28
0
 /file/sdcard/backups/apps/NextGenEndPoint_1.0.apk. 

No that is only a part of the content sheme you got. File Manager app from ASUS will deliver

 content://com.asus.filemanager.OpenFileProvider/file/sdcard/backups/apps/NextGeEndPoint_1.0.apk. 

You better show your code where you determine the 'path' as now you do it wrong.

greenapps
  • 11,154
  • 2
  • 16
  • 19
  • but my problem is with installIntent.setData and this works using the path "/storage/emulated/0/backups/apps/NextGenEndPoint_1.0.apk" which also does not have the first part content://... – David Nov 03 '16 at 13:32
  • Indeed. Because that is a valid file system path delivered by ES File Explorer .. But ASUS File Manager does not give you a file system path but a content scheme path. – greenapps Nov 03 '16 at 13:35
0

The problem was using getUriForFile for file system paths and also for File Provider paths that actually must be used with a content resolver, so the solution was following:

            Uri uri;
            if (ContentResolver.SCHEME_CONTENT.equals(fileUri.getScheme())) {
                uri = new Uri.Builder()
                        .path(fileUri.getPath())
                        .authority(fileUri.getAuthority())
                        .scheme(ContentResolver.SCHEME_CONTENT)
                        .build();
            } else {
                uri = getUriForFile(context, "com.myapp.fileprovider", new File(fileUri.getPath()));
            }
David
  • 3,971
  • 1
  • 26
  • 65