Reputation: 2070
Here is what I'm trying to do in my app. I download files (docx, pptx, pdf, mov, etc) and store them in a File
. After having downloaded the file, I want the user to be able to open it and read it. I don't want the user to be able to modify the File
!
Here is how I have tried to achieve this.
String uri = nameFileStatic + extension;
RestClientGetAsFile client = new RestClientGetAsFile(url, getActivity(), uri) {
@Override
protected void onPostExecute(File results) {
if (results != null) {
if (results.exists()) {
Uri path = Uri.fromFile(results);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(path, type); //type
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
try {
startActivity(intent);
} catch (ActivityNotFoundException e) {
Toast.makeText(DescriberAttachments.this.getActivity(),
"No Application Available to View file with extension " + extension, Toast.LENGTH_SHORT).show();
}
}
}
}
};
client.execute();
Basically, I download the file inside a AsyncTask instance. Then in the onPostExecute()
method I open the file with an Intent.
Now the question is: where to store the file ? Here is what I tried:
getDir("SLIMS", Context.MODE_WORLD_READABLE ).getAbsolutePath() + "/Attachments/myfile.docx"
. Before saving the file I always make sure the dir exists. File directoryMain = new File(getDir("SLIMS", Context.MODE_PRIVATE).getAbsolutePath()); directoryMain.mkdir(); File directoryAttachments = new File( getDir("SLIMS", Context.MODE_PRIVATE).getAbsolutePath() + "/Attachments"); directoryAttachments.mkdir();
Unfortunately, I can't open the file afterwards... I got an message error (From Polaris Office) but can't find any relevant message inside my Log.
uri = getFilesDir() + "/Attachments/myfile.docx".
I got the very same error as in the previous point.
uri = Environment.getExternalStorageDirectory() + "/Attachments/myfile.docx"
. This time I can open the File in Polaris Office, but I can't make the File
read-only. I tried myFile.setReadOnly()
, myFile.setReadable(true)
and myFile.setWritable(false)
but I was still able to modify the File in the end.
So I guess for now I will still store those File in the sdcard but I'm really annoyed about the write permission.
Any suggestion ?
Upvotes: 1
Views: 1300
Reputation: 2070
As 323go suggested, I implemented a ContentProvider. My code is from CommonsWare's post.
Here is my code to download the file. Once the file is downloaded, I save it as "ComingFromSLIMSDatabase" + extension. Extension can be docx, pptx, pdf, ect. Once my file is downloaded, I call start an Activity with an implicit Intent and give the uri of the content Provider.
String uri = nameFileStatic + extension;
RestClientGetAsFile client = new RestClientGetAsFile(url, getActivity(), uri) {
@Override
protected void onPostExecute(File results) {
if (results != null) {
if (results.exists()) {
results.setReadable(true);
try {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(AttachmentProvider.CONTENT_URI
+ "ComingFromSLIMSDatabase" + extension)));
} catch (ActivityNotFoundException e) {
Toast.makeText(DescriberAttachments.this.getActivity(),
"No Application Available to View file with extension " + extension, Toast.LENGTH_SHORT).show();
}
}
}
}
};
client.execute();
Then the ContentProvider catches the call and open the file I want to show.
public class FileProvider extends ContentProvider {
public static final Uri CONTENT_URI=Uri.parse("content://com.commonsware.android.cp.files/");
private static final HashMap<String, String> MIME_TYPES=new HashMap<String, String>();
static {
MIME_TYPES.put(".pdf", "application/pdf");
}
@Override
public boolean onCreate() {
File f=new File(getContext().getFilesDir(), "test.pdf");
if (!f.exists()) {
AssetManager assets=getContext().getResources().getAssets();
try {
copy(assets.open("test.pdf"), f);
}
catch (IOException e) {
Log.e("FileProvider", "Exception copying from assets", e);
return(false);
}
}
return(true);
}
@Override
public String getType(Uri uri) {
String path=uri.toString();
for (String extension : MIME_TYPES.keySet()) {
if (path.endsWith(extension)) {
return(MIME_TYPES.get(extension));
}
}
return(null);
}
@Override
public ParcelFileDescriptor openFile(Uri uri, String mode)
throws FileNotFoundException {
String path = uri.getPath();
File f=new File(getContext().getFilesDir(),path);
if (f.exists()) {
return(ParcelFileDescriptor.open(f,
ParcelFileDescriptor.MODE_READ_ONLY));
}
throw new FileNotFoundException(uri.getPath());
}
@Override
public Cursor query(Uri url, String[] projection, String selection,
String[] selectionArgs, String sort) {
throw new RuntimeException("Operation not supported");
}
@Override
public Uri insert(Uri uri, ContentValues initialValues) {
throw new RuntimeException("Operation not supported");
}
@Override
public int update(Uri uri, ContentValues values, String where, String[] whereArgs) {
throw new RuntimeException("Operation not supported");
}
@Override
public int delete(Uri uri, String where, String[] whereArgs) {
throw new RuntimeException("Operation not supported");
}
static private void copy(InputStream in, File dst) throws IOException {
FileOutputStream out=new FileOutputStream(dst);
byte[] buf=new byte[1024];
int len;
while((len=in.read(buf))>0) {
out.write(buf, 0, len);
}
in.close();
out.close();
}
}
With this method, the user can open a file even if it was stored in Context.getFilesDir(). Now I'm still confused. Because if I open a doc file, I can still modify it and save it somewhere else. And it's not a desirable feature at the moment.
I would like to know if anyone knows a way to view the content of the file without letting another application save it somewhere else.
Upvotes: 0
Reputation: 14274
Create a ContentProvider
inside your app and launch the viewer app with a reference to the content scheme, such as content://com.mydomain.myapp/file/filename.jpg
.
Upvotes: 2