From 5b4dea0fc781fe40548e7b58fe5bd201a05f3913 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Tue, 6 Jun 2023 14:35:19 +0800 Subject: Update Android port * java/org/gnu/emacs/EmacsContextMenu.java (display): Use `EmacsHolder' instead of `Holder'. * java/org/gnu/emacs/EmacsDialog.java (toAlertDialog): Use `EmacsDialogButtonLayout' to ensure that buttons are wrapped properly. (display): Adjust for new holder class. * java/org/gnu/emacs/EmacsDialogButtonLayout.java (EmacsDialogButtonLayout, onMeasure, onLayout): New functions. * java/org/gnu/emacs/EmacsDrawLine.java: * java/org/gnu/emacs/EmacsFillPolygon.java: Remove redundant imports. * java/org/gnu/emacs/EmacsHolder.java (EmacsHolder): * java/org/gnu/emacs/EmacsService.java (class Holder) (getEmacsView, EmacsService): Rename `Holder' to `EmacsHolder' and make it public. --- java/org/gnu/emacs/EmacsDialogButtonLayout.java | 152 ++++++++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 java/org/gnu/emacs/EmacsDialogButtonLayout.java (limited to 'java/org/gnu/emacs/EmacsDialogButtonLayout.java') diff --git a/java/org/gnu/emacs/EmacsDialogButtonLayout.java b/java/org/gnu/emacs/EmacsDialogButtonLayout.java new file mode 100644 index 00000000000..5d97eea32aa --- /dev/null +++ b/java/org/gnu/emacs/EmacsDialogButtonLayout.java @@ -0,0 +1,152 @@ +/* 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.content.Context; + +import android.view.View; +import android.view.View.MeasureSpec; +import android.view.ViewGroup; + + + +/* This ``view group'' implements a container widget for multiple + buttons of the type found in pop-up dialogs. It is used when + displaying a dialog box that contains more than three buttons, as + the default dialog box widget is not capable of holding more than + that many. */ + + + +public class EmacsDialogButtonLayout extends ViewGroup +{ + public + EmacsDialogButtonLayout (Context context) + { + super (context); + } + + @Override + protected void + onMeasure (int widthMeasureSpec, int heightMeasureSpec) + { + int width, count, i, x, y, height, spec, tempSpec; + View view; + + /* Obtain the width of this widget and create the measure + specification used to measure children. */ + + width = MeasureSpec.getSize (widthMeasureSpec); + spec = MeasureSpec.makeMeasureSpec (0, MeasureSpec.UNSPECIFIED); + tempSpec + = MeasureSpec.makeMeasureSpec (width, MeasureSpec.AT_MOST); + x = y = height = 0; + + /* Run through each widget. */ + + count = getChildCount (); + + for (i = 0; i < count; ++i) + { + view = getChildAt (i); + + /* Measure this view. */ + view.measure (spec, spec); + + if (width - x < view.getMeasuredWidth ()) + { + /* Move onto the next line, unless this line is empty. */ + + if (x != 0) + { + y += height; + height = x = 0; + } + + if (view.getMeasuredWidth () > width) + /* Measure the view again, this time forcing it to be at + most width wide, if it is not already. */ + view.measure (tempSpec, spec); + } + + height = Math.max (height, view.getMeasuredHeight ()); + x += view.getMeasuredWidth (); + } + + /* Now set the measured size of this widget. */ + setMeasuredDimension (width, y + height); + } + + @Override + protected void + onLayout (boolean changed, int left, int top, int right, + int bottom) + { + int width, count, i, x, y, height, spec, tempSpec; + View view; + + /* Obtain the width of this widget and create the measure + specification used to measure children. */ + + width = getMeasuredWidth (); + spec = MeasureSpec.makeMeasureSpec (0, MeasureSpec.UNSPECIFIED); + tempSpec + = MeasureSpec.makeMeasureSpec (width, MeasureSpec.AT_MOST); + x = y = height = 0; + + /* Run through each widget. */ + + count = getChildCount (); + + for (i = 0; i < count; ++i) + { + view = getChildAt (i); + + /* Measure this view. */ + view.measure (spec, spec); + + if (width - x < view.getMeasuredWidth ()) + { + /* Move onto the next line, unless this line is empty. */ + + if (x != 0) + { + y += height; + height = x = 0; + } + + if (view.getMeasuredWidth () > width) + /* Measure the view again, this time forcing it to be at + most width wide, if it is not already. */ + view.measure (tempSpec, spec); + } + + /* Now assign this view its position. */ + view.layout (x, y, x + view.getMeasuredWidth (), + y + view.getMeasuredHeight ()); + + /* And move on to the next widget. */ + height = Math.max (height, view.getMeasuredHeight ()); + x += view.getMeasuredWidth (); + } + } +}; -- cgit v1.3 From 1661762784520eb6834aa9831dcb646396efde73 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Thu, 8 Jun 2023 20:50:02 +0800 Subject: Correctly display popup dialogs from Emacsclient * java/org/gnu/emacs/EmacsContextMenu.java (EmacsContextMenu): Make subclasses final. * java/org/gnu/emacs/EmacsDialog.java (display1): Check if an instance of EmacsOpenActivity is open; if it is, try using it to display the pop up dialog. * java/org/gnu/emacs/EmacsDialogButtonLayout.java (EmacsDialogButtonLayout): Make final. * java/org/gnu/emacs/EmacsHolder.java (EmacsHolder): Likewise. * java/org/gnu/emacs/EmacsOpenActivity.java (EmacsOpenActivity): New field `currentActivity'. (onCreate, onDestroy, onWindowFocusChanged, onPause): Set that field as appropriate. --- java/org/gnu/emacs/EmacsContextMenu.java | 2 +- java/org/gnu/emacs/EmacsDialog.java | 17 ++++-- java/org/gnu/emacs/EmacsDialogButtonLayout.java | 2 +- java/org/gnu/emacs/EmacsHolder.java | 2 +- java/org/gnu/emacs/EmacsOpenActivity.java | 70 ++++++++++++++++++++++++- 5 files changed, 85 insertions(+), 8 deletions(-) (limited to 'java/org/gnu/emacs/EmacsDialogButtonLayout.java') diff --git a/java/org/gnu/emacs/EmacsContextMenu.java b/java/org/gnu/emacs/EmacsContextMenu.java index 60f2db67fb0..d69d0263b93 100644 --- a/java/org/gnu/emacs/EmacsContextMenu.java +++ b/java/org/gnu/emacs/EmacsContextMenu.java @@ -58,7 +58,7 @@ public final class EmacsContextMenu /* The last group ID used for a menu item. */ public int lastGroupId; - private static class Item implements MenuItem.OnMenuItemClickListener + private static final class Item implements MenuItem.OnMenuItemClickListener { public int itemID; public String itemName, tooltip; diff --git a/java/org/gnu/emacs/EmacsDialog.java b/java/org/gnu/emacs/EmacsDialog.java index afdce3c50ec..3f8fe0109c0 100644 --- a/java/org/gnu/emacs/EmacsDialog.java +++ b/java/org/gnu/emacs/EmacsDialog.java @@ -68,8 +68,8 @@ public final class EmacsDialog implements DialogInterface.OnDismissListener /* The menu serial associated with this dialog box. */ private int menuEventSerial; - private class EmacsButton implements View.OnClickListener, - DialogInterface.OnClickListener + private final class EmacsButton implements View.OnClickListener, + DialogInterface.OnClickListener { /* Name of this button. */ public String name; @@ -244,13 +244,22 @@ public final class EmacsDialog implements DialogInterface.OnDismissListener if (EmacsActivity.focusedActivities.isEmpty ()) { /* If focusedActivities is empty then this dialog may have - been displayed immediately after a popup dialog is + been displayed immediately after another popup dialog was dismissed. Or Emacs might legitimately be in the - background. Try the service context first if possible. */ + background, possibly displaying this popup in response to + an Emacsclient request. Try the service context if it will + 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; + else if (EmacsOpenActivity.currentActivity != null) + context = EmacsOpenActivity.currentActivity; else context = EmacsActivity.lastFocusedActivity; diff --git a/java/org/gnu/emacs/EmacsDialogButtonLayout.java b/java/org/gnu/emacs/EmacsDialogButtonLayout.java index 5d97eea32aa..fd8d63d81d3 100644 --- a/java/org/gnu/emacs/EmacsDialogButtonLayout.java +++ b/java/org/gnu/emacs/EmacsDialogButtonLayout.java @@ -37,7 +37,7 @@ import android.view.ViewGroup; -public class EmacsDialogButtonLayout extends ViewGroup +public final class EmacsDialogButtonLayout extends ViewGroup { public EmacsDialogButtonLayout (Context context) diff --git a/java/org/gnu/emacs/EmacsHolder.java b/java/org/gnu/emacs/EmacsHolder.java index 3ca803d1640..6cd48ba57ce 100644 --- a/java/org/gnu/emacs/EmacsHolder.java +++ b/java/org/gnu/emacs/EmacsHolder.java @@ -24,7 +24,7 @@ package org.gnu.emacs; /* This class serves as a simple reference to an object of type T. Nothing could be found inside the standard library. */ -public class EmacsHolder +public final class EmacsHolder { T thing; }; diff --git a/java/org/gnu/emacs/EmacsOpenActivity.java b/java/org/gnu/emacs/EmacsOpenActivity.java index f402e25c7fb..6af2b2d2e94 100644 --- a/java/org/gnu/emacs/EmacsOpenActivity.java +++ b/java/org/gnu/emacs/EmacsOpenActivity.java @@ -72,8 +72,17 @@ public final class EmacsOpenActivity extends Activity DialogInterface.OnCancelListener { private static final String TAG = "EmacsOpenActivity"; + + /* The name of any file that should be opened as EmacsThread starts + Emacs. This is never cleared, even if EmacsOpenActivity is + started a second time, as EmacsThread only starts once. */ public static String fileToOpen; + /* Any currently focused EmacsOpenActivity. Used to show pop ups + while the activity is active and Emacs doesn't have permission to + display over other programs. */ + public static EmacsOpenActivity currentActivity; + private class EmacsClientThread extends Thread { private ProcessBuilder builder; @@ -362,6 +371,15 @@ public final class EmacsOpenActivity extends Activity thread.start (); } + /* Run emacsclient to open the file specified in the Intent that + caused this activity to start. + + Determine the name of the file corresponding to the URI specified + in that intent; then, run emacsclient and wait for it to finish. + + Finally, display any error message, transfer the focus to an + Emacs frame, and finish the activity. */ + @Override public void onCreate (Bundle savedInstanceState) @@ -463,10 +481,60 @@ public final class EmacsOpenActivity extends Activity } } - /* And start emacsclient. */ + /* And start emacsclient. Set `currentActivity' to this now. + Presumably, it will shortly become capable of displaying + dialogs. */ + currentActivity = this; startEmacsClient (fileName); } else finish (); } + + + + @Override + public void + onDestroy () + { + Log.d (TAG, "onDestroy: " + this); + + /* Clear `currentActivity' if it refers to the activity being + destroyed. */ + + if (currentActivity == this) + this.currentActivity = null; + + super.onDestroy (); + } + + @Override + public void + onWindowFocusChanged (boolean isFocused) + { + Log.d (TAG, "onWindowFocusChanged: " + this + ", is now focused: " + + isFocused); + + if (isFocused) + currentActivity = this; + else if (currentActivity == this) + currentActivity = null; + + super.onWindowFocusChanged (isFocused); + } + + @Override + 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. */ + + if (currentActivity == this) + currentActivity = null; + + super.onPause (); + } } -- cgit v1.3