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.List;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
import java.util.concurrent.FutureTask;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
|
||||||
@ -344,8 +347,7 @@ private static final class Item implements MenuItem.OnMenuItemClickListener
|
|||||||
display (final EmacsWindow window, final int xPosition,
|
display (final EmacsWindow window, final int xPosition,
|
||||||
final int yPosition, final int serial)
|
final int yPosition, final int serial)
|
||||||
{
|
{
|
||||||
Runnable runnable;
|
FutureTask<Boolean> task;
|
||||||
final EmacsHolder<Boolean> rc;
|
|
||||||
|
|
||||||
/* Android will permanently cease to display any popup menus at
|
/* Android will permanently cease to display any popup menus at
|
||||||
all if the list of menu items is empty. Prevent this by
|
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 ())
|
if (menuItems.isEmpty ())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
rc = new EmacsHolder<Boolean> ();
|
task = new FutureTask<Boolean> (new Callable<Boolean> () {
|
||||||
rc.thing = false;
|
|
||||||
|
|
||||||
runnable = new Runnable () {
|
|
||||||
@Override
|
@Override
|
||||||
public void
|
public Boolean
|
||||||
run ()
|
call ()
|
||||||
{
|
|
||||||
synchronized (this)
|
|
||||||
{
|
{
|
||||||
lastMenuEventSerial = serial;
|
lastMenuEventSerial = serial;
|
||||||
rc.thing = display1 (window, xPosition, yPosition);
|
return display1 (window, xPosition, yPosition);
|
||||||
notify ();
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
};
|
|
||||||
|
|
||||||
EmacsService.syncRunnable (runnable);
|
return EmacsService.<Boolean>syncRunnable (task);
|
||||||
return rc.thing;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Dismiss this context menu. WINDOW is the window where the
|
/* Dismiss this context menu. WINDOW is the window where the
|
||||||
|
@ -22,6 +22,9 @@
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
import java.util.concurrent.FutureTask;
|
||||||
|
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@ -388,26 +391,18 @@ else if (EmacsOpenActivity.currentActivity != null)
|
|||||||
public boolean
|
public boolean
|
||||||
display ()
|
display ()
|
||||||
{
|
{
|
||||||
Runnable runnable;
|
FutureTask<Boolean> task;
|
||||||
final EmacsHolder<Boolean> rc;
|
|
||||||
|
|
||||||
rc = new EmacsHolder<Boolean> ();
|
task = new FutureTask<Boolean> (new Callable<Boolean> () {
|
||||||
rc.thing = false;
|
|
||||||
runnable = new Runnable () {
|
|
||||||
@Override
|
@Override
|
||||||
public void
|
public Boolean
|
||||||
run ()
|
call ()
|
||||||
{
|
{
|
||||||
synchronized (this)
|
return display1 ();
|
||||||
{
|
|
||||||
rc.thing = display1 ();
|
|
||||||
notify ();
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
};
|
|
||||||
|
|
||||||
EmacsService.syncRunnable (runnable);
|
return EmacsService.<Boolean>syncRunnable (task);
|
||||||
return rc.thing;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -27,6 +27,10 @@
|
|||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
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 java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
@ -331,52 +335,45 @@ invocation of app_process (through android-emacs) can
|
|||||||
final boolean isFocusedByDefault)
|
final boolean isFocusedByDefault)
|
||||||
{
|
{
|
||||||
Runnable runnable;
|
Runnable runnable;
|
||||||
final EmacsHolder<EmacsView> view;
|
FutureTask<EmacsView> task;
|
||||||
|
|
||||||
view = new EmacsHolder<EmacsView> ();
|
task = new FutureTask<EmacsView> (new Callable<EmacsView> () {
|
||||||
|
|
||||||
runnable = new Runnable () {
|
|
||||||
@Override
|
@Override
|
||||||
public void
|
public EmacsView
|
||||||
run ()
|
call ()
|
||||||
{
|
{
|
||||||
synchronized (this)
|
EmacsView view;
|
||||||
{
|
|
||||||
view.thing = new EmacsView (window);
|
view = new EmacsView (window);
|
||||||
view.thing.setVisibility (visibility);
|
view.setVisibility (visibility);
|
||||||
|
|
||||||
/* The following function is only present on Android 26
|
/* The following function is only present on Android 26
|
||||||
or later. */
|
or later. */
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
|
||||||
view.thing.setFocusedByDefault (isFocusedByDefault);
|
view.setFocusedByDefault (isFocusedByDefault);
|
||||||
|
|
||||||
notify ();
|
return view;
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
};
|
|
||||||
|
|
||||||
syncRunnable (runnable);
|
return EmacsService.<EmacsView>syncRunnable (task);
|
||||||
return view.thing;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void
|
public void
|
||||||
getLocationOnScreen (final EmacsView view, final int[] coordinates)
|
getLocationOnScreen (final EmacsView view, final int[] coordinates)
|
||||||
{
|
{
|
||||||
Runnable runnable;
|
FutureTask<Void> task;
|
||||||
|
|
||||||
runnable = new Runnable () {
|
task = new FutureTask<Void> (new Callable<Void> () {
|
||||||
public void
|
public Void
|
||||||
run ()
|
call ()
|
||||||
{
|
|
||||||
synchronized (this)
|
|
||||||
{
|
{
|
||||||
view.getLocationOnScreen (coordinates);
|
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
|
public ClipboardManager
|
||||||
getClipboardManager ()
|
getClipboardManager ()
|
||||||
{
|
{
|
||||||
final EmacsHolder<ClipboardManager> manager;
|
FutureTask<Object> task;
|
||||||
Runnable runnable;
|
|
||||||
|
|
||||||
manager = new EmacsHolder<ClipboardManager> ();
|
task = new FutureTask<Object> (new Callable<Object> () {
|
||||||
|
public Object
|
||||||
runnable = new Runnable () {
|
call ()
|
||||||
public void
|
|
||||||
run ()
|
|
||||||
{
|
{
|
||||||
Object tem;
|
return getSystemService (Context.CLIPBOARD_SERVICE);
|
||||||
|
|
||||||
synchronized (this)
|
|
||||||
{
|
|
||||||
tem = getSystemService (Context.CLIPBOARD_SERVICE);
|
|
||||||
manager.thing = (ClipboardManager) tem;
|
|
||||||
notify ();
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
};
|
|
||||||
|
|
||||||
syncRunnable (runnable);
|
return (ClipboardManager) EmacsService.<Object>syncRunnable (task);
|
||||||
return manager.thing;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void
|
public void
|
||||||
@ -738,33 +724,37 @@ invocation of app_process (through android-emacs) can
|
|||||||
System.exit (0);
|
System.exit (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Wait synchronously for the specified RUNNABLE to complete in the
|
/* Wait synchronously for the specified TASK to complete in the UI
|
||||||
UI thread. Must be called from the Emacs thread. */
|
thread, then return its result. Must be called from the Emacs
|
||||||
|
thread. */
|
||||||
|
|
||||||
public static void
|
public static <V> V
|
||||||
syncRunnable (Runnable runnable)
|
syncRunnable (FutureTask<V> task)
|
||||||
{
|
{
|
||||||
|
V object;
|
||||||
|
|
||||||
EmacsNative.beginSynchronous ();
|
EmacsNative.beginSynchronous ();
|
||||||
|
SERVICE.runOnUiThread (task);
|
||||||
|
|
||||||
synchronized (runnable)
|
|
||||||
{
|
|
||||||
SERVICE.runOnUiThread (runnable);
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
runnable.wait ();
|
object = task.get ();
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
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 ();
|
EmacsNative.endSynchronous ();
|
||||||
|
|
||||||
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1283,71 +1273,61 @@ else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
|
|||||||
public int
|
public int
|
||||||
requestDirectoryAccess ()
|
requestDirectoryAccess ()
|
||||||
{
|
{
|
||||||
Runnable runnable;
|
FutureTask<Integer> task;
|
||||||
final EmacsHolder<Integer> rc;
|
|
||||||
|
|
||||||
/* Return 1 if Android is too old to support this feature. */
|
/* Return 1 if Android is too old to support this feature. */
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP)
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
rc = new EmacsHolder<Integer> ();
|
task = new FutureTask<Integer> (new Callable<Integer> () {
|
||||||
rc.thing = Integer.valueOf (1);
|
|
||||||
|
|
||||||
runnable = new Runnable () {
|
|
||||||
@Override
|
@Override
|
||||||
public void
|
public Integer
|
||||||
run ()
|
call ()
|
||||||
{
|
{
|
||||||
EmacsActivity activity;
|
EmacsActivity activity;
|
||||||
Intent intent;
|
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 (EmacsActivity.focusedActivities.isEmpty ())
|
||||||
{
|
{
|
||||||
/* If focusedActivities is empty then this dialog
|
/* If focusedActivities is empty then this dialog may
|
||||||
may have been displayed immediately after another
|
have been displayed immediately after another popup
|
||||||
popup dialog was dismissed. Try the
|
dialog was dismissed. Try the EmacsActivity to be
|
||||||
EmacsActivity to be focused. */
|
focused. */
|
||||||
|
|
||||||
activity = EmacsActivity.lastFocusedActivity;
|
activity = EmacsActivity.lastFocusedActivity;
|
||||||
|
|
||||||
if (activity == null)
|
if (activity == null)
|
||||||
{
|
|
||||||
/* Still no luck. Return failure. */
|
/* Still no luck. Return failure. */
|
||||||
notify ();
|
return 1;
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
activity = EmacsActivity.focusedActivities.get (0);
|
activity = EmacsActivity.focusedActivities.get (0);
|
||||||
|
|
||||||
/* Now create the intent. */
|
/* Now create the intent. */
|
||||||
intent = new Intent (Intent.ACTION_OPEN_DOCUMENT_TREE);
|
intent = new Intent (Intent.ACTION_OPEN_DOCUMENT_TREE);
|
||||||
|
rc = 1;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
id = EmacsActivity.ACCEPT_DOCUMENT_TREE;
|
id = EmacsActivity.ACCEPT_DOCUMENT_TREE;
|
||||||
activity.startActivityForResult (intent, id, null);
|
activity.startActivityForResult (intent, id, null);
|
||||||
rc.thing = Integer.valueOf (0);
|
rc = 0;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
e.printStackTrace ();
|
e.printStackTrace ();
|
||||||
}
|
}
|
||||||
|
|
||||||
notify ();
|
return rc;
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
};
|
|
||||||
|
|
||||||
syncRunnable (runnable);
|
return EmacsService.<Integer>syncRunnable (task);
|
||||||
return rc.thing;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return an array of each tree provided by the document PROVIDER
|
/* Return an array of each tree provided by the document PROVIDER
|
||||||
|
Loading…
Reference in New Issue
Block a user