1

I am working on a simple app that plays audio files and I would like to be able to open the app from an audio file in, for example, a file browser. The intent filter and all that is set, but I am struggling with how to use what I receive.

the content:// uri I receive doesn't seem to be meant to be used to get to the actual file - I have looked at the answers to the question here: Android: Getting a file URI from a content URI?, but the approach described there to get a file and not just use the inputStream (which is basically what I want) doesn't seem to be the right way, judging from the discouaging comments and also this site: How to Consume Content from a Uri. Or am I mistaken?

Right now, I am calling this method in my MainActivity to handle my intent, which basically just creates a temporary copy of the file and passes it to where it's used:

 private fun handleIntent() {

    val uri = intent.data
    val inputStream = contentResolver.openInputStream(uri)
    val outputFile = File(this.cacheDir, "output.wav")
    val outputStream = FileOutputStream(outputFile)
    inputStream.use { input ->
        outputStream.use { output ->
            input.copyTo(output)
        }
    }
    DataRepository.handleFileFromIntent(outputFile)
    showPlayerFragmentWithFreshSelection()
}

This almost works (as in I get what is passed to the app as a File), but in a wrong way. Since I want to add the file to a selection of audio files my player can go through, and would like to be able to save this selection, saving a temporary file, or even a copy at all is not the right approach here (I just named the file "output.wav" here because I knew for my test I would be using a .wav file)

Is there any proper and safe way to get the actual path to the file from my content uri or is this just something that can't (or shouldn't) be done at all?

I am writing this in Kotlin, but answers using Java are very wellcome too!

michpohl
  • 852
  • 8
  • 30
  • There is no way to do this for all Content Uri's, although you could attempt to get a usable file path and fallback to opening the InputStream and copying if it doesn't work. See https://commonsware.com/blog/2016/03/15/how-consume-content-uri.html – Steve M Jan 08 '19 at 21:22

1 Answers1

1

We are using same thing in a production level app, and it is working fine.

        filePath = FileUtils.getPathFromURI(mUri);

 public static String getPathFromURI(Uri contentUri) {

        Cursor cursor = null;
        try {
            final String[] proj = {MediaStore.Images.Media.DATA};
            cursor = getAppContext().getContentResolver().query(contentUri, proj, null, null, null);
            if (cursor == null || cursor.getCount() == 0)
                return "";
            final int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
            cursor.moveToFirst();
            return cursor.getString(column_index);
        } catch (IllegalArgumentException|SecurityException e) {
                return "";
        } finally {
            if (cursor != null && !cursor.isClosed()) cursor.close();
        }
    }
nkalra0123
  • 2,281
  • 16
  • 17
  • This won't work if the uri isn't for something in the MediaStore. – Steve M Jan 08 '19 at 21:21
  • So as long as I know I only work with audio files I am safe because the should be in the MediaStore? I'll give this a go anyway and see how well it works because it doesn't look like there are any real alternatives. – michpohl Jan 09 '19 at 08:07
  • @michpohl there can be audio content Uri's that aren't in the MediaStore... some file explorers will send files like that for example. – Steve M Jan 10 '19 at 20:25
  • So, it seems like you can't really. I'm marking this as a solution, because it seems to be the most valid way of retrieving a path from a content Uri. For its caveats see @SteveM 's valuable comments and the linked sources. – michpohl Feb 20 '19 at 13:25