How to call Android scanner for 3rd party SD card vendors, not the one obtained via getExternalStorage ()

My app allows the user to save files to an external SD card besides the getExternalStorage () path. I understand that Android has no idea about external SD cards, but as we know, many device manufacturers provide an additional SD card slot for tablets / phones. And the path to that specific SD card may be vendor dependent.

My application is giving the user a preference when he can provide a vendor path to the SD card other than the path returned by getExternalStorage ().

Previously, I used the following code to call the media player,

  sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://"
  + Environment.getExternalStorageDirectory())));

      

But now I'm wondering if the following code might work:

  sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://"
  + "/someotherpath/blah/");

      

Will this work? I do not have such a device with an additional SD card slot to test it, your opinion will be helpful to me.

+3


source to share


2 answers


I have looked in the open source Android (Android 4.1)

There is a file called /packages/providers/MediaProvider/src/com/android/providers/media/MediaScannerReceiver.java

It has the following code:

 @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        Uri uri = intent.getData();
        if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
            // scan internal storage
            scan(context, MediaProvider.INTERNAL_VOLUME);
        } else {
            if (uri.getScheme().equals("file")) {
                // handle intents related to external storage
                String path = uri.getPath();
                String externalStoragePath = Environment.getExternalStorageDirectory().getPath();

                Log.d(TAG, "action: " + action + " path: " + path);
                if (action.equals(Intent.ACTION_MEDIA_MOUNTED)) {
                    // scan whenever any volume is mounted
                    scan(context, MediaProvider.EXTERNAL_VOLUME);
                } else if (action.equals(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE) &&
                        path != null && path.startsWith(externalStoragePath + "/")) {
                    scanFile(context, path);
                }
            }
        }
    }

      

As you can see it will check the ACTION_MEDIA_MOUNT (which you are using) and it will call scan (). However, it will use hardcoded MediaProvier.EXTERNAL_VOLUME (instead of the file URI passed in).

To answer your question, you don't need to change your code. Any URI with a file scheme will work the same.

However, there is a possibility that the vendor will change this code.



One more thing. Android 4.2 introduced the multi-user concept and each user has their own external storage. Based on this, the shown code is subject to change.

Update 1

It is interesting. Initially, I just looked through the MediaScannerReceiver part and was under the impression that it only scans one outer volume. However, after you told me you looked at the code and asked if it would work. I investigated a bit and found that it will look for all mountable volumes (as you said).

As I understand it, it goes through the following execution path (this is in the form of pseudo Java code to ignore all instances, etc.)

  • MediaScannerReceiver.onReceive calls check (context, MediaProvider.EXTERNAL_VOLUME);
  • MediaScannerReceiver.scan calls context.startService (new Intent (context, MediaScannerService.class) .putExtras (args)); where args contain key / value pair "volume" = MediaProvider.EXTERNAL_VOLUME)
  • MediaScannerService.onStartCommand calls mServicehandler.sendMessage
  • MediaScannerService.ServiceHandler.handleMessage receives the message and names the scan equivalent (StorageManager.getVolumePaths (), MediaProvider.EXTERNAL_VOLUME)
  • MediaScannerService.scan calls MediaScanner.scanDirectories
  • MediaScanner goes through each directory one by one.

Whereas "StorageManager.getVolumePaths ()" should return all mounted volumes, I think it should be fine with your current code (it will scan all volumes).

0


source


For Api 8 and above, you can use this

 MediaScannerConnection.scanFile(this,
      new String[] { file.toString() }, null,
      new MediaScannerConnection.OnScanCompletedListener() {
  public void onScanCompleted(String path, Uri uri) {
      Log.i("ExternalStorage", "Scanned " + path + ":");
      Log.i("ExternalStorage", "-> uri=" + uri);
  }
 });

      



This only scans a single file, and you can specify any path here, including alternate external storage.

0


source







All Articles