Search code examples
androiddownloadscoped-storage

I don't understand why in Android 11 use of `storage\emulated...\downloads` folder can read/write some files and not others?


Problem: I cannot seem to understand why, targeting API 30 (Android 11), my app can still upload and download from the storage\emulated...\download folder for a variety of files all day long, but it fails every time on *.db files... and I was able to on API 29 without issue.

Being a new app, and my first, I don't really want to depend on legacy workarounds. I would rather this work correctly from the start. This app needs to be capable of allowing the user to import and export file attachments to this app's database.

So, back to my original issue... I don't understand why using new FileInputStream(filename) has no issue with using the same path for one file and not another? This is the only shared folder the app and user needs, it caches everything else.

Works with this file and same path

xml file

Doesn't with this file and same path

enter image description here

UPDATE: Added code to clarify intentions to copy.

InputStream source = new FileInputStream(sourcePath);
OutputStream destination = new FileOutputStream(destinationPath);
DatabaseManager.copyDatabase(dbSource, destination);

I can update and replace using the getContentResolver but the same issue still persists -- working for one device and not the other.

InputStream source = getContentResolver().openInputStream(uri);

Solution

  • With help from Mark in the comments above this solved my problem. Since the .db extension is not recognizable, I had to use intent.setType("*/*") and validate the file and extension at the resultLauncher (i.e., ActivityResultLauncher).

    https://developer.android.com/training/data-storage/shared/documents-files#open-file

    private void setupImportDBButton(){
        mImportDB.setOnClickListener(v -> {
            Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
            intent.addCategory(Intent.CATEGORY_OPENABLE);
            intent.setType("*/*");
            resultLauncher.launch(intent);
        });
    }
    

    Included within the ActivityResultLauncher: Basics of the functionality that worked to resolve the multi-device use forced by Android 11 (API 30) requirements. The key was the use of the getContentResolver().

    Uri uri = result.getData().getData();
    String destinationPath = this.getDatabasePath(strDBName).getPath();
    
        InputStream source = this.getContentResolver().openInputStream(uri);
        OutputStream destination = this.getContentResolver().openOutputStream(Uri.fromFile(new File(destinationPath)));
        DatabaseManager.copyDatabase(source, destination);