title: Accessing public download files onActivityResult Android 28 Samsung Galaxy S9+ (Verizon)
body: <blockquote>
    <blockquote>
      <hr>
      
      <p>UPDATE </p>
    </blockquote>
    
    <p>I have a Samsung Galaxy S8+ running 8.0.0 T-Mobile  that it works fine on running
     8.0.0 </p>
    
    <p>My Samsung Galaxy S9+ running 8.0.0 Verizon, it fails everytime with illegal argument. </p>
    
    <p>My Samsung Galaxy S9+ running 8.0.0 T-Mobile has no issues and works fine</p>
    
    <p>So this may be OEM specific model issue, but not
    sure how to fix it yet. I have also tried rebooting the Phone, no
    change in outcome.</p>
    
    <p>Also, I opened the public downloads from within Evernote and saved the
    file as an attachment to a Note, which tells me that Evernote is able
    to access the public directory just fine and attach the file, so it is
    possible to do on the device. Leading me to believe it is code
    related.</p>
    
    <blockquote>
      <hr>
    </blockquote>
  </blockquote>
  
  <p>So I've recently upgraded a project that was working just fine and it now has a bug now that it is compiling with build tools 28, for the latest version of Android.</p>
  
  <p>So I have always used this PathUtil to get the file path I needed from an implicit intent to get file selection from the user. I'll share a link to the code that I am using for a long time now below.</p>
  
  <p><a href="https://gist.github.com/tatocaster/32aad15f6e0c50311626" rel="noreferrer">PathUtil</a></p>
  
  <p>It's just a utility class that checks the provider authority and gets the absolute path for the file you are attempting to read.</p>
  
  <p>When the user selects a file from the public downloads directory it returns to <strong>onActivityResult</strong> with:</p>
  
  <pre><code>content://com.android.providers.downloads.documents/document/2025
  </code></pre>
  
  <p>Now the nice utility parses this out and tells me that this is a download directory file and is a document with id 2025. Thanks utility, that's a great start.</p>
  
  <blockquote>
    <p>Next up is to use the content resolver to find the file absolute path.
    This is what used to work, but no longer does :(.</p>
  </blockquote>
  
  <p>Now the path utility simply uses the contract data that they most likely got from the core library themselves. I tried to import the provider class to avoid static strings, but it doesn't seem to be available, so I guess simply using matching strings is the best way to go for now.</p>
  
  <p>Here is the core DownloadProvider for reference that is providing all the access for the content resolver. 
  <a href="https://android.googlesource.com/platform/packages/providers/DownloadProvider/+/master/src/com/android/providers/downloads/DownloadProvider.java" rel="noreferrer">DownloadProvider</a></p>
  
  <blockquote>
    <p>NOTE* This DownloadProvider is Androids, not mine</p>
  </blockquote>
  
  <p>Here is the code that builds the Uri for the contentProvider</p>
  
  <pre><code> val id = DocumentsContract.getDocumentId(uri)
   val contentUri = ContentUris.withAppendedId(Uri.parse(PUBLIC_DOWNLOAD_PATH), id.toLong())
   return getDataColumn(context, contentUri, null, null)
  </code></pre>
  
  <p>the call references:</p>
  
  <pre><code>    private fun getDataColumn(context: Context, uri: Uri, selection: String?, selectionArgs: Array&lt;String&gt;?): String? {
          var cursor: Cursor? = null
          val column = "_data"
          val projection = arrayOf(column)
          try {
              cursor = context.contentResolver.query(uri, projection, selection, selectionArgs, null)
              if (cursor != null &amp;&amp; cursor.moveToFirst()) {
                  val column_index = cursor.getColumnIndexOrThrow(column)
                  return cursor.getString(column_index)
              }
          }catch (ex: Exception){
              A35Log.e("PathUtils", "Error getting uri for cursor to read file: ${ex.message}")
          } finally {
              if (cursor != null)
                  cursor.close()
          }
          return null
      }
  </code></pre>
  
  <p>Essentially the contentUri to be resolved ends up being</p>
  
  <blockquote>
    <p>content://downloads/public_downloads/2025</p>
  </blockquote>
  
  <p>Then when you call the query method it throws:</p>
  
  <blockquote>
    <p>java.lang.IllegalArgumentException: Unknown URI: content://downloads/public_downloads/2025</p>
  </blockquote>
  
  <p>Things I've confirmed or tried</p>
  
  <ol>
  <li>Read external permissions (comes with write, but did it anyway)</li>
  <li>Write external permissions</li>
  <li>Permissions are in manifest and retrieved at runtime</li>
  <li>I've selected multiple different files to see if one is weird</li>
  <li>I've confirmed permissions are granted in application settings</li>
  <li>I've hard coded the Uri to /1 or even /#2052 on the end to try various ending types</li>
  <li>I've researched the uriMatching on the core library to look for how it expects it to be formatted and ensured it matches</li>
  <li>I've played around with all_downloads directory in the uri and that resolves!!, but with security exception so the resolver must exist.</li>
  </ol>
  
  <p>I don't know what else to try, any help would be appreciated.</p>