Android Intent.ACTION_SEND from Internal Storage with Content Provider
S

1

5

I am saving a file on internal storage. It is just a .txt file with some information about objects:

    FileOutputStream outputStream;
    String filename = "file.txt";

    File cacheDir = context.getCacheDir();
    File outFile = new File(cacheDir, filename);
    outputStream = new FileOutputStream(outFile.getAbsolutePath());
    outputStream.write(myString.getBytes());
    outputStream.flush();
    outputStream.close();

Then I am creating a "shareIntent" to share this file:

    Uri notificationUri = Uri.parse("content://com.package.example/file.txt");
    Intent shareIntent = new Intent(Intent.ACTION_SEND);
    shareIntent.putExtra(Intent.EXTRA_STREAM, notificationUri);
    shareIntent.setType("text/plain");
    context.startActivity(Intent.createChooser(shareIntent, context.getResources().getText(R.string.chooser)));

The chosen app now needs access to the private file so I created a Content provider. I just changed the openFile method:

@Override
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
    File privateFile = new File(getContext().getCacheDir(), uri.getPath());
    return ParcelFileDescriptor.open(privateFile, ParcelFileDescriptor.MODE_READ_ONLY);
}

The manifest:

<provider
        android:name=".ShareContentProvider"
        android:authorities="com.package.example"
        android:grantUriPermissions="true"
        android:exported="true">
    </provider>

When opening the Mail App to share the file it says, that it could not attach the file because it only has 0 Bytes. Sharing it via Bluetooth also failed. But I can read out the privateFile in the Content Provider, so it exists and it has content. What is the problem?

Surcingle answered 20/11, 2016 at 11:21 Comment(13)
is query() method called in your custom ContentProvider?Caveman
Yes is called 3 times before openFile. First argument is always: content://com.package.example/file.txtSurcingle
and the projection / columns are: _display_name and _size ? BTW why not to use android.support.v4.content.FileProvider?Caveman
Yes they are in the second argument. I only found ContentProvider when searching this. But I'll take a look at FileProvider now too.Surcingle
but if you still want your custom ContentProvider see android.provider.OpenableColumnsCaveman
Try to get it running with ContentProvider as it is much more flexible then FilePrivider.Laban
they are in the second argument. And.. do you provide the requested info?Laban
just use a MatrixCursor if you dont know what to return from query methodCaveman
What do you mean with flexible? All I need is the access to the private file.Surcingle
flexible? All I need is the access to the private file. Maybe today only. But later... With FileProvider you only can serve files from predetermined directories. Predetermind by Google. Not by you.Laban
opening the Mail App to share the file. Which one? There mostly are more on a system. Try others too.Laban
Okay then I try that out again. I only have one on the device. But sending with bluetooth failed too, saying it cannot find the file.Surcingle
To encourange you: your code looks ok.Laban
S
7

Thanks for pskink. FileProvider worked perfectly:

Gradle dependency:

compile 'com.android.support:support-v4:25.0.0'

Manifest:

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

file_paths.xml in XML folder:

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

Sharing Intent:

    File file = new File(context.getCacheDir(), filename);

    Uri contentUri = FileProvider.getUriForFile(context, "com.package.example", file);

    Intent shareIntent = new Intent(Intent.ACTION_SEND);
    shareIntent.putExtra(Intent.EXTRA_STREAM, contentUri);
    shareIntent.setType("text/plain");
    context.startActivity(Intent.createChooser(shareIntent, context.getResources().getText(R.string.chooser)));
Surcingle answered 20/11, 2016 at 11:57 Comment(1)
You may also need to add this to the intent: shareIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);Oust

© 2022 - 2024 — McMap. All rights reserved.