InputEventSender.java revision c28867a1d67121ce5963de135e3ae2b1dbd9a33d
1/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.view;
18
19import dalvik.system.CloseGuard;
20
21import android.os.Looper;
22import android.os.MessageQueue;
23import android.util.Log;
24
25/**
26 * Provides a low-level mechanism for an application to send input events.
27 * @hide
28 */
29public abstract class InputEventSender {
30    private static final String TAG = "InputEventSender";
31
32    private final CloseGuard mCloseGuard = CloseGuard.get();
33
34    private int mSenderPtr;
35
36    // We keep references to the input channel and message queue objects here so that
37    // they are not GC'd while the native peer of the receiver is using them.
38    private InputChannel mInputChannel;
39    private MessageQueue mMessageQueue;
40
41    private static native int nativeInit(InputEventSender sender,
42            InputChannel inputChannel, MessageQueue messageQueue);
43    private static native void nativeDispose(int senderPtr);
44    private static native boolean nativeSendKeyEvent(int senderPtr, int seq, KeyEvent event);
45    private static native boolean nativeSendMotionEvent(int senderPtr, int seq, MotionEvent event);
46
47    /**
48     * Creates an input event sender bound to the specified input channel.
49     *
50     * @param inputChannel The input channel.
51     * @param looper The looper to use when invoking callbacks.
52     */
53    public InputEventSender(InputChannel inputChannel, Looper looper) {
54        if (inputChannel == null) {
55            throw new IllegalArgumentException("inputChannel must not be null");
56        }
57        if (looper == null) {
58            throw new IllegalArgumentException("looper must not be null");
59        }
60
61        mInputChannel = inputChannel;
62        mMessageQueue = looper.getQueue();
63        mSenderPtr = nativeInit(this, inputChannel, mMessageQueue);
64
65        mCloseGuard.open("dispose");
66    }
67
68    @Override
69    protected void finalize() throws Throwable {
70        try {
71            dispose(true);
72        } finally {
73            super.finalize();
74        }
75    }
76
77    /**
78     * Disposes the receiver.
79     */
80    public void dispose() {
81        dispose(false);
82    }
83
84    private void dispose(boolean finalized) {
85        if (mCloseGuard != null) {
86            if (finalized) {
87                mCloseGuard.warnIfOpen();
88            }
89            mCloseGuard.close();
90        }
91
92        if (mSenderPtr != 0) {
93            nativeDispose(mSenderPtr);
94            mSenderPtr = 0;
95        }
96        mInputChannel = null;
97        mMessageQueue = null;
98    }
99
100    /**
101     * Called when an input event is finished.
102     *
103     * @param seq The input event sequence number.
104     * @param handled True if the input event was handled.
105     */
106    public void onInputEventFinished(int seq, boolean handled) {
107    }
108
109    /**
110     * Sends an input event.
111     * Must be called on the same Looper thread to which the sender is attached.
112     *
113     * @param seq The input event sequence number.
114     * @param event The input event to send.
115     * @return True if the entire event was sent successfully.  May return false
116     * if the input channel buffer filled before all samples were dispatched.
117     */
118    public final boolean sendInputEvent(int seq, InputEvent event) {
119        if (event == null) {
120            throw new IllegalArgumentException("event must not be null");
121        }
122        if (mSenderPtr == 0) {
123            Log.w(TAG, "Attempted to send an input event but the input event "
124                    + "sender has already been disposed.");
125            return false;
126        }
127
128        if (event instanceof KeyEvent) {
129            return nativeSendKeyEvent(mSenderPtr, seq, (KeyEvent)event);
130        } else {
131            return nativeSendMotionEvent(mSenderPtr, seq, (MotionEvent)event);
132        }
133    }
134
135    // Called from native code.
136    @SuppressWarnings("unused")
137    private void dispatchInputEventFinished(int seq, boolean handled) {
138        onInputEventFinished(seq, handled);
139    }
140}
141