From 16a611e4c507ef5deff695008874a42a889359d6 Mon Sep 17 00:00:00 2001 From: Raunak Raj <71929976+bajrangCoder@users.noreply.github.com> Date: Tue, 13 Jan 2026 13:37:28 +0530 Subject: [PATCH 1/2] feat: add proper fallback and saf uri handling for ischeck --- src/lib/editorFile.js | 46 +++++++++++++------ .../android/com/foxdebug/system/System.java | 42 +++++++++++++++-- 2 files changed, 70 insertions(+), 18 deletions(-) diff --git a/src/lib/editorFile.js b/src/lib/editorFile.js index 3ae657299..bf44701dc 100644 --- a/src/lib/editorFile.js +++ b/src/lib/editorFile.js @@ -612,39 +612,55 @@ export default class EditorFile { const protocol = Url.getProtocol(this.#uri); const text = this.session.getValue(); + // Helper for JS-based comparison (used as fallback) + const jsCompare = async (fileUri) => { + const fs = fsOperation(fileUri); + const oldText = await fs.readFile(this.encoding); + return await system.compareTexts(oldText, text); + }; + if (/s?ftp:/.test(protocol)) { - // if file is a ftp or sftp file, get file content from cached file. - // remove ':' from protocol because cache file of remote files are - // stored as ftp102525465N i.e. protocol + id - // Cache files are local file:// URIs, so native file reading works + // FTP/SFTP files use cached local file const cacheFilename = protocol.slice(0, -1) + this.id; const cacheFileUri = Url.join(CACHE_STORAGE, cacheFilename); try { return await system.compareFileText(cacheFileUri, this.encoding, text); } catch (error) { - console.error("Native compareFileText failed:", error); - return false; + console.error( + "Native compareFileText failed, using JS fallback:", + error, + ); + try { + return await jsCompare(cacheFileUri); + } catch (fallbackError) { + console.error(fallbackError); + return false; + } } } if (/^(file|content):/.test(protocol)) { - // file:// and content:// URIs can be handled by native Android code - // Native reads file AND compares in background thread + // file:// and content:// URIs - try native first, fallback to JS try { return await system.compareFileText(this.uri, this.encoding, text); } catch (error) { - console.error("Native compareFileText failed:", error); - return false; + console.error( + "Native compareFileText failed, using JS fallback:", + error, + ); + try { + return await jsCompare(this.uri); + } catch (fallbackError) { + console.error(fallbackError); + return false; + } } } + // Other protocols - JS reads file, native compares strings try { - const fs = fsOperation(this.uri); - const oldText = await fs.readFile(this.encoding); - - // Offload string comparison to background thread - return await system.compareTexts(oldText, text); + return await jsCompare(this.uri); } catch (error) { console.error(error); return false; diff --git a/src/plugins/system/android/com/foxdebug/system/System.java b/src/plugins/system/android/com/foxdebug/system/System.java index 520653b2c..5fdf6ecf6 100644 --- a/src/plugins/system/android/com/foxdebug/system/System.java +++ b/src/plugins/system/android/com/foxdebug/system/System.java @@ -89,6 +89,7 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.net.Uri; +import android.provider.DocumentsContract; import android.provider.Settings; import androidx.core.content.ContextCompat; @@ -681,11 +682,43 @@ private void compareFileText( Path path = file.toPath(); fileContent = new String(Files.readAllBytes(path), charset); - } else { - // Handle content:// URIs + } else if ("content".equalsIgnoreCase(uri.getScheme())) { + // Handle content:// URIs (including SAF tree URIs) InputStream inputStream = null; try { - inputStream = context.getContentResolver().openInputStream(uri); + String uriString = fileUri; + Uri resolvedUri = uri; + + // Check if this is a SAF tree URI with :: separator + if (uriString.contains("::")) { + try { + // Split into tree URI and document ID + String[] parts = uriString.split("::", 2); + String treeUriStr = parts[0]; + String docId = parts[1]; + + // Convert to proper document URI using DocumentsContract + Uri treeUri = Uri.parse(treeUriStr); + String treeDocId = DocumentsContract.getTreeDocumentId(treeUri); + Uri baseUri = DocumentsContract.buildDocumentUriUsingTree(treeUri, treeDocId); + resolvedUri = DocumentsContract.buildDocumentUriUsingTree(baseUri, docId); + } catch (Exception e) { + callback.error("SAF_FALLBACK: Invalid SAF URI format - " + e.getMessage()); + return; + } + } else if (uriString.contains("/tree/")) { + // Regular tree URI without :: separator + try { + String treeDocId = DocumentsContract.getTreeDocumentId(uri); + resolvedUri = DocumentsContract.buildDocumentUriUsingTree(uri, treeDocId); + } catch (Exception e) { + // Not a valid tree URI, use as-is + resolvedUri = uri; + } + } + + // Try to open the resolved URI + inputStream = context.getContentResolver().openInputStream(resolvedUri); if (inputStream == null) { callback.error("Cannot open file"); @@ -710,6 +743,9 @@ private void compareFileText( } catch (IOException ignored) {} } } + } else { + callback.error("Unsupported URI scheme: " + uri.getScheme()); + return; } // check length first From 12ff7bcf2d0bb20413f77601ee83f6f8df693c90 Mon Sep 17 00:00:00 2001 From: Raunak Raj <71929976+bajrangCoder@users.noreply.github.com> Date: Tue, 13 Jan 2026 13:49:34 +0530 Subject: [PATCH 2/2] fix --- .../android/com/foxdebug/system/System.java | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/plugins/system/android/com/foxdebug/system/System.java b/src/plugins/system/android/com/foxdebug/system/System.java index 5fdf6ecf6..7ddf6c547 100644 --- a/src/plugins/system/android/com/foxdebug/system/System.java +++ b/src/plugins/system/android/com/foxdebug/system/System.java @@ -697,24 +697,13 @@ private void compareFileText( String treeUriStr = parts[0]; String docId = parts[1]; - // Convert to proper document URI using DocumentsContract + // Build document URI directly from tree URI and document ID Uri treeUri = Uri.parse(treeUriStr); - String treeDocId = DocumentsContract.getTreeDocumentId(treeUri); - Uri baseUri = DocumentsContract.buildDocumentUriUsingTree(treeUri, treeDocId); - resolvedUri = DocumentsContract.buildDocumentUriUsingTree(baseUri, docId); + resolvedUri = DocumentsContract.buildDocumentUriUsingTree(treeUri, docId); } catch (Exception e) { callback.error("SAF_FALLBACK: Invalid SAF URI format - " + e.getMessage()); return; } - } else if (uriString.contains("/tree/")) { - // Regular tree URI without :: separator - try { - String treeDocId = DocumentsContract.getTreeDocumentId(uri); - resolvedUri = DocumentsContract.buildDocumentUriUsingTree(uri, treeDocId); - } catch (Exception e) { - // Not a valid tree URI, use as-is - resolvedUri = uri; - } } // Try to open the resolved URI