5

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!

voidbar
  • 141
  • 2
  • 7
  • Why not just open the `File` directly (e.g., with `FileInputStream`)? Why are you using a `Uri` and a `ContentResolver`? Bear in mind that even with `android:requestLegacyExternalStorage="true"` that you still need to request runtime permissions. Also, where are you getting `downloadDir` from? – CommonsWare Mar 25 '20 at 18:42
  • `FileInputStream` I receive the same outcome. I didn't mentioning but i did ask for the needed runtime permissions. – voidbar Mar 25 '20 at 18:53
  • Are other locations working? In other words, is your problem limited to this one directory, or are you unable to access files everywhere on external storage? – CommonsWare Mar 25 '20 at 18:56
  • Just tried with `Environment.DIRECTORY_DOCUMENTS` and `Environment.DCIM`, received the same outcome. – voidbar Mar 25 '20 at 19:03
  • Then perhaps there is an issue with where and how you applied `android:requestLegacyExternalStorage="true"`. Can you post your manifest? – CommonsWare Mar 25 '20 at 19:11
  • Sure: here it is: https://pastebin.com/cjvPMVrf – voidbar Mar 25 '20 at 19:22
  • OK, that looks normal. I and others have used `android:requestLegacyExternalStorage="true"` without a problem, so I am uncertain as to what is going wrong here for you. – CommonsWare Mar 25 '20 at 19:40
  • It can be hep you .[answer](https://stackoverflow.com/a/56468733/8956604) – Kasım Özdemir Mar 25 '20 at 20:32
  • 1
    Kasim, the answer you provided is for writing files, not reading them :(. – voidbar Mar 25 '20 at 21:15
  • CommonsWare, do you might have a code sample that work for you? I'd be happy to take a look. Thanks! – voidbar Mar 25 '20 at 21:16

3 Answers3

0

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.

Reza
  • 845
  • 13
  • 18
  • Hi, please note that I said that i asked for the runtime permissions. – voidbar Mar 25 '20 at 19:11
  • @v0idbar it is interesting that I ran into a problem like yours today. below link helped me. try it. https://stackoverflow.com/a/38858040/8136868 – Reza Mar 26 '20 at 15:38
0

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

Kasım Özdemir
  • 5,414
  • 3
  • 18
  • 35
0

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.

voidbar
  • 141
  • 2
  • 7
  • Please note that adding `android:requestLegacyExternalStorage="true"` is not safe as it's a temporary flag and would be removed soon. Also targeting SDK 29 for new and old app is going to be mandatory on play store by end of the year. So please refrain from suggesting this as a solution, and using this as solution. – shaktiman_droid Apr 30 '20 at 19:59