diff options
| author | Po Lu | 2023-03-08 15:04:49 +0800 |
|---|---|---|
| committer | Po Lu | 2023-03-08 15:04:49 +0800 |
| commit | bb55528c7b58c5f50336ed3f2ff9759559d78680 (patch) | |
| tree | 6a4422afb19dc4ac9644d62b12d2a8aaf145deb3 /src | |
| parent | fdff5442a59fd2387c23e2be2658dafa39466891 (diff) | |
| download | emacs-bb55528c7b58c5f50336ed3f2ff9759559d78680.tar.gz emacs-bb55528c7b58c5f50336ed3f2ff9759559d78680.zip | |
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.
Diffstat (limited to 'src')
| -rw-r--r-- | src/android.c | 44 | ||||
| -rw-r--r-- | src/androidgui.h | 2 | ||||
| -rw-r--r-- | src/androidterm.c | 111 | ||||
| -rw-r--r-- | src/androidterm.h | 10 |
4 files changed, 155 insertions, 12 deletions
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 | |||
| 112 | jmethodID check_content_uri; | 112 | jmethodID check_content_uri; |
| 113 | jmethodID query_battery; | 113 | jmethodID query_battery; |
| 114 | jmethodID display_toast; | 114 | jmethodID display_toast; |
| 115 | jmethodID update_extracted_text; | ||
| 115 | }; | 116 | }; |
| 116 | 117 | ||
| 117 | struct android_emacs_pixmap | 118 | struct android_emacs_pixmap |
| @@ -1236,13 +1237,12 @@ android_hack_asset_fd_fallback (AAsset *asset) | |||
| 1236 | Creating an ashmem file descriptor and reading from it doesn't | 1237 | Creating an ashmem file descriptor and reading from it doesn't |
| 1237 | work on these old Android versions. */ | 1238 | work on these old Android versions. */ |
| 1238 | 1239 | ||
| 1239 | snprintf (filename, PATH_MAX, "%s/%s.%d", | 1240 | snprintf (filename, PATH_MAX, "%s/temp~unlinked.%d", |
| 1240 | android_cache_dir, "temp-unlinked", | 1241 | android_cache_dir, getpid ()); |
| 1241 | getpid ()); | ||
| 1242 | fd = open (filename, O_CREAT | O_RDWR | O_TRUNC, | 1242 | fd = open (filename, O_CREAT | O_RDWR | O_TRUNC, |
| 1243 | S_IRUSR | S_IWUSR); | 1243 | S_IRUSR | S_IWUSR); |
| 1244 | 1244 | ||
| 1245 | if (fd < 1) | 1245 | if (fd < 0) |
| 1246 | return -1; | 1246 | return -1; |
| 1247 | 1247 | ||
| 1248 | if (unlink (filename)) | 1248 | if (unlink (filename)) |
| @@ -2135,6 +2135,9 @@ android_init_emacs_service (void) | |||
| 2135 | FIND_METHOD (query_battery, "queryBattery", "()[J"); | 2135 | FIND_METHOD (query_battery, "queryBattery", "()[J"); |
| 2136 | FIND_METHOD (display_toast, "displayToast", | 2136 | FIND_METHOD (display_toast, "displayToast", |
| 2137 | "(Ljava/lang/String;)V"); | 2137 | "(Ljava/lang/String;)V"); |
| 2138 | FIND_METHOD (update_extracted_text, "updateExtractedText", | ||
| 2139 | "(Lorg/gnu/emacs/EmacsWindow;" | ||
| 2140 | "Landroid/view/inputmethod/ExtractedText;I)V"); | ||
| 2138 | #undef FIND_METHOD | 2141 | #undef FIND_METHOD |
| 2139 | } | 2142 | } |
| 2140 | 2143 | ||
| @@ -5991,6 +5994,37 @@ android_reset_ic (android_window window, enum android_ic_mode mode) | |||
| 5991 | android_exception_check (); | 5994 | android_exception_check (); |
| 5992 | } | 5995 | } |
| 5993 | 5996 | ||
| 5997 | /* Make updates to extracted text known to the input method on | ||
| 5998 | WINDOW. TEXT should be a local reference to the new | ||
| 5999 | extracted text. TOKEN should be the token specified by the | ||
| 6000 | input method. */ | ||
| 6001 | |||
| 6002 | void | ||
| 6003 | android_update_extracted_text (android_window window, void *text, | ||
| 6004 | int token) | ||
| 6005 | { | ||
| 6006 | jobject object; | ||
| 6007 | jmethodID method; | ||
| 6008 | |||
| 6009 | object = android_resolve_handle (window, ANDROID_HANDLE_WINDOW); | ||
| 6010 | method = service_class.update_extracted_text; | ||
| 6011 | |||
| 6012 | (*android_java_env)->CallNonvirtualVoidMethod (android_java_env, | ||
| 6013 | emacs_service, | ||
| 6014 | service_class.class, | ||
| 6015 | method, object, | ||
| 6016 | /* N.B. that | ||
| 6017 | text is not | ||
| 6018 | jobject, | ||
| 6019 | because that | ||
| 6020 | type is not | ||
| 6021 | available in | ||
| 6022 | androidgui.h. */ | ||
| 6023 | (jobject) text, | ||
| 6024 | (jint) token); | ||
| 6025 | android_exception_check_1 (text); | ||
| 6026 | } | ||
| 6027 | |||
| 5994 | 6028 | ||
| 5995 | 6029 | ||
| 5996 | /* Window decoration management functions. */ | 6030 | /* Window decoration management functions. */ |
| @@ -6083,7 +6117,7 @@ android_open_asset (const char *filename, int oflag, mode_t mode) | |||
| 6083 | get a regular file descriptor. */ | 6117 | get a regular file descriptor. */ |
| 6084 | 6118 | ||
| 6085 | fd.fd = android_open (filename, oflag, mode); | 6119 | fd.fd = android_open (filename, oflag, mode); |
| 6086 | if (fd.fd < 1) | 6120 | if (fd.fd < 0) |
| 6087 | return fd; | 6121 | return fd; |
| 6088 | 6122 | ||
| 6089 | /* Set fd.asset to NULL, signifying that it is a file | 6123 | /* 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 *, | |||
| 613 | extern void android_update_ic (android_window, ptrdiff_t, ptrdiff_t, | 613 | extern void android_update_ic (android_window, ptrdiff_t, ptrdiff_t, |
| 614 | ptrdiff_t, ptrdiff_t); | 614 | ptrdiff_t, ptrdiff_t); |
| 615 | extern void android_reset_ic (android_window, enum android_ic_mode); | 615 | extern void android_reset_ic (android_window, enum android_ic_mode); |
| 616 | extern void android_update_extracted_text (android_window, void *, | ||
| 617 | int); | ||
| 616 | extern int android_set_fullscreen (android_window, bool); | 618 | extern int android_set_fullscreen (android_window, bool); |
| 617 | 619 | ||
| 618 | #endif | 620 | #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, | |||
| 4968 | android_write_event (&event); | 4968 | android_write_event (&event); |
| 4969 | } | 4969 | } |
| 4970 | 4970 | ||
| 4971 | |||
| 4972 | |||
| 4973 | /* Text extraction. */ | ||
| 4974 | |||
| 4971 | struct android_get_extracted_text_context | 4975 | struct android_get_extracted_text_context |
| 4972 | { | 4976 | { |
| 4973 | /* The parameters of the request. */ | 4977 | /* The parameters of the request. */ |
| @@ -4976,6 +4980,9 @@ struct android_get_extracted_text_context | |||
| 4976 | /* Token for the request. */ | 4980 | /* Token for the request. */ |
| 4977 | int token; | 4981 | int token; |
| 4978 | 4982 | ||
| 4983 | /* Flags associated with the request. */ | ||
| 4984 | int flags; | ||
| 4985 | |||
| 4979 | /* The returned text, or NULL. */ | 4986 | /* The returned text, or NULL. */ |
| 4980 | char *text; | 4987 | char *text; |
| 4981 | 4988 | ||
| @@ -5011,6 +5018,14 @@ android_get_extracted_text (void *data) | |||
| 5011 | = get_extracted_text (f, min (request->hint_max_chars, 600), | 5018 | = get_extracted_text (f, min (request->hint_max_chars, 600), |
| 5012 | &request->start, &request->offset, | 5019 | &request->start, &request->offset, |
| 5013 | &request->length, &request->bytes); | 5020 | &request->length, &request->bytes); |
| 5021 | |||
| 5022 | /* See if request->flags & GET_EXTRACTED_TEXT_MONITOR. If so, then | ||
| 5023 | the input method has asked to monitor changes to the extracted | ||
| 5024 | text until the next IM context reset. */ | ||
| 5025 | |||
| 5026 | FRAME_ANDROID_OUTPUT (f)->extracted_text_flags = request->flags; | ||
| 5027 | FRAME_ANDROID_OUTPUT (f)->extracted_text_token = request->token; | ||
| 5028 | FRAME_ANDROID_OUTPUT (f)->extracted_text_hint = request->hint_max_chars; | ||
| 5014 | } | 5029 | } |
| 5015 | 5030 | ||
| 5016 | /* Structure describing the `ExtractedTextRequest' class. | 5031 | /* Structure describing the `ExtractedTextRequest' class. |
| @@ -5038,6 +5053,51 @@ struct android_extracted_text_class | |||
| 5038 | jfieldID text; | 5053 | jfieldID text; |
| 5039 | }; | 5054 | }; |
| 5040 | 5055 | ||
| 5056 | /* Fields and methods associated with the `ExtractedTextRequest' | ||
| 5057 | class. */ | ||
| 5058 | struct android_extracted_text_request_class request_class; | ||
| 5059 | |||
| 5060 | /* Fields and methods associated with the `ExtractedText' class. */ | ||
| 5061 | struct android_extracted_text_class text_class; | ||
| 5062 | |||
| 5063 | /* Return an ExtractedText object corresponding to the extracted text | ||
| 5064 | TEXT. START is a character position describing the offset of the | ||
| 5065 | first character in TEXT. OFFSET is the offset of point relative to | ||
| 5066 | START. | ||
| 5067 | |||
| 5068 | Assume that request_class and text_class have already been | ||
| 5069 | initialized. | ||
| 5070 | |||
| 5071 | Value is NULL if an error occurs; the exception is not cleared, | ||
| 5072 | else a local reference to the ExtractedText object. */ | ||
| 5073 | |||
| 5074 | static jobject | ||
| 5075 | android_build_extracted_text (jstring text, ptrdiff_t start, | ||
| 5076 | ptrdiff_t offset) | ||
| 5077 | { | ||
| 5078 | JNIEnv *env; | ||
| 5079 | jobject object; | ||
| 5080 | |||
| 5081 | env = android_java_env; | ||
| 5082 | |||
| 5083 | /* Create an ExtractedText object containing this information. */ | ||
| 5084 | object = (*env)->NewObject (env, text_class.class, | ||
| 5085 | text_class.constructor); | ||
| 5086 | if (!object) | ||
| 5087 | return NULL; | ||
| 5088 | |||
| 5089 | (*env)->SetIntField (env, object, text_class.partial_start_offset, -1); | ||
| 5090 | (*env)->SetIntField (env, object, text_class.partial_end_offset, -1); | ||
| 5091 | (*env)->SetIntField (env, object, text_class.selection_start, | ||
| 5092 | min (offset, TYPE_MAXIMUM (jint))); | ||
| 5093 | (*env)->SetIntField (env, object, text_class.selection_end, | ||
| 5094 | min (offset, TYPE_MAXIMUM (jint))); | ||
| 5095 | (*env)->SetIntField (env, object, text_class.start_offset, | ||
| 5096 | min (start, TYPE_MAXIMUM (jint))); | ||
| 5097 | (*env)->SetObjectField (env, object, text_class.text, text); | ||
| 5098 | return object; | ||
| 5099 | } | ||
| 5100 | |||
| 5041 | JNIEXPORT jobject JNICALL | 5101 | JNIEXPORT jobject JNICALL |
| 5042 | NATIVE_NAME (getExtractedText) (JNIEnv *env, jobject ignored_object, | 5102 | NATIVE_NAME (getExtractedText) (JNIEnv *env, jobject ignored_object, |
| 5043 | jshort window, jobject request, | 5103 | jshort window, jobject request, |
| @@ -5046,14 +5106,10 @@ NATIVE_NAME (getExtractedText) (JNIEnv *env, jobject ignored_object, | |||
| 5046 | JNI_STACK_ALIGNMENT_PROLOGUE; | 5106 | JNI_STACK_ALIGNMENT_PROLOGUE; |
| 5047 | 5107 | ||
| 5048 | struct android_get_extracted_text_context context; | 5108 | struct android_get_extracted_text_context context; |
| 5049 | static struct android_extracted_text_request_class request_class; | ||
| 5050 | static struct android_extracted_text_class text_class; | ||
| 5051 | jstring string; | 5109 | jstring string; |
| 5052 | jclass class; | 5110 | jclass class; |
| 5053 | jobject object; | 5111 | jobject object; |
| 5054 | 5112 | ||
| 5055 | /* TODO: report changes to extracted text. */ | ||
| 5056 | |||
| 5057 | /* Initialize both classes if necessary. */ | 5113 | /* Initialize both classes if necessary. */ |
| 5058 | 5114 | ||
| 5059 | if (!request_class.initialized) | 5115 | if (!request_class.initialized) |
| @@ -5106,6 +5162,7 @@ NATIVE_NAME (getExtractedText) (JNIEnv *env, jobject ignored_object, | |||
| 5106 | = (*env)->GetIntField (env, request, request_class.hint_max_chars); | 5162 | = (*env)->GetIntField (env, request, request_class.hint_max_chars); |
| 5107 | context.token | 5163 | context.token |
| 5108 | = (*env)->GetIntField (env, request, request_class.token); | 5164 | = (*env)->GetIntField (env, request, request_class.token); |
| 5165 | context.flags = flags; | ||
| 5109 | context.text = NULL; | 5166 | context.text = NULL; |
| 5110 | context.window = window; | 5167 | context.window = window; |
| 5111 | 5168 | ||
| @@ -5126,8 +5183,8 @@ NATIVE_NAME (getExtractedText) (JNIEnv *env, jobject ignored_object, | |||
| 5126 | return NULL; | 5183 | return NULL; |
| 5127 | 5184 | ||
| 5128 | /* Create an ExtractedText object containing this information. */ | 5185 | /* Create an ExtractedText object containing this information. */ |
| 5129 | object = (*android_java_env)->NewObject (env, text_class.class, | 5186 | object = (*env)->NewObject (env, text_class.class, |
| 5130 | text_class.constructor); | 5187 | text_class.constructor); |
| 5131 | if (!object) | 5188 | if (!object) |
| 5132 | return NULL; | 5189 | return NULL; |
| 5133 | 5190 | ||
| @@ -5143,6 +5200,8 @@ NATIVE_NAME (getExtractedText) (JNIEnv *env, jobject ignored_object, | |||
| 5143 | return object; | 5200 | return object; |
| 5144 | } | 5201 | } |
| 5145 | 5202 | ||
| 5203 | |||
| 5204 | |||
| 5146 | JNIEXPORT jstring JNICALL | 5205 | JNIEXPORT jstring JNICALL |
| 5147 | NATIVE_NAME (getSelectedText) (JNIEnv *env, jobject object, | 5206 | NATIVE_NAME (getSelectedText) (JNIEnv *env, jobject object, |
| 5148 | jshort window) | 5207 | jshort window) |
| @@ -5210,8 +5269,12 @@ NATIVE_NAME (requestSelectionUpdate) (JNIEnv *env, jobject object, | |||
| 5210 | static void | 5269 | static void |
| 5211 | android_update_selection (struct frame *f, struct window *w) | 5270 | android_update_selection (struct frame *f, struct window *w) |
| 5212 | { | 5271 | { |
| 5213 | ptrdiff_t start, end, point, mark; | 5272 | ptrdiff_t start, end, point, mark, offset, length, bytes; |
| 5214 | struct buffer *b; | 5273 | struct buffer *b; |
| 5274 | int hint, token; | ||
| 5275 | char *text; | ||
| 5276 | jobject extracted; | ||
| 5277 | jstring string; | ||
| 5215 | 5278 | ||
| 5216 | if (MARKERP (f->conversion.compose_region_start)) | 5279 | if (MARKERP (f->conversion.compose_region_start)) |
| 5217 | { | 5280 | { |
| @@ -5246,6 +5309,36 @@ android_update_selection (struct frame *f, struct window *w) | |||
| 5246 | the selection is less than or equal to the end. */ | 5309 | the selection is less than or equal to the end. */ |
| 5247 | android_update_ic (FRAME_ANDROID_WINDOW (f), min (point, mark), | 5310 | android_update_ic (FRAME_ANDROID_WINDOW (f), min (point, mark), |
| 5248 | max (point, mark), start, end); | 5311 | max (point, mark), start, end); |
| 5312 | |||
| 5313 | /* Update the extracted text as well, if the input method has asked | ||
| 5314 | for updates. 1 is | ||
| 5315 | InputConnection.GET_EXTRACTED_TEXT_MONITOR. */ | ||
| 5316 | |||
| 5317 | if (FRAME_ANDROID_OUTPUT (f)->extracted_text_flags & 1) | ||
| 5318 | { | ||
| 5319 | hint = FRAME_ANDROID_OUTPUT (f)->extracted_text_hint; | ||
| 5320 | token = FRAME_ANDROID_OUTPUT (f)->extracted_text_token; | ||
| 5321 | text = get_extracted_text (f, min (hint, 600), &start, | ||
| 5322 | &offset, &length, &bytes); | ||
| 5323 | |||
| 5324 | /* Make a string out of the extracted text. */ | ||
| 5325 | string = android_text_to_string (android_java_env, | ||
| 5326 | text, length, bytes); | ||
| 5327 | xfree (text); | ||
| 5328 | android_exception_check (); | ||
| 5329 | |||
| 5330 | /* Make extracted text out of that string. */ | ||
| 5331 | extracted = android_build_extracted_text (string, start, | ||
| 5332 | offset); | ||
| 5333 | android_exception_check_1 (string); | ||
| 5334 | ANDROID_DELETE_LOCAL_REF (string); | ||
| 5335 | |||
| 5336 | /* extracted is now an associated ExtractedText object. Perform | ||
| 5337 | the update. */ | ||
| 5338 | android_update_extracted_text (FRAME_ANDROID_WINDOW (f), | ||
| 5339 | extracted, token); | ||
| 5340 | ANDROID_DELETE_LOCAL_REF (extracted); | ||
| 5341 | } | ||
| 5249 | } | 5342 | } |
| 5250 | 5343 | ||
| 5251 | /* Notice that the input method connection to F should be reset as a | 5344 | /* Notice that the input method connection to F should be reset as a |
| @@ -5283,6 +5376,10 @@ android_reset_conversion (struct frame *f) | |||
| 5283 | 5376 | ||
| 5284 | android_reset_ic (FRAME_ANDROID_WINDOW (f), mode); | 5377 | android_reset_ic (FRAME_ANDROID_WINDOW (f), mode); |
| 5285 | 5378 | ||
| 5379 | /* Clear extracted text flags. Since the IM has been reinitialised, | ||
| 5380 | it should no longer be displaying extracted text. */ | ||
| 5381 | FRAME_ANDROID_OUTPUT (f)->extracted_text_flags = 0; | ||
| 5382 | |||
| 5286 | /* Move its selection to the specified position. */ | 5383 | /* Move its selection to the specified position. */ |
| 5287 | android_update_selection (f, NULL); | 5384 | android_update_selection (f, NULL); |
| 5288 | } | 5385 | } |
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 | |||
| 241 | /* List of all tools (either styluses or fingers) pressed onto the | 241 | /* List of all tools (either styluses or fingers) pressed onto the |
| 242 | frame. */ | 242 | frame. */ |
| 243 | struct android_touch_point *touch_points; | 243 | struct android_touch_point *touch_points; |
| 244 | |||
| 245 | /* Flags associated with the last request to obtain ``extracted | ||
| 246 | text''. */ | ||
| 247 | int extracted_text_flags; | ||
| 248 | |||
| 249 | /* Token asssociated with that request. */ | ||
| 250 | int extracted_text_token; | ||
| 251 | |||
| 252 | /* The number of characters of extracted text wanted by the IM. */ | ||
| 253 | int extracted_text_hint; | ||
| 244 | }; | 254 | }; |
| 245 | 255 | ||
| 246 | enum | 256 | enum |