Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Open file in cache directory with ACTION_VIEW

I have been searching for this for a while now but it I can't make this to work correctly. Let me explain.

I have an android application that saves files (images, documents, ...) in the cache directory. At first I used to getExternalCacheDir() method and save them over there but because it should be cached on devices that do not have an SD-card, I have to use getCacheDir().

When I used to getExternalCacheDir() method, it was no problem to open those files in another application like this:

Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(file), mimetype);

But when using the getCacheDir(), those files are saved in the application sandbox and are not accessible from outside the application. So I googled it and came on the **ContentProvider. A ContentProvider makes it possible to open private files with external applications. But when I try to implement it, it doesn't work.

I tried implementing the ContentProvider thanks to this post: How to open private files saved to the internal storage using Intent.ACTION_VIEW? but with no success.

package com.myapplication.providers;

import java.io.File;
import java.io.FileNotFoundException;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.ParcelFileDescriptor;

public class FileProvider extends ContentProvider {

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

    @Override
    public int delete(Uri arg0, String arg1, String[] arg2) {
        return 0;
    }

    @Override
    public String getType(Uri arg0) {
        return null;
    }

    @Override
    public Uri insert(Uri arg0, ContentValues arg1) {
        return null;
    }

    @Override
    public boolean onCreate() {
        return false;
    }

    @Override
    public Cursor query(Uri arg0, String[] arg1, String arg2, String[] arg3,
            String arg4) {
        return null;
    }

    @Override
    public int update(Uri arg0, ContentValues arg1, String arg2, String[] arg3) {
        return 0;
    }
}

Added this provider to the application manifest

<provider
    android:name="com.myapplication.providers.FileProvider"
    android:authorities="com.myapplication"
    android:exported="true" />

And using this code to open the file:

Uri uri = Uri.parse("content://com.myapplication/" + filename);

Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(uri, mimetype);

Thanks in advance!

like image 327
user3669004 Avatar asked May 23 '14 13:05

user3669004


People also ask

Can you access app files on android?

On your Android 10 device, open the app drawer and tap the icon for Files. By default, the app displays your most recent files. Swipe down the screen to view all your recent files (Figure A). To see only specific types of files, tap one of the categories at the top, such as Images, Videos, Audio, or Documents.

What is cache directory in android?

Your Android phone's limited storage can fill up quickly. And one cause of this that's easy to overlook is the stored information that apps regularly create to run at their best. These temporary data files are known as a cache; a fair chunk of your Android phone's storage space might be filled up with cache files.

Where is the cache directory?

Cache files are stored in C:/Documents and Settings/<UserName>/Local Settings/Temporary Internet Files. You can also discover the person's cookies in a similar location, C:/Documents and Settings/<User Name>/Cookies.


1 Answers

I found out that I had to do things differently.

Instead of creating my own ContentProvider, the v4 support library offers a FileProvider class that can be used.

In AndroidManifest.xml add

<application ...>

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

</application>

The FILE_PROVIDER_PATHS is an xml file that describes which files can be read by other applications.

So I added a file_paths.xml file to the res/xml folder.

<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <cache-path name="my_cache" path="." />
</paths>

And the only thing you have to do then is create and start the intent to show the file.

File file = new File(getCacheDir(), "test.pdf");

Uri uri = FileProvider.getUriForFile(context, "be.myapplication", file);

Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setDataAndType(uri, "application/pdf");

startActivity(intent);

And actually that's it.

IMPORTANT: Please do not forget setting FLAG_GRANT_READ_URI_PERMISSION flags for the intent. Otherwise it will not work.

like image 75
user3669004 Avatar answered Oct 04 '22 15:10

user3669004