summaryrefslogtreecommitdiff
path: root/java
diff options
context:
space:
mode:
authorPo Lu <luangruo@yahoo.com>2024-03-19 12:08:17 +0800
committerPo Lu <luangruo@yahoo.com>2024-03-19 12:08:17 +0800
commitf2e239c6a7d54ec3849a3bb783685953b6683752 (patch)
tree0bb5d158eb1da4672d727057d2e045d8a9eb0bcc /java
parentce29ae32d0b05cedbc9ba65c1a347ab7c34420ad (diff)
downloademacs-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.java10
-rw-r--r--java/org/gnu/emacs/EmacsOpenActivity.java9
-rw-r--r--java/org/gnu/emacs/EmacsService.java80
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 ();
}