1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2026-01-09 13:10:57 -08:00

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.
This commit is contained in:
Po Lu 2024-03-19 12:08:17 +08:00
parent ce29ae32d0
commit f2e239c6a7
5 changed files with 231 additions and 25 deletions

View file

@ -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

View file

@ -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

View file

@ -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;
builder = new StringBuilder ("/content/by-authority/");
displayName = null;
cursor = null;
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 ();
}