Loading core/java/android/service/wallpaper/WallpaperService.java +23 −14 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -229,22 +228,27 @@ 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 Loading Loading @@ -534,6 +538,8 @@ public abstract class WallpaperService extends Service { } Message msg = mCaller.obtainMessageO(MSG_TOUCH_EVENT, event); mCaller.sendMessage(msg); } else { event.recycle(); } } Loading Loading @@ -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(); Loading Loading @@ -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); Loading Loading @@ -970,6 +977,8 @@ public abstract class WallpaperService extends Service { public void dispatchPointer(MotionEvent event) { if (mEngine != null) { mEngine.dispatchPointer(event); } else { event.recycle(); } } Loading core/java/android/view/InputEvent.java +55 −2 Original line number Diff line number Diff line Loading @@ -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. */ Loading @@ -28,7 +30,20 @@ public abstract class InputEvent implements Parcelable { /** @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(); } /** Loading Loading @@ -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 Loading Loading @@ -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; } Loading core/java/android/view/InputEventConsistencyVerifier.java +6 −5 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; } Loading core/java/android/view/InputEventReceiver.java 0 → 100644 +151 −0 Original line number Diff line number Diff line /* * 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); } } core/java/android/view/InputHandler.javadeleted 100644 → 0 +0 −35 Original line number Diff line number Diff line /* * 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); } } Loading
core/java/android/service/wallpaper/WallpaperService.java +23 −14 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -229,22 +228,27 @@ 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 Loading Loading @@ -534,6 +538,8 @@ public abstract class WallpaperService extends Service { } Message msg = mCaller.obtainMessageO(MSG_TOUCH_EVENT, event); mCaller.sendMessage(msg); } else { event.recycle(); } } Loading Loading @@ -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(); Loading Loading @@ -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); Loading Loading @@ -970,6 +977,8 @@ public abstract class WallpaperService extends Service { public void dispatchPointer(MotionEvent event) { if (mEngine != null) { mEngine.dispatchPointer(event); } else { event.recycle(); } } Loading
core/java/android/view/InputEvent.java +55 −2 Original line number Diff line number Diff line Loading @@ -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. */ Loading @@ -28,7 +30,20 @@ public abstract class InputEvent implements Parcelable { /** @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(); } /** Loading Loading @@ -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 Loading Loading @@ -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; } Loading
core/java/android/view/InputEventConsistencyVerifier.java +6 −5 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; } Loading
core/java/android/view/InputEventReceiver.java 0 → 100644 +151 −0 Original line number Diff line number Diff line /* * 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); } }
core/java/android/view/InputHandler.javadeleted 100644 → 0 +0 −35 Original line number Diff line number Diff line /* * 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); } }