1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-25 06:50:46 -08:00

Update Android port

* doc/emacs/android.texi (Android Startup): Document `content'
special directory.
* java/debug.sh (is_root): Improve /bin/tee detection.
* java/org/gnu/emacs/EmacsNative.java (EmacsNative): New
function `dup'.
* java/org/gnu/emacs/EmacsOpenActivity.java (EmacsOpenActivity)
(checkReadableOrCopy, onCreate): Create content directory names
when the file is not readable.
* java/org/gnu/emacs/EmacsService.java (EmacsService)
(openContentUri, checkContentUri): New functions.
* src/android.c (struct android_emacs_service): New methods.
(android_content_name_p, android_get_content_name)
(android_check_content_access): New function.
(android_fstatat, android_open): Implement opening content URIs.
(dup): Export to Java.
(android_init_emacs_service): Initialize new methods.
(android_faccessat): Implement content file names.
This commit is contained in:
Po Lu 2023-02-21 15:28:06 +08:00
parent d197d73491
commit 7aa4ffddd8
6 changed files with 379 additions and 13 deletions

View file

@ -31,6 +31,10 @@ public class EmacsNative
initialization. */
private static final String[] libraryDeps;
/* Like `dup' in C. */
public static native int dup (int fd);
/* Obtain the fingerprint of this build of Emacs. The fingerprint
can be used to determine the dump file name. */
public static native String getFingerprint ();

View file

@ -57,6 +57,8 @@ import android.os.Build;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.util.Log;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
@ -69,6 +71,8 @@ import java.io.UnsupportedEncodingException;
public class EmacsOpenActivity extends Activity
implements DialogInterface.OnClickListener
{
private static final String TAG = "EmacsOpenActivity";
private class EmacsClientThread extends Thread
{
private ProcessBuilder builder;
@ -178,12 +182,16 @@ public class EmacsOpenActivity extends Activity
dialog.show ();
}
/* Check that the specified FILE is readable. If it is not, then
copy the file in FD to a location in the system cache
directory and return the name of that file. */
/* Check that the specified FILE is readable. If Android 4.4 or
later is being used, return URI formatted into a `/content/' file
name.
If it is not, then copy the file in FD to a location in the
system cache directory and return the name of that file. */
private String
checkReadableOrCopy (String file, ParcelFileDescriptor fd)
checkReadableOrCopy (String file, ParcelFileDescriptor fd,
Uri uri)
throws IOException, FileNotFoundException
{
File inFile;
@ -191,12 +199,34 @@ public class EmacsOpenActivity extends Activity
InputStream stream;
byte buffer[];
int read;
String content;
Log.d (TAG, "checkReadableOrCopy: " + file);
inFile = new File (file);
if (inFile.setReadable (true))
if (inFile.canRead ())
return file;
Log.d (TAG, "checkReadableOrCopy: NO");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
{
content = "/content/" + uri.getEncodedAuthority ();
for (String segment : uri.getPathSegments ())
content += "/" + Uri.encode (segment);
/* Append the URI query. */
if (uri.getEncodedQuery () != null)
content += "?" + uri.getEncodedQuery ();
Log.d (TAG, "checkReadableOrCopy: " + content);
return content;
}
/* inFile is now the file being written to. */
inFile = new File (getCacheDir (), inFile.getName ());
buffer = new byte[4098];
@ -398,7 +428,7 @@ public class EmacsOpenActivity extends Activity
if (names != null)
fileName = new String (names, "UTF-8");
fileName = checkReadableOrCopy (fileName, fd);
fileName = checkReadableOrCopy (fileName, fd, uri);
}
catch (FileNotFoundException exception)
{

View file

@ -19,7 +19,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
package org.gnu.emacs;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.ArrayList;
@ -41,22 +44,31 @@ import android.app.Service;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.ContentResolver;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager.ApplicationInfoFlags;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.net.Uri;
import android.os.Build;
import android.os.Looper;
import android.os.IBinder;
import android.os.Handler;
import android.os.ParcelFileDescriptor;
import android.os.Vibrator;
import android.os.VibratorManager;
import android.os.VibrationEffect;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
import android.util.Log;
import android.util.DisplayMetrics;
@ -79,6 +91,7 @@ public class EmacsService extends Service
private EmacsThread thread;
private Handler handler;
private ContentResolver resolver;
/* Keep this in synch with androidgui.h. */
public static final int IC_MODE_NULL = 0;
@ -193,6 +206,7 @@ public class EmacsService extends Service
metrics = getResources ().getDisplayMetrics ();
pixelDensityX = metrics.xdpi;
pixelDensityY = metrics.ydpi;
resolver = getContentResolver ();
try
{
@ -643,4 +657,109 @@ public class EmacsService extends Service
window.view.setICMode (icMode);
window.view.imManager.restartInput (window.view);
}
/* Open a content URI described by the bytes BYTES, a non-terminated
string; make it writable if WRITABLE, and readable if READABLE.
Truncate the file if TRUNCATE.
Value is the resulting file descriptor or -1 upon failure. */
public int
openContentUri (byte[] bytes, boolean writable, boolean readable,
boolean truncate)
{
String name, mode;
ParcelFileDescriptor fd;
int i;
/* Figure out the file access mode. */
mode = "";
if (readable)
mode += "r";
if (writable)
mode += "w";
if (truncate)
mode += "t";
/* Try to open an associated ParcelFileDescriptor. */
try
{
/* The usual file name encoding question rears its ugly head
again. */
name = new String (bytes, "UTF-8");
Log.d (TAG, "openContentUri: " + Uri.parse (name));
fd = resolver.openFileDescriptor (Uri.parse (name), mode);
/* Use detachFd on newer versions of Android or plain old
dup. */
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1)
{
i = fd.detachFd ();
fd.close ();
return i;
}
else
{
i = EmacsNative.dup (fd.getFd ());
fd.close ();
return i;
}
}
catch (Exception exception)
{
return -1;
}
}
public boolean
checkContentUri (byte[] string, boolean readable, boolean writable)
{
String mode, name;
ParcelFileDescriptor fd;
/* Decode this into a URI. */
try
{
/* The usual file name encoding question rears its ugly head
again. */
name = new String (string, "UTF-8");
Log.d (TAG, "checkContentUri: " + Uri.parse (name));
}
catch (UnsupportedEncodingException exception)
{
name = null;
throw new RuntimeException (exception);
}
mode = "r";
if (writable)
mode += "w";
try
{
fd = resolver.openFileDescriptor (Uri.parse (name), mode);
fd.close ();
Log.d (TAG, "checkContentUri: YES");
return true;
}
catch (Exception exception)
{
Log.d (TAG, "checkContentUri: NO");
Log.d (TAG, exception.toString ());
return false;
}
}
};