title: Issues traversing through directory hierarchy with Android Storage Access Framework / DocumentProvider using MTP
body: <p>UPDATE:
  My initial question may be misleading so I want to rephrase it:
  I want to traverse through the hierarchy tree from an MTP connected device through Android's Storage Access Framework.  I can't seem to achieve this because I get a <code>SecurityException</code> stating that a subnode is not a descendant of its parent node.  Is there a way to workaround this issue?  Or is this a known issue?  Thanks.</p>
  
  <p>I'm writing an Android application that attempts to traverse and access documents through the hierarchy tree using Android's Storage Access Framework (SAF) via the <code>MtpDocumentsProvider</code>. I am more or less following the code example described in <a href="https://github.com/googlesamples/android-DirectorySelection" rel="noreferrer">https://github.com/googlesamples/android-DirectorySelection</a> on how to launch the SAF Picker from my app, select the MTP data source, and then, in <code>onActivityResult</code>, use the returned <code>Uri</code> to traverse through the hierarchy.  Unfortunately, this doesn't seem to work because as soon as I access a sub-folder and try to traverse that, I always get a <code>SecurityException</code> stating that <code>document xx is not a descendant of yy</code></p>
  
  <p>So my question is, using the <code>MtpDocumentProvider</code>, how can I successfully traverse through the hierarchy tree from my app and avoid this exception?</p>
  
  <p>To be specific, in my app, first, I call the following method to launch the SAF Picker:</p>
  
  <pre><code>private void launchStoragePicker() {
      Intent browseIntent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
      browseIntent.addFlags(
          Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
              | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION
              | Intent.FLAG_GRANT_READ_URI_PERMISSION
              | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
      );
      startActivityForResult(browseIntent, REQUEST_CODE_OPEN_DIRECTORY);
  }
  </code></pre>
  
  <p>The Android SAF picker then launches, and I see my connected device recognized as the MTP data source.  I select said data source and I get the <code>Uri</code> from my <code>onActivityResult</code>:</p>
  
  <pre><code>@Override
  public void onActivityResult(int requestCode, int resultCode, Intent data) {
      super.onActivityResult(requestCode, resultCode, data);
      if (requestCode == REQUEST_CODE_OPEN_DIRECTORY &amp;&amp; resultCode == Activity.RESULT_OK) {
          traverseDirectoryEntries(data.getData()); // getData() returns the root uri node
      }
  }
  </code></pre>
  
  <p>Then, using the returned <code>Uri</code>, I call <code>DocumentsContract.buildChildDocumentsUriUsingTree</code> to get a <code>Uri</code> which I can then use to query and access the tree hierarchy:</p>
  
  <pre><code>void traverseDirectoryEntries(Uri rootUri) {
      ContentResolver contentResolver = getActivity().getContentResolver();
      Uri childrenUri = DocumentsContract.buildChildDocumentsUriUsingTree(rootUri, DocumentsContract.getTreeDocumentId(rootUri));
  
      // Keep track of our directory hierarchy
      List&lt;Uri&gt; dirNodes = new LinkedList&lt;&gt;();
      dirNodes.add(childrenUri);
  
      while(!dirNodes.isEmpty()) {
          childrenUri = dirNodes.remove(0); // get the item from top
          Log.d(TAG, "node uri: ", childrenUri);
          Cursor c = contentResolver.query(childrenUri, new String[]{Document.COLUMN_DOCUMENT_ID, Document.COLUMN_DISPLAY_NAME, Document.COLUMN_MIME_TYPE}, null, null, null);
          try {
              while (c.moveToNext()) {
                  final String docId = c.getString(0);
                  final String name = c.getString(1);
                  final String mime = c.getString(2);
                  Log.d(TAG, "docId: " + id + ", name: " + name + ", mime: " + mime);
                  if(isDirectory(mime)) {
                      final Uri newNode = DocumentsContract.buildChildDocumentsUriUsingTree(rootUri, docId);
                      dirNodes.add(newNode);
                  }
              }
          } finally {
              closeQuietly(c);
          }
      }
  }
  
  // Util method to check if the mime type is a directory
  private static boolean isDirectory(String mimeType) {
      return DocumentsContract.Document.MIME_TYPE_DIR.equals(mimeType);
  }
  
  // Util method to close a closeable
  private static void closeQuietly(Closeable closeable) {
      if (closeable != null) {
          try {
              closeable.close();
          } catch (RuntimeException re) {
              throw re;
          } catch (Exception ignore) {
              // ignore exception
          }
      }
  }
  </code></pre>
  
  <p>The first iteration on the outer while loop succeeds: the call to <code>query</code> returned a valid <code>Cursor</code> for me to traverse.  The problem is the second iteration: when I try to query for the <code>Uri</code>, which happens to be a subnode of <code>rootUri</code>, I get a <code>SecurityException</code> stating the document xx is not a descendent of yy.</p>
  
  <blockquote>
    <p>D/MyApp(19241): node uri: content://com.android.mtp.documents/tree/2/document/2/children
    D/MyApp(19241): docId: 4, name: DCIM, mime: vnd.android.document/directory
    D/MyApp(19241): node uri: content://com.android.mtp.documents/tree/2/document/4/children
    E/DatabaseUtils(20944): Writing exception to parcel
    E/DatabaseUtils(20944): java.lang.SecurityException: Document 4 is not a descendant of 2</p>
  </blockquote>
  
  <p>Can anyone provide some insight as to what I'm doing wrong? If I use a different data source provider, for example, one that is from external storage (i.e. an SD Card attached via a standard USB OTG reader), everything works fine.</p>
  
  <p>Additional information:
  I'm running this on a Nexus 6P, Android 7.1.1, and my app <code>minSdkVersion</code> is 19.</p>