2

how to check if a Uri user selected from action_open_document tree is got from removable Sd card? i check this but its same for primary sd card and removable sd card! is there any other way?

   protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

     String id=DocumentsContract.getTreeDocumentId(uri);

                    Uri mainuri=DocumentsContract.buildDocumentUriUsingTree(uri,id);


                    grantUriPermission(G.context.getPackageName(), uri,   Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);

          if(   "com.android.externalstorage.documents".equals(uri.getAuthority())){

// its return true for primary and removable sd card !!


}
Mostafa
  • 95
  • 1
  • 10

2 Answers2

2

No.

There is no requirement that a Uri from a storage provider be identifiable in any way. Your assumption (that the authority is com.android.externalstorage.documents for a certain storage provider) does not have to be correct on any Android device. Device manufacturers can supply their own storage providers, with their own Uri structures.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • is there any way to determine user selected removable storage? – Mostafa Sep 02 '17 at 16:12
  • @Mostafa: As I wrote, no. Moreover, your app should not care. If you are using the Storage Access Framework, treat all storage providers equally. – CommonsWare Sep 02 '17 at 16:31
  • I posted on your other answer as well, my question is very similar to this one - https://stackoverflow.com/questions/52830390/null-when-trying-to-parse-uri-from-string-path – ClassA Oct 17 '18 at 09:40
  • @Mostafa if you find a string like XXXX-XXXX in the uri.getPath(), its a removable media – nnyerges Jun 12 '20 at 17:24
2

Since android Q, you must use SAF. In order to know if a URI is a removable media, you can try using the path string: if you find a string like "HHHH-HHHH:" (where H = hexadecimal string character) in the uri.getPath() it means that is a removable media.

 /**
 * Check if SAF uri point to a removable media
 * Search for this regular expression:
 * ".*\\b[ABCDFE[0-9]][ABCDFE[0-9]][ABCDFE[0-9]][ABCDFE[0-9]]-[ABCDFE[0-9]][ABCDFE[0-9]][ABCDFE[0-9]][ABCDFE[0-9]]:\\b.*"
 * @param uri: SAF URI
 * @return true if removable, false if is internal
 */
public boolean isRemovable (Uri uri) {
    String path = uri.getPath();
    String r1 = "[ABCDEF[0-9]]";
    String r2 = r1 + r1 + r1 + r1;
    String regex = ".*\\b" + r2 + "-" + r2 + ":\\b.*";
    if (path != null) {
        return path.matches(regex);
    } else return false;
}

The last method use less memory. The following method is faster nut consume more memory due the regex string, but is short and faster:

public boolean isRemovable (Uri uri) {
    String path = uri.getPath();
    if (path != null) {
        return path.matches(".*\\b[ABCDFE[0-9]][ABCDFE[0-9]][ABCDFE[0-9]][ABCDFE[0-9]]-[ABCDFE[0-9]][ABCDFE[0-9]][ABCDFE[0-9]][ABCDFE[0-9]]:\\b.*");
    } else return false;
}

UPDATE: The original regex only works for subfolder on the SDCARD. To include the root directory, delete the last '\d' characters. This is the correct REGEX:

".*\\b[ABCDFE[0-9]][ABCDFE[0-9]][ABCDFE[0-9]][ABCDFE[0-9]]-[ABCDFE[0-9]][ABCDFE[0-9]][ABCDFE[0-9]][ABCDFE[0-9]]:.*"

so the correct function would be:

private boolean isRemovable (Uri uri) {
    String path = uri.getPath();
    String r1 = "[ABCDEF[0-9]]";
    String r2 = r1 + r1 + r1 + r1;
    String regex = ".*\\b" + r2 + "-" + r2 + ":.*";
    if (path != null) {
        return path.matches(regex);
    } else return false;
}
nnyerges
  • 563
  • 4
  • 15