14

Is there a simple API call that would tell me if an app running on Android 10 or later must use Scoped Storage access, that is, if the normal file access, a.k.a. "Legacy External Storage" is disabled? Note that even if the app in AndroidManifest.xml, section declared:

  android:requestLegacyExternalStorage="true"

the file access may still be denied due to Google policy changes in the future, so testing this value is useless. The only way I found is to test if the external storage root directory is readable, but for that, the app must first ask for Storage permission, which is useless for anything else, if legacy storage is disabled.

public static boolean mustUseScopedStorage() {
    // Impractical must first ask for useless Storage permission...
    File exSD = Environment.getExternalStorageDirectory();
    return !exSD.canRead(); // this test works only if Storage permission was granted.
}

I think I have once seen a new API to detect this, but cannot find that article anymore...

Pablo Escobar
  • 679
  • 4
  • 20
gregko
  • 5,642
  • 9
  • 49
  • 76
  • `an app running on Android 10 or later must use Scoped Storage access` ? Can you explain what you mean with that? Which fuctions do you have in mind? I know that for instance Storage Volumes and Storage Manager that were brought for N are already deprecated for Q. – blackapps Oct 07 '19 at 18:53
  • I mean regular Java File access beyond the sandbox assigned to the app by the system, or e.g. in C/C++ JNI code fopen("filename.ext", mode); will not work (access denied) if file path is beyond the app directory assigned by the system. Well, it will work on Android 10 now, if you use android:requestLegacyExternalStorage="true" in the manifest, but it's a temporary solution and may be disabled completely next year. Read more e.g. https://www.androidcentral.com/what-scoped-storage-android-q – gregko Oct 07 '19 at 22:32
  • Even in that article it's not clear what scoped storage would be. – blackapps Oct 08 '19 at 09:00
  • @blackapps, maybe this article explains it better: https://developer.android.com/training/data-storage/files/external-scoped – gregko Oct 09 '19 at 00:25
  • Ok. Restricted access to apps private directories only. – blackapps Oct 09 '19 at 04:57
  • You can read/write anywhere you want, if you ask the user nicely and they give you access, just with a completely different API interface (unnecessary programming work), and 10x - 50x slower when you need to list or search directories. No idea what possessed Google to force this idiocy on us. – gregko Oct 09 '19 at 12:25
  • `and 10x - 50x slower when you need to list or search directories.` No. Not true. Then you do something wrong. The times are about equal. – blackapps Oct 09 '19 at 17:34
  • @blackapps please post your code for listing and searching directories with Scoped Storage API that works as fast as the old File class functions, thanks. – gregko Oct 10 '19 at 00:31
  • @blackapps, OK, I understand that you don't have any code for listing or searching directories using only Scoped Storage API, that works as fast as regular File access... Thanks. – gregko Oct 15 '19 at 12:21
  • Scoped Storage Api uses getFilesDIr(), getExternalFilesDir() and getExternalFilesDirs(). They deliver normal File classes and you can handle them with the classic file routines. – blackapps Oct 15 '19 at 12:51
  • "Scoped Storage Api uses getFilesDIr(), getExternalFilesDir() and getExternalFilesDirs()" - I'm sorry, this is totally unhelpful. When legacy storage access is disabled, you simply CANNOT access directories and files beyond the app assigned directories, which you get with these functions. Try to list e.g. the Download directory with similar functions (using File class), total failure. – gregko Oct 16 '19 at 12:20
  • Yes it is pretty clear that you cannot acces files outside the scoped storage ones with the normal file classes. – blackapps Oct 17 '19 at 07:58

1 Answers1

15

You can use these two methods from android.os.Environment:

  • isExternalStorageLegacy(File path)

    Returns whether the shared/external storage media at the given path is a legacy view that includes files not owned by the app.

  • isExternalStorageLegacy()

    Returns whether the primary shared/external storage media is a legacy view that includes files not owned by the app.

This value may be different from the value requested by requestLegacyExternalStorage in the app's manifest, since an app may inherit its legacy state based on when it was first installed.

Non-legacy apps can continue to discover and read media belonging to other apps via MediaStore.

In case you discover that you have access to legacy storage, personally I think it's better to just migrate data over to scoped storage and use it instead since legacy storage may stop working without warning.

Community
  • 1
  • 1
Zaffy
  • 16,801
  • 8
  • 50
  • 77