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