mirror of
https://git.savannah.gnu.org/git/emacs.git
synced 2025-01-22 18:35:09 +00:00
Simplify code relating to UI thread synchronization
* java/org/gnu/emacs/EmacsContextMenu.java (display): * java/org/gnu/emacs/EmacsDialog.java (display): * java/org/gnu/emacs/EmacsService.java (getEmacsView) (getLocationOnScreen, getClipboardManager) (requestDirectoryAccess): Replace manual synchronization within Runnable objects by usage of FutureTask. (syncRunnable): Accept FutureTask<V> in place of Runnables, and obtain and return results from calls to its get method.
This commit is contained in:
parent
fe2b68d405
commit
94e3d11593
@ -22,6 +22,9 @@
|
||||
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 @@ private static final class Item implements MenuItem.OnMenuItemClickListener
|
||||
display (final EmacsWindow window, final int xPosition,
|
||||
final int yPosition, final int serial)
|
||||
{
|
||||
Runnable runnable;
|
||||
final EmacsHolder<Boolean> rc;
|
||||
FutureTask<Boolean> 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 @@ private static final class Item implements MenuItem.OnMenuItemClickListener
|
||||
if (menuItems.isEmpty ())
|
||||
return false;
|
||||
|
||||
rc = new EmacsHolder<Boolean> ();
|
||||
rc.thing = false;
|
||||
|
||||
runnable = new Runnable () {
|
||||
task = new FutureTask<Boolean> (new Callable<Boolean> () {
|
||||
@Override
|
||||
public void
|
||||
run ()
|
||||
{
|
||||
synchronized (this)
|
||||
public Boolean
|
||||
call ()
|
||||
{
|
||||
lastMenuEventSerial = serial;
|
||||
rc.thing = display1 (window, xPosition, yPosition);
|
||||
notify ();
|
||||
return display1 (window, xPosition, yPosition);
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
EmacsService.syncRunnable (runnable);
|
||||
return rc.thing;
|
||||
return EmacsService.<Boolean>syncRunnable (task);
|
||||
}
|
||||
|
||||
/* Dismiss this context menu. WINDOW is the window where the
|
||||
|
@ -22,6 +22,9 @@
|
||||
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 @@ else if (EmacsOpenActivity.currentActivity != null)
|
||||
public boolean
|
||||
display ()
|
||||
{
|
||||
Runnable runnable;
|
||||
final EmacsHolder<Boolean> rc;
|
||||
FutureTask<Boolean> task;
|
||||
|
||||
rc = new EmacsHolder<Boolean> ();
|
||||
rc.thing = false;
|
||||
runnable = new Runnable () {
|
||||
task = new FutureTask<Boolean> (new Callable<Boolean> () {
|
||||
@Override
|
||||
public void
|
||||
run ()
|
||||
public Boolean
|
||||
call ()
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
rc.thing = display1 ();
|
||||
notify ();
|
||||
return display1 ();
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
EmacsService.syncRunnable (runnable);
|
||||
return rc.thing;
|
||||
return EmacsService.<Boolean>syncRunnable (task);
|
||||
}
|
||||
|
||||
|
||||
|
@ -27,6 +27,10 @@
|
||||
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 @@ invocation of app_process (through android-emacs) can
|
||||
final boolean isFocusedByDefault)
|
||||
{
|
||||
Runnable runnable;
|
||||
final EmacsHolder<EmacsView> view;
|
||||
FutureTask<EmacsView> task;
|
||||
|
||||
view = new EmacsHolder<EmacsView> ();
|
||||
|
||||
runnable = new Runnable () {
|
||||
task = new FutureTask<EmacsView> (new Callable<EmacsView> () {
|
||||
@Override
|
||||
public void
|
||||
run ()
|
||||
public EmacsView
|
||||
call ()
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
view.thing = new EmacsView (window);
|
||||
view.thing.setVisibility (visibility);
|
||||
EmacsView view;
|
||||
|
||||
view = new EmacsView (window);
|
||||
view.setVisibility (visibility);
|
||||
|
||||
/* 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.setFocusedByDefault (isFocusedByDefault);
|
||||
|
||||
notify ();
|
||||
return view;
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
syncRunnable (runnable);
|
||||
return view.thing;
|
||||
return EmacsService.<EmacsView>syncRunnable (task);
|
||||
}
|
||||
|
||||
public void
|
||||
getLocationOnScreen (final EmacsView view, final int[] coordinates)
|
||||
{
|
||||
Runnable runnable;
|
||||
FutureTask<Void> task;
|
||||
|
||||
runnable = new Runnable () {
|
||||
public void
|
||||
run ()
|
||||
{
|
||||
synchronized (this)
|
||||
task = new FutureTask<Void> (new Callable<Void> () {
|
||||
public Void
|
||||
call ()
|
||||
{
|
||||
view.getLocationOnScreen (coordinates);
|
||||
notify ();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
syncRunnable (runnable);
|
||||
EmacsService.<Void>syncRunnable (task);
|
||||
}
|
||||
|
||||
|
||||
@ -702,28 +699,17 @@ invocation of app_process (through android-emacs) can
|
||||
public ClipboardManager
|
||||
getClipboardManager ()
|
||||
{
|
||||
final EmacsHolder<ClipboardManager> manager;
|
||||
Runnable runnable;
|
||||
FutureTask<Object> task;
|
||||
|
||||
manager = new EmacsHolder<ClipboardManager> ();
|
||||
|
||||
runnable = new Runnable () {
|
||||
public void
|
||||
run ()
|
||||
task = new FutureTask<Object> (new Callable<Object> () {
|
||||
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.<Object>syncRunnable (task);
|
||||
}
|
||||
|
||||
public void
|
||||
@ -738,33 +724,37 @@ invocation of app_process (through android-emacs) can
|
||||
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> V
|
||||
syncRunnable (FutureTask<V> task)
|
||||
{
|
||||
V object;
|
||||
|
||||
EmacsNative.beginSynchronous ();
|
||||
SERVICE.runOnUiThread (task);
|
||||
|
||||
synchronized (runnable)
|
||||
{
|
||||
SERVICE.runOnUiThread (runnable);
|
||||
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
runnable.wait ();
|
||||
break;
|
||||
object = task.get ();
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
catch (ExecutionException exception)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
/* 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 @@ else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
|
||||
public int
|
||||
requestDirectoryAccess ()
|
||||
{
|
||||
Runnable runnable;
|
||||
final EmacsHolder<Integer> rc;
|
||||
FutureTask<Integer> 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<Integer> ();
|
||||
rc.thing = Integer.valueOf (1);
|
||||
|
||||
runnable = new Runnable () {
|
||||
task = new FutureTask<Integer> (new Callable<Integer> () {
|
||||
@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. */
|
||||
/* Try to obtain an activity that will receive the response
|
||||
from the file chooser dialog. */
|
||||
|
||||
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. */
|
||||
/* 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;
|
||||
|
||||
if (activity == null)
|
||||
{
|
||||
/* Still no luck. Return failure. */
|
||||
notify ();
|
||||
return;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
activity = EmacsActivity.focusedActivities.get (0);
|
||||
|
||||
/* 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.thing = Integer.valueOf (0);
|
||||
rc = 0;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace ();
|
||||
}
|
||||
|
||||
notify ();
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
syncRunnable (runnable);
|
||||
return rc.thing;
|
||||
return EmacsService.<Integer>syncRunnable (task);
|
||||
}
|
||||
|
||||
/* Return an array of each tree provided by the document PROVIDER
|
||||
|
Loading…
Reference in New Issue
Block a user