Check visible paths as well when generate docId from file system path.
getDocumentUri(String, List<UriPermission>) needs it because MediaStore
can only provide path under visible paths for external SD cards.
Test: Manual test w/ SD card. Relative CTS tests pass. Happy to add
automated tests for SD card cases if somebody shows me how.
Bug: 33819522
Change-Id: I15cdd60a2d2c94275dd661f20b5b0deb0d80d258
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index 8cf375a..cbd295e1 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -287,26 +287,23 @@
String path = file.getAbsolutePath();
// Find the most-specific root path
- String mostSpecificId = null;
- String mostSpecificPath = null;
- synchronized (mRootsLock) {
- for (int i = 0; i < mRoots.size(); i++) {
- final String rootId = mRoots.keyAt(i);
- final String rootPath = mRoots.valueAt(i).path.getAbsolutePath();
- if (path.startsWith(rootPath) && (mostSpecificPath == null
- || rootPath.length() > mostSpecificPath.length())) {
- mostSpecificId = rootId;
- mostSpecificPath = rootPath;
- }
- }
+ boolean visiblePath = false;
+ RootInfo mostSpecificRoot = getMostSpecificRootForPath(path, false);
+
+ if (mostSpecificRoot == null) {
+ // Try visible path if no internal path matches. MediaStore uses visible paths.
+ visiblePath = true;
+ mostSpecificRoot = getMostSpecificRootForPath(path, true);
}
- if (mostSpecificPath == null) {
+ if (mostSpecificRoot == null) {
throw new FileNotFoundException("Failed to find root that contains " + path);
}
// Start at first char of path under root
- final String rootPath = mostSpecificPath;
+ final String rootPath = visiblePath
+ ? mostSpecificRoot.visiblePath.getAbsolutePath()
+ : mostSpecificRoot.path.getAbsolutePath();
if (rootPath.equals(path)) {
path = "";
} else if (rootPath.endsWith("/")) {
@@ -322,7 +319,29 @@
}
}
- return mostSpecificId + ':' + path;
+ return mostSpecificRoot.rootId + ':' + path;
+ }
+
+ private RootInfo getMostSpecificRootForPath(String path, boolean visible) {
+ // Find the most-specific root path
+ RootInfo mostSpecificRoot = null;
+ String mostSpecificPath = null;
+ synchronized (mRootsLock) {
+ for (int i = 0; i < mRoots.size(); i++) {
+ final RootInfo root = mRoots.valueAt(i);
+ final File rootFile = visible ? root.visiblePath : root.path;
+ if (rootFile != null) {
+ final String rootPath = rootFile.getAbsolutePath();
+ if (path.startsWith(rootPath) && (mostSpecificPath == null
+ || rootPath.length() > mostSpecificPath.length())) {
+ mostSpecificRoot = root;
+ mostSpecificPath = rootPath;
+ }
+ }
+ }
+ }
+
+ return mostSpecificRoot;
}
private File getFileForDocId(String docId) throws FileNotFoundException {
@@ -519,15 +538,13 @@
boolean matchesRequestedDoc = false;
if (DocumentsContract.isTreeUri(uri)) {
final String parentDocId = DocumentsContract.getTreeDocumentId(uri);
- File parentFile = getFileForDocId(parentDocId);
- if (FileUtils.contains(parentFile, doc)) {
+ if (isChildDocument(parentDocId, docId)) {
treeUriPermission = uriPermission;
matchesRequestedDoc = true;
}
} else {
final String candidateDocId = DocumentsContract.getDocumentId(uri);
- final File candidateDoc = getFileForDocId(candidateDocId);
- if (Objects.equals(doc.getAbsolutePath(), candidateDoc.getAbsolutePath())) {
+ if (Objects.equals(docId, candidateDocId)) {
docUriPermission = uriPermission;
matchesRequestedDoc = true;
}