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:
parent
d197d73491
commit
7aa4ffddd8
6 changed files with 379 additions and 13 deletions
|
|
@ -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 ();
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue