Create and Share a File from Internal Storage

Create and Share a File from Internal Storage

It is possible to expose a file stored in your apps private directory via a ContentProvider. Here is some example code I made showing how to create a content provider that can do this.

Manifest

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.providertest"
android:versionCode="1"
android:versionName="1.0">

<uses-sdk android:minSdkVersion="11" android:targetSdkVersion="15" />

<application android:label="@string/app_name"
android:icon="@drawable/ic_launcher"
android:theme="@style/AppTheme">

<activity
android:name=".MainActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

<provider
android:name="MyProvider"
android:authorities="com.example.prov"
android:exported="true"
/>
</application>
</manifest>

In your ContentProvider override openFile to return the ParcelFileDescriptor

@Override
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
File cacheDir = getContext().getCacheDir();
File privateFile = new File(cacheDir, "file.xml");

return ParcelFileDescriptor.open(privateFile, ParcelFileDescriptor.MODE_READ_ONLY);
}

Make sure you have copied your xml file to the cache directory

    private void copyFileToInternal() {
try {
InputStream is = getAssets().open("file.xml");

File cacheDir = getCacheDir();
File outFile = new File(cacheDir, "file.xml");

OutputStream os = new FileOutputStream(outFile.getAbsolutePath());

byte[] buff = new byte[1024];
int len;
while ((len = is.read(buff)) > 0) {
os.write(buff, 0, len);
}
os.flush();
os.close();
is.close();

} catch (IOException e) {
e.printStackTrace(); // TODO: should close streams properly here
}
}

Now any other apps should be able to get an InputStream for your private file by using the content uri (content://com.example.prov/myfile.xml)

For a simple test, call the content provider from a seperate app similar to the following

    private class MyTask extends AsyncTask<String, Integer, String> {

@Override
protected String doInBackground(String... params) {

Uri uri = Uri.parse("content://com.example.prov/myfile.xml");
InputStream is = null;
StringBuilder result = new StringBuilder();
try {
is = getApplicationContext().getContentResolver().openInputStream(uri);
BufferedReader r = new BufferedReader(new InputStreamReader(is));
String line;
while ((line = r.readLine()) != null) {
result.append(line);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try { if (is != null) is.close(); } catch (IOException e) { }
}

return result.toString();
}

@Override
protected void onPostExecute(String result) {
Toast.makeText(CallerActivity.this, result, Toast.LENGTH_LONG).show();
super.onPostExecute(result);
}
}

Android Intent.ACTION_SEND from Internal Storage with Content Provider

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

Share text file via Intent from internal storage

I found one of solution for this problem. How @CommonsWare suggested I used a FileProvider. I follow this example. But in provider_paths.xml I put this code, because I use a internal storage.

<Paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path name="files" path="."/>
</Paths>

Then in activity I send a file via intent like this:

       Uri path = FileProvider.getUriForFile(this,"same_authoritory_which_was_in_manifest", new File(FILE_TO_SAVE.getPath()));
Intent i = new Intent(Intent.ACTION_SEND);
i.putExtra(Intent.EXTRA_TEXT, "Test");
i.putExtra(Intent.EXTRA_STREAM, path);
i.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
i.setType("plain/*");
startActivity(i);

How could I create a file in the Internal Storage Directory?

After a while later I found the answer to this question.

public void createDirectory() {
File file = new File(Environment.getExternalStorageDirectory(), "/test");
if (!file.exists()) {
file.mkdirs();
Log.w("DEBUG", "Created default directory.");

}
}

This is how you create it code wise. The reason it wasn't creating was due to Samsungs weird permissions.

Make sure you have the storage permission enabled in Settings -> Apps -> App Name -> Permissions. I needed to turn it on so it would create the folder.

Writing to file in Documents folder in internal storage

File file = new File(Environment.DIRECTORY_DOCUMENTS, "myFile.txt");

File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS), "myFile.txt");


Related Topics



Leave a reply



Submit