summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Jeff Brown <jeffbrown@google.com> 2011-12-01 14:01:49 -0800
committer Jeff Brown <jeffbrown@google.com> 2011-12-01 21:04:47 -0800
commit32cbc3855c2a971aa5a801fd339fb6a37db91a1a (patch)
tree40d3fcf12181eb6d50fac3a3734ecf3c9f4953ec
parentdb918cf171afd3d4b3c22aab6dd3403d1dec94de (diff)
Refactor InputQueue as InputEventReceiver.
This change simplifies the code associated with receiving input events from input channels and makes it more robust. It also does a better job of ensuring that input events are properly recycled (sometimes we dropped them on the floor). This change also adds a sequence number to all events, which is handy for determining whether we are looking at the same event or a new one, particularly when events are recycled. Change-Id: I4ebd88f73b5f77f3e150778cd550e7f91956aac2
-rw-r--r--core/java/android/service/wallpaper/WallpaperService.java37
-rwxr-xr-xcore/java/android/view/InputEvent.java57
-rw-r--r--core/java/android/view/InputEventConsistencyVerifier.java11
-rw-r--r--core/java/android/view/InputEventReceiver.java151
-rw-r--r--core/java/android/view/InputHandler.java35
-rw-r--r--core/java/android/view/InputQueue.java124
-rwxr-xr-xcore/java/android/view/KeyEvent.java8
-rw-r--r--core/java/android/view/MotionEvent.java20
-rw-r--r--core/java/android/view/ViewRootImpl.java54
-rw-r--r--core/java/android/view/WindowManagerPolicy.java3
-rw-r--r--core/jni/Android.mk2
-rw-r--r--core/jni/AndroidRuntime.cpp4
-rw-r--r--core/jni/android_view_InputEventReceiver.cpp307
-rw-r--r--core/jni/android_view_InputQueue.cpp522
-rwxr-xr-xpolicy/src/com/android/internal/policy/impl/PhoneWindowManager.java53
-rw-r--r--services/java/com/android/server/wm/DragState.java10
-rw-r--r--services/java/com/android/server/wm/FakeWindowImpl.java12
-rw-r--r--services/java/com/android/server/wm/WindowManagerService.java23
18 files changed, 643 insertions, 790 deletions
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 133549bdf8a3..7ce96c0e31bd 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -45,8 +45,7 @@ import android.view.IWindowSession;
import android.view.InputChannel;
import android.view.InputDevice;
import android.view.InputEvent;
-import android.view.InputHandler;
-import android.view.InputQueue;
+import android.view.InputEventReceiver;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.View;
@@ -228,24 +227,29 @@ public abstract class WallpaperService extends Service {
}
};
-
- final InputHandler mInputHandler = new InputHandler() {
+
+ final class WallpaperInputEventReceiver extends InputEventReceiver {
+ public WallpaperInputEventReceiver(InputChannel inputChannel, Looper looper) {
+ super(inputChannel, looper);
+ }
+
@Override
- public void handleInputEvent(InputEvent event,
- InputQueue.FinishedCallback finishedCallback) {
+ public void onInputEvent(InputEvent event) {
boolean handled = false;
try {
if (event instanceof MotionEvent
&& (event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
- dispatchPointer((MotionEvent)event);
+ MotionEvent dup = MotionEvent.obtainNoHistory((MotionEvent)event);
+ dispatchPointer(dup);
handled = true;
}
} finally {
- finishedCallback.finished(handled);
+ finishInputEvent(event, handled);
}
}
- };
-
+ }
+ WallpaperInputEventReceiver mInputEventReceiver;
+
final BaseIWindow mWindow = new BaseIWindow() {
@Override
public void resized(int w, int h, Rect coveredInsets,
@@ -534,6 +538,8 @@ public abstract class WallpaperService extends Service {
}
Message msg = mCaller.obtainMessageO(MSG_TOUCH_EVENT, event);
mCaller.sendMessage(msg);
+ } else {
+ event.recycle();
}
}
@@ -599,8 +605,8 @@ public abstract class WallpaperService extends Service {
}
mCreated = true;
- InputQueue.registerInputChannel(mInputChannel, mInputHandler,
- Looper.myQueue());
+ mInputEventReceiver = new WallpaperInputEventReceiver(
+ mInputChannel, Looper.myLooper());
}
mSurfaceHolder.mSurfaceLock.lock();
@@ -902,8 +908,9 @@ public abstract class WallpaperService extends Service {
if (DEBUG) Log.v(TAG, "Removing window and destroying surface "
+ mSurfaceHolder.getSurface() + " of: " + this);
- if (mInputChannel != null) {
- InputQueue.unregisterInputChannel(mInputChannel);
+ if (mInputEventReceiver != null) {
+ mInputEventReceiver.dispose();
+ mInputEventReceiver = null;
}
mSession.remove(mWindow);
@@ -970,6 +977,8 @@ public abstract class WallpaperService extends Service {
public void dispatchPointer(MotionEvent event) {
if (mEngine != null) {
mEngine.dispatchPointer(event);
+ } else {
+ event.recycle();
}
}
diff --git a/core/java/android/view/InputEvent.java b/core/java/android/view/InputEvent.java
index 01ddcc9bf1a4..c42bbdcadf04 100755
--- a/core/java/android/view/InputEvent.java
+++ b/core/java/android/view/InputEvent.java
@@ -19,6 +19,8 @@ package android.view;
import android.os.Parcel;
import android.os.Parcelable;
+import java.util.concurrent.atomic.AtomicInteger;
+
/**
* Common base class for input events.
*/
@@ -27,8 +29,21 @@ public abstract class InputEvent implements Parcelable {
protected static final int PARCEL_TOKEN_MOTION_EVENT = 1;
/** @hide */
protected static final int PARCEL_TOKEN_KEY_EVENT = 2;
-
+
+ // Next sequence number.
+ private static final AtomicInteger mNextSeq = new AtomicInteger();
+
+ /** @hide */
+ protected int mSeq;
+
+ /** @hide */
+ protected boolean mRecycled;
+
+ private static final boolean TRACK_RECYCLED_LOCATION = false;
+ private RuntimeException mRecycledLocation;
+
/*package*/ InputEvent() {
+ mSeq = mNextSeq.getAndIncrement();
}
/**
@@ -82,7 +97,29 @@ public abstract class InputEvent implements Parcelable {
* objects are fine. See {@link KeyEvent#recycle()} for details.
* @hide
*/
- public abstract void recycle();
+ public void recycle() {
+ if (TRACK_RECYCLED_LOCATION) {
+ if (mRecycledLocation != null) {
+ throw new RuntimeException(toString() + " recycled twice!", mRecycledLocation);
+ }
+ mRecycledLocation = new RuntimeException("Last recycled here");
+ } else {
+ if (mRecycled) {
+ throw new RuntimeException(toString() + " recycled twice!");
+ }
+ mRecycled = true;
+ }
+ }
+
+ /**
+ * Reinitializes the event on reuse (after recycling).
+ * @hide
+ */
+ protected void prepareForReuse() {
+ mRecycled = false;
+ mRecycledLocation = null;
+ mSeq = mNextSeq.getAndIncrement();
+ }
/**
* Gets a private flag that indicates when the system has detected that this input event
@@ -113,6 +150,22 @@ public abstract class InputEvent implements Parcelable {
*/
public abstract long getEventTimeNano();
+ /**
+ * Gets the unique sequence number of this event.
+ * Every input event that is created or received by a process has a
+ * unique sequence number. Moreover, a new sequence number is obtained
+ * each time an event object is recycled.
+ *
+ * Sequence numbers are only guaranteed to be locally unique within a process.
+ * Sequence numbers are not preserved when events are parceled.
+ *
+ * @return The unique sequence number of this event.
+ * @hide
+ */
+ public int getSequenceNumber() {
+ return mSeq;
+ }
+
public int describeContents() {
return 0;
}
diff --git a/core/java/android/view/InputEventConsistencyVerifier.java b/core/java/android/view/InputEventConsistencyVerifier.java
index 9b081b207dff..fafe416defdf 100644
--- a/core/java/android/view/InputEventConsistencyVerifier.java
+++ b/core/java/android/view/InputEventConsistencyVerifier.java
@@ -58,7 +58,7 @@ public final class InputEventConsistencyVerifier {
// so that the verifier can detect when it has been asked to verify the same event twice.
// It does not make sense to examine the contents of the last event since it may have
// been recycled.
- private InputEvent mLastEvent;
+ private int mLastEventSeq;
private String mLastEventType;
private int mLastNestingLevel;
@@ -140,7 +140,7 @@ public final class InputEventConsistencyVerifier {
* Resets the state of the input event consistency verifier.
*/
public void reset() {
- mLastEvent = null;
+ mLastEventSeq = -1;
mLastNestingLevel = 0;
mTrackballDown = false;
mTrackballUnhandled = false;
@@ -573,17 +573,18 @@ public final class InputEventConsistencyVerifier {
private boolean startEvent(InputEvent event, int nestingLevel, String eventType) {
// Ignore the event if we already checked it at a higher nesting level.
- if (event == mLastEvent && nestingLevel < mLastNestingLevel
+ final int seq = event.getSequenceNumber();
+ if (seq == mLastEventSeq && nestingLevel < mLastNestingLevel
&& eventType == mLastEventType) {
return false;
}
if (nestingLevel > 0) {
- mLastEvent = event;
+ mLastEventSeq = seq;
mLastEventType = eventType;
mLastNestingLevel = nestingLevel;
} else {
- mLastEvent = null;
+ mLastEventSeq = -1;
mLastEventType = null;
mLastNestingLevel = 0;
}
diff --git a/core/java/android/view/InputEventReceiver.java b/core/java/android/view/InputEventReceiver.java
new file mode 100644
index 000000000000..abb52810c446
--- /dev/null
+++ b/core/java/android/view/InputEventReceiver.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import dalvik.system.CloseGuard;
+
+import android.os.Looper;
+import android.os.MessageQueue;
+import android.util.Log;
+
+/**
+ * Provides a low-level mechanism for an application to receive input events.
+ * @hide
+ */
+public abstract class InputEventReceiver {
+ private static final String TAG = "InputEventReceiver";
+
+ private final CloseGuard mCloseGuard = CloseGuard.get();
+
+ private int mReceiverPtr;
+
+ // 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.
+ private InputChannel mInputChannel;
+ private MessageQueue mMessageQueue;
+
+ // The sequence number of the event that is in progress.
+ private int mEventSequenceNumberInProgress = -1;
+
+ private static native int nativeInit(InputEventReceiver receiver,
+ InputChannel inputChannel, MessageQueue messageQueue);
+ private static native void nativeDispose(int receiverPtr);
+ private static native void nativeFinishInputEvent(int receiverPtr, boolean handled);
+
+ /**
+ * Creates an input event receiver bound to the specified input channel.
+ *
+ * @param inputChannel The input channel.
+ * @param looper The looper to use when invoking callbacks.
+ */
+ public InputEventReceiver(InputChannel inputChannel, Looper looper) {
+ if (inputChannel == null) {
+ throw new IllegalArgumentException("inputChannel must not be null");
+ }
+ if (looper == null) {
+ throw new IllegalArgumentException("looper must not be null");
+ }
+
+ mInputChannel = inputChannel;
+ mMessageQueue = looper.getQueue();
+ mReceiverPtr = nativeInit(this, inputChannel, mMessageQueue);
+
+ mCloseGuard.open("dispose");
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ dispose();
+ } finally {
+ super.finalize();
+ }
+ }
+
+ /**
+ * Disposes the receiver.
+ */
+ public void dispose() {
+ if (mCloseGuard != null) {
+ mCloseGuard.close();
+ }
+ if (mReceiverPtr != 0) {
+ nativeDispose(mReceiverPtr);
+ mReceiverPtr = 0;
+ }
+ mInputChannel = null;
+ mMessageQueue = null;
+ }
+
+ /**
+ * Called when an input event is received.
+ * The recipient should process the input event and then call {@link #finishInputEvent}
+ * to indicate whether the event was handled. No new input events will be received
+ * until {@link #finishInputEvent} is called.
+ *
+ * @param event The input event that was received.
+ */
+ public void onInputEvent(InputEvent event) {
+ finishInputEvent(event, false);
+ }
+
+ /**
+ * Finishes an input event and indicates whether it was handled.
+ *
+ * @param event The input event that was finished.
+ * @param handled True if the event was handled.
+ */
+ public void finishInputEvent(InputEvent event, boolean handled) {
+ if (event == null) {
+ throw new IllegalArgumentException("event must not be null");
+ }
+ if (mReceiverPtr == 0) {
+ Log.w(TAG, "Attempted to finish an input event but the input event "
+ + "receiver has already been disposed.");
+ } else {
+ if (event.getSequenceNumber() != mEventSequenceNumberInProgress) {
+ Log.w(TAG, "Attempted to finish an input event that is not in progress.");
+ } else {
+ mEventSequenceNumberInProgress = -1;
+ nativeFinishInputEvent(mReceiverPtr, handled);
+ }
+ }
+ recycleInputEvent(event);
+ }
+
+ // Called from native code.
+ @SuppressWarnings("unused")
+ private void dispatchInputEvent(InputEvent event) {
+ mEventSequenceNumberInProgress = event.getSequenceNumber();
+ onInputEvent(event);
+ }
+
+ private static void recycleInputEvent(InputEvent event) {
+ if (event instanceof MotionEvent) {
+ // Event though key events are also recyclable, we only recycle motion events.
+ // Historically, key events were not recyclable and applications expect
+ // them to be immutable. We only ever recycle key events behind the
+ // scenes where an application never sees them (so, not here).
+ event.recycle();
+ }
+ }
+
+ public static interface Factory {
+ public InputEventReceiver createInputEventReceiver(
+ InputChannel inputChannel, Looper looper);
+ }
+}
diff --git a/core/java/android/view/InputHandler.java b/core/java/android/view/InputHandler.java
deleted file mode 100644
index 192a42794f40..000000000000
--- a/core/java/android/view/InputHandler.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.view;
-
-/**
- * Handles input messages that arrive on an input channel.
- * @hide
- */
-public class InputHandler {
- /**
- * Handle an input event.
- * It is the responsibility of the callee to ensure that the finished callback is
- * eventually invoked when the event processing is finished and the input system
- * can send the next event.
- * @param event The input event.
- * @param finishedCallback The callback to invoke when event processing is finished.
- */
- public void handleInputEvent(InputEvent event, InputQueue.FinishedCallback finishedCallback) {
- finishedCallback.finished(false);
- }
-}
diff --git a/core/java/android/view/InputQueue.java b/core/java/android/view/InputQueue.java
index 12065184ccda..909a3b2b9d24 100644
--- a/core/java/android/view/InputQueue.java
+++ b/core/java/android/view/InputQueue.java
@@ -16,18 +16,11 @@
package android.view;
-import android.os.MessageQueue;
-import android.util.Slog;
-
/**
* 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 static final String TAG = "InputQueue";
-
- private static final boolean DEBUG = false;
-
/**
* Interface to receive notification of when an InputQueue is associated
* and dissociated with a thread.
@@ -48,13 +41,6 @@ public final class InputQueue {
final InputChannel mChannel;
- private static final Object sLock = new Object();
-
- private static native void nativeRegisterInputChannel(InputChannel inputChannel,
- InputHandler inputHandler, MessageQueue messageQueue);
- private static native void nativeUnregisterInputChannel(InputChannel inputChannel);
- private static native void nativeFinished(long finishedToken, boolean handled);
-
/** @hide */
public InputQueue(InputChannel channel) {
mChannel = channel;
@@ -64,114 +50,4 @@ public final class InputQueue {
public InputChannel getInputChannel() {
return mChannel;
}
-
- /**
- * Registers an input channel and handler.
- * @param inputChannel The input channel to register.
- * @param inputHandler The input handler to input events send to the target.
- * @param messageQueue The message queue on whose thread the handler should be invoked.
- * @hide
- */
- public static void registerInputChannel(InputChannel inputChannel, InputHandler inputHandler,
- MessageQueue messageQueue) {
- if (inputChannel == null) {
- throw new IllegalArgumentException("inputChannel must not be null");
- }
- if (inputHandler == null) {
- throw new IllegalArgumentException("inputHandler must not be null");
- }
- if (messageQueue == null) {
- throw new IllegalArgumentException("messageQueue must not be null");
- }
-
- synchronized (sLock) {
- if (DEBUG) {
- Slog.d(TAG, "Registering input channel '" + inputChannel + "'");
- }
-
- nativeRegisterInputChannel(inputChannel, inputHandler, messageQueue);
- }
- }
-
- /**
- * Unregisters an input channel.
- * Does nothing if the channel is not currently registered.
- * @param inputChannel The input channel to unregister.
- * @hide
- */
- public static void unregisterInputChannel(InputChannel inputChannel) {
- if (inputChannel == null) {
- throw new IllegalArgumentException("inputChannel must not be null");
- }
-
- synchronized (sLock) {
- if (DEBUG) {
- Slog.d(TAG, "Unregistering input channel '" + inputChannel + "'");
- }
-
- nativeUnregisterInputChannel(inputChannel);
- }
- }
-
- @SuppressWarnings("unused")
- private static void dispatchInputEvent(InputHandler inputHandler,
- InputEvent event, long finishedToken) {
- FinishedCallback finishedCallback = FinishedCallback.obtain(finishedToken);
- inputHandler.handleInputEvent(event, finishedCallback);
- }
-
- /**
- * A callback that must be invoked to when finished processing an event.
- * @hide
- */
- public static final class FinishedCallback {
- private static final boolean DEBUG_RECYCLING = false;
-
- private static final int RECYCLE_MAX_COUNT = 4;
-
- private static FinishedCallback sRecycleHead;
- private static int sRecycleCount;
-
- private FinishedCallback mRecycleNext;
- private long mFinishedToken;
-
- private FinishedCallback() {
- }
-
- public static FinishedCallback obtain(long finishedToken) {
- synchronized (sLock) {
- FinishedCallback callback = sRecycleHead;
- if (callback != null) {
- sRecycleHead = callback.mRecycleNext;
- sRecycleCount -= 1;
- callback.mRecycleNext = null;
- } else {
- callback = new FinishedCallback();
- }
- callback.mFinishedToken = finishedToken;
- return callback;
- }
- }
-
- public void finished(boolean handled) {
- synchronized (sLock) {
- if (mFinishedToken == -1) {
- throw new IllegalStateException("Event finished callback already invoked.");
- }
-
- nativeFinished(mFinishedToken, handled);
- mFinishedToken = -1;
-
- if (sRecycleCount < RECYCLE_MAX_COUNT) {
- mRecycleNext = sRecycleHead;
- sRecycleHead = this;
- sRecycleCount += 1;
-
- if (DEBUG_RECYCLING) {
- Slog.d(TAG, "Recycled finished callbacks: " + sRecycleCount);
- }
- }
- }
- }
- }
}
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index f53e42cb4603..9a46aab76922 100755
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -1225,7 +1225,6 @@ public class KeyEvent extends InputEvent implements Parcelable {
private static KeyEvent gRecyclerTop;
private KeyEvent mNext;
- private boolean mRecycled;
private int mDeviceId;
private int mSource;
@@ -1535,8 +1534,8 @@ public class KeyEvent extends InputEvent implements Parcelable {
gRecyclerTop = ev.mNext;
gRecyclerUsed -= 1;
}
- ev.mRecycled = false;
ev.mNext = null;
+ ev.prepareForReuse();
return ev;
}
@@ -1598,10 +1597,7 @@ public class KeyEvent extends InputEvent implements Parcelable {
* @hide
*/
public final void recycle() {
- if (mRecycled) {
- throw new RuntimeException(toString() + " recycled twice!");
- }
- mRecycled = true;
+ super.recycle();
mCharacters = null;
synchronized (gRecyclerLock) {
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index 8e0ab1a12502..e49193e2c69c 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -167,7 +167,6 @@ import android.util.SparseArray;
*/
public final class MotionEvent extends InputEvent implements Parcelable {
private static final long NS_PER_MS = 1000000;
- private static final boolean TRACK_RECYCLED_LOCATION = false;
/**
* An invalid pointer id.
@@ -1315,8 +1314,6 @@ public final class MotionEvent extends InputEvent implements Parcelable {
private int mNativePtr;
private MotionEvent mNext;
- private RuntimeException mRecycledLocation;
- private boolean mRecycled;
private static native int nativeInitialize(int nativePtr,
int deviceId, int source, int action, int flags, int edgeFlags,
@@ -1397,9 +1394,8 @@ public final class MotionEvent extends InputEvent implements Parcelable {
gRecyclerTop = ev.mNext;
gRecyclerUsed -= 1;
}
- ev.mRecycledLocation = null;
- ev.mRecycled = false;
ev.mNext = null;
+ ev.prepareForReuse();
return ev;
}
@@ -1647,19 +1643,7 @@ public final class MotionEvent extends InputEvent implements Parcelable {
* this function you must not ever touch the event again.
*/
public final void recycle() {
- // Ensure recycle is only called once!
- if (TRACK_RECYCLED_LOCATION) {
- if (mRecycledLocation != null) {
- throw new RuntimeException(toString() + " recycled twice!", mRecycledLocation);
- }
- mRecycledLocation = new RuntimeException("Last recycled here");
- //Log.w("MotionEvent", "Recycling event " + this, mRecycledLocation);
- } else {
- if (mRecycled) {
- throw new RuntimeException(toString() + " recycled twice!");
- }
- mRecycled = true;
- }
+ super.recycle();
synchronized (gRecyclerLock) {
if (gRecyclerUsed < MAX_RECYCLED) {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 0e6533412379..f23c3127e3a9 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -221,7 +221,6 @@ public final class ViewRootImpl extends Handler implements ViewParent,
private static final int MAX_QUEUED_INPUT_EVENT_POOL_SIZE = 10;
private QueuedInputEvent mQueuedInputEventPool;
private int mQueuedInputEventPoolSize;
- private int mQueuedInputEventNextSeq;
// Input event queue.
QueuedInputEvent mFirstPendingInputEvent;
@@ -559,8 +558,8 @@ public final class ViewRootImpl extends Handler implements ViewParent,
mInputQueue = new InputQueue(mInputChannel);
mInputQueueCallback.onInputQueueCreated(mInputQueue);
} else {
- InputQueue.registerInputChannel(mInputChannel, mInputHandler,
- Looper.myQueue());
+ mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
+ Looper.myLooper());
}
}
@@ -2283,8 +2282,9 @@ public final class ViewRootImpl extends Handler implements ViewParent,
mInputQueueCallback.onInputQueueDestroyed(mInputQueue);
mInputQueueCallback = null;
mInputQueue = null;
- } else if (mInputChannel != null) {
- InputQueue.unregisterInputChannel(mInputChannel);
+ } else if (mInputEventReceiver != null) {
+ mInputEventReceiver.dispose();
+ mInputEventReceiver = null;
}
try {
sWindowSession.remove(mWindow);
@@ -3199,9 +3199,10 @@ public final class ViewRootImpl extends Handler implements ViewParent,
if (mLastWasImTarget) {
InputMethodManager imm = InputMethodManager.peekInstance();
if (imm != null) {
+ final int seq = event.getSequenceNumber();
if (DEBUG_IMF) Log.v(TAG, "Sending key event to IME: seq="
- + q.mSeq + " event=" + event);
- imm.dispatchKeyEvent(mView.getContext(), q.mSeq, event, mInputMethodCallback);
+ + seq + " event=" + event);
+ imm.dispatchKeyEvent(mView.getContext(), seq, event, mInputMethodCallback);
return;
}
}
@@ -3213,7 +3214,7 @@ public final class ViewRootImpl extends Handler implements ViewParent,
void handleImeFinishedEvent(int seq, boolean handled) {
final QueuedInputEvent q = mCurrentInputEvent;
- if (q != null && q.mSeq == seq) {
+ if (q != null && q.mEvent.getSequenceNumber() == seq) {
final KeyEvent event = (KeyEvent)q.mEvent;
if (DEBUG_IMF) {
Log.v(TAG, "IME finished event: seq=" + seq
@@ -3715,9 +3716,8 @@ public final class ViewRootImpl extends Handler implements ViewParent,
public QueuedInputEvent mNext;
public InputEvent mEvent;
- public InputQueue.FinishedCallback mFinishedCallback;
+ public InputEventReceiver mReceiver;
public int mFlags;
- public int mSeq;
// Used for latency calculations.
public long mReceiveTimeNanos;
@@ -3726,7 +3726,7 @@ public final class ViewRootImpl extends Handler implements ViewParent,
}
private QueuedInputEvent obtainQueuedInputEvent(InputEvent event,
- InputQueue.FinishedCallback finishedCallback, int flags) {
+ InputEventReceiver receiver, int flags) {
QueuedInputEvent q = mQueuedInputEventPool;
if (q != null) {
mQueuedInputEventPoolSize -= 1;
@@ -3737,15 +3737,14 @@ public final class ViewRootImpl extends Handler implements ViewParent,
}
q.mEvent = event;
- q.mFinishedCallback = finishedCallback;
+ q.mReceiver = receiver;
q.mFlags = flags;
- q.mSeq = mQueuedInputEventNextSeq++;
return q;
}
private void recycleQueuedInputEvent(QueuedInputEvent q) {
q.mEvent = null;
- q.mFinishedCallback = null;
+ q.mReceiver = null;
if (mQueuedInputEventPoolSize < MAX_QUEUED_INPUT_EVENT_POOL_SIZE) {
mQueuedInputEventPoolSize += 1;
@@ -3755,8 +3754,8 @@ public final class ViewRootImpl extends Handler implements ViewParent,
}
void enqueueInputEvent(InputEvent event,
- InputQueue.FinishedCallback finishedCallback, int flags) {
- QueuedInputEvent q = obtainQueuedInputEvent(event, finishedCallback, flags);
+ InputEventReceiver receiver, int flags) {
+ QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
if (ViewDebug.DEBUG_LATENCY) {
q.mReceiveTimeNanos = System.nanoTime();
@@ -3847,11 +3846,9 @@ public final class ViewRootImpl extends Handler implements ViewParent,
Log.d(ViewDebug.DEBUG_LATENCY_TAG, msg.toString());
}
- if (q.mFinishedCallback != null) {
- q.mFinishedCallback.finished(handled);
- }
-
- if (q.mEvent instanceof MotionEvent) {
+ if (q.mReceiver != null) {
+ q.mReceiver.finishInputEvent(q.mEvent, handled);
+ } else if (q.mEvent instanceof MotionEvent) {
// Event though key events are also recyclable, we only recycle motion events.
// Historically, key events were not recyclable and applications expect
// them to be immutable. We only ever recycle key events behind the
@@ -3867,12 +3864,17 @@ public final class ViewRootImpl extends Handler implements ViewParent,
}
}
- private final InputHandler mInputHandler = new InputHandler() {
- public void handleInputEvent(InputEvent event,
- InputQueue.FinishedCallback finishedCallback) {
- enqueueInputEvent(event, finishedCallback, 0);
+ final class WindowInputEventReceiver extends InputEventReceiver {
+ public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
+ super(inputChannel, looper);
}
- };
+
+ @Override
+ public void onInputEvent(InputEvent event) {
+ enqueueInputEvent(event, this, 0);
+ }
+ }
+ WindowInputEventReceiver mInputEventReceiver;
public void dispatchKey(KeyEvent event) {
enqueueInputEvent(event, null, 0);
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 2e19bf64d3e1..7d729c68ab4d 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -340,7 +340,8 @@ public interface WindowManagerPolicy {
* Add a fake window to the window manager. This window sits
* at the top of the other windows and consumes events.
*/
- public FakeWindow addFakeWindow(Looper looper, InputHandler inputHandler,
+ public FakeWindow addFakeWindow(Looper looper,
+ InputEventReceiver.Factory inputEventReceiverFactory,
String name, int windowType, int layoutParamsFlags, boolean canReceiveKeys,
boolean hasFocus, boolean touchFullscreen);
}
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 71c5d2662292..f20fbbb6019e 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -50,7 +50,7 @@ LOCAL_SRC_FILES:= \
android_view_Surface.cpp \
android_view_TextureView.cpp \
android_view_InputChannel.cpp \
- android_view_InputQueue.cpp \
+ android_view_InputEventReceiver.cpp \
android_view_KeyEvent.cpp \
android_view_KeyCharacterMap.cpp \
android_view_HardwareRenderer.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 6d1410cc84f6..c6447e198b17 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -168,7 +168,7 @@ extern int register_android_app_backup_FullBackup(JNIEnv *env);
extern int register_android_app_ActivityThread(JNIEnv *env);
extern int register_android_app_NativeActivity(JNIEnv *env);
extern int register_android_view_InputChannel(JNIEnv* env);
-extern int register_android_view_InputQueue(JNIEnv* env);
+extern int register_android_view_InputEventReceiver(JNIEnv* env);
extern int register_android_view_KeyEvent(JNIEnv* env);
extern int register_android_view_MotionEvent(JNIEnv* env);
extern int register_android_view_PointerIcon(JNIEnv* env);
@@ -1192,7 +1192,7 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_app_ActivityThread),
REG_JNI(register_android_app_NativeActivity),
REG_JNI(register_android_view_InputChannel),
- REG_JNI(register_android_view_InputQueue),
+ REG_JNI(register_android_view_InputEventReceiver),
REG_JNI(register_android_view_KeyEvent),
REG_JNI(register_android_view_MotionEvent),
REG_JNI(register_android_view_PointerIcon),
diff --git a/core/jni/android_view_InputEventReceiver.cpp b/core/jni/android_view_InputEventReceiver.cpp
new file mode 100644
index 000000000000..9ae63dd61db2
--- /dev/null
+++ b/core/jni/android_view_InputEventReceiver.cpp
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "InputEventReceiver"
+
+//#define LOG_NDEBUG 0
+
+// Log debug messages about the dispatch cycle.
+#define DEBUG_DISPATCH_CYCLE 0
+
+
+#include "JNIHelp.h"
+
+#include <android_runtime/AndroidRuntime.h>
+#include <utils/Log.h>
+#include <utils/Looper.h>
+#include <utils/KeyedVector.h>
+#include <utils/threads.h>
+#include <ui/InputTransport.h>
+#include "android_os_MessageQueue.h"
+#include "android_view_InputChannel.h"
+#include "android_view_KeyEvent.h"
+#include "android_view_MotionEvent.h"
+
+namespace android {
+
+static struct {
+ jclass clazz;
+
+ jmethodID dispatchInputEvent;
+} gInputEventReceiverClassInfo;
+
+
+class NativeInputEventReceiver : public RefBase {
+public:
+ NativeInputEventReceiver(JNIEnv* env,
+ jobject receiverObj, const sp<InputChannel>& inputChannel,
+ const sp<Looper>& looper);
+
+ status_t initialize();
+ status_t finishInputEvent(bool handled);
+ static int handleReceiveCallback(int receiveFd, int events, void* data);
+
+protected:
+ virtual ~NativeInputEventReceiver();
+
+private:
+ jobject mReceiverObjGlobal;
+ InputConsumer mInputConsumer;
+ sp<Looper> mLooper;
+ bool mEventInProgress;
+ PreallocatedInputEventFactory mInputEventFactory;
+
+ const char* getInputChannelName() {
+ return mInputConsumer.getChannel()->getName().string();
+ }
+};
+
+
+NativeInputEventReceiver::NativeInputEventReceiver(JNIEnv* env,
+ jobject receiverObj, const sp<InputChannel>& inputChannel, const sp<Looper>& looper) :
+ mReceiverObjGlobal(env->NewGlobalRef(receiverObj)),
+ mInputConsumer(inputChannel), mLooper(looper), mEventInProgress(false) {
+#if DEBUG_DISPATCH_CYCLE
+ LOGD("channel '%s' ~ Initializing input event receiver.", getInputChannelName());
+#endif
+}
+
+NativeInputEventReceiver::~NativeInputEventReceiver() {
+#if DEBUG_DISPATCH_CYCLE
+ LOGD("channel '%s' ~ Disposing input event receiver.", getInputChannelName());
+#endif
+
+ mLooper->removeFd(mInputConsumer.getChannel()->getReceivePipeFd());
+ if (mEventInProgress) {
+ mInputConsumer.sendFinishedSignal(false); // ignoring result
+ }
+
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ env->DeleteGlobalRef(mReceiverObjGlobal);
+}
+
+status_t NativeInputEventReceiver::initialize() {
+ status_t result = mInputConsumer.initialize();
+ if (result) {
+ LOGW("Failed to initialize input consumer for input channel '%s', status=%d",
+ getInputChannelName(), result);
+ return result;
+ }
+
+ int32_t receiveFd = mInputConsumer.getChannel()->getReceivePipeFd();
+ mLooper->addFd(receiveFd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
+ return OK;
+}
+
+status_t NativeInputEventReceiver::finishInputEvent(bool handled) {
+ if (mEventInProgress) {
+#if DEBUG_DISPATCH_CYCLE
+ LOGD("channel '%s' ~ Finished input event.", getInputChannelName());
+#endif
+ mEventInProgress = false;
+
+ status_t status = mInputConsumer.sendFinishedSignal(handled);
+ if (status) {
+ LOGW("Failed to send finished signal on channel '%s'. status=%d",
+ getInputChannelName(), status);
+ }
+ return status;
+ } else {
+ LOGW("Ignoring attempt to finish input event while no event is in progress.");
+ return OK;
+ }
+}
+
+int NativeInputEventReceiver::handleReceiveCallback(int receiveFd, int events, void* data) {
+ sp<NativeInputEventReceiver> r = static_cast<NativeInputEventReceiver*>(data);
+
+ if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
+ LOGE("channel '%s' ~ Publisher closed input channel or an error occurred. "
+ "events=0x%x", r->getInputChannelName(), events);
+ return 0; // remove the callback
+ }
+
+ if (!(events & ALOOPER_EVENT_INPUT)) {
+ LOGW("channel '%s' ~ Received spurious callback for unhandled poll event. "
+ "events=0x%x", r->getInputChannelName(), events);
+ return 1;
+ }
+
+ status_t status = r->mInputConsumer.receiveDispatchSignal();
+ if (status) {
+ LOGE("channel '%s' ~ Failed to receive dispatch signal. status=%d",
+ r->getInputChannelName(), status);
+ return 0; // remove the callback
+ }
+
+ if (r->mEventInProgress) {
+ LOGW("channel '%s' ~ Publisher sent spurious dispatch signal.",
+ r->getInputChannelName());
+ return 1;
+ }
+
+ InputEvent* inputEvent;
+ status = r->mInputConsumer.consume(&r->mInputEventFactory, &inputEvent);
+ if (status) {
+ LOGW("channel '%s' ~ Failed to consume input event. status=%d",
+ r->getInputChannelName(), status);
+ r->mInputConsumer.sendFinishedSignal(false);
+ return 1;
+ }
+
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ jobject inputEventObj;
+ switch (inputEvent->getType()) {
+ case AINPUT_EVENT_TYPE_KEY:
+#if DEBUG_DISPATCH_CYCLE
+ LOGD("channel '%s' ~ Received key event.",
+ r->getInputChannelName());
+#endif
+ inputEventObj = android_view_KeyEvent_fromNative(env,
+ static_cast<KeyEvent*>(inputEvent));
+ break;
+
+ case AINPUT_EVENT_TYPE_MOTION:
+#if DEBUG_DISPATCH_CYCLE
+ LOGD("channel '%s' ~ Received motion event.",
+ r->getInputChannelName());
+#endif
+ inputEventObj = android_view_MotionEvent_obtainAsCopy(env,
+ static_cast<MotionEvent*>(inputEvent));
+ break;
+
+ default:
+ assert(false); // InputConsumer should prevent this from ever happening
+ inputEventObj = NULL;
+ }
+
+ if (!inputEventObj) {
+ LOGW("channel '%s' ~ Failed to obtain event object.",
+ r->getInputChannelName());
+ r->mInputConsumer.sendFinishedSignal(false);
+ return 1;
+ }
+
+ r->mEventInProgress = true;
+
+#if DEBUG_DISPATCH_CYCLE
+ LOGD("channel '%s' ~ Invoking input handler.", r->getInputChannelName());
+#endif
+ env->CallVoidMethod(r->mReceiverObjGlobal,
+ gInputEventReceiverClassInfo.dispatchInputEvent, inputEventObj);
+#if DEBUG_DISPATCH_CYCLE
+ LOGD("channel '%s' ~ Returned from input handler.", r->getInputChannelName());
+#endif
+
+ if (env->ExceptionCheck()) {
+ LOGE("channel '%s' ~ An exception occurred while dispatching an event.",
+ r->getInputChannelName());
+ LOGE_EX(env);
+ env->ExceptionClear();
+
+ if (r->mEventInProgress) {
+ r->mInputConsumer.sendFinishedSignal(false);
+ r->mEventInProgress = false;
+ }
+ }
+
+ env->DeleteLocalRef(inputEventObj);
+ return 1;
+}
+
+
+static jint nativeInit(JNIEnv* env, jclass clazz, jobject receiverObj,
+ jobject inputChannelObj, jobject messageQueueObj) {
+ sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
+ inputChannelObj);
+ if (inputChannel == NULL) {
+ jniThrowRuntimeException(env, "InputChannel is not initialized.");
+ return 0;
+ }
+
+ sp<Looper> looper = android_os_MessageQueue_getLooper(env, messageQueueObj);
+ if (looper == NULL) {
+ jniThrowRuntimeException(env, "MessageQueue is not initialized.");
+ return 0;
+ }
+
+ sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env,
+ receiverObj, inputChannel, looper);
+ status_t status = receiver->initialize();
+ if (status) {
+ String8 message;
+ message.appendFormat("Failed to initialize input event receiver. status=%d", status);
+ jniThrowRuntimeException(env, message.string());
+ return 0;
+ }
+
+ receiver->incStrong(gInputEventReceiverClassInfo.clazz); // retain a reference for the object
+ return reinterpret_cast<jint>(receiver.get());
+}
+
+static void nativeDispose(JNIEnv* env, jclass clazz, jint receiverPtr) {
+ sp<NativeInputEventReceiver> receiver =
+ reinterpret_cast<NativeInputEventReceiver*>(receiverPtr);
+ receiver->decStrong(gInputEventReceiverClassInfo.clazz); // drop reference held by the object
+}
+
+static void nativeFinishInputEvent(JNIEnv* env, jclass clazz, jint receiverPtr, jboolean handled) {
+ sp<NativeInputEventReceiver> receiver =
+ reinterpret_cast<NativeInputEventReceiver*>(receiverPtr);
+ status_t status = receiver->finishInputEvent(handled);
+ if (status) {
+ String8 message;
+ message.appendFormat("Failed to finish input event. status=%d", status);
+ jniThrowRuntimeException(env, message.string());
+ }
+}
+
+
+static JNINativeMethod gMethods[] = {
+ /* name, signature, funcPtr */
+ { "nativeInit",
+ "(Landroid/view/InputEventReceiver;Landroid/view/InputChannel;Landroid/os/MessageQueue;)I",
+ (void*)nativeInit },
+ { "nativeDispose",
+ "(I)V",
+ (void*)nativeDispose },
+ { "nativeFinishInputEvent", "(IZ)V",
+ (void*)nativeFinishInputEvent }
+};
+
+#define FIND_CLASS(var, className) \
+ var = env->FindClass(className); \
+ LOG_FATAL_IF(! var, "Unable to find class " className); \
+ var = jclass(env->NewGlobalRef(var));
+
+#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
+ var = env->GetMethodID(clazz, methodName, methodDescriptor); \
+ LOG_FATAL_IF(! var, "Unable to find method " methodName);
+
+int register_android_view_InputEventReceiver(JNIEnv* env) {
+ int res = jniRegisterNativeMethods(env, "android/view/InputEventReceiver",
+ gMethods, NELEM(gMethods));
+ LOG_FATAL_IF(res < 0, "Unable to register native methods.");
+
+ FIND_CLASS(gInputEventReceiverClassInfo.clazz, "android/view/InputEventReceiver");
+
+ GET_METHOD_ID(gInputEventReceiverClassInfo.dispatchInputEvent,
+ gInputEventReceiverClassInfo.clazz,
+ "dispatchInputEvent", "(Landroid/view/InputEvent;)V");
+ return 0;
+}
+
+} // namespace android
diff --git a/core/jni/android_view_InputQueue.cpp b/core/jni/android_view_InputQueue.cpp
deleted file mode 100644
index 549f5750c39b..000000000000
--- a/core/jni/android_view_InputQueue.cpp
+++ /dev/null
@@ -1,522 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "InputQueue-JNI"
-
-//#define LOG_NDEBUG 0
-
-// Log debug messages about the dispatch cycle.
-#define DEBUG_DISPATCH_CYCLE 0
-
-// Log debug messages about registrations.
-#define DEBUG_REGISTRATION 0
-
-
-#include "JNIHelp.h"
-
-#include <android_runtime/AndroidRuntime.h>
-#include <utils/Log.h>
-#include <utils/Looper.h>
-#include <utils/KeyedVector.h>
-#include <utils/threads.h>
-#include <ui/InputTransport.h>
-#include "android_os_MessageQueue.h"
-#include "android_view_InputChannel.h"
-#include "android_view_KeyEvent.h"
-#include "android_view_MotionEvent.h"
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-static struct {
- jclass clazz;
-
- jmethodID dispatchInputEvent;
-} gInputQueueClassInfo;
-
-// ----------------------------------------------------------------------------
-
-class NativeInputQueue {
-public:
- NativeInputQueue();
- ~NativeInputQueue();
-
- status_t registerInputChannel(JNIEnv* env, jobject inputChannelObj,
- jobject inputHandlerObj, jobject messageQueueObj);
-
- status_t unregisterInputChannel(JNIEnv* env, jobject inputChannelObj);
-
- status_t finished(JNIEnv* env, jlong finishedToken, bool handled, bool ignoreSpuriousFinish);
-
-private:
- class Connection : public RefBase {
- protected:
- virtual ~Connection();
-
- public:
- enum Status {
- // Everything is peachy.
- STATUS_NORMAL,
- // The input channel has been unregistered.
- STATUS_ZOMBIE
- };
-
- Connection(uint16_t id,
- const sp<InputChannel>& inputChannel, const sp<Looper>& looper);
-
- inline const char* getInputChannelName() const { return inputChannel->getName().string(); }
-
- // A unique id for this connection.
- uint16_t id;
-
- Status status;
-
- sp<InputChannel> inputChannel;
- InputConsumer inputConsumer;
- sp<Looper> looper;
- jobject inputHandlerObjGlobal;
- PreallocatedInputEventFactory inputEventFactory;
-
- // The sequence number of the current event being dispatched.
- // This is used as part of the finished token as a way to determine whether the finished
- // token is still valid before sending a finished signal back to the publisher.
- uint16_t messageSeqNum;
-
- // True if a message has been received from the publisher but not yet finished.
- bool messageInProgress;
- };
-
- Mutex mLock;
- uint16_t mNextConnectionId;
- KeyedVector<int32_t, sp<Connection> > mConnectionsByReceiveFd;
-
- ssize_t getConnectionIndex(const sp<InputChannel>& inputChannel);
-
- static void handleInputChannelDisposed(JNIEnv* env,
- jobject inputChannelObj, const sp<InputChannel>& inputChannel, void* data);
-
- static int handleReceiveCallback(int receiveFd, int events, void* data);
-
- static jlong generateFinishedToken(int32_t receiveFd,
- uint16_t connectionId, uint16_t messageSeqNum);
-
- static void parseFinishedToken(jlong finishedToken,
- int32_t* outReceiveFd, uint16_t* outConnectionId, uint16_t* outMessageIndex);
-};
-
-// ----------------------------------------------------------------------------
-
-NativeInputQueue::NativeInputQueue() :
- mNextConnectionId(0) {
-}
-
-NativeInputQueue::~NativeInputQueue() {
-}
-
-status_t NativeInputQueue::registerInputChannel(JNIEnv* env, jobject inputChannelObj,
- jobject inputHandlerObj, jobject messageQueueObj) {
- sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
- inputChannelObj);
- if (inputChannel == NULL) {
- LOGW("Input channel is not initialized.");
- return BAD_VALUE;
- }
-
-#if DEBUG_REGISTRATION
- LOGD("channel '%s' - Registered", inputChannel->getName().string());
-#endif
-
- sp<Looper> looper = android_os_MessageQueue_getLooper(env, messageQueueObj);
-
- { // acquire lock
- AutoMutex _l(mLock);
-
- if (getConnectionIndex(inputChannel) >= 0) {
- LOGW("Attempted to register already registered input channel '%s'",
- inputChannel->getName().string());
- return BAD_VALUE;
- }
-
- uint16_t connectionId = mNextConnectionId++;
- sp<Connection> connection = new Connection(connectionId, inputChannel, looper);
- status_t result = connection->inputConsumer.initialize();
- if (result) {
- LOGW("Failed to initialize input consumer for input channel '%s', status=%d",
- inputChannel->getName().string(), result);
- return result;
- }
-
- connection->inputHandlerObjGlobal = env->NewGlobalRef(inputHandlerObj);
-
- int32_t receiveFd = inputChannel->getReceivePipeFd();
- mConnectionsByReceiveFd.add(receiveFd, connection);
-
- looper->addFd(receiveFd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
- } // release lock
-
- android_view_InputChannel_setDisposeCallback(env, inputChannelObj,
- handleInputChannelDisposed, this);
- return OK;
-}
-
-status_t NativeInputQueue::unregisterInputChannel(JNIEnv* env, jobject inputChannelObj) {
- sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
- inputChannelObj);
- if (inputChannel == NULL) {
- LOGW("Input channel is not initialized.");
- return BAD_VALUE;
- }
-
-#if DEBUG_REGISTRATION
- LOGD("channel '%s' - Unregistered", inputChannel->getName().string());
-#endif
-
- { // acquire lock
- AutoMutex _l(mLock);
-
- ssize_t connectionIndex = getConnectionIndex(inputChannel);
- if (connectionIndex < 0) {
- LOGW("Attempted to unregister already unregistered input channel '%s'",
- inputChannel->getName().string());
- return BAD_VALUE;
- }
-
- sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
- mConnectionsByReceiveFd.removeItemsAt(connectionIndex);
-
- connection->status = Connection::STATUS_ZOMBIE;
-
- connection->looper->removeFd(inputChannel->getReceivePipeFd());
-
- env->DeleteGlobalRef(connection->inputHandlerObjGlobal);
- connection->inputHandlerObjGlobal = NULL;
-
- if (connection->messageInProgress) {
- LOGI("Sending finished signal for input channel '%s' since it is being unregistered "
- "while an input message is still in progress.",
- connection->getInputChannelName());
- connection->messageInProgress = false;
- connection->inputConsumer.sendFinishedSignal(false); // ignoring result
- }
- } // release lock
-
- android_view_InputChannel_setDisposeCallback(env, inputChannelObj, NULL, NULL);
- return OK;
-}
-
-ssize_t NativeInputQueue::getConnectionIndex(const sp<InputChannel>& inputChannel) {
- ssize_t connectionIndex = mConnectionsByReceiveFd.indexOfKey(inputChannel->getReceivePipeFd());
- if (connectionIndex >= 0) {
- sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
- if (connection->inputChannel.get() == inputChannel.get()) {
- return connectionIndex;
- }
- }
-
- return -1;
-}
-
-status_t NativeInputQueue::finished(JNIEnv* env, jlong finishedToken,
- bool handled, bool ignoreSpuriousFinish) {
- int32_t receiveFd;
- uint16_t connectionId;
- uint16_t messageSeqNum;
- parseFinishedToken(finishedToken, &receiveFd, &connectionId, &messageSeqNum);
-
- { // acquire lock
- AutoMutex _l(mLock);
-
- ssize_t connectionIndex = mConnectionsByReceiveFd.indexOfKey(receiveFd);
- if (connectionIndex < 0) {
- if (! ignoreSpuriousFinish) {
- LOGI("Ignoring finish signal on channel that is no longer registered.");
- }
- return DEAD_OBJECT;
- }
-
- sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
- if (connectionId != connection->id) {
- if (! ignoreSpuriousFinish) {
- LOGI("Ignoring finish signal on channel that is no longer registered.");
- }
- return DEAD_OBJECT;
- }
-
- if (messageSeqNum != connection->messageSeqNum || ! connection->messageInProgress) {
- if (! ignoreSpuriousFinish) {
- LOGW("Attempted to finish input twice on channel '%s'. "
- "finished messageSeqNum=%d, current messageSeqNum=%d, messageInProgress=%d",
- connection->getInputChannelName(),
- messageSeqNum, connection->messageSeqNum, connection->messageInProgress);
- }
- return INVALID_OPERATION;
- }
-
- connection->messageInProgress = false;
-
- status_t status = connection->inputConsumer.sendFinishedSignal(handled);
- if (status) {
- LOGW("Failed to send finished signal on channel '%s'. status=%d",
- connection->getInputChannelName(), status);
- return status;
- }
-
-#if DEBUG_DISPATCH_CYCLE
- LOGD("channel '%s' ~ Finished event.",
- connection->getInputChannelName());
-#endif
- } // release lock
-
- return OK;
-}
-
-void NativeInputQueue::handleInputChannelDisposed(JNIEnv* env,
- jobject inputChannelObj, const sp<InputChannel>& inputChannel, void* data) {
- LOGW("Input channel object '%s' was disposed without first being unregistered with "
- "the input queue!", inputChannel->getName().string());
-
- NativeInputQueue* q = static_cast<NativeInputQueue*>(data);
- q->unregisterInputChannel(env, inputChannelObj);
-}
-
-int NativeInputQueue::handleReceiveCallback(int receiveFd, int events, void* data) {
- NativeInputQueue* q = static_cast<NativeInputQueue*>(data);
- JNIEnv* env = AndroidRuntime::getJNIEnv();
-
- sp<Connection> connection;
- InputEvent* inputEvent;
- jobject inputHandlerObjLocal;
- jlong finishedToken;
- { // acquire lock
- AutoMutex _l(q->mLock);
-
- ssize_t connectionIndex = q->mConnectionsByReceiveFd.indexOfKey(receiveFd);
- if (connectionIndex < 0) {
- LOGE("Received spurious receive callback for unknown input channel. "
- "fd=%d, events=0x%x", receiveFd, events);
- return 0; // remove the callback
- }
-
- connection = q->mConnectionsByReceiveFd.valueAt(connectionIndex);
- if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
- LOGE("channel '%s' ~ Publisher closed input channel or an error occurred. "
- "events=0x%x", connection->getInputChannelName(), events);
- return 0; // remove the callback
- }
-
- if (! (events & ALOOPER_EVENT_INPUT)) {
- LOGW("channel '%s' ~ Received spurious callback for unhandled poll event. "
- "events=0x%x", connection->getInputChannelName(), events);
- return 1;
- }
-
- status_t status = connection->inputConsumer.receiveDispatchSignal();
- if (status) {
- LOGE("channel '%s' ~ Failed to receive dispatch signal. status=%d",
- connection->getInputChannelName(), status);
- return 0; // remove the callback
- }
-
- if (connection->messageInProgress) {
- LOGW("channel '%s' ~ Publisher sent spurious dispatch signal.",
- connection->getInputChannelName());
- return 1;
- }
-
- status = connection->inputConsumer.consume(& connection->inputEventFactory, & inputEvent);
- if (status) {
- LOGW("channel '%s' ~ Failed to consume input event. status=%d",
- connection->getInputChannelName(), status);
- connection->inputConsumer.sendFinishedSignal(false);
- return 1;
- }
-
- connection->messageInProgress = true;
- connection->messageSeqNum += 1;
-
- finishedToken = generateFinishedToken(receiveFd, connection->id, connection->messageSeqNum);
-
- inputHandlerObjLocal = env->NewLocalRef(connection->inputHandlerObjGlobal);
- } // release lock
-
- // Invoke the handler outside of the lock.
- //
- // Note: inputEvent is stored in a field of the connection object which could potentially
- // become disposed due to the input channel being unregistered concurrently.
- // For this reason, we explicitly keep the connection object alive by holding
- // a strong pointer to it within this scope. We also grabbed a local reference to
- // the input handler object itself for the same reason.
-
- int32_t inputEventType = inputEvent->getType();
-
- jobject inputEventObj;
- switch (inputEventType) {
- case AINPUT_EVENT_TYPE_KEY:
-#if DEBUG_DISPATCH_CYCLE
- LOGD("channel '%s' ~ Received key event.", connection->getInputChannelName());
-#endif
- inputEventObj = android_view_KeyEvent_fromNative(env,
- static_cast<KeyEvent*>(inputEvent));
- break;
-
- case AINPUT_EVENT_TYPE_MOTION:
-#if DEBUG_DISPATCH_CYCLE
- LOGD("channel '%s' ~ Received motion event.", connection->getInputChannelName());
-#endif
- inputEventObj = android_view_MotionEvent_obtainAsCopy(env,
- static_cast<MotionEvent*>(inputEvent));
- break;
-
- default:
- assert(false); // InputConsumer should prevent this from ever happening
- inputEventObj = NULL;
- }
-
- if (! inputEventObj) {
- LOGW("channel '%s' ~ Failed to obtain DVM event object.",
- connection->getInputChannelName());
- env->DeleteLocalRef(inputHandlerObjLocal);
- q->finished(env, finishedToken, false, false);
- return 1;
- }
-
-#if DEBUG_DISPATCH_CYCLE
- LOGD("Invoking input handler.");
-#endif
- env->CallStaticVoidMethod(gInputQueueClassInfo.clazz,
- gInputQueueClassInfo.dispatchInputEvent, inputHandlerObjLocal, inputEventObj,
- jlong(finishedToken));
-#if DEBUG_DISPATCH_CYCLE
- LOGD("Returned from input handler.");
-#endif
-
- if (env->ExceptionCheck()) {
- LOGE("An exception occurred while invoking the input handler for an event.");
- LOGE_EX(env);
- env->ExceptionClear();
-
- q->finished(env, finishedToken, false, true /*ignoreSpuriousFinish*/);
- }
-
- env->DeleteLocalRef(inputEventObj);
- env->DeleteLocalRef(inputHandlerObjLocal);
- return 1;
-}
-
-jlong NativeInputQueue::generateFinishedToken(int32_t receiveFd, uint16_t connectionId,
- uint16_t messageSeqNum) {
- return (jlong(receiveFd) << 32) | (jlong(connectionId) << 16) | jlong(messageSeqNum);
-}
-
-void NativeInputQueue::parseFinishedToken(jlong finishedToken,
- int32_t* outReceiveFd, uint16_t* outConnectionId, uint16_t* outMessageIndex) {
- *outReceiveFd = int32_t(finishedToken >> 32);
- *outConnectionId = uint16_t(finishedToken >> 16);
- *outMessageIndex = uint16_t(finishedToken);
-}
-
-// ----------------------------------------------------------------------------
-
-NativeInputQueue::Connection::Connection(uint16_t id,
- const sp<InputChannel>& inputChannel, const sp<Looper>& looper) :
- id(id), status(STATUS_NORMAL), inputChannel(inputChannel), inputConsumer(inputChannel),
- looper(looper), inputHandlerObjGlobal(NULL),
- messageSeqNum(0), messageInProgress(false) {
-}
-
-NativeInputQueue::Connection::~Connection() {
-}
-
-// ----------------------------------------------------------------------------
-
-static NativeInputQueue gNativeInputQueue;
-
-static void android_view_InputQueue_nativeRegisterInputChannel(JNIEnv* env, jclass clazz,
- jobject inputChannelObj, jobject inputHandlerObj, jobject messageQueueObj) {
- status_t status = gNativeInputQueue.registerInputChannel(
- env, inputChannelObj, inputHandlerObj, messageQueueObj);
-
- if (status) {
- String8 message;
- message.appendFormat("Failed to register input channel. status=%d", status);
- jniThrowRuntimeException(env, message.string());
- }
-}
-
-static void android_view_InputQueue_nativeUnregisterInputChannel(JNIEnv* env, jclass clazz,
- jobject inputChannelObj) {
- status_t status = gNativeInputQueue.unregisterInputChannel(env, inputChannelObj);
-
- if (status) {
- String8 message;
- message.appendFormat("Failed to unregister input channel. status=%d", status);
- jniThrowRuntimeException(env, message.string());
- }
-}
-
-static void android_view_InputQueue_nativeFinished(JNIEnv* env, jclass clazz,
- jlong finishedToken, bool handled) {
- status_t status = gNativeInputQueue.finished(
- env, finishedToken, handled, false /*ignoreSpuriousFinish*/);
-
- // We ignore the case where an event could not be finished because the input channel
- // was no longer registered (DEAD_OBJECT) since it is a common race that can occur
- // during application shutdown. The input dispatcher recovers gracefully anyways.
- if (status != OK && status != DEAD_OBJECT) {
- String8 message;
- message.appendFormat("Failed to finish input event. status=%d", status);
- jniThrowRuntimeException(env, message.string());
- }
-}
-
-// ----------------------------------------------------------------------------
-
-static JNINativeMethod gInputQueueMethods[] = {
- /* name, signature, funcPtr */
- { "nativeRegisterInputChannel",
- "(Landroid/view/InputChannel;Landroid/view/InputHandler;Landroid/os/MessageQueue;)V",
- (void*)android_view_InputQueue_nativeRegisterInputChannel },
- { "nativeUnregisterInputChannel",
- "(Landroid/view/InputChannel;)V",
- (void*)android_view_InputQueue_nativeUnregisterInputChannel },
- { "nativeFinished", "(JZ)V",
- (void*)android_view_InputQueue_nativeFinished }
-};
-
-#define FIND_CLASS(var, className) \
- var = env->FindClass(className); \
- LOG_FATAL_IF(! var, "Unable to find class " className); \
- var = jclass(env->NewGlobalRef(var));
-
-#define GET_STATIC_METHOD_ID(var, clazz, methodName, methodDescriptor) \
- var = env->GetStaticMethodID(clazz, methodName, methodDescriptor); \
- LOG_FATAL_IF(! var, "Unable to find static method " methodName);
-
-int register_android_view_InputQueue(JNIEnv* env) {
- int res = jniRegisterNativeMethods(env, "android/view/InputQueue",
- gInputQueueMethods, NELEM(gInputQueueMethods));
- LOG_FATAL_IF(res < 0, "Unable to register native methods.");
-
- FIND_CLASS(gInputQueueClassInfo.clazz, "android/view/InputQueue");
-
- GET_STATIC_METHOD_ID(gInputQueueClassInfo.dispatchInputEvent, gInputQueueClassInfo.clazz,
- "dispatchInputEvent",
- "(Landroid/view/InputHandler;Landroid/view/InputEvent;J)V");
- return 0;
-}
-
-} // namespace android
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 08cef011f57d..e6b86fcf7c5f 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -45,6 +45,7 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.IRemoteCallback;
import android.os.LocalPowerManager;
+import android.os.Looper;
import android.os.Message;
import android.os.Messenger;
import android.os.PowerManager;
@@ -75,8 +76,7 @@ import android.view.IWindowManager;
import android.view.InputChannel;
import android.view.InputDevice;
import android.view.InputEvent;
-import android.view.InputQueue;
-import android.view.InputHandler;
+import android.view.InputEventReceiver;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -345,10 +345,13 @@ public class PhoneWindowManager implements WindowManagerPolicy {
WindowState mFocusedWindow;
IApplicationToken mFocusedApp;
- private final InputHandler mPointerLocationInputHandler = new InputHandler() {
+ final class PointerLocationInputEventReceiver extends InputEventReceiver {
+ public PointerLocationInputEventReceiver(InputChannel inputChannel, Looper looper) {
+ super(inputChannel, looper);
+ }
+
@Override
- public void handleInputEvent(InputEvent event,
- InputQueue.FinishedCallback finishedCallback) {
+ public void onInputEvent(InputEvent event) {
boolean handled = false;
try {
if (event instanceof MotionEvent
@@ -362,11 +365,12 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
} finally {
- finishedCallback.finished(handled);
+ finishInputEvent(event, handled);
}
}
- };
-
+ }
+ PointerLocationInputEventReceiver mPointerLocationInputEventReceiver;
+
// The current size of the screen; really; (ir)regardless of whether the status
// bar can be hidden or not
int mUnrestrictedScreenLeft, mUnrestrictedScreenTop;
@@ -1003,9 +1007,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
if (mPointerLocationInputChannel == null) {
try {
mPointerLocationInputChannel =
- mWindowManager.monitorInput("PointerLocationView");
- InputQueue.registerInputChannel(mPointerLocationInputChannel,
- mPointerLocationInputHandler, mHandler.getLooper().getQueue());
+ mWindowManager.monitorInput("PointerLocationView");
+ mPointerLocationInputEventReceiver =
+ new PointerLocationInputEventReceiver(
+ mPointerLocationInputChannel, mHandler.getLooper());
} catch (RemoteException ex) {
Slog.e(TAG, "Could not set up input monitoring channel for PointerLocation.",
ex);
@@ -1013,8 +1018,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
if (removeView != null) {
+ if (mPointerLocationInputEventReceiver != null) {
+ mPointerLocationInputEventReceiver.dispose();
+ mPointerLocationInputEventReceiver = null;
+ }
if (mPointerLocationInputChannel != null) {
- InputQueue.unregisterInputChannel(mPointerLocationInputChannel);
mPointerLocationInputChannel.dispose();
mPointerLocationInputChannel = null;
}
@@ -1839,10 +1847,13 @@ public class PhoneWindowManager implements WindowManagerPolicy {
* to determine when the nav bar should be shown and prevent applications from
* receiving those touches.
*/
- final InputHandler mHideNavInputHandler = new InputHandler() {
+ final class HideNavInputEventReceiver extends InputEventReceiver {
+ public HideNavInputEventReceiver(InputChannel inputChannel, Looper looper) {
+ super(inputChannel, looper);
+ }
+
@Override
- public void handleInputEvent(InputEvent event,
- InputQueue.FinishedCallback finishedCallback) {
+ public void onInputEvent(InputEvent event) {
boolean handled = false;
try {
if (event instanceof MotionEvent
@@ -1885,9 +1896,17 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
} finally {
- finishedCallback.finished(handled);
+ finishInputEvent(event, handled);
}
}
+ }
+ final InputEventReceiver.Factory mHideNavInputEventReceiverFactory =
+ new InputEventReceiver.Factory() {
+ @Override
+ public InputEventReceiver createInputEventReceiver(
+ InputChannel inputChannel, Looper looper) {
+ return new HideNavInputEventReceiver(inputChannel, looper);
+ }
};
@Override
@@ -1951,7 +1970,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
} else if (mHideNavFakeWindow == null) {
mHideNavFakeWindow = mWindowManagerFuncs.addFakeWindow(
- mHandler.getLooper(), mHideNavInputHandler,
+ mHandler.getLooper(), mHideNavInputEventReceiverFactory,
"hidden nav", WindowManager.LayoutParams.TYPE_HIDDEN_NAV_CONSUMER,
0, false, false, true);
}
diff --git a/services/java/com/android/server/wm/DragState.java b/services/java/com/android/server/wm/DragState.java
index 73cd64e9f735..a19035afabae 100644
--- a/services/java/com/android/server/wm/DragState.java
+++ b/services/java/com/android/server/wm/DragState.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import com.android.server.wm.WindowManagerService.DragInputEventReceiver;
import com.android.server.wm.WindowManagerService.H;
import android.content.ClipData;
@@ -28,7 +29,6 @@ import android.os.RemoteException;
import android.util.Slog;
import android.view.DragEvent;
import android.view.InputChannel;
-import android.view.InputQueue;
import android.view.Surface;
import android.view.View;
import android.view.WindowManager;
@@ -50,6 +50,7 @@ class DragState {
float mCurrentX, mCurrentY;
float mThumbOffsetX, mThumbOffsetY;
InputChannel mServerChannel, mClientChannel;
+ DragInputEventReceiver mInputEventReceiver;
InputApplicationHandle mDragApplicationHandle;
InputWindowHandle mDragWindowHandle;
WindowState mTargetWindow;
@@ -90,8 +91,8 @@ class DragState {
mServerChannel = channels[0];
mClientChannel = channels[1];
mService.mInputManager.registerInputChannel(mServerChannel, null);
- InputQueue.registerInputChannel(mClientChannel, mService.mDragInputHandler,
- mService.mH.getLooper().getQueue());
+ mInputEventReceiver = mService.new DragInputEventReceiver(mClientChannel,
+ mService.mH.getLooper());
mDragApplicationHandle = new InputApplicationHandle(null);
mDragApplicationHandle.name = "drag";
@@ -139,7 +140,8 @@ class DragState {
Slog.e(WindowManagerService.TAG, "Unregister of nonexistent drag input channel");
} else {
mService.mInputManager.unregisterInputChannel(mServerChannel);
- InputQueue.unregisterInputChannel(mClientChannel);
+ mInputEventReceiver.dispose();
+ mInputEventReceiver = null;
mClientChannel.dispose();
mServerChannel.dispose();
mClientChannel = null;
diff --git a/services/java/com/android/server/wm/FakeWindowImpl.java b/services/java/com/android/server/wm/FakeWindowImpl.java
index 0e72f7d989a2..121ce1861bd4 100644
--- a/services/java/com/android/server/wm/FakeWindowImpl.java
+++ b/services/java/com/android/server/wm/FakeWindowImpl.java
@@ -20,7 +20,7 @@ import android.os.Looper;
import android.os.Process;
import android.util.Slog;
import android.view.InputChannel;
-import android.view.InputHandler;
+import android.view.InputEventReceiver;
import android.view.InputQueue;
import android.view.WindowManagerPolicy;
@@ -29,11 +29,13 @@ public final class FakeWindowImpl implements WindowManagerPolicy.FakeWindow {
final InputChannel mServerChannel, mClientChannel;
final InputApplicationHandle mApplicationHandle;
final InputWindowHandle mWindowHandle;
+ final InputEventReceiver mInputEventReceiver;
final int mWindowLayer;
boolean mTouchFullscreen;
- public FakeWindowImpl(WindowManagerService service, Looper looper, InputHandler inputHandler,
+ public FakeWindowImpl(WindowManagerService service,
+ Looper looper, InputEventReceiver.Factory inputEventReceiverFactory,
String name, int windowType, int layoutParamsFlags, boolean canReceiveKeys,
boolean hasFocus, boolean touchFullscreen) {
mService = service;
@@ -42,7 +44,9 @@ public final class FakeWindowImpl implements WindowManagerPolicy.FakeWindow {
mServerChannel = channels[0];
mClientChannel = channels[1];
mService.mInputManager.registerInputChannel(mServerChannel, null);
- InputQueue.registerInputChannel(mClientChannel, inputHandler, looper.getQueue());
+
+ mInputEventReceiver = inputEventReceiverFactory.createInputEventReceiver(
+ mClientChannel, looper);
mApplicationHandle = new InputApplicationHandle(null);
mApplicationHandle.name = name;
@@ -87,8 +91,8 @@ public final class FakeWindowImpl implements WindowManagerPolicy.FakeWindow {
public void dismiss() {
synchronized (mService.mWindowMap) {
if (mService.removeFakeWindowLocked(this)) {
+ mInputEventReceiver.dispose();
mService.mInputManager.unregisterInputChannel(mServerChannel);
- InputQueue.unregisterInputChannel(mClientChannel);
mClientChannel.dispose();
mServerChannel.dispose();
}
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index d7dcacb71df9..75ace4f3082f 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -106,8 +106,7 @@ import android.view.IWindowSession;
import android.view.InputChannel;
import android.view.InputDevice;
import android.view.InputEvent;
-import android.view.InputHandler;
-import android.view.InputQueue;
+import android.view.InputEventReceiver;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.Surface;
@@ -570,10 +569,14 @@ public class WindowManagerService extends IWindowManager.Stub
boolean mTurnOnScreen;
DragState mDragState = null;
- final InputHandler mDragInputHandler = new InputHandler() {
+
+ final class DragInputEventReceiver extends InputEventReceiver {
+ public DragInputEventReceiver(InputChannel inputChannel, Looper looper) {
+ super(inputChannel, looper);
+ }
+
@Override
- public void handleInputEvent(InputEvent event,
- InputQueue.FinishedCallback finishedCallback) {
+ public void onInputEvent(InputEvent event) {
boolean handled = false;
try {
if (event instanceof MotionEvent
@@ -625,10 +628,10 @@ public class WindowManagerService extends IWindowManager.Stub
} catch (Exception e) {
Slog.e(TAG, "Exception caught by drag handleMotion", e);
} finally {
- finishedCallback.finished(handled);
+ finishInputEvent(event, handled);
}
}
- };
+ }
/**
* Whether the UI is currently running in touch mode (not showing
@@ -9380,11 +9383,13 @@ public class WindowManagerService extends IWindowManager.Stub
}
@Override
- public FakeWindow addFakeWindow(Looper looper, InputHandler inputHandler,
+ public FakeWindow addFakeWindow(Looper looper,
+ InputEventReceiver.Factory inputEventReceiverFactory,
String name, int windowType, int layoutParamsFlags, boolean canReceiveKeys,
boolean hasFocus, boolean touchFullscreen) {
synchronized (mWindowMap) {
- FakeWindowImpl fw = new FakeWindowImpl(this, looper, inputHandler, name, windowType,
+ FakeWindowImpl fw = new FakeWindowImpl(this, looper, inputEventReceiverFactory,
+ name, windowType,
layoutParamsFlags, canReceiveKeys, hasFocus, touchFullscreen);
int i=0;
while (i<mFakeWindows.size()) {