diff options
author | Po Lu <luangruo@yahoo.com> | 2024-03-19 12:08:17 +0800 |
---|---|---|
committer | Po Lu <luangruo@yahoo.com> | 2024-03-19 12:08:17 +0800 |
commit | f2e239c6a7d54ec3849a3bb783685953b6683752 (patch) | |
tree | 0bb5d158eb1da4672d727057d2e045d8a9eb0bcc /java | |
parent | ce29ae32d0b05cedbc9ba65c1a347ab7c34420ad (diff) | |
download | emacs-f2e239c6a7d54ec3849a3bb783685953b6683752.tar.gz |
Respect display names of Android content URIs
* java/org/gnu/emacs/EmacsNative.java (displayNameHash): New
function.
* java/org/gnu/emacs/EmacsService.java (buildContentName): New
argument RESOLVER. Generate names holding URI's display name if
available. All callers changed.
* lisp/international/mule-cmds.el (set-default-coding-systems):
Fix file name coding system as utf-8-unix on Android as on Mac
OS.
* src/androidvfs.c (enum android_vnode_type): New enum
ANDROID_VNODE_CONTENT_AUTHORITY_NAMED.
(android_content_name): Register root directories for this new
type.
(displayNameHash): New function.
(android_get_content_name): New argument WITH_CHECKSUM. If
present, treat the final two components as a pair of checksum
and display name, and verify and exclude the two.
(android_authority_name): Provide new argument as appropriate.
(android_authority_initial_name): New function.
Diffstat (limited to 'java')
-rw-r--r-- | java/org/gnu/emacs/EmacsNative.java | 10 | ||||
-rw-r--r-- | java/org/gnu/emacs/EmacsOpenActivity.java | 9 | ||||
-rw-r--r-- | java/org/gnu/emacs/EmacsService.java | 80 |
3 files changed, 91 insertions, 8 deletions
diff --git a/java/org/gnu/emacs/EmacsNative.java b/java/org/gnu/emacs/EmacsNative.java index 898eaef41a7..654e94b1a7d 100644 --- a/java/org/gnu/emacs/EmacsNative.java +++ b/java/org/gnu/emacs/EmacsNative.java @@ -281,7 +281,7 @@ public final class EmacsNative public static native int[] getSelection (short window); - /* Graphics functions used as a replacement for potentially buggy + /* Graphics functions used as replacements for potentially buggy Android APIs. */ public static native void blitRect (Bitmap src, Bitmap dest, int x1, @@ -289,7 +289,6 @@ public final class EmacsNative /* Increment the generation ID of the specified BITMAP, forcing its texture to be re-uploaded to the GPU. */ - public static native void notifyPixelsChanged (Bitmap bitmap); @@ -313,6 +312,13 @@ public final class EmacsNative in the process. */ public static native boolean ftruncate (int fd); + + /* Functions that assist in generating content file names. */ + + /* Calculate an 8 digit checksum for the byte array DISPLAYNAME + suitable for inclusion in a content file name. */ + public static native String displayNameHash (byte[] displayName); + static { /* Older versions of Android cannot link correctly with shared diff --git a/java/org/gnu/emacs/EmacsOpenActivity.java b/java/org/gnu/emacs/EmacsOpenActivity.java index 9ae1bf353dd..2cdfa2ec776 100644 --- a/java/org/gnu/emacs/EmacsOpenActivity.java +++ b/java/org/gnu/emacs/EmacsOpenActivity.java @@ -252,7 +252,7 @@ public final class EmacsOpenActivity extends Activity if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - content = EmacsService.buildContentName (uri); + content = EmacsService.buildContentName (uri, getContentResolver ()); return content; } @@ -423,6 +423,7 @@ public final class EmacsOpenActivity extends Activity /* Obtain the intent that started Emacs. */ intent = getIntent (); action = intent.getAction (); + resolver = getContentResolver (); if (action == null) { @@ -536,7 +537,7 @@ public final class EmacsOpenActivity extends Activity if ((scheme = uri.getScheme ()) != null && scheme.equals ("content")) { - tem1 = EmacsService.buildContentName (uri); + tem1 = EmacsService.buildContentName (uri, resolver); attachmentString = ("'(\"" + (tem1.replace ("\\", "\\\\") .replace ("\"", "\\\"") .replace ("$", "\\$")) @@ -568,7 +569,8 @@ public final class EmacsOpenActivity extends Activity && (scheme = uri.getScheme ()) != null && scheme.equals ("content")) { - tem1 = EmacsService.buildContentName (uri); + tem1 + = EmacsService.buildContentName (uri, resolver); builder.append ("\""); builder.append (tem1.replace ("\\", "\\\\") .replace ("\"", "\\\"") @@ -609,7 +611,6 @@ public final class EmacsOpenActivity extends Activity underlying file, but it cannot be found without opening the file and doing readlink on its file descriptor in /proc/self/fd. */ - resolver = getContentResolver (); fd = null; try diff --git a/java/org/gnu/emacs/EmacsService.java b/java/org/gnu/emacs/EmacsService.java index 9bc40d63311..19aa3dee456 100644 --- a/java/org/gnu/emacs/EmacsService.java +++ b/java/org/gnu/emacs/EmacsService.java @@ -79,6 +79,7 @@ import android.os.VibrationEffect; import android.provider.DocumentsContract; import android.provider.DocumentsContract.Document; +import android.provider.OpenableColumns; import android.provider.Settings; import android.util.Log; @@ -1033,22 +1034,87 @@ public final class EmacsService extends Service return false; } + /* Return a 8 character checksum for the string STRING, after encoding + as UTF-8 data. */ + + public static String + getDisplayNameHash (String string) + { + byte[] encoded; + + try + { + encoded = string.getBytes ("UTF-8"); + return EmacsNative.displayNameHash (encoded); + } + catch (UnsupportedEncodingException exception) + { + /* This should be impossible. */ + return "error"; + } + } + /* Build a content file name for URI. Return a file name within the /contents/by-authority pseudo-directory that `android_get_content_name' can then transform back into an encoded URI. + If a display name can be requested from URI (using the resolver + RESOLVER), append it to this file name. + A content name consists of any number of unencoded path segments separated by `/' characters, possibly followed by a question mark and an encoded query string. */ public static String - buildContentName (Uri uri) + buildContentName (Uri uri, ContentResolver resolver) { StringBuilder builder; + String displayName; + String[] projection; + Cursor cursor; + int column; + + displayName = null; + cursor = null; - builder = new StringBuilder ("/content/by-authority/"); + try + { + projection = new String[] { OpenableColumns.DISPLAY_NAME, }; + cursor = resolver.query (uri, projection, null, null, null); + + if (cursor != null) + { + cursor.moveToFirst (); + column + = cursor.getColumnIndexOrThrow (OpenableColumns.DISPLAY_NAME); + displayName + = cursor.getString (column); + + /* Verify that the display name is valid, i.e. it + contains no characters unsuitable for a file name and + is nonempty. */ + if (displayName.isEmpty () || displayName.contains ("/")) + displayName = null; + } + } + catch (Exception e) + { + /* Ignored. */ + } + finally + { + if (cursor != null) + cursor.close (); + } + + /* If a display name is available, at this point it should be the + value of displayName. */ + + builder = new StringBuilder (displayName != null + ? "/content/by-authority-named/" + : "/content/by-authority/"); builder.append (uri.getAuthority ()); /* First, append each path segment. */ @@ -1065,6 +1131,16 @@ public final class EmacsService extends Service if (uri.getEncodedQuery () != null) builder.append ('?').append (uri.getEncodedQuery ()); + /* Append the display name. */ + + if (displayName != null) + { + builder.append ('/'); + builder.append (getDisplayNameHash (displayName)); + builder.append ('/'); + builder.append (displayName); + } + return builder.toString (); } |