jmethodID check_content_uri;
jmethodID query_battery;
jmethodID display_toast;
+ jmethodID update_extracted_text;
};
struct android_emacs_pixmap
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))
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
}
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);
+}
+
\f
/* Window decoration management functions. */
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
android_write_event (&event);
}
+\f
+
+/* Text extraction. */
+
struct android_get_extracted_text_context
{
/* The parameters of the request. */
/* Token for the request. */
int token;
+ /* Flags associated with the request. */
+ int flags;
+
/* The returned text, or NULL. */
char *text;
= 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.
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,
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)
= (*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;
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;
return object;
}
+\f
+
JNIEXPORT jstring JNICALL
NATIVE_NAME (getSelectedText) (JNIEnv *env, jobject object,
jshort window)
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))
{
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
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);
}