emacs-diffs
[Top][All Lists]
Advanced

[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



reply via email to

[Prev in Thread] Current Thread [Next in Thread]