diff --git a/java/org/gnu/emacs/EmacsContextMenu.java b/java/org/gnu/emacs/EmacsContextMenu.java index 2652f35b545..b6c63c3cbe1 100644 --- a/java/org/gnu/emacs/EmacsContextMenu.java +++ b/java/org/gnu/emacs/EmacsContextMenu.java @@ -22,6 +22,9 @@ package org.gnu.emacs; import java.util.List; import java.util.ArrayList; +import java.util.concurrent.Callable; +import java.util.concurrent.FutureTask; + import android.content.Context; import android.content.Intent; @@ -344,8 +347,7 @@ public final class EmacsContextMenu display (final EmacsWindow window, final int xPosition, final int yPosition, final int serial) { - Runnable runnable; - final EmacsHolder rc; + FutureTask task; /* Android will permanently cease to display any popup menus at all if the list of menu items is empty. Prevent this by @@ -354,25 +356,17 @@ public final class EmacsContextMenu if (menuItems.isEmpty ()) return false; - rc = new EmacsHolder (); - rc.thing = false; - - runnable = new Runnable () { + task = new FutureTask (new Callable () { @Override - public void - run () + public Boolean + call () { - synchronized (this) - { - lastMenuEventSerial = serial; - rc.thing = display1 (window, xPosition, yPosition); - notify (); - } + lastMenuEventSerial = serial; + return display1 (window, xPosition, yPosition); } - }; + }); - EmacsService.syncRunnable (runnable); - return rc.thing; + return EmacsService.syncRunnable (task); } /* Dismiss this context menu. WINDOW is the window where the diff --git a/java/org/gnu/emacs/EmacsDialog.java b/java/org/gnu/emacs/EmacsDialog.java index bad1ddde227..7552b16b370 100644 --- a/java/org/gnu/emacs/EmacsDialog.java +++ b/java/org/gnu/emacs/EmacsDialog.java @@ -22,6 +22,9 @@ package org.gnu.emacs; import java.util.List; import java.util.ArrayList; +import java.util.concurrent.Callable; +import java.util.concurrent.FutureTask; + import android.app.AlertDialog; import android.content.Context; @@ -388,26 +391,18 @@ public final class EmacsDialog implements DialogInterface.OnDismissListener public boolean display () { - Runnable runnable; - final EmacsHolder rc; + FutureTask task; - rc = new EmacsHolder (); - rc.thing = false; - runnable = new Runnable () { + task = new FutureTask (new Callable () { @Override - public void - run () + public Boolean + call () { - synchronized (this) - { - rc.thing = display1 (); - notify (); - } + return display1 (); } - }; + }); - EmacsService.syncRunnable (runnable); - return rc.thing; + return EmacsService.syncRunnable (task); } diff --git a/java/org/gnu/emacs/EmacsService.java b/java/org/gnu/emacs/EmacsService.java index c71670b3e47..7934d6f9cd3 100644 --- a/java/org/gnu/emacs/EmacsService.java +++ b/java/org/gnu/emacs/EmacsService.java @@ -27,6 +27,10 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.FutureTask; + import java.util.concurrent.atomic.AtomicInteger; import android.database.Cursor; @@ -331,52 +335,45 @@ public final class EmacsService extends Service final boolean isFocusedByDefault) { Runnable runnable; - final EmacsHolder view; + FutureTask task; - view = new EmacsHolder (); - - runnable = new Runnable () { + task = new FutureTask (new Callable () { @Override - public void - run () + public EmacsView + call () { - synchronized (this) - { - view.thing = new EmacsView (window); - view.thing.setVisibility (visibility); + EmacsView view; - /* The following function is only present on Android 26 - or later. */ - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) - view.thing.setFocusedByDefault (isFocusedByDefault); + view = new EmacsView (window); + view.setVisibility (visibility); - notify (); - } + /* The following function is only present on Android 26 + or later. */ + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) + view.setFocusedByDefault (isFocusedByDefault); + + return view; } - }; + }); - syncRunnable (runnable); - return view.thing; + return EmacsService.syncRunnable (task); } public void getLocationOnScreen (final EmacsView view, final int[] coordinates) { - Runnable runnable; + FutureTask task; - runnable = new Runnable () { - public void - run () + task = new FutureTask (new Callable () { + public Void + call () { - synchronized (this) - { - view.getLocationOnScreen (coordinates); - notify (); - } + view.getLocationOnScreen (coordinates); + return null; } - }; + }); - syncRunnable (runnable); + EmacsService.syncRunnable (task); } @@ -702,28 +699,17 @@ public final class EmacsService extends Service public ClipboardManager getClipboardManager () { - final EmacsHolder manager; - Runnable runnable; + FutureTask task; - manager = new EmacsHolder (); - - runnable = new Runnable () { - public void - run () + task = new FutureTask (new Callable () { + public Object + call () { - Object tem; - - synchronized (this) - { - tem = getSystemService (Context.CLIPBOARD_SERVICE); - manager.thing = (ClipboardManager) tem; - notify (); - } + return getSystemService (Context.CLIPBOARD_SERVICE); } - }; + }); - syncRunnable (runnable); - return manager.thing; + return (ClipboardManager) EmacsService.syncRunnable (task); } public void @@ -738,33 +724,37 @@ public final class EmacsService extends Service System.exit (0); } - /* Wait synchronously for the specified RUNNABLE to complete in the - UI thread. Must be called from the Emacs thread. */ + /* Wait synchronously for the specified TASK to complete in the UI + thread, then return its result. Must be called from the Emacs + thread. */ - public static void - syncRunnable (Runnable runnable) + public static V + syncRunnable (FutureTask task) { + V object; + EmacsNative.beginSynchronous (); + SERVICE.runOnUiThread (task); - synchronized (runnable) + try { - SERVICE.runOnUiThread (runnable); - - while (true) - { - try - { - runnable.wait (); - break; - } - catch (InterruptedException e) - { - continue; - } - } + object = task.get (); + } + catch (ExecutionException exception) + { + /* Wrap this exception in a RuntimeException and signal it to + the caller. */ + throw new RuntimeException (exception.getCause ()); + } + catch (InterruptedException exception) + { + EmacsNative.emacsAbort (); + object = null; } EmacsNative.endSynchronous (); + + return object; } @@ -1283,71 +1273,61 @@ public final class EmacsService extends Service public int requestDirectoryAccess () { - Runnable runnable; - final EmacsHolder rc; + FutureTask task; /* Return 1 if Android is too old to support this feature. */ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) return 1; - rc = new EmacsHolder (); - rc.thing = Integer.valueOf (1); - - runnable = new Runnable () { + task = new FutureTask (new Callable () { @Override - public void - run () + public Integer + call () { EmacsActivity activity; Intent intent; - int id; + int id, rc; - synchronized (this) + /* Try to obtain an activity that will receive the response + from the file chooser dialog. */ + + if (EmacsActivity.focusedActivities.isEmpty ()) { - /* Try to obtain an activity that will receive the - response from the file chooser dialog. */ + /* If focusedActivities is empty then this dialog may + have been displayed immediately after another popup + dialog was dismissed. Try the EmacsActivity to be + focused. */ - if (EmacsActivity.focusedActivities.isEmpty ()) - { - /* If focusedActivities is empty then this dialog - may have been displayed immediately after another - popup dialog was dismissed. Try the - EmacsActivity to be focused. */ + activity = EmacsActivity.lastFocusedActivity; - activity = EmacsActivity.lastFocusedActivity; - - if (activity == null) - { - /* Still no luck. Return failure. */ - notify (); - return; - } - } - else - activity = EmacsActivity.focusedActivities.get (0); - - /* Now create the intent. */ - intent = new Intent (Intent.ACTION_OPEN_DOCUMENT_TREE); - - try - { - id = EmacsActivity.ACCEPT_DOCUMENT_TREE; - activity.startActivityForResult (intent, id, null); - rc.thing = Integer.valueOf (0); - } - catch (Exception e) - { - e.printStackTrace (); - } - - notify (); + if (activity == null) + /* Still no luck. Return failure. */ + return 1; } - } - }; + else + activity = EmacsActivity.focusedActivities.get (0); - syncRunnable (runnable); - return rc.thing; + /* Now create the intent. */ + intent = new Intent (Intent.ACTION_OPEN_DOCUMENT_TREE); + rc = 1; + + try + { + id = EmacsActivity.ACCEPT_DOCUMENT_TREE; + activity.startActivityForResult (intent, id, null); + rc = 0; + } + catch (Exception e) + { + e.printStackTrace (); + } + + return rc; + } + }); + + return EmacsService.syncRunnable (task); } /* Return an array of each tree provided by the document PROVIDER @@ -1969,7 +1949,7 @@ public final class EmacsService extends Service /* Now request these permissions. */ activity.requestPermissions (new String[] { permission, permission1, }, - 0); + 0); } };