diff options
Diffstat (limited to 'core/java')
| -rw-r--r-- | core/java/android/app/NativeActivity.java | 46 | ||||
| -rw-r--r-- | core/java/android/view/InputQueue.java | 130 | ||||
| -rw-r--r-- | core/java/android/view/KeyEvent.java | 6 | ||||
| -rw-r--r-- | core/java/android/view/ViewRootImpl.java | 64 |
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); + } } /** |
