Gordak
Gordak

Reputation: 2070

How to create a file that other applications (Polaris Office) can read only?

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:

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.

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

Answers (2)

Gordak
Gordak

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

323go
323go

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

Related Questions