[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
feature/android bb55528c7b5 1/3: Update Android port
From: |
Po Lu |
Subject: |
feature/android bb55528c7b5 1/3: Update Android port |
Date: |
Wed, 8 Mar 2023 07:07:25 -0500 (EST) |
branch: feature/android
commit bb55528c7b58c5f50336ed3f2ff9759559d78680
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>
Update Android port
* doc/emacs/android.texi (Android File System): Document what
`temp~unlinked' means in the temporary files directory.
* java/org/gnu/emacs/EmacsService.java (updateExtractedText):
New function.
* java/org/gnu/emacs/EmacsView.java (onCreateInputConnection):
Ask the input method nicely to not display the extracted text
UI.
* src/android.c (struct android_emacs_service): New method
`updateExtractedText'.
(android_hack_asset_fd_fallback): Improve naming convention.
Fix typo.
(android_init_emacs_service): Add new method.
(android_update_extracted_text): New function.
(android_open_asset): Fix typo.
* src/androidgui.h: Update prototypes.
* src/androidterm.c (struct android_get_extracted_text_context):
New field `flags'.
(android_get_extracted_text): Set flags on the frame's output
data.
(android_build_extracted_text): New function.
(getExtractedText): Move out class structures.
(android_update_selection): Send updates to extracted text if
the input method asked for them.
(android_reset_conversion): Clear extracted text flags.
* src/androidterm.h (struct android_output): New fields for
storing extracted text data.
---
doc/emacs/android.texi | 7 +++
java/org/gnu/emacs/EmacsService.java | 12 ++++
java/org/gnu/emacs/EmacsView.java | 1 +
src/android.c | 44 ++++++++++++--
src/androidgui.h | 2 +
src/androidterm.c | 111 ++++++++++++++++++++++++++++++++---
src/androidterm.h | 10 ++++
7 files changed, 175 insertions(+), 12 deletions(-)
diff --git a/doc/emacs/android.texi b/doc/emacs/android.texi
index d49e0754b0a..8e98b92314a 100644
--- a/doc/emacs/android.texi
+++ b/doc/emacs/android.texi
@@ -205,6 +205,13 @@ other directories are not found at any fixed location,
although the
app data directory is typically symlinked to
@file{/data/data/org.gnu.emacs}.
+@cindex temp~unlinked.NNNN files, Android
+ On Android devices running very old (2.6.29) versions of the Linux
+kernel, Emacs needs to create files named starting with
+@file{temp~unlinked} in the the temporary file directory in order to
+read from asset files. Do not create files with such names yourself,
+or they may be overwritten or removed.
+
@cindex file system limitations, Android 11
On Android 11 and later, the Android system restricts applications
from accessing files in the @file{/sdcard} directory using
diff --git a/java/org/gnu/emacs/EmacsService.java
b/java/org/gnu/emacs/EmacsService.java
index f99d7a40067..848ad4de789 100644
--- a/java/org/gnu/emacs/EmacsService.java
+++ b/java/org/gnu/emacs/EmacsService.java
@@ -29,6 +29,7 @@ import android.graphics.Point;
import android.view.InputDevice;
import android.view.KeyEvent;
+import android.view.inputmethod.ExtractedText;
import android.app.Notification;
import android.app.NotificationManager;
@@ -811,4 +812,15 @@ public final class EmacsService extends Service
}
});
}
+
+ public void
+ updateExtractedText (EmacsWindow window, ExtractedText text,
+ int token)
+ {
+ if (DEBUG_IC)
+ Log.d (TAG, "updateExtractedText: @" + token + ", " + text);
+
+ window.view.imManager.updateExtractedText (window.view,
+ token, text);
+ }
};
diff --git a/java/org/gnu/emacs/EmacsView.java
b/java/org/gnu/emacs/EmacsView.java
index 90a2c912a5a..6ace609f386 100644
--- a/java/org/gnu/emacs/EmacsView.java
+++ b/java/org/gnu/emacs/EmacsView.java
@@ -569,6 +569,7 @@ public final class EmacsView extends ViewGroup
/* Make sure the input method never displays a full screen input
box that obscures Emacs. */
info.imeOptions = EditorInfo.IME_FLAG_NO_FULLSCREEN;
+ info.imeOptions |= EditorInfo.IME_FLAG_NO_EXTRACT_UI;
/* Set a reasonable inputType. */
info.inputType = InputType.TYPE_CLASS_TEXT;
diff --git a/src/android.c b/src/android.c
index 11b0fa5e0f3..e620a041348 100644
--- a/src/android.c
+++ b/src/android.c
@@ -112,6 +112,7 @@ struct android_emacs_service
jmethodID check_content_uri;
jmethodID query_battery;
jmethodID display_toast;
+ jmethodID update_extracted_text;
};
struct android_emacs_pixmap
@@ -1236,13 +1237,12 @@ android_hack_asset_fd_fallback (AAsset *asset)
Creating an ashmem file descriptor and reading from it doesn't
work on these old Android versions. */
- snprintf (filename, PATH_MAX, "%s/%s.%d",
- android_cache_dir, "temp-unlinked",
- getpid ());
+ snprintf (filename, PATH_MAX, "%s/temp~unlinked.%d",
+ android_cache_dir, getpid ());
fd = open (filename, O_CREAT | O_RDWR | O_TRUNC,
S_IRUSR | S_IWUSR);
- if (fd < 1)
+ if (fd < 0)
return -1;
if (unlink (filename))
@@ -2135,6 +2135,9 @@ android_init_emacs_service (void)
FIND_METHOD (query_battery, "queryBattery", "()[J");
FIND_METHOD (display_toast, "displayToast",
"(Ljava/lang/String;)V");
+ FIND_METHOD (update_extracted_text, "updateExtractedText",
+ "(Lorg/gnu/emacs/EmacsWindow;"
+ "Landroid/view/inputmethod/ExtractedText;I)V");
#undef FIND_METHOD
}
@@ -5991,6 +5994,37 @@ android_reset_ic (android_window window, enum
android_ic_mode mode)
android_exception_check ();
}
+/* Make updates to extracted text known to the input method on
+ WINDOW. TEXT should be a local reference to the new
+ extracted text. TOKEN should be the token specified by the
+ input method. */
+
+void
+android_update_extracted_text (android_window window, void *text,
+ int token)
+{
+ jobject object;
+ jmethodID method;
+
+ object = android_resolve_handle (window, ANDROID_HANDLE_WINDOW);
+ method = service_class.update_extracted_text;
+
+ (*android_java_env)->CallNonvirtualVoidMethod (android_java_env,
+ emacs_service,
+ service_class.class,
+ method, object,
+ /* N.B. that
+ text is not
+ jobject,
+ because that
+ type is not
+ available in
+ androidgui.h. */
+ (jobject) text,
+ (jint) token);
+ android_exception_check_1 (text);
+}
+
/* Window decoration management functions. */
@@ -6083,7 +6117,7 @@ android_open_asset (const char *filename, int oflag,
mode_t mode)
get a regular file descriptor. */
fd.fd = android_open (filename, oflag, mode);
- if (fd.fd < 1)
+ if (fd.fd < 0)
return fd;
/* Set fd.asset to NULL, signifying that it is a file
diff --git a/src/androidgui.h b/src/androidgui.h
index e1c80a71a59..afcaed98cae 100644
--- a/src/androidgui.h
+++ b/src/androidgui.h
@@ -613,6 +613,8 @@ extern int android_wc_lookup_string
(android_key_pressed_event *,
extern void android_update_ic (android_window, ptrdiff_t, ptrdiff_t,
ptrdiff_t, ptrdiff_t);
extern void android_reset_ic (android_window, enum android_ic_mode);
+extern void android_update_extracted_text (android_window, void *,
+ int);
extern int android_set_fullscreen (android_window, bool);
#endif
diff --git a/src/androidterm.c b/src/androidterm.c
index 0cc2b35099c..f4a535292f2 100644
--- a/src/androidterm.c
+++ b/src/androidterm.c
@@ -4968,6 +4968,10 @@ NATIVE_NAME (performEditorAction) (JNIEnv *env, jobject
object,
android_write_event (&event);
}
+
+
+/* Text extraction. */
+
struct android_get_extracted_text_context
{
/* The parameters of the request. */
@@ -4976,6 +4980,9 @@ struct android_get_extracted_text_context
/* Token for the request. */
int token;
+ /* Flags associated with the request. */
+ int flags;
+
/* The returned text, or NULL. */
char *text;
@@ -5011,6 +5018,14 @@ android_get_extracted_text (void *data)
= get_extracted_text (f, min (request->hint_max_chars, 600),
&request->start, &request->offset,
&request->length, &request->bytes);
+
+ /* See if request->flags & GET_EXTRACTED_TEXT_MONITOR. If so, then
+ the input method has asked to monitor changes to the extracted
+ text until the next IM context reset. */
+
+ FRAME_ANDROID_OUTPUT (f)->extracted_text_flags = request->flags;
+ FRAME_ANDROID_OUTPUT (f)->extracted_text_token = request->token;
+ FRAME_ANDROID_OUTPUT (f)->extracted_text_hint = request->hint_max_chars;
}
/* Structure describing the `ExtractedTextRequest' class.
@@ -5038,6 +5053,51 @@ struct android_extracted_text_class
jfieldID text;
};
+/* Fields and methods associated with the `ExtractedTextRequest'
+ class. */
+struct android_extracted_text_request_class request_class;
+
+/* Fields and methods associated with the `ExtractedText' class. */
+struct android_extracted_text_class text_class;
+
+/* Return an ExtractedText object corresponding to the extracted text
+ TEXT. START is a character position describing the offset of the
+ first character in TEXT. OFFSET is the offset of point relative to
+ START.
+
+ Assume that request_class and text_class have already been
+ initialized.
+
+ Value is NULL if an error occurs; the exception is not cleared,
+ else a local reference to the ExtractedText object. */
+
+static jobject
+android_build_extracted_text (jstring text, ptrdiff_t start,
+ ptrdiff_t offset)
+{
+ JNIEnv *env;
+ jobject object;
+
+ env = android_java_env;
+
+ /* Create an ExtractedText object containing this information. */
+ object = (*env)->NewObject (env, text_class.class,
+ text_class.constructor);
+ if (!object)
+ return NULL;
+
+ (*env)->SetIntField (env, object, text_class.partial_start_offset, -1);
+ (*env)->SetIntField (env, object, text_class.partial_end_offset, -1);
+ (*env)->SetIntField (env, object, text_class.selection_start,
+ min (offset, TYPE_MAXIMUM (jint)));
+ (*env)->SetIntField (env, object, text_class.selection_end,
+ min (offset, TYPE_MAXIMUM (jint)));
+ (*env)->SetIntField (env, object, text_class.start_offset,
+ min (start, TYPE_MAXIMUM (jint)));
+ (*env)->SetObjectField (env, object, text_class.text, text);
+ return object;
+}
+
JNIEXPORT jobject JNICALL
NATIVE_NAME (getExtractedText) (JNIEnv *env, jobject ignored_object,
jshort window, jobject request,
@@ -5046,14 +5106,10 @@ NATIVE_NAME (getExtractedText) (JNIEnv *env, jobject
ignored_object,
JNI_STACK_ALIGNMENT_PROLOGUE;
struct android_get_extracted_text_context context;
- static struct android_extracted_text_request_class request_class;
- static struct android_extracted_text_class text_class;
jstring string;
jclass class;
jobject object;
- /* TODO: report changes to extracted text. */
-
/* Initialize both classes if necessary. */
if (!request_class.initialized)
@@ -5106,6 +5162,7 @@ NATIVE_NAME (getExtractedText) (JNIEnv *env, jobject
ignored_object,
= (*env)->GetIntField (env, request, request_class.hint_max_chars);
context.token
= (*env)->GetIntField (env, request, request_class.token);
+ context.flags = flags;
context.text = NULL;
context.window = window;
@@ -5126,8 +5183,8 @@ NATIVE_NAME (getExtractedText) (JNIEnv *env, jobject
ignored_object,
return NULL;
/* Create an ExtractedText object containing this information. */
- object = (*android_java_env)->NewObject (env, text_class.class,
- text_class.constructor);
+ object = (*env)->NewObject (env, text_class.class,
+ text_class.constructor);
if (!object)
return NULL;
@@ -5143,6 +5200,8 @@ NATIVE_NAME (getExtractedText) (JNIEnv *env, jobject
ignored_object,
return object;
}
+
+
JNIEXPORT jstring JNICALL
NATIVE_NAME (getSelectedText) (JNIEnv *env, jobject object,
jshort window)
@@ -5210,8 +5269,12 @@ NATIVE_NAME (requestSelectionUpdate) (JNIEnv *env,
jobject object,
static void
android_update_selection (struct frame *f, struct window *w)
{
- ptrdiff_t start, end, point, mark;
+ ptrdiff_t start, end, point, mark, offset, length, bytes;
struct buffer *b;
+ int hint, token;
+ char *text;
+ jobject extracted;
+ jstring string;
if (MARKERP (f->conversion.compose_region_start))
{
@@ -5246,6 +5309,36 @@ android_update_selection (struct frame *f, struct window
*w)
the selection is less than or equal to the end. */
android_update_ic (FRAME_ANDROID_WINDOW (f), min (point, mark),
max (point, mark), start, end);
+
+ /* Update the extracted text as well, if the input method has asked
+ for updates. 1 is
+ InputConnection.GET_EXTRACTED_TEXT_MONITOR. */
+
+ if (FRAME_ANDROID_OUTPUT (f)->extracted_text_flags & 1)
+ {
+ hint = FRAME_ANDROID_OUTPUT (f)->extracted_text_hint;
+ token = FRAME_ANDROID_OUTPUT (f)->extracted_text_token;
+ text = get_extracted_text (f, min (hint, 600), &start,
+ &offset, &length, &bytes);
+
+ /* Make a string out of the extracted text. */
+ string = android_text_to_string (android_java_env,
+ text, length, bytes);
+ xfree (text);
+ android_exception_check ();
+
+ /* Make extracted text out of that string. */
+ extracted = android_build_extracted_text (string, start,
+ offset);
+ android_exception_check_1 (string);
+ ANDROID_DELETE_LOCAL_REF (string);
+
+ /* extracted is now an associated ExtractedText object. Perform
+ the update. */
+ android_update_extracted_text (FRAME_ANDROID_WINDOW (f),
+ extracted, token);
+ ANDROID_DELETE_LOCAL_REF (extracted);
+ }
}
/* Notice that the input method connection to F should be reset as a
@@ -5283,6 +5376,10 @@ android_reset_conversion (struct frame *f)
android_reset_ic (FRAME_ANDROID_WINDOW (f), mode);
+ /* Clear extracted text flags. Since the IM has been reinitialised,
+ it should no longer be displaying extracted text. */
+ FRAME_ANDROID_OUTPUT (f)->extracted_text_flags = 0;
+
/* Move its selection to the specified position. */
android_update_selection (f, NULL);
}
diff --git a/src/androidterm.h b/src/androidterm.h
index ac845187a66..9bd11bb7853 100644
--- a/src/androidterm.h
+++ b/src/androidterm.h
@@ -241,6 +241,16 @@ struct android_output
/* List of all tools (either styluses or fingers) pressed onto the
frame. */
struct android_touch_point *touch_points;
+
+ /* Flags associated with the last request to obtain ``extracted
+ text''. */
+ int extracted_text_flags;
+
+ /* Token asssociated with that request. */
+ int extracted_text_token;
+
+ /* The number of characters of extracted text wanted by the IM. */
+ int extracted_text_hint;
};
enum