Skip to content

Commit 9b465c2

Browse files
fix: isMyChild
1 parent a055199 commit 9b465c2

2 files changed

Lines changed: 63 additions & 32 deletions

File tree

src/fileSystem/SAFDocumentFile.ts

Lines changed: 11 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -36,50 +36,29 @@ export class SAFDocumentFile implements FileObject {
3636
});
3737
}
3838

39-
//if this fails then...
4039
async isMyChild(fileObject: FileObject): Promise<boolean> {
41-
console.log(`[isMyChild] Checking if`, fileObject, `is a child of`, this);
42-
4340
if (!(fileObject instanceof SAFDocumentFile)) {
4441
console.log(`[isMyChild] Not an SAFDocumentFile`);
4542
return false;
4643
}
4744

48-
const isDir = await this.isDirectory();
49-
if (!isDir) {
50-
console.log(`[isMyChild] This file is not a directory`);
51-
return false;
52-
}
53-
54-
let current: FileObject | null = fileObject;
55-
56-
while (current !== null) {
57-
console.log(`[isMyChild] Checking parent of`, current);
58-
59-
const parent: FileObject | null = await current.getParentFile();
60-
if (parent === null) {
61-
console.log(`[isMyChild] Reached root without finding match`);
62-
return false;
63-
}
45+
try {
46+
console.log(`[isMyChild] Checking if ${fileObject.uri} is a child of ${this.uri}`);
47+
const result = await this.execPlugin("isMyChild", [fileObject.uri]);
6448

65-
const parentUri = (await parent.toUri())?.replace(/\/+$/, "");
66-
const thisUri = this.uri?.replace(/\/+$/, "");
49+
// result will be 1 or 0 (from the native plugin)
50+
const isChild = result === 1 || result === true;
6751

68-
console.log(`[isMyChild] parentUri=${parentUri}, thisUri=${thisUri}`);
69-
70-
if (parentUri === thisUri) {
71-
console.log(`[isMyChild] Match found!`);
72-
return true;
73-
}
74-
75-
current = parent;
52+
console.log(`[isMyChild] Result from native =`, isChild);
53+
return isChild;
54+
} catch (err) {
55+
console.error(`[isMyChild] Error:`, err);
56+
return false;
7657
}
77-
78-
console.log(`[isMyChild] No match found after traversal`);
79-
return false;
8058
}
8159

8260

61+
8362
async canRead(): Promise<boolean> {
8463
const stat = await this.stat();
8564
return !!stat.canRead;

src/plugins/file/src/android/documentFile.java

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
import java.io.InputStream;
1515
import java.io.OutputStream;
1616
import java.nio.charset.StandardCharsets;
17+
import android.provider.DocumentsContract;
18+
1719

1820
public class documentFile extends CordovaPlugin {
1921

@@ -41,6 +43,7 @@ public boolean execute(String action, JSONArray args, CallbackContext callbackCo
4143
case "canWrite": return handleCanWrite(args, callbackContext);
4244
case "childByNameExists": return handleChildByNameExists(args, callbackContext);
4345
case "getChildByName": return handleGetChildByName(args, callbackContext);
46+
case "isMyChild": return handleIsMyChild(args, callbackContext);
4447
case "toUri": return handleToUri(args, callbackContext);
4548
default: return false;
4649
}
@@ -50,6 +53,55 @@ public boolean execute(String action, JSONArray args, CallbackContext callbackCo
5053
}
5154
}
5255

56+
private boolean handleIsMyChild(JSONArray args, CallbackContext cb) throws JSONException {
57+
String parentUriStr = args.getString(0);
58+
String childUriStr = args.getString(1);
59+
60+
try {
61+
Uri parentUri = Uri.parse(parentUriStr);
62+
Uri childUri = Uri.parse(childUriStr);
63+
64+
boolean result = false;
65+
66+
// SAF-safe check
67+
if (DocumentsContract.isDocumentUri(getContext(), childUri)) {
68+
try {
69+
result = DocumentsContract.isChildDocument(
70+
getContext().getContentResolver(),
71+
parentUri,
72+
childUri
73+
);
74+
} catch (Exception e) {
75+
// If that fails, fallback to ID-based check
76+
result = isChildByDocIdFallback(parentUri, childUri);
77+
}
78+
} else {
79+
// Non-SAF fallback: compare normalized paths
80+
String p = parentUri.getPath();
81+
String c = childUri.getPath();
82+
if (p != null && c != null && c.startsWith(p)) {
83+
result = true;
84+
}
85+
}
86+
87+
cb.success(result ? 1 : 0);
88+
} catch (Exception e) {
89+
cb.error("Error: " + e.getMessage());
90+
}
91+
return true;
92+
}
93+
94+
/**
95+
* Fallback if DocumentsContract.isChildDocument() fails.
96+
* Checks if the child’s document ID starts with parent’s document ID.
97+
*/
98+
private boolean isChildByDocIdFallback(Uri parentUri, Uri childUri) {
99+
String parentId = DocumentsContract.getDocumentId(parentUri);
100+
String childId = DocumentsContract.getDocumentId(childUri);
101+
return childId != null && parentId != null && childId.startsWith(parentId + "%2F");
102+
}
103+
104+
53105
private DocumentFile fromUri(String uriStr) {
54106
try {
55107
// Decode once if double-encoded

0 commit comments

Comments
 (0)