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