0

I have updated my app using guidance elsewhere on this forum to use the Android 6.0 permissions model for accessing external SD cards. While the app/permissions work fine when installing the app from new, if I upgrade the app from the previous version (which relied on permissions set in AndroidManifest.xml) the app gets refused access to the SD card - I need to uninstall the existing version and re-install it to regain access.

Can anyone explain why this app update "breaks" external SD card permissions when I replace an already-installed version of the app?

The code I have used (in the onCreate method of my MainActivity) is:

if (Build.VERSION.SDK_INT >= 23) {
    // For Marshmallow devices check permissions for accessing External SD card
    if (Build.VERSION.SDK_INT >= 23) {
        if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
                == PackageManager.PERMISSION_GRANTED) {
            logger.info("Permission is granted");
            return;
        } else {

            logger.info("Permission is revoked");
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
            return;
        }
    }
    else { //permission is automatically granted on sdk<23 upon installation
        logger.info("Permission is granted");
        return;
    }
}

Edit: This code returns "InvalidSourceFolder" when the app has been upgraded from the previous release on a Lollipop device:

File f = new File("/storage/external_SD/DCIM/Camera");
File file[] = f.listFiles();
//If file is null then the source folder isn't valid
if (file == null) {
    return "InvalidSourceFolder";
}
Floern
  • 33,559
  • 24
  • 104
  • 119
  • I should add that this refers to upgrading the app on a phone running Android 5.* (Lollipop) – user1175461 Feb 10 '16 at 17:50
  • "the app gets refused access to the SD card" -- first, your code shown here has nothing to do with [removable storage](https://commonsware.com/blog/2014/04/09/storage-situation-removable-storage.html). It is for [external storage](https://commonsware.com/blog/2014/04/08/storage-situation-external-storage.html). Second, why are you checking `Build.VERSION.SDK_INT >= 23` twice? Third, you are not showing us any file-access code, nor showing how you are confirming that you hold the permission before accessing external storage, so we have no idea what "gets refused access" means. – CommonsWare Feb 10 '16 at 17:54
  • BY "SD card" I mean the external SD card. The double-check for SDK 23 was a typo - apologies. By "refused access" I mean the code below returns "InvalidSourceFolder" – user1175461 Feb 10 '16 at 18:38
  • "I mean the external SD card" -- `WRITE_EXTERNAL_STORAGE` has nothing to do with an "external SD card", otherwise known as [removable storage](https://commonsware.com/blog/2014/04/09/storage-situation-removable-storage.html). – CommonsWare Feb 10 '16 at 18:48
  • Your comment seems to be at odds with the advice given here: http://stackoverflow.com/questions/32629792/cant-create-a-directory-in-external-sd-card-lollipop – user1175461 Feb 10 '16 at 18:58
  • and here: http://stackoverflow.com/questions/2121833/permission-to-write-to-the-sd-card – user1175461 Feb 10 '16 at 19:00
  • No, what I am saying aligns with the accepted answer on the first question and the upvoted question on the second one. – CommonsWare Feb 10 '16 at 19:01
  • So what permission needs to be sought to read/write to an external SD card? – user1175461 Feb 10 '16 at 19:02

1 Answers1

0

what permission needs to be sought to read/write to an external SD card?

You have no ability to "read/write to an external SD card" in general, starting with Android 4.4.

You are welcome to use getExternalFilesDirs(), getExternalCacheDirs(), and getExternalMediaDirs() (note the plural forms) on Context. If the device has supported removable storage, then the second and subsequent entries of the returned paths from those methods will be on removable storage (what you call an "external SD card"). No permission is needed to use these directories.

Beyond that, you have no direct filesystem access to removable storage. The primary exception are devices that shipped with earlier versions of Android (e.g., Android 4.3) and got upgraded to Android 4.4 (or higher). The secondary exception are devices that do not legitimately ship with the Play Store. Devices shipping with Android 4.4+ that legitimately have the Play Store cannot offer direct filesystem access to removable media as part of compatibility testing.

Note that you are also welcome to use the Storage Access Framework (e.g., ACTION_OPEN_DOCUMENT). This allows the user to choose where to place files, and supports not only removable storage but also cloud storage services (e.g., Google Drive, Dropbox). However, you work purely with streams from a ContentResolver, not files.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • Up to now the app has been able to read folders and files from external SD cards on Android 4.3, 4.4 and 5.1. It has been doing this using a file path prefixed with "/storage" (as per the example above). In doing so I guess I've been exploiting a workaround. What I don't understand is why this approach is "broken" by installing an app update containing the Android 6.0 code above (i.e. the /storage... location does not return any files), whereas if I uninstall the previous app version and install the new version (with the v6.0 code) it works fine. Hopefully that makes sense? – user1175461 Feb 10 '16 at 19:28
  • @user1175461: "In doing so I guess I've been exploiting a workaround" -- the device that you have been using presumably fits one of the two exceptions that I cited. "What I don't understand..." -- you would have to ask your device manufacturer or custom ROM author why the change occurs. Your end state (no direct filesystem access) is what you will experience on most Play Store-equipped Android 4.4+ devices. – CommonsWare Feb 10 '16 at 19:32