132cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown/* 232cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown * Copyright (C) 2011 The Android Open Source Project 332cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown * 432cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown * Licensed under the Apache License, Version 2.0 (the "License"); 532cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown * you may not use this file except in compliance with the License. 632cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown * You may obtain a copy of the License at 732cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown * 832cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown * http://www.apache.org/licenses/LICENSE-2.0 932cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown * 1032cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown * Unless required by applicable law or agreed to in writing, software 1132cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown * distributed under the License is distributed on an "AS IS" BASIS, 1232cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1332cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown * See the License for the specific language governing permissions and 1432cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown * limitations under the License. 1532cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown */ 1632cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown 1732cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brownpackage android.view; 1832cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown 1932cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brownimport dalvik.system.CloseGuard; 2032cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown 2132cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brownimport android.os.Looper; 2232cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brownimport android.os.MessageQueue; 2332cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brownimport android.util.Log; 24072ec96a4900d4616574733646ee46311cb5d2cbJeff Brownimport android.util.SparseIntArray; 2532cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown 2632cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown/** 2732cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown * Provides a low-level mechanism for an application to receive input events. 2832cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown * @hide 2932cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown */ 3032cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brownpublic abstract class InputEventReceiver { 3132cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown private static final String TAG = "InputEventReceiver"; 3232cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown 3332cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown private final CloseGuard mCloseGuard = CloseGuard.get(); 3432cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown 3532cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown private int mReceiverPtr; 3632cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown 3732cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown // We keep references to the input channel and message queue objects here so that 3832cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown // they are not GC'd while the native peer of the receiver is using them. 3932cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown private InputChannel mInputChannel; 4032cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown private MessageQueue mMessageQueue; 4132cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown 42072ec96a4900d4616574733646ee46311cb5d2cbJeff Brown // Map from InputEvent sequence numbers to dispatcher sequence numbers. 43072ec96a4900d4616574733646ee46311cb5d2cbJeff Brown private final SparseIntArray mSeqMap = new SparseIntArray(); 4432cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown 4532cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown private static native int nativeInit(InputEventReceiver receiver, 4632cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown InputChannel inputChannel, MessageQueue messageQueue); 4732cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown private static native void nativeDispose(int receiverPtr); 48072ec96a4900d4616574733646ee46311cb5d2cbJeff Brown private static native void nativeFinishInputEvent(int receiverPtr, int seq, boolean handled); 49771526c88f5cc4b56a41cb12aa06a28d377a07d5Jeff Brown private static native void nativeConsumeBatchedInputEvents(int receiverPtr, 50771526c88f5cc4b56a41cb12aa06a28d377a07d5Jeff Brown long frameTimeNanos); 5132cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown 5232cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown /** 5332cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown * Creates an input event receiver bound to the specified input channel. 5432cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown * 5532cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown * @param inputChannel The input channel. 5632cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown * @param looper The looper to use when invoking callbacks. 5732cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown */ 5832cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown public InputEventReceiver(InputChannel inputChannel, Looper looper) { 5932cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown if (inputChannel == null) { 6032cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown throw new IllegalArgumentException("inputChannel must not be null"); 6132cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown } 6232cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown if (looper == null) { 6332cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown throw new IllegalArgumentException("looper must not be null"); 6432cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown } 6532cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown 6632cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown mInputChannel = inputChannel; 6732cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown mMessageQueue = looper.getQueue(); 6832cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown mReceiverPtr = nativeInit(this, inputChannel, mMessageQueue); 6932cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown 7032cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown mCloseGuard.open("dispose"); 7132cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown } 7232cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown 7332cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown @Override 7432cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown protected void finalize() throws Throwable { 7532cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown try { 763e7e7f025e8d7dc6ab8c361118c8e949bdf3e451Jeff Brown dispose(true); 7732cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown } finally { 7832cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown super.finalize(); 7932cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown } 8032cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown } 8132cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown 8232cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown /** 8332cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown * Disposes the receiver. 8432cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown */ 8532cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown public void dispose() { 863e7e7f025e8d7dc6ab8c361118c8e949bdf3e451Jeff Brown dispose(false); 873e7e7f025e8d7dc6ab8c361118c8e949bdf3e451Jeff Brown } 883e7e7f025e8d7dc6ab8c361118c8e949bdf3e451Jeff Brown 893e7e7f025e8d7dc6ab8c361118c8e949bdf3e451Jeff Brown private void dispose(boolean finalized) { 9032cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown if (mCloseGuard != null) { 913e7e7f025e8d7dc6ab8c361118c8e949bdf3e451Jeff Brown if (finalized) { 923e7e7f025e8d7dc6ab8c361118c8e949bdf3e451Jeff Brown mCloseGuard.warnIfOpen(); 933e7e7f025e8d7dc6ab8c361118c8e949bdf3e451Jeff Brown } 9432cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown mCloseGuard.close(); 9532cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown } 963e7e7f025e8d7dc6ab8c361118c8e949bdf3e451Jeff Brown 9732cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown if (mReceiverPtr != 0) { 9832cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown nativeDispose(mReceiverPtr); 9932cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown mReceiverPtr = 0; 10032cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown } 10132cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown mInputChannel = null; 10232cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown mMessageQueue = null; 10332cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown } 10432cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown 10532cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown /** 10632cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown * Called when an input event is received. 10732cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown * The recipient should process the input event and then call {@link #finishInputEvent} 10832cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown * to indicate whether the event was handled. No new input events will be received 10932cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown * until {@link #finishInputEvent} is called. 11032cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown * 11132cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown * @param event The input event that was received. 11232cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown */ 11332cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown public void onInputEvent(InputEvent event) { 11432cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown finishInputEvent(event, false); 11532cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown } 11632cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown 11732cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown /** 118072ec96a4900d4616574733646ee46311cb5d2cbJeff Brown * Called when a batched input event is pending. 119072ec96a4900d4616574733646ee46311cb5d2cbJeff Brown * 120072ec96a4900d4616574733646ee46311cb5d2cbJeff Brown * The batched input event will continue to accumulate additional movement 121072ec96a4900d4616574733646ee46311cb5d2cbJeff Brown * samples until the recipient calls {@link #consumeBatchedInputEvents} or 122072ec96a4900d4616574733646ee46311cb5d2cbJeff Brown * an event is received that ends the batch and causes it to be consumed 123072ec96a4900d4616574733646ee46311cb5d2cbJeff Brown * immediately (such as a pointer up event). 124072ec96a4900d4616574733646ee46311cb5d2cbJeff Brown */ 125072ec96a4900d4616574733646ee46311cb5d2cbJeff Brown public void onBatchedInputEventPending() { 126771526c88f5cc4b56a41cb12aa06a28d377a07d5Jeff Brown consumeBatchedInputEvents(-1); 127072ec96a4900d4616574733646ee46311cb5d2cbJeff Brown } 128072ec96a4900d4616574733646ee46311cb5d2cbJeff Brown 129072ec96a4900d4616574733646ee46311cb5d2cbJeff Brown /** 13032cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown * Finishes an input event and indicates whether it was handled. 131072ec96a4900d4616574733646ee46311cb5d2cbJeff Brown * Must be called on the same Looper thread to which the receiver is attached. 13232cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown * 13332cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown * @param event The input event that was finished. 13432cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown * @param handled True if the event was handled. 13532cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown */ 136072ec96a4900d4616574733646ee46311cb5d2cbJeff Brown public final void finishInputEvent(InputEvent event, boolean handled) { 13732cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown if (event == null) { 13832cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown throw new IllegalArgumentException("event must not be null"); 13932cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown } 14032cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown if (mReceiverPtr == 0) { 14132cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown Log.w(TAG, "Attempted to finish an input event but the input event " 14232cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown + "receiver has already been disposed."); 14332cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown } else { 144072ec96a4900d4616574733646ee46311cb5d2cbJeff Brown int index = mSeqMap.indexOfKey(event.getSequenceNumber()); 145072ec96a4900d4616574733646ee46311cb5d2cbJeff Brown if (index < 0) { 14632cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown Log.w(TAG, "Attempted to finish an input event that is not in progress."); 14732cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown } else { 148072ec96a4900d4616574733646ee46311cb5d2cbJeff Brown int seq = mSeqMap.valueAt(index); 149072ec96a4900d4616574733646ee46311cb5d2cbJeff Brown mSeqMap.removeAt(index); 150072ec96a4900d4616574733646ee46311cb5d2cbJeff Brown nativeFinishInputEvent(mReceiverPtr, seq, handled); 15132cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown } 15232cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown } 15392cc2d8dc35f2bdd1bb95ab24787066371064899Jeff Brown event.recycleIfNeededAfterDispatch(); 15432cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown } 15532cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown 156072ec96a4900d4616574733646ee46311cb5d2cbJeff Brown /** 157072ec96a4900d4616574733646ee46311cb5d2cbJeff Brown * Consumes all pending batched input events. 158072ec96a4900d4616574733646ee46311cb5d2cbJeff Brown * Must be called on the same Looper thread to which the receiver is attached. 159072ec96a4900d4616574733646ee46311cb5d2cbJeff Brown * 160072ec96a4900d4616574733646ee46311cb5d2cbJeff Brown * This method forces all batched input events to be delivered immediately. 161072ec96a4900d4616574733646ee46311cb5d2cbJeff Brown * Should be called just before animating or drawing a new frame in the UI. 162771526c88f5cc4b56a41cb12aa06a28d377a07d5Jeff Brown * 163771526c88f5cc4b56a41cb12aa06a28d377a07d5Jeff Brown * @param frameTimeNanos The time in the {@link System#nanoTime()} time base 164771526c88f5cc4b56a41cb12aa06a28d377a07d5Jeff Brown * when the current display frame started rendering, or -1 if unknown. 165072ec96a4900d4616574733646ee46311cb5d2cbJeff Brown */ 166771526c88f5cc4b56a41cb12aa06a28d377a07d5Jeff Brown public final void consumeBatchedInputEvents(long frameTimeNanos) { 167072ec96a4900d4616574733646ee46311cb5d2cbJeff Brown if (mReceiverPtr == 0) { 168072ec96a4900d4616574733646ee46311cb5d2cbJeff Brown Log.w(TAG, "Attempted to consume batched input events but the input event " 169072ec96a4900d4616574733646ee46311cb5d2cbJeff Brown + "receiver has already been disposed."); 170072ec96a4900d4616574733646ee46311cb5d2cbJeff Brown } else { 171771526c88f5cc4b56a41cb12aa06a28d377a07d5Jeff Brown nativeConsumeBatchedInputEvents(mReceiverPtr, frameTimeNanos); 172072ec96a4900d4616574733646ee46311cb5d2cbJeff Brown } 173072ec96a4900d4616574733646ee46311cb5d2cbJeff Brown } 174072ec96a4900d4616574733646ee46311cb5d2cbJeff Brown 17532cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown // Called from native code. 17632cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown @SuppressWarnings("unused") 177072ec96a4900d4616574733646ee46311cb5d2cbJeff Brown private void dispatchInputEvent(int seq, InputEvent event) { 178072ec96a4900d4616574733646ee46311cb5d2cbJeff Brown mSeqMap.put(event.getSequenceNumber(), seq); 17932cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown onInputEvent(event); 18032cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown } 18132cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown 182072ec96a4900d4616574733646ee46311cb5d2cbJeff Brown // Called from native code. 183072ec96a4900d4616574733646ee46311cb5d2cbJeff Brown @SuppressWarnings("unused") 184072ec96a4900d4616574733646ee46311cb5d2cbJeff Brown private void dispatchBatchedInputEventPending() { 185072ec96a4900d4616574733646ee46311cb5d2cbJeff Brown onBatchedInputEventPending(); 186072ec96a4900d4616574733646ee46311cb5d2cbJeff Brown } 187072ec96a4900d4616574733646ee46311cb5d2cbJeff Brown 18832cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown public static interface Factory { 18932cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown public InputEventReceiver createInputEventReceiver( 19032cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown InputChannel inputChannel, Looper looper); 19132cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown } 19232cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown} 193