问题
I am trying to read a file from the download folder on Android Q by doing this:
        File downloadDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
        File f = new File(downloadDir, "some-existing-file");
        if(!f.exists()) {
            throw new IllegalStateException();
        }
        Uri furi = Uri.fromFile(f);
        try {
            ParcelFileDescriptor des = getContentResolver().openFileDescriptor(
                    furi, "r", null);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
I also set android:requestLegacyExternalStorage="true" in the manifest, and requested WRITE_EXTERNAL_STORAGE and READ_EXTERNAL_STORAGE runtime permissions.
The file exists but when trying to open the file descriptor, an exception arises: 
java.io.FileNotFoundException: open failed: EACCES (Permission denied).
I read the changes made in Android Q storage, but could not figure out how can I just read the file without having user interaction.
Thanks!
回答1:
From Android 6 (Marshmallow) some of critical permissions should be granted at runtime by the user so he/she will know what things can your app access.
this link is all what you need
EDIT
add these to manifest
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
then add this code to your oncreate method
if (android.os.Build.VERSION.SDK_INT >= 23 && (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) !=
                PackageManager.PERMISSION_GRANTED)) {
            ActivityCompat.requestPermissions(
                    this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
                    2000);
        }
this will popup the user a dialog to agree permissions. if the user agrees onRequestPermissionsResult method will be called, so override onRequestPermissionsResult like this
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED && requestCode == 2000) {
        //do what you want with files
    }
}
just pay attention that I set request code to 2000. it's optional.
回答2:
This method was deprecated in API level 29. To improve user privacy, direct access to shared/external storage devices is deprecated. When an app targets Build.VERSION_CODES.Q, the path returned from this method is no longer directly accessible to apps. Apps can continue to access content stored on shared/external storage by migrating to alternatives such as Context#getExternalFilesDir(String), MediaStore, or Intent#ACTION_OPEN_DOCUMENT.
Copied from Android documents.docs
回答3:
After too many hours of trying to figure out what the hell is going on, I managed to find a solution.
I addded to the manifest:
android:requestLegacyExternalStorage="true"
When rebuilding and reinstalling directly from Android Studio, the build system or android runtime does not register a change in the manifest, and the request for  requestLegacyExternalStorage does not register.
I fixed it by completely uninstalling the app: adb uninstall com.example.app and installing it again from android studio.
来源:https://stackoverflow.com/questions/60855299/how-to-read-a-file-directly-from-external-download-directory-on-android-10-q