0

The following code is working absolutely fine in devices with API 22 but in devices with API 24 it gives the following error:

java.lang.SecurityException: MODE_WORLD_READABLE no longer supported

Here is my code:

private void CopyReadAssets(String filename) {
    AssetManager assetManager = getAssets();
    InputStream in = null;
    OutputStream out = null;
    File file = new File(getFilesDir(), filename);

    try {
        in = assetManager.open(filename);
            out = openFileOutput(file.getName(), Context.MODE_WORLD_READABLE);

        copyFile(in, out);
        in.close();
        in = null;
        out.flush();
        out.close();
        out = null;

        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setDataAndType(Uri.fromFile(file),"application/pdf");

        startActivity(intent);
    } catch (Exception e)
    {
        Log.e("cra",e.toString());
        Toast.makeText(PdfFilesList.this, "cra: "+e.toString(), Toast.LENGTH_SHORT).show();
    }
}

If I change MODE_WORLD_READABLE to MODE_PRIVATE then it stops working in all devices. devices with API 22 give the following error

11-16 12:00:53.133 16531-31103/? E/DisplayData: openFd: java.io.FileNotFoundException: Permission denied
11-16 12:00:53.134 16531-31103/? E/PdfLoader: Can't load file (doesn't open)  Display Data [PDF : 818 New Jeevan Nidhi.pdf] +FileOpenable, uri: file:///data/data/com.user.plansmart/files/818%20New%20Jeevan%20Nidhi.pdf

Device with API 24 throw the following exception

11-16 12:05:00.100 2682-2682/com.user.plansmart E/cra: android.os.FileUriExposedException: file:///data/user/0/com.user.plansmart/files/827%20Jeevan%20Rakshak.pdf exposed beyond app through Intent.getData()

Can someone help me in resolving the issue.

Thanks.

pamo
  • 111
  • 2
  • 13
  • `cannot-display-pdf-file-from-assets-folder` Wrong info. You are trying to let an external app display a pdf file from your apps internal storage. NOT from assets. – greenapps Nov 16 '17 at 09:24

2 Answers2

0

Found a workaround instead of using MODE_WORLD_READABLE since looking here

int MODE_WORLD_READABLE This constant was deprecated in API level 17. Creating world-readable files is very dangerous, and likely to cause security holes in applications. It is strongly discouraged; instead, applications should use more formal mechanism for interactions such as ContentProvider, BroadcastReceiver, and Service. There are no guarantees that this access mode will remain on a file, such as when it goes through a backup and restore.

private void CopyReadAssets(String filename) {
    AssetManager assetManager = getAssets();
    InputStream in;
    OutputStream out;

    try {
        in = assetManager.open(filename);
        String outDir = Environment.getExternalStorageDirectory().getAbsolutePath();

        File outFile = new File(outDir, filename);
        if(outFile.createNewFile()){
            return;
        }

        out = new FileOutputStream(outFile);

        copyFile(in, out);
        in.close();
        out.flush();
        out.close();

        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setDataAndType(Uri.fromFile(outFile), "application/pdf");

        startActivity(intent);
    } catch (Exception e) {
        Log.e("cra", e.toString());
        Toast.makeText(this, "cra: " + e.toString(), Toast.LENGTH_SHORT).show();
    }
}

For devices, after M you need to ask permission separately.

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(this,
                new String[]{Manifest.permission
                        .READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE},
                102);
    }
} else {
    CopyReadAssets("yourpdf.pdf");
}

Then in onRequestPermissionsResult implement, your code.

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    switch (requestCode) {
        case 102:
            CopyReadAssets("yourpdf.pdf");
            break;
    }
}

Hope this helps

Gautam Chibde
  • 1,167
  • 3
  • 14
  • 27
0

You should use a FileProvider to serve your files with Intent.ACTION_VIEW.

Code doing so you can find plenty on this site.

greenapps
  • 11,154
  • 2
  • 16
  • 19
  • Yes I have come to realise that this can be done only with Fileprovider and yes there is plenty of code but none fulfills my need. I'm just waiting if someone can help me here. – pamo Nov 17 '17 at 00:19