summaryrefslogtreecommitdiff
path: root/java
diff options
context:
space:
mode:
authorPo Lu <luangruo@yahoo.com>2023-02-21 15:28:06 +0800
committerPo Lu <luangruo@yahoo.com>2023-02-21 15:28:06 +0800
commit7aa4ffddd842e495d1ae388afff12075317ecb07 (patch)
tree9ba8cb2c232665ee59113494f7e35eeb33ab8619 /java
parentd197d7349121b972d50e37d66017567bf6cba652 (diff)
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.
Diffstat (limited to 'java')
-rwxr-xr-xjava/debug.sh2
-rw-r--r--java/org/gnu/emacs/EmacsNative.java4
-rw-r--r--java/org/gnu/emacs/EmacsOpenActivity.java42
-rw-r--r--java/org/gnu/emacs/EmacsService.java119
4 files changed, 160 insertions, 7 deletions
diff --git a/java/debug.sh b/java/debug.sh
index 30e5a94eee5..f07bb98ed7d 100755
--- a/java/debug.sh
+++ b/java/debug.sh
@@ -281,7 +281,7 @@ else
# Upload the specified gdbserver binary to the device.
adb -s $device push "$gdbserver" "$gdbserver_bin"
- if (adb -s $device pull /system/bin/tee /dev/null &> /dev/null); then
+ if adb -s $device shell ls /system/bin/tee; then
# Copy it to the user directory.
adb -s $device shell "$gdbserver_cat"
adb -s $device shell "run-as $package chmod +x gdbserver"
diff --git a/java/org/gnu/emacs/EmacsNative.java b/java/org/gnu/emacs/EmacsNative.java
index ef1a0e75a5c..f0917a68120 100644
--- a/java/org/gnu/emacs/EmacsNative.java
+++ b/java/org/gnu/emacs/EmacsNative.java
@@ -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 ();
diff --git a/java/org/gnu/emacs/EmacsOpenActivity.java b/java/org/gnu/emacs/EmacsOpenActivity.java
index c8501d91025..87ce454a816 100644
--- a/java/org/gnu/emacs/EmacsOpenActivity.java
+++ b/java/org/gnu/emacs/EmacsOpenActivity.java
@@ -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)
{
diff --git a/java/org/gnu/emacs/EmacsService.java b/java/org/gnu/emacs/EmacsService.java
index ba6ec485d62..c9701ff2990 100644
--- a/java/org/gnu/emacs/EmacsService.java
+++ b/java/org/gnu/emacs/EmacsService.java
@@ -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;
+ }
+ }
};