summaryrefslogtreecommitdiff
path: root/core/java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/app/NativeActivity.java46
-rw-r--r--core/java/android/view/InputQueue.java130
-rw-r--r--core/java/android/view/KeyEvent.java6
-rw-r--r--core/java/android/view/ViewRootImpl.java64
4 files changed, 179 insertions, 67 deletions
diff --git a/core/java/android/app/NativeActivity.java b/core/java/android/app/NativeActivity.java
index 7d8a36e34f5a..63c6acd4f396 100644
--- a/core/java/android/app/NativeActivity.java
+++ b/core/java/android/app/NativeActivity.java
@@ -27,7 +27,6 @@ import android.os.Environment;
import android.os.Looper;
import android.os.MessageQueue;
import android.util.AttributeSet;
-import android.view.InputChannel;
import android.view.InputQueue;
import android.view.KeyEvent;
import android.view.Surface;
@@ -111,11 +110,9 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback2,
int format, int width, int height);
private native void onSurfaceRedrawNeededNative(int handle, Surface surface);
private native void onSurfaceDestroyedNative(int handle);
- private native void onInputChannelCreatedNative(int handle, InputChannel channel);
- private native void onInputChannelDestroyedNative(int handle, InputChannel channel);
+ private native void onInputQueueCreatedNative(int handle, int queuePtr);
+ private native void onInputQueueDestroyedNative(int handle, int queuePtr);
private native void onContentRectChangedNative(int handle, int x, int y, int w, int h);
- private native void dispatchKeyEventNative(int handle, KeyEvent event);
- private native void finishPreDispatchKeyEventNative(int handle, int seq, boolean handled);
static class NativeContentView extends View {
NativeActivity mActivity;
@@ -197,7 +194,7 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback2,
mCurSurfaceHolder = null;
}
if (mCurInputQueue != null) {
- onInputChannelDestroyedNative(mNativeHandle, mCurInputQueue.getInputChannel());
+ onInputQueueDestroyedNative(mNativeHandle, mCurInputQueue.getNativePtr());
mCurInputQueue = null;
}
unloadNativeCode(mNativeHandle);
@@ -261,18 +258,6 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback2,
}
}
- @Override
- public boolean dispatchKeyEvent(KeyEvent event) {
- if (mDispatchingUnhandledKey) {
- return super.dispatchKeyEvent(event);
- } else {
- // Key events from the IME do not go through the input channel;
- // we need to intercept them here to hand to the application.
- dispatchKeyEventNative(mNativeHandle, event);
- return true;
- }
- }
-
public void surfaceCreated(SurfaceHolder holder) {
if (!mDestroyed) {
mCurSurfaceHolder = holder;
@@ -304,14 +289,14 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback2,
public void onInputQueueCreated(InputQueue queue) {
if (!mDestroyed) {
mCurInputQueue = queue;
- onInputChannelCreatedNative(mNativeHandle, queue.getInputChannel());
+ onInputQueueCreatedNative(mNativeHandle, queue.getNativePtr());
}
}
public void onInputQueueDestroyed(InputQueue queue) {
- mCurInputQueue = null;
if (!mDestroyed) {
- onInputChannelDestroyedNative(mNativeHandle, queue.getInputChannel());
+ onInputQueueDestroyedNative(mNativeHandle, queue.getNativePtr());
+ mCurInputQueue = null;
}
}
@@ -332,25 +317,6 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback2,
}
}
- boolean dispatchUnhandledKeyEvent(KeyEvent event) {
- try {
- mDispatchingUnhandledKey = true;
- View decor = getWindow().getDecorView();
- if (decor != null) {
- return decor.dispatchKeyEvent(event);
- } else {
- return false;
- }
- } finally {
- mDispatchingUnhandledKey = false;
- }
- }
-
- void preDispatchKeyEvent(KeyEvent event, int seq) {
- // FIXME: Input dispatch should be redirected back through ViewRootImpl again.
- finishPreDispatchKeyEventNative(mNativeHandle, seq, false);
- }
-
void setWindowFlags(int flags, int mask) {
getWindow().setFlags(flags, mask);
}
diff --git a/core/java/android/view/InputQueue.java b/core/java/android/view/InputQueue.java
index 909a3b2b9d24..e3de89d1cc00 100644
--- a/core/java/android/view/InputQueue.java
+++ b/core/java/android/view/InputQueue.java
@@ -16,11 +16,127 @@
package android.view;
+import dalvik.system.CloseGuard;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.MessageQueue;
+import android.util.Pools.Pool;
+import android.util.Pools.SimplePool;
+import android.util.SparseArray;
+
+import java.lang.ref.WeakReference;
+
/**
* An input queue provides a mechanism for an application to receive incoming
* input events. Currently only usable from native code.
*/
public final class InputQueue {
+ private final SparseArray<ActiveInputEvent> mActiveEventArray =
+ new SparseArray<ActiveInputEvent>(20);
+ private final Pool<ActiveInputEvent> mActiveInputEventPool =
+ new SimplePool<ActiveInputEvent>(20);
+
+ private final CloseGuard mCloseGuard = CloseGuard.get();
+
+ private int mPtr;
+
+ private static native int nativeInit(WeakReference<InputQueue> weakQueue,
+ MessageQueue messageQueue);
+ private static native int nativeSendKeyEvent(int ptr, KeyEvent e, boolean preDispatch);
+ private static native int nativeSendMotionEvent(int ptr, MotionEvent e);
+ private static native void nativeDispose(int ptr);
+
+ /** @hide */
+ public InputQueue() {
+ mPtr = nativeInit(new WeakReference<InputQueue>(this), Looper.myQueue());
+
+ mCloseGuard.open("dispose");
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ dispose(true);
+ } finally {
+ super.finalize();
+ }
+ }
+
+ /** @hide */
+ public void dispose() {
+ dispose(false);
+ }
+
+ /** @hide */
+ public void dispose(boolean finalized) {
+ if (mCloseGuard != null) {
+ if (finalized) {
+ mCloseGuard.warnIfOpen();
+ }
+ mCloseGuard.close();
+ }
+
+ if (mPtr != 0) {
+ nativeDispose(mPtr);
+ mPtr = 0;
+ }
+ }
+
+ /** @hide */
+ public int getNativePtr() {
+ return mPtr;
+ }
+
+ /** @hide */
+ public void sendInputEvent(InputEvent e, Object token, boolean predispatch,
+ FinishedInputEventCallback callback) {
+ ActiveInputEvent event = obtainActiveInputEvent(token, callback);
+ int id;
+ if (e instanceof KeyEvent) {
+ id = nativeSendKeyEvent(mPtr, (KeyEvent) e, predispatch);
+ } else {
+ id = nativeSendMotionEvent(mPtr, (MotionEvent) e);
+ }
+ mActiveEventArray.put(id, event);
+ }
+
+ private void finishInputEvent(int id, boolean handled) {
+ int index = mActiveEventArray.indexOfKey(id);
+ if (index >= 0) {
+ ActiveInputEvent e = mActiveEventArray.valueAt(index);
+ mActiveEventArray.removeAt(index);
+ e.mCallback.onFinishedInputEvent(e.mToken, handled);
+ recycleActiveInputEvent(e);
+ }
+ }
+
+ private ActiveInputEvent obtainActiveInputEvent(Object token,
+ FinishedInputEventCallback callback) {
+ ActiveInputEvent e = mActiveInputEventPool.acquire();
+ if (e == null) {
+ e = new ActiveInputEvent();
+ }
+ e.mToken = token;
+ e.mCallback = callback;
+ return e;
+ }
+
+ private void recycleActiveInputEvent(ActiveInputEvent e) {
+ e.recycle();
+ mActiveInputEventPool.release(e);
+ }
+
+ private final class ActiveInputEvent {
+ public Object mToken;
+ public FinishedInputEventCallback mCallback;
+
+ public void recycle() {
+ mToken = null;
+ mCallback = null;
+ }
+ }
+
/**
* Interface to receive notification of when an InputQueue is associated
* and dissociated with a thread.
@@ -31,7 +147,7 @@ public final class InputQueue {
* thread making this call, so it can start receiving events from it.
*/
void onInputQueueCreated(InputQueue queue);
-
+
/**
* Called when the given InputQueue is no longer associated with
* the thread and thus not dispatching events.
@@ -39,15 +155,9 @@ public final class InputQueue {
void onInputQueueDestroyed(InputQueue queue);
}
- final InputChannel mChannel;
-
- /** @hide */
- public InputQueue(InputChannel channel) {
- mChannel = channel;
- }
-
/** @hide */
- public InputChannel getInputChannel() {
- return mChannel;
+ public static interface FinishedInputEventCallback {
+ void onFinishedInputEvent(Object token, boolean handled);
}
+
}
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 7ec3776e7540..b178ea86a4e1 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -1233,6 +1233,12 @@ public class KeyEvent extends InputEvent implements Parcelable {
public static final int FLAG_FALLBACK = 0x400;
/**
+ * Signifies that the key is being predispatched.
+ * @hide
+ */
+ public static final int FLAG_PREDISPATCH = 0x20000000;
+
+ /**
* Private control to determine when an app is tracking a key sequence.
* @hide
*/
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 3215e21e1b1f..f34d390137b3 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -600,12 +600,11 @@ public final class ViewRootImpl implements ViewParent,
}
if (mInputChannel != null) {
if (mInputQueueCallback != null) {
- mInputQueue = new InputQueue(mInputChannel);
+ mInputQueue = new InputQueue();
mInputQueueCallback.onInputQueueCreated(mInputQueue);
- } else {
- mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
- Looper.myLooper());
}
+ mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
+ Looper.myLooper());
}
view.assignParent(this);
@@ -2825,9 +2824,11 @@ public final class ViewRootImpl implements ViewParent,
if (mInputQueueCallback != null && mInputQueue != null) {
mInputQueueCallback.onInputQueueDestroyed(mInputQueue);
+ mInputQueue.dispose();
mInputQueueCallback = null;
mInputQueue = null;
- } else if (mInputEventReceiver != null) {
+ }
+ if (mInputEventReceiver != null) {
mInputEventReceiver.dispose();
mInputEventReceiver = null;
}
@@ -3350,6 +3351,15 @@ public final class ViewRootImpl implements ViewParent,
if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {
forward(q);
} else if (mView == null || !mAdded) {
+ Slog.w(TAG, "Dropping event due to root view being removed: " + q.mEvent);
+ finish(q, false);
+ } else if (!mAttachInfo.mHasWindowFocus &&
+ !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER) &&
+ !isTerminalInputEvent(q.mEvent)) {
+ // If this is a focused event and the window doesn't currently have input focus,
+ // then drop this event. This could be an event that came back from the previous
+ // stage but the window has lost focus in the meantime.
+ Slog.w(TAG, "Dropping event due to no window focus: " + q.mEvent);
finish(q, false);
} else {
apply(q, onProcess(q));
@@ -3550,15 +3560,30 @@ public final class ViewRootImpl implements ViewParent,
* Delivers pre-ime input events to a native activity.
* Does not support pointer events.
*/
- final class NativePreImeInputStage extends AsyncInputStage {
+ final class NativePreImeInputStage extends AsyncInputStage
+ implements InputQueue.FinishedInputEventCallback {
public NativePreImeInputStage(InputStage next, String traceCounter) {
super(next, traceCounter);
}
@Override
protected int onProcess(QueuedInputEvent q) {
+ if (mInputQueue != null && q.mEvent instanceof KeyEvent) {
+ mInputQueue.sendInputEvent(q.mEvent, q, true, this);
+ return DEFER;
+ }
return FORWARD;
}
+
+ @Override
+ public void onFinishedInputEvent(Object token, boolean handled) {
+ QueuedInputEvent q = (QueuedInputEvent)token;
+ if (handled) {
+ finish(q, true);
+ return;
+ }
+ forward(q);
+ }
}
/**
@@ -3624,16 +3649,6 @@ public final class ViewRootImpl implements ViewParent,
finish(q, true);
return;
}
-
- // If the window doesn't currently have input focus, then drop
- // this event. This could be an event that came back from the
- // IME dispatch but the window has lost focus in the meantime.
- if (!mAttachInfo.mHasWindowFocus && !isTerminalInputEvent(q.mEvent)) {
- Slog.w(TAG, "Dropping event due to no window focus: " + q.mEvent);
- finish(q, false);
- return;
- }
-
forward(q);
}
}
@@ -3705,15 +3720,30 @@ public final class ViewRootImpl implements ViewParent,
/**
* Delivers post-ime input events to a native activity.
*/
- final class NativePostImeInputStage extends AsyncInputStage {
+ final class NativePostImeInputStage extends AsyncInputStage
+ implements InputQueue.FinishedInputEventCallback {
public NativePostImeInputStage(InputStage next, String traceCounter) {
super(next, traceCounter);
}
@Override
protected int onProcess(QueuedInputEvent q) {
+ if (mInputQueue != null) {
+ mInputQueue.sendInputEvent(q.mEvent, q, false, this);
+ return DEFER;
+ }
return FORWARD;
}
+
+ @Override
+ public void onFinishedInputEvent(Object token, boolean handled) {
+ QueuedInputEvent q = (QueuedInputEvent)token;
+ if (handled) {
+ finish(q, true);
+ return;
+ }
+ forward(q);
+ }
}
/**