Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.2k views
in Technique[技术] by (71.8m points)

java - Android 11: Primary directory (invalid) not allowed for content://media/external/file allowed directories are [Download, Documents]

I am trying to create PDF file from base64 string. Because of Storage Update in Android 11, I have to change my code but I'm getting following error in Android 11 devices:

java.lang.IllegalArgumentException: Primary directory (invalid) not allowed for content://media/external/file; allowed directories are [Download, Documents]
   at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:172)
   at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:142)
   at android.content.ContentProviderProxy.insert(ContentProviderNative.java:549)
   at android.content.ContentResolver.insert(ContentResolver.java:2149)
   at android.content.ContentResolver.insert(ContentResolver.java:2111)

This code create a PDF file and save it into folder.

public static void createPDF(Context mContext, String fileName, String base64) {
    try {
        String folderPath;
        File dwldsPath;

        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) {
            folderPath = mContext.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS) + File.separator + "appFolderName";
            dwldsPath = new File(folderPath + "/" + fileName);

            File folder = new File(folderPath);
            folder.mkdirs();

            ContentValues values = new ContentValues();
            values.put(MediaStore.MediaColumns.DISPLAY_NAME, fileName); // file name
            values.put(MediaStore.MediaColumns.MIME_TYPE, "application/pdf"); // file extension, will automatically add to file
            values.put(MediaStore.DownloadColumns.RELATIVE_PATH, folderPath); // end "/" is not mandatory
            Uri uriFile = mContext.getContentResolver().insert(MediaStore.Files.getContentUri("external"), values); // important!
            OutputStream outputStream = mContext.getContentResolver().openOutputStream(uriFile);
            outputStream.write(Base64.decode(base64, 0));
            outputStream.close();
        } else {
            folderPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS) + File.separator + "appFolderName";
            dwldsPath = new File(folderPath + "/" + fileName);

            File folder = new File(folderPath);
            folder.mkdirs();

            FileOutputStream os = new FileOutputStream(dwldsPath, false);
            os.write(Base64.decode(base64, 0));
            os.flush();
            os.close();
        }

        openPDF(mContext, dwldsPath);
    } catch (IOException e) {
        e.printStackTrace();
    } catch (ActivityNotFoundException e) {
        Toast.makeText(mContext, "No PDF Viewer Installed", Toast.LENGTH_LONG).show();
    }
}

This code is working for opening file

  public static void openPDF(Context mContext, File dwldsPath) {
        Intent intentUrl = new Intent(Intent.ACTION_VIEW);
        Uri uri = FileProvider.getUriForFile(mContext, BuildConfig.APPLICATION_ID + ".provider", dwldsPath);
        intentUrl.setDataAndType(uri, "application/pdf");
        intentUrl.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        intentUrl.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        mContext.startActivity(intentUrl);
    }

In addition to this error, folder.mkdirs() returns false in Android 11. Here is provider_paths.xml and defined in AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-path
        name="external"
        path="." />
    <external-files-path
        name="external_files"
        path="." />
    <files-path
        name="files"
        path="." />
</paths>

I google it but I couldn't find any working solution to fix problem. Thanks in advance.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I finally found a solution. I can't say it's a best solution but it works perfectly.

folderPath = mContext.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS) + File.separator + "appFolderName";

to

folderPath = mContext.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS) + File.separator + "appFolderName";

I suppose in Android 11, they allowed to create folder/file in DOWNLOADS folder but not DOCUMENTS. At least I couldn't success. Best regards.

Note for Huawei Developers: You just keep the current file writing strategy. No need to Android 11 special code for now. I tried the new file writing method and it crashed. Apperantly, they didn't fully implemented Android 11.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...