summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/view/InputEventSender.java43
1 files changed, 35 insertions, 8 deletions
diff --git a/core/java/android/view/InputEventSender.java b/core/java/android/view/InputEventSender.java
index 64f62c75199e..c843bbea561f 100644
--- a/core/java/android/view/InputEventSender.java
+++ b/core/java/android/view/InputEventSender.java
@@ -18,6 +18,7 @@ package android.view;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
+import android.os.Handler;
import android.os.Looper;
import android.os.MessageQueue;
import android.util.Log;
@@ -25,6 +26,10 @@ import android.util.Log;
import dalvik.system.CloseGuard;
import java.lang.ref.WeakReference;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.RunnableFuture;
/**
* Provides a low-level mechanism for an application to send input events.
@@ -37,10 +42,10 @@ public abstract class InputEventSender {
private long mSenderPtr;
- // We keep references to the input channel and message queue objects here so that
- // they are not GC'd while the native peer of the receiver is using them.
+ // We keep references to the input channel and message queue objects (indirectly through
+ // Handler) here so that they are not GC'd while the native peer of the receiver is using them.
private InputChannel mInputChannel;
- private MessageQueue mMessageQueue;
+ private Handler mHandler;
private static native long nativeInit(WeakReference<InputEventSender> sender,
InputChannel inputChannel, MessageQueue messageQueue);
@@ -63,9 +68,9 @@ public abstract class InputEventSender {
}
mInputChannel = inputChannel;
- mMessageQueue = looper.getQueue();
+ mHandler = new Handler(looper);
mSenderPtr = nativeInit(new WeakReference<InputEventSender>(this),
- mInputChannel, mMessageQueue);
+ mInputChannel, looper.getQueue());
mCloseGuard.open("InputEventSender.dispose");
}
@@ -98,8 +103,8 @@ public abstract class InputEventSender {
nativeDispose(mSenderPtr);
mSenderPtr = 0;
}
+ mHandler = null;
mInputChannel = null;
- mMessageQueue = null;
}
/**
@@ -122,8 +127,8 @@ public abstract class InputEventSender {
}
/**
- * Sends an input event.
- * Must be called on the same Looper thread to which the sender is attached.
+ * Sends an input event. Can be called from any thread. Do not call this if the looper thread
+ * is blocked! It would cause a deadlock.
*
* @param seq The input event sequence number.
* @param event The input event to send.
@@ -140,6 +145,28 @@ public abstract class InputEventSender {
return false;
}
+ if (mHandler.getLooper().isCurrentThread()) {
+ return sendInputEventInternal(seq, event);
+ }
+ // This is being called on another thread. Post a runnable to the looper thread
+ // with the event injection, and wait until it's processed.
+ final RunnableFuture<Boolean> task = new FutureTask<>(new Callable<Boolean>() {
+ @Override
+ public Boolean call() throws Exception {
+ return sendInputEventInternal(seq, event);
+ }
+ });
+ mHandler.post(task);
+ try {
+ return task.get();
+ } catch (InterruptedException exc) {
+ throw new IllegalStateException("Interrupted while sending " + event + ": " + exc);
+ } catch (ExecutionException exc) {
+ throw new IllegalStateException("Couldn't send " + event + ": " + exc);
+ }
+ }
+
+ private boolean sendInputEventInternal(int seq, InputEvent event) {
if (event instanceof KeyEvent) {
return nativeSendKeyEvent(mSenderPtr, seq, (KeyEvent)event);
} else {