Update Android port

* java/org/gnu/emacs/EmacsActivity.java (attachWindow, onDestroy)
(onWindowFocusChanged, onContextMenuClosed):

* java/org/gnu/emacs/EmacsContextMenu.java (onMenuItemClick):

* java/org/gnu/emacs/EmacsDialog.java (onClick, display1, onDismiss):

* java/org/gnu/emacs/EmacsOpenActivity.java (checkReadableOrCopy)
(onDestroy, onWindowFocusChanged, onPause):

* java/org/gnu/emacs/EmacsWindowAttachmentManager.java
(registerWindow, removeWindowConsumer, detachWindow)
(noticeIconified, noticeDeiconified): Remove superfluous
debugging code now that the Android port is stable.

* java/org/gnu/emacs/EmacsView.java (onLayout): Detect if the
IME is hidden while a toplevel window is focused, and clear
isCurrentlyTextEditor in that case.
(onApplyWindowInsets): New function.
(raise, lower, popupMenu, onCreateInputConnection): Delete
aforementioned debugging code.
This commit is contained in:
Po Lu 2023-08-28 13:08:22 +08:00
parent 967fa846fc
commit 2134fd9f27
6 changed files with 79 additions and 76 deletions

View file

@ -149,8 +149,6 @@ public class EmacsActivity extends Activity
public final void
attachWindow (EmacsWindow child)
{
Log.d (TAG, "attachWindow: " + child);
if (window != null)
throw new IllegalStateException ("trying to attach window when one"
+ " already exists");
@ -257,7 +255,6 @@ public class EmacsActivity extends Activity
/* The activity will die shortly hereafter. If there is a window
attached, close it now. */
Log.d (TAG, "onDestroy " + this);
isMultitask = this instanceof EmacsMultitaskActivity;
manager.removeWindowConsumer (this, isMultitask || isFinishing ());
focusedActivities.remove (this);
@ -274,9 +271,6 @@ public class EmacsActivity extends Activity
public final void
onWindowFocusChanged (boolean isFocused)
{
Log.d (TAG, ("onWindowFocusChanged: "
+ (isFocused ? "YES" : "NO")));
if (isFocused && !focusedActivities.contains (this))
{
focusedActivities.add (this);
@ -323,8 +317,6 @@ public class EmacsActivity extends Activity
{
int serial;
Log.d (TAG, "onContextMenuClosed: " + menu);
/* See the comment inside onMenuItemClick. */
if (((EmacsContextMenu.wasSubmenuSelected == -2)

View file

@ -72,8 +72,6 @@ private static final class Item implements MenuItem.OnMenuItemClickListener
public boolean
onMenuItemClick (MenuItem item)
{
Log.d (TAG, "onMenuItemClick: " + itemName + " (" + itemID + ")");
if (subMenu != null)
{
/* Android 6.0 and earlier don't support nested submenus
@ -81,8 +79,6 @@ private static final class Item implements MenuItem.OnMenuItemClickListener
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N)
{
Log.d (TAG, "onMenuItemClick: displaying submenu " + subMenu);
/* Still set wasSubmenuSelected -- if not set, the
dismissal of this context menu will result in a
context menu event being sent. */

View file

@ -88,8 +88,6 @@ private final class EmacsButton implements View.OnClickListener,
public void
onClick (View view)
{
Log.d (TAG, "onClicked " + this);
wasButtonClicked = true;
EmacsNative.sendContextMenu ((short) 0, id, menuEventSerial);
dismissDialog.dismiss ();
@ -99,8 +97,6 @@ private final class EmacsButton implements View.OnClickListener,
public void
onClick (DialogInterface dialog, int which)
{
Log.d (TAG, "onClicked " + this);
wasButtonClicked = true;
EmacsNative.sendContextMenu ((short) 0, id, menuEventSerial);
}
@ -300,10 +296,6 @@ private final class EmacsButton implements View.OnClickListener,
work, then any focused EmacsOpenActivity, and finally the
last EmacsActivity to be focused. */
Log.d (TAG, "display1: no focused activities...");
Log.d (TAG, ("display1: EmacsOpenActivity.currentActivity: "
+ EmacsOpenActivity.currentActivity));
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M
|| Settings.canDrawOverlays (EmacsService.SERVICE))
context = EmacsService.SERVICE;
@ -321,8 +313,6 @@ else if (EmacsOpenActivity.currentActivity != null)
consistently. */
context = EmacsActivity.focusedActivities.get (0);
Log.d (TAG, "display1: using context " + context);
dialog = dismissDialog = toAlertDialog (context);
try
@ -418,8 +408,6 @@ else if (EmacsOpenActivity.currentActivity != null)
public void
onDismiss (DialogInterface dialog)
{
Log.d (TAG, "onDismiss: " + this);
if (wasButtonClicked)
return;

View file

@ -232,19 +232,14 @@ private class EmacsClientThread extends Thread
int read;
String content;
Log.d (TAG, "checkReadableOrCopy: " + file);
inFile = new File (file);
if (inFile.canRead ())
return file;
Log.d (TAG, "checkReadableOrCopy: NO");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
{
content = EmacsService.buildContentName (uri);
Log.d (TAG, "checkReadableOrCopy: " + content);
return content;
}
@ -509,8 +504,6 @@ private class EmacsClientThread extends Thread
public void
onDestroy ()
{
Log.d (TAG, "onDestroy: " + this);
/* Clear `currentActivity' if it refers to the activity being
destroyed. */
@ -524,9 +517,6 @@ private class EmacsClientThread extends Thread
public void
onWindowFocusChanged (boolean isFocused)
{
Log.d (TAG, "onWindowFocusChanged: " + this + ", is now focused: "
+ isFocused);
if (isFocused)
currentActivity = this;
else if (currentActivity == this)
@ -539,8 +529,6 @@ else if (currentActivity == this)
public void
onPause ()
{
Log.d (TAG, "onPause: " + this);
/* XXX: clear currentActivity here as well; I don't know whether
or not onWindowFocusChanged is always called prior to this. */

View file

@ -29,6 +29,7 @@
import android.view.MotionEvent;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.WindowInsets;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
@ -302,6 +303,26 @@ else if (MeasureSpec.getMode (heightMeasureSpec) == MeasureSpec.AT_MOST
super.setMeasuredDimension (width, height);
}
/* Return whether this view's window is focused. This is made
necessary by Android 11's unreliable dispatch of
onWindowFocusChanged prior to gesture navigation away from a
frame. */
public boolean
checkWindowFocus ()
{
EmacsActivity activity;
Object consumer;
consumer = window.getAttachedConsumer ();
if (!(consumer instanceof EmacsActivity))
return false;
activity = (EmacsActivity) consumer;
return activity.hasWindowFocus ();
}
/* Note that the monitor lock for the window must never be held from
within the lock for the view, because the window also locks the
other way around. */
@ -315,6 +336,7 @@ else if (MeasureSpec.getMode (heightMeasureSpec) == MeasureSpec.AT_MOST
View child;
Rect windowRect;
boolean needExpose;
WindowInsets rootWindowInsets;
count = getChildCount ();
needExpose = false;
@ -349,14 +371,37 @@ else if (MeasureSpec.getMode (heightMeasureSpec) == MeasureSpec.AT_MOST
if (right - left > oldMeasuredWidth
|| bottom - top > oldMeasuredHeight)
needExpose = true;
/* This might return NULL if this view is not attached. */
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
{
/* If a toplevel view is focused and isCurrentlyTextEditor
is enabled when the IME is hidden, clear
isCurrentlyTextEditor so it isn't shown again if the
user dismisses Emacs before returning. */
rootWindowInsets = getRootWindowInsets ();
if (isCurrentlyTextEditor
&& rootWindowInsets != null
&& isAttachedToWindow
&& !rootWindowInsets.isVisible (WindowInsets.Type.ime ())
/* N.B. that the keyboard is dismissed during gesture
navigation under Android 30, but the system is
quite tempermental regarding whether the window is
focused at that point. Ideally
isCurrentlyTextEditor shouldn't be reset in that
case, but detecting that situation appears to be
impossible. Sigh. */
&& (window == EmacsActivity.focusedWindow
&& hasWindowFocus ()))
isCurrentlyTextEditor = false;
}
}
for (i = 0; i < count; ++i)
{
child = getChildAt (i);
Log.d (TAG, "onLayout: " + child);
if (child == surfaceView)
child.layout (0, 0, right - left, bottom - top);
else if (child.getVisibility () != GONE)
@ -491,6 +536,8 @@ else if (child.getVisibility () != GONE)
return window.onTouchEvent (motion);
}
private void
moveChildToBack (View child)
{
@ -518,8 +565,6 @@ else if (child.getVisibility () != GONE)
parent = (EmacsView) getParent ();
Log.d (TAG, "raise: parent " + parent);
if (parent.indexOfChild (this)
== parent.getChildCount () - 1)
return;
@ -534,8 +579,6 @@ else if (child.getVisibility () != GONE)
parent = (EmacsView) getParent ();
Log.d (TAG, "lower: parent " + parent);
if (parent.indexOfChild (this) == 1)
return;
@ -562,9 +605,6 @@ else if (child.getVisibility () != GONE)
contextMenu = menu;
popupActive = true;
Log.d (TAG, "popupMenu: " + menu + " @" + xPosition
+ ", " + yPosition + " " + force);
/* Use showContextMenu (float, float) on N to get actual popup
behavior. */
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
@ -700,14 +740,8 @@ else if (child.getVisibility () != GONE)
selection = EmacsService.viewGetSelection (window.handle);
if (selection != null)
Log.d (TAG, "onCreateInputConnection: current selection is: "
+ selection[0] + ", by " + selection[1]);
else
if (selection == null)
{
Log.d (TAG, "onCreateInputConnection: current selection could"
+ " not be retrieved.");
/* If the selection could not be obtained, return 0 by 0.
However, ask for the selection position to be updated as
soon as possible. */
@ -780,4 +814,33 @@ else if (child.getVisibility () != GONE)
window.notifyContentRectPosition (locations[0],
locations[1]);
}
@Override
public WindowInsets
onApplyWindowInsets (WindowInsets insets)
{
WindowInsets rootWindowInsets;
/* This function is called when window insets change, which
encompasses input method visibility changes under Android 30
and later. If a toplevel view is focused and
isCurrentlyTextEditor is enabled when the IME is hidden, clear
isCurrentlyTextEditor so it isn't shown again if the user
dismisses Emacs before returning. */
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R)
return super.onApplyWindowInsets (insets);
/* This might return NULL if this view is not attached. */
rootWindowInsets = getRootWindowInsets ();
if (isCurrentlyTextEditor
&& rootWindowInsets != null
&& isAttachedToWindow
&& !rootWindowInsets.isVisible (WindowInsets.Type.ime ())
&& window == EmacsActivity.focusedWindow)
isCurrentlyTextEditor = false;
return super.onApplyWindowInsets (insets);
}
};

View file

@ -87,21 +87,17 @@ public interface WindowConsumer
public void
registerWindowConsumer (WindowConsumer consumer)
{
Log.d (TAG, "registerWindowConsumer " + consumer);
consumers.add (consumer);
for (EmacsWindow window : windows)
{
if (window.getAttachedConsumer () == null)
{
Log.d (TAG, "registerWindowConsumer: attaching " + window);
consumer.attachWindow (window);
return;
}
}
Log.d (TAG, "registerWindowConsumer: sendWindowAction 0, 0");
EmacsNative.sendWindowAction ((short) 0, 0);
}
@ -111,21 +107,16 @@ public interface WindowConsumer
Intent intent;
ActivityOptions options;
Log.d (TAG, "registerWindow (maybe): " + window);
if (windows.contains (window))
/* The window is already registered. */
return;
Log.d (TAG, "registerWindow: " + window);
windows.add (window);
for (WindowConsumer consumer : consumers)
{
if (consumer.getAttachedWindow () == null)
{
Log.d (TAG, "registerWindow: attaching " + consumer);
consumer.attachWindow (window);
return;
}
@ -147,8 +138,6 @@ public interface WindowConsumer
EmacsService.SERVICE.startActivity (intent,
options.toBundle ());
}
Log.d (TAG, "registerWindow: startActivity");
}
public void
@ -156,19 +145,14 @@ public interface WindowConsumer
{
EmacsWindow window;
Log.d (TAG, "removeWindowConsumer " + consumer);
window = consumer.getAttachedWindow ();
if (window != null)
{
Log.d (TAG, "removeWindowConsumer: detaching " + window);
consumer.detachWindow ();
window.onActivityDetached (isFinishing);
}
Log.d (TAG, "removeWindowConsumer: removing " + consumer);
consumers.remove (consumer);
}
@ -177,14 +161,10 @@ public interface WindowConsumer
{
WindowConsumer consumer;
Log.d (TAG, "detachWindow " + window);
if (window.getAttachedConsumer () != null)
{
consumer = window.getAttachedConsumer ();
Log.d (TAG, "detachWindow: removing" + consumer);
consumers.remove (consumer);
consumer.destroy ();
}
@ -197,8 +177,6 @@ public interface WindowConsumer
{
EmacsWindow window;
Log.d (TAG, "noticeIconified " + consumer);
/* If a window is attached, send the appropriate iconification
events. */
window = consumer.getAttachedWindow ();
@ -212,8 +190,6 @@ public interface WindowConsumer
{
EmacsWindow window;
Log.d (TAG, "noticeDeiconified " + consumer);
/* If a window is attached, send the appropriate iconification
events. */
window = consumer.getAttachedWindow ();