From d44b60c2f001d57b010f0e9b82f798fbad9a23d6 Mon Sep 17 00:00:00 2001
From: Po Lu
Date: Fri, 20 Jan 2023 19:06:32 +0800
Subject: Update Android port
* .gitignore: Don't ignore verbose.mk.android.
* doc/emacs/Makefile.in (EMACSSOURCES): Add android.texi and
input.texi.
* doc/emacs/android.texi (Android): Document support for the
on-screen keyboard.
(Android Startup): Document how to start Emacs with -Q on
Android.
(Android Environment): Document how Emacs works around the
system ``task killer''. Document changes to frame deletion
behavior.
* doc/emacs/emacs.texi (Top):
* doc/emacs/input.texi (Other Input Devices, On-Screen
Keyboards): Document how to use Emacs with virtual keyboards.
* doc/lispref/commands.texi (Touchscreen Events): Document
changes to `touch-screen-track-drag'.
* doc/lispref/frames.texi (Frames, On-Screen Keyboards): New
node.
* java/AndroidManifest.xml.in: Add settings activity and
appropriate OSK adjustment mode.
* java/org/gnu/emacs/EmacsActivity.java (onCreate): Allow
creating Emacs with -Q.
(onDestroy): Don't remove if killed by the system.
* java/org/gnu/emacs/EmacsContextMenu.java (inflateMenuItems):
Fix context menus again.
* java/org/gnu/emacs/EmacsNative.java (EmacsNative): Make all
event sending functions return long.
* java/org/gnu/emacs/EmacsPreferencesActivity.java
(EmacsPreferencesActivity): New class.
* java/org/gnu/emacs/EmacsService.java (EmacsService)
(onStartCommand, onCreate, startEmacsService): Start as a
foreground service if necessary to bypass system restrictions.
* java/org/gnu/emacs/EmacsSurfaceView.java (EmacsSurfaceView):
* java/org/gnu/emacs/EmacsThread.java (EmacsThread, run):
* java/org/gnu/emacs/EmacsView.java (EmacsView, onLayout)
(onDetachedFromWindow):
* java/org/gnu/emacs/EmacsWindow.java (EmacsWindow, viewLayout):
Implement frame resize synchronization..
* java/org/gnu/emacs/EmacsWindowAttachmentManager.java
(EmacsWindowAttachmentManager, removeWindowConsumer): Adjust
accordingly for changes to frame deletion behavior.
* lisp/frame.el (android-toggle-on-screen-keyboard)
(frame-toggle-on-screen-keyboard): New function.
* lisp/minibuffer.el (minibuffer-setup-on-screen-keyboard)
(minibuffer-exit-on-screen-keyboard): New functions.
(minibuffer-setup-hook, minibuffer-exit-hook): Add new functions
to hooks.
* lisp/touch-screen.el (touch-screen-relative-xy): Accept new
value of window `frame'. Return frame coordinates in that case.
(touch-screen-set-point-commands): New variable.
(touch-screen-handle-point-up): Respect that variable.
(touch-screen-track-drag): Return `no-drag' where appropriate.
(touch-screen-drag-mode-line-1, touch-screen-drag-mode-line):
Refactor to use `no-drag'.
* src/android.c (struct android_emacs_window): New methods.
Make all event sending functions return the event serial.
(android_toggle_on_screen_keyboard, android_window_updated): New
functions.
* src/android.h: Update prototypes.
* src/androidfns.c (Fandroid_toggle_on_screen_keyboard)
(syms_of_androidfns): New function.
* src/androidgui.h (struct android_any_event)
(struct android_key_event, struct android_configure_event)
(struct android_focus_event, struct android_window_action_event)
(struct android_crossing_event, struct android_motion_event)
(struct android_button_event, struct android_touch_event)
(struct android_wheel_event, struct android_iconify_event)
(struct android_menu_event): Add `serial' fields.
* src/androidterm.c (handle_one_android_event)
(android_frame_up_to_date):
* src/androidterm.h (struct android_output): Implement frame
resize synchronization.
---
java/org/gnu/emacs/EmacsActivity.java | 20 +++-
java/org/gnu/emacs/EmacsContextMenu.java | 1 +
java/org/gnu/emacs/EmacsNative.java | 39 ++++---
java/org/gnu/emacs/EmacsPreferencesActivity.java | 98 ++++++++++++++++
java/org/gnu/emacs/EmacsService.java | 62 +++++++++-
java/org/gnu/emacs/EmacsSurfaceView.java | 127 +++++++++++++++------
java/org/gnu/emacs/EmacsThread.java | 12 +-
java/org/gnu/emacs/EmacsView.java | 55 ++++++++-
java/org/gnu/emacs/EmacsWindow.java | 58 ++++++++--
.../gnu/emacs/EmacsWindowAttachmentManager.java | 4 +-
10 files changed, 400 insertions(+), 76 deletions(-)
create mode 100644 java/org/gnu/emacs/EmacsPreferencesActivity.java
(limited to 'java/org/gnu')
diff --git a/java/org/gnu/emacs/EmacsActivity.java b/java/org/gnu/emacs/EmacsActivity.java
index 79c0991a5d3..d377cf982ef 100644
--- a/java/org/gnu/emacs/EmacsActivity.java
+++ b/java/org/gnu/emacs/EmacsActivity.java
@@ -161,6 +161,13 @@ public class EmacsActivity extends Activity
onCreate (Bundle savedInstanceState)
{
FrameLayout.LayoutParams params;
+ Intent intent;
+
+ /* See if Emacs should be started with -Q. */
+ intent = getIntent ();
+ EmacsService.needDashQ
+ = intent.getBooleanExtra ("org.gnu.emacs.START_DASH_Q",
+ false);
/* Set the theme to one without a title bar. */
@@ -179,9 +186,8 @@ public class EmacsActivity extends Activity
/* Set it as the content view. */
setContentView (layout);
- if (EmacsService.SERVICE == null)
- /* Start the Emacs service now. */
- startService (new Intent (this, EmacsService.class));
+ /* Maybe start the Emacs service if necessary. */
+ EmacsService.startEmacsService (this);
/* Add this activity to the list of available activities. */
EmacsWindowAttachmentManager.MANAGER.registerWindowConsumer (this);
@@ -193,10 +199,16 @@ public class EmacsActivity extends Activity
public void
onDestroy ()
{
+ EmacsWindowAttachmentManager manager;
+ boolean isMultitask;
+
+ manager = EmacsWindowAttachmentManager.MANAGER;
+
/* The activity will die shortly hereafter. If there is a window
attached, close it now. */
Log.d (TAG, "onDestroy " + this);
- EmacsWindowAttachmentManager.MANAGER.removeWindowConsumer (this);
+ isMultitask = this instanceof EmacsMultitaskActivity;
+ manager.removeWindowConsumer (this, isMultitask || isFinishing ());
focusedActivities.remove (this);
invalidateFocus ();
super.onDestroy ();
diff --git a/java/org/gnu/emacs/EmacsContextMenu.java b/java/org/gnu/emacs/EmacsContextMenu.java
index ac67ebe4aa0..056d8fb692c 100644
--- a/java/org/gnu/emacs/EmacsContextMenu.java
+++ b/java/org/gnu/emacs/EmacsContextMenu.java
@@ -174,6 +174,7 @@ public class EmacsContextMenu
support doing so, create the submenu and add the
contents of the menu to it. */
submenu = menu.addSubMenu (item.itemName);
+ item.subMenu.inflateMenuItems (submenu);
}
catch (UnsupportedOperationException exception)
{
diff --git a/java/org/gnu/emacs/EmacsNative.java b/java/org/gnu/emacs/EmacsNative.java
index 2f3a732ea7c..3efdc0cff9a 100644
--- a/java/org/gnu/emacs/EmacsNative.java
+++ b/java/org/gnu/emacs/EmacsNative.java
@@ -61,75 +61,76 @@ public class EmacsNative
/* Abort and generate a native core dump. */
public static native void emacsAbort ();
- /* Send an ANDROID_CONFIGURE_NOTIFY event. */
- public static native void sendConfigureNotify (short window, long time,
+ /* Send an ANDROID_CONFIGURE_NOTIFY event. The values of all the
+ functions below are the serials of the events sent. */
+ public static native long sendConfigureNotify (short window, long time,
int x, int y, int width,
int height);
/* Send an ANDROID_KEY_PRESS event. */
- public static native void sendKeyPress (short window, long time, int state,
+ public static native long sendKeyPress (short window, long time, int state,
int keyCode, int unicodeChar);
/* Send an ANDROID_KEY_RELEASE event. */
- public static native void sendKeyRelease (short window, long time, int state,
+ public static native long sendKeyRelease (short window, long time, int state,
int keyCode, int unicodeChar);
/* Send an ANDROID_FOCUS_IN event. */
- public static native void sendFocusIn (short window, long time);
+ public static native long sendFocusIn (short window, long time);
/* Send an ANDROID_FOCUS_OUT event. */
- public static native void sendFocusOut (short window, long time);
+ public static native long sendFocusOut (short window, long time);
/* Send an ANDROID_WINDOW_ACTION event. */
- public static native void sendWindowAction (short window, int action);
+ public static native long sendWindowAction (short window, int action);
/* Send an ANDROID_ENTER_NOTIFY event. */
- public static native void sendEnterNotify (short window, int x, int y,
+ public static native long sendEnterNotify (short window, int x, int y,
long time);
/* Send an ANDROID_LEAVE_NOTIFY event. */
- public static native void sendLeaveNotify (short window, int x, int y,
+ public static native long sendLeaveNotify (short window, int x, int y,
long time);
/* Send an ANDROID_MOTION_NOTIFY event. */
- public static native void sendMotionNotify (short window, int x, int y,
+ public static native long sendMotionNotify (short window, int x, int y,
long time);
/* Send an ANDROID_BUTTON_PRESS event. */
- public static native void sendButtonPress (short window, int x, int y,
+ public static native long sendButtonPress (short window, int x, int y,
long time, int state,
int button);
/* Send an ANDROID_BUTTON_RELEASE event. */
- public static native void sendButtonRelease (short window, int x, int y,
+ public static native long sendButtonRelease (short window, int x, int y,
long time, int state,
int button);
/* Send an ANDROID_TOUCH_DOWN event. */
- public static native void sendTouchDown (short window, int x, int y,
+ public static native long sendTouchDown (short window, int x, int y,
long time, int pointerID);
/* Send an ANDROID_TOUCH_UP event. */
- public static native void sendTouchUp (short window, int x, int y,
+ public static native long sendTouchUp (short window, int x, int y,
long time, int pointerID);
/* Send an ANDROID_TOUCH_MOVE event. */
- public static native void sendTouchMove (short window, int x, int y,
+ public static native long sendTouchMove (short window, int x, int y,
long time, int pointerID);
/* Send an ANDROID_WHEEL event. */
- public static native void sendWheel (short window, int x, int y,
+ public static native long sendWheel (short window, int x, int y,
long time, int state,
float xDelta, float yDelta);
/* Send an ANDROID_ICONIFIED event. */
- public static native void sendIconified (short window);
+ public static native long sendIconified (short window);
/* Send an ANDROID_DEICONIFIED event. */
- public static native void sendDeiconified (short window);
+ public static native long sendDeiconified (short window);
/* Send an ANDROID_CONTEXT_MENU event. */
- public static native void sendContextMenu (short window, int menuEventID);
+ public static native long sendContextMenu (short window, int menuEventID);
static
{
diff --git a/java/org/gnu/emacs/EmacsPreferencesActivity.java b/java/org/gnu/emacs/EmacsPreferencesActivity.java
new file mode 100644
index 00000000000..0db983984fd
--- /dev/null
+++ b/java/org/gnu/emacs/EmacsPreferencesActivity.java
@@ -0,0 +1,98 @@
+/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
+
+Copyright (C) 2023 Free Software Foundation, Inc.
+
+This file is part of GNU Emacs.
+
+GNU Emacs is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or (at
+your option) any later version.
+
+GNU Emacs is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Emacs. If not, see . */
+
+package org.gnu.emacs;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Build;
+import android.view.View;
+import android.view.ViewGroup.LayoutParams;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import android.R;
+
+/* This module provides a ``preferences'' display for Emacs. It is
+ supposed to be launched from inside the Settings application to
+ perform various actions, such as starting Emacs with the ``-Q''
+ option, which would not be possible otherwise, as there is no
+ command line on Android. */
+
+public class EmacsPreferencesActivity extends Activity
+{
+ /* The linear layout associated with the activity. */
+ private LinearLayout layout;
+
+ /* Restart Emacs with -Q. Call EmacsThread.exit to kill Emacs now, and
+ tell the system to EmacsActivity with some parameters later. */
+
+ private void
+ startEmacsQ ()
+ {
+ Intent intent;
+
+ intent = new Intent (this, EmacsActivity.class);
+ intent.addFlags (Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ intent.putExtra ("org.gnu.emacs.START_DASH_Q", true);
+ startActivity (intent);
+ System.exit (0);
+ }
+
+ @Override
+ public void
+ onCreate (Bundle savedInstanceState)
+ {
+ LinearLayout layout;
+ TextView textView;
+ LinearLayout.LayoutParams params;
+ int resid;
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
+ setTheme (R.style.Theme_DeviceDefault_Settings);
+ else if (Build.VERSION.SDK_INT
+ >= Build.VERSION_CODES.ICE_CREAM_SANDWICH)
+ setTheme (R.style.Theme_DeviceDefault);
+
+ layout = new LinearLayout (this);
+ layout.setOrientation (LinearLayout.VERTICAL);
+ setContentView (layout);
+
+ textView = new TextView (this);
+ textView.setPadding (8, 20, 20, 8);
+
+ params = new LinearLayout.LayoutParams (LayoutParams.MATCH_PARENT,
+ LayoutParams.WRAP_CONTENT);
+ textView.setLayoutParams (params);
+ textView.setText ("(Re)start Emacs with -Q");
+ textView.setOnClickListener (new View.OnClickListener () {
+ @Override
+ public void
+ onClick (View view)
+ {
+ startEmacsQ ();
+ }
+ });
+ layout.addView (textView);
+
+ super.onCreate (savedInstanceState);
+ }
+};
diff --git a/java/org/gnu/emacs/EmacsService.java b/java/org/gnu/emacs/EmacsService.java
index bcf8d9ff6e8..95f21b211a3 100644
--- a/java/org/gnu/emacs/EmacsService.java
+++ b/java/org/gnu/emacs/EmacsService.java
@@ -32,7 +32,13 @@ import android.view.InputDevice;
import android.view.KeyEvent;
import android.annotation.TargetApi;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.NotificationChannel;
+import android.app.PendingIntent;
import android.app.Service;
+
import android.content.Context;
import android.content.Intent;
import android.content.res.AssetManager;
@@ -63,6 +69,7 @@ public class EmacsService extends Service
public static final String TAG = "EmacsService";
public static final int MAX_PENDING_REQUESTS = 256;
public static volatile EmacsService SERVICE;
+ public static boolean needDashQ;
private EmacsThread thread;
private Handler handler;
@@ -74,6 +81,31 @@ public class EmacsService extends Service
public int
onStartCommand (Intent intent, int flags, int startId)
{
+ Notification notification;
+ NotificationManager manager;
+ NotificationChannel channel;
+ String infoBlurb;
+ Object tem;
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
+ {
+ tem = getSystemService (Context.NOTIFICATION_SERVICE);
+ manager = (NotificationManager) tem;
+ infoBlurb = ("See (emacs)Android Environment for more"
+ + " details about this notification.");
+ channel
+ = new NotificationChannel ("emacs", "Emacs persistent notification",
+ NotificationManager.IMPORTANCE_DEFAULT);
+ manager.createNotificationChannel (channel);
+ notification = (new Notification.Builder (this, "emacs")
+ .setContentTitle ("Emacs")
+ .setContentText (infoBlurb)
+ .setSmallIcon (android.R.drawable.sym_def_app_icon)
+ .build ());
+ manager.notify (1, notification);
+ startForeground (1, notification);
+ }
+
return START_NOT_STICKY;
}
@@ -137,7 +169,7 @@ public class EmacsService extends Service
this);
/* Start the thread that runs Emacs. */
- thread = new EmacsThread (this);
+ thread = new EmacsThread (this, needDashQ);
thread.start ();
}
catch (IOException exception)
@@ -444,4 +476,32 @@ public class EmacsService extends Service
}
}
}
+
+
+
+ /* Start the Emacs service if necessary. On Android 26 and up,
+ start Emacs as a foreground service with a notification, to avoid
+ it being killed by the system.
+
+ On older systems, simply start it as a normal background
+ service. */
+
+ public static void
+ startEmacsService (Context context)
+ {
+ PendingIntent intent;
+
+ if (EmacsService.SERVICE == null)
+ {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O)
+ /* Start the Emacs service now. */
+ context.startService (new Intent (context,
+ EmacsService.class));
+ else
+ /* Display the permanant notification and start Emacs as a
+ foreground service. */
+ context.startForegroundService (new Intent (context,
+ EmacsService.class));
+ }
+ }
};
diff --git a/java/org/gnu/emacs/EmacsSurfaceView.java b/java/org/gnu/emacs/EmacsSurfaceView.java
index f713818d4bc..2fe9e103b2b 100644
--- a/java/org/gnu/emacs/EmacsSurfaceView.java
+++ b/java/org/gnu/emacs/EmacsSurfaceView.java
@@ -32,53 +32,106 @@ import android.util.Log;
public class EmacsSurfaceView extends SurfaceView
{
private static final String TAG = "EmacsSurfaceView";
-
public Object surfaceChangeLock;
private boolean created;
+ private EmacsView view;
- public
- EmacsSurfaceView (final EmacsView view)
- {
- super (view.getContext ());
-
- surfaceChangeLock = new Object ();
+ /* This is the callback used on Android 8 to 25. */
- getHolder ().addCallback (new SurfaceHolder.Callback () {
- @Override
- public void
- surfaceChanged (SurfaceHolder holder, int format,
- int width, int height)
+ private class Callback implements SurfaceHolder.Callback
+ {
+ @Override
+ public void
+ surfaceChanged (SurfaceHolder holder, int format,
+ int width, int height)
+ {
+ Log.d (TAG, "surfaceChanged: " + view + ", " + view.pendingConfigure);
+
+ /* Make sure not to swap buffers if there is pending
+ configuration, because otherwise the redraw callback will not
+ run correctly. */
+
+ if (view.pendingConfigure == 0)
+ view.swapBuffers ();
+ }
+
+ @Override
+ public void
+ surfaceCreated (SurfaceHolder holder)
+ {
+ synchronized (surfaceChangeLock)
{
- Log.d (TAG, "surfaceChanged: " + view);
- view.swapBuffers ();
+ Log.d (TAG, "surfaceCreated: " + view);
+ created = true;
}
- @Override
- public void
- surfaceCreated (SurfaceHolder holder)
- {
- synchronized (surfaceChangeLock)
- {
- Log.d (TAG, "surfaceCreated: " + view);
- created = true;
- }
-
- /* Drop the lock when doing this, or a deadlock can
- result. */
- view.swapBuffers ();
- }
+ /* Drop the lock when doing this, or a deadlock can
+ result. */
+ view.swapBuffers ();
+ }
- @Override
- public void
- surfaceDestroyed (SurfaceHolder holder)
+ @Override
+ public void
+ surfaceDestroyed (SurfaceHolder holder)
+ {
+ synchronized (surfaceChangeLock)
{
- synchronized (surfaceChangeLock)
- {
- Log.d (TAG, "surfaceDestroyed: " + view);
- created = false;
- }
+ Log.d (TAG, "surfaceDestroyed: " + view);
+ created = false;
}
- });
+ }
+ }
+
+ /* And this is the callback used on Android 26 and later. It is
+ used because it can tell the system when drawing completes. */
+
+ private class Callback2 extends Callback implements SurfaceHolder.Callback2
+ {
+ @Override
+ public void
+ surfaceRedrawNeeded (SurfaceHolder holder)
+ {
+ /* This version is not supported. */
+ return;
+ }
+
+ @Override
+ public void
+ surfaceRedrawNeededAsync (SurfaceHolder holder,
+ Runnable drawingFinished)
+ {
+ Runnable old;
+
+ Log.d (TAG, "surfaceRedrawNeededAsync: " + view.pendingConfigure);
+
+ /* The system calls this function when it wants to know whether
+ or not Emacs is still configuring itself in response to a
+ resize.
+
+ If the view did not send an outstanding ConfigureNotify
+ event, then call drawingFinish immediately. Else, give it to
+ the view to execute after drawing completes. */
+
+ if (view.pendingConfigure == 0)
+ drawingFinished.run ();
+ else
+ /* And set this runnable to run once drawing completes. */
+ view.drawingFinished = drawingFinished;
+ }
+ }
+
+ public
+ EmacsSurfaceView (final EmacsView view)
+ {
+ super (view.getContext ());
+
+ this.surfaceChangeLock = new Object ();
+ this.view = view;
+
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O)
+ getHolder ().addCallback (new Callback ());
+ else
+ getHolder ().addCallback (new Callback2 ());
}
public boolean
diff --git a/java/org/gnu/emacs/EmacsThread.java b/java/org/gnu/emacs/EmacsThread.java
index 0882753747f..f9bc132f354 100644
--- a/java/org/gnu/emacs/EmacsThread.java
+++ b/java/org/gnu/emacs/EmacsThread.java
@@ -23,12 +23,13 @@ import java.lang.Thread;
public class EmacsThread extends Thread
{
- EmacsService context;
+ /* Whether or not Emacs should be started -Q. */
+ private boolean startDashQ;
public
- EmacsThread (EmacsService service)
+ EmacsThread (EmacsService service, boolean startDashQ)
{
- context = service;
+ this.startDashQ = startDashQ;
}
public void
@@ -36,7 +37,10 @@ public class EmacsThread extends Thread
{
String args[];
- args = new String[] { "libandroid-emacs.so", };
+ if (!startDashQ)
+ args = new String[] { "libandroid-emacs.so", };
+ else
+ args = new String[] { "libandroid-emacs.so", "-Q", };
/* Run the native code now. */
EmacsNative.initEmacs (args);
diff --git a/java/org/gnu/emacs/EmacsView.java b/java/org/gnu/emacs/EmacsView.java
index 82f44acaebe..74bbb7b3ecc 100644
--- a/java/org/gnu/emacs/EmacsView.java
+++ b/java/org/gnu/emacs/EmacsView.java
@@ -19,6 +19,7 @@ along with GNU Emacs. If not, see . */
package org.gnu.emacs;
+import android.content.Context;
import android.content.res.ColorStateList;
import android.view.ContextMenu;
@@ -27,6 +28,8 @@ import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.ViewGroup;
+import android.view.inputmethod.InputMethodManager;
+
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;
@@ -86,11 +89,23 @@ public class EmacsView extends ViewGroup
/* The serial of the last clip rectangle change. */
private long lastClipSerial;
+ /* The InputMethodManager for this view's context. */
+ private InputMethodManager imManager;
+
+ /* Runnable that will run once drawing completes. */
+ public Runnable drawingFinished;
+
+ /* Serial of the last ConfigureNotify event sent that Emacs has not
+ yet responded to. 0 if there is no such outstanding event. */
+ public long pendingConfigure;
+
public
EmacsView (EmacsWindow window)
{
super (EmacsService.SERVICE);
+ Object tem;
+
this.window = window;
this.damageRegion = new Region ();
this.paint = new Paint ();
@@ -111,6 +126,10 @@ public class EmacsView extends ViewGroup
/* Get rid of the default focus highlight. */
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O)
setDefaultFocusHighlightEnabled (false);
+
+ /* Obtain the input method manager. */
+ tem = getContext ().getSystemService (Context.INPUT_METHOD_SERVICE);
+ imManager = (InputMethodManager) tem;
}
private void
@@ -259,7 +278,8 @@ public class EmacsView extends ViewGroup
if (changed || mustReportLayout)
{
mustReportLayout = false;
- window.viewLayout (left, top, right, bottom);
+ pendingConfigure
+ = window.viewLayout (left, top, right, bottom);
}
measuredWidth = right - left;
@@ -538,4 +558,37 @@ public class EmacsView extends ViewGroup
Runtime.getRuntime ().gc ();
}
}
+
+ public void
+ showOnScreenKeyboard ()
+ {
+ /* Specifying no flags at all tells the system the user asked for
+ the input method to be displayed. */
+ imManager.showSoftInput (this, 0);
+ }
+
+ public void
+ hideOnScreenKeyboard ()
+ {
+ imManager.hideSoftInputFromWindow (this.getWindowToken (),
+ 0);
+ }
+
+ public void
+ windowUpdated (long serial)
+ {
+ Log.d (TAG, "windowUpdated: serial is " + serial);
+
+ if (pendingConfigure <= serial
+ /* Detect wraparound. */
+ || pendingConfigure - serial >= 0x7fffffff)
+ {
+ pendingConfigure = 0;
+
+ if (drawingFinished != null)
+ drawingFinished.run ();
+
+ drawingFinished = null;
+ }
+ }
};
diff --git a/java/org/gnu/emacs/EmacsWindow.java b/java/org/gnu/emacs/EmacsWindow.java
index c5b1522086c..8511af9193e 100644
--- a/java/org/gnu/emacs/EmacsWindow.java
+++ b/java/org/gnu/emacs/EmacsWindow.java
@@ -233,7 +233,7 @@ public class EmacsWindow extends EmacsHandleObject
return attached;
}
- public void
+ public long
viewLayout (int left, int top, int right, int bottom)
{
int rectWidth, rectHeight;
@@ -249,10 +249,10 @@ public class EmacsWindow extends EmacsHandleObject
rectWidth = right - left;
rectHeight = bottom - top;
- EmacsNative.sendConfigureNotify (this.handle,
- System.currentTimeMillis (),
- left, top, rectWidth,
- rectHeight);
+ return EmacsNative.sendConfigureNotify (this.handle,
+ System.currentTimeMillis (),
+ left, top, rectWidth,
+ rectHeight);
}
public void
@@ -589,11 +589,20 @@ public class EmacsWindow extends EmacsHandleObject
EmacsActivity.invalidateFocus ();
}
+ /* Notice that the activity has been detached or destroyed.
+
+ ISFINISHING is set if the activity is not the main activity, or
+ if the activity was not destroyed in response to explicit user
+ action. */
+
public void
- onActivityDetached ()
+ onActivityDetached (boolean isFinishing)
{
- /* Destroy the associated frame when the activity is detached. */
- EmacsNative.sendWindowAction (this.handle, 0);
+ /* Destroy the associated frame when the activity is detached in
+ response to explicit user action. */
+
+ if (isFinishing)
+ EmacsNative.sendWindowAction (this.handle, 0);
}
/* Look through the button state to determine what button EVENT was
@@ -1064,4 +1073,37 @@ public class EmacsWindow extends EmacsHandleObject
/* Return the resulting coordinates. */
return array;
}
+
+ public void
+ toggleOnScreenKeyboard (final boolean on)
+ {
+ EmacsService.SERVICE.runOnUiThread (new Runnable () {
+ @Override
+ public void
+ run ()
+ {
+ if (on)
+ view.showOnScreenKeyboard ();
+ else
+ view.hideOnScreenKeyboard ();
+ }
+ });
+ }
+
+ /* Notice that outstanding configure events have been processed.
+ SERIAL is checked in the UI thread to verify that no new
+ configure events have been generated in the mean time. */
+
+ public void
+ windowUpdated (final long serial)
+ {
+ EmacsService.SERVICE.runOnUiThread (new Runnable () {
+ @Override
+ public void
+ run ()
+ {
+ view.windowUpdated (serial);
+ }
+ });
+ }
};
diff --git a/java/org/gnu/emacs/EmacsWindowAttachmentManager.java b/java/org/gnu/emacs/EmacsWindowAttachmentManager.java
index 15eb3bb65c2..510300571b8 100644
--- a/java/org/gnu/emacs/EmacsWindowAttachmentManager.java
+++ b/java/org/gnu/emacs/EmacsWindowAttachmentManager.java
@@ -134,7 +134,7 @@ public class EmacsWindowAttachmentManager
}
public void
- removeWindowConsumer (WindowConsumer consumer)
+ removeWindowConsumer (WindowConsumer consumer, boolean isFinishing)
{
EmacsWindow window;
@@ -147,7 +147,7 @@ public class EmacsWindowAttachmentManager
Log.d (TAG, "removeWindowConsumer: detaching " + window);
consumer.detachWindow ();
- window.onActivityDetached ();
+ window.onActivityDetached (isFinishing);
}
Log.d (TAG, "removeWindowConsumer: removing " + consumer);
--
cgit v1.2.1