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 
17 package android.view;
18 
19 import dalvik.system.CloseGuard;
20 
21 import android.os.Looper;
22 import android.os.MessageQueue;
23 import android.util.Log;
24 
25 import java.lang.ref.WeakReference;
26 
27 /**
28  * Provides a low-level mechanism for an application to send input events.
29  * @hide
30  */
31 public abstract class InputEventSender {
32     private static final String TAG = "InputEventSender";
33 
34     private final CloseGuard mCloseGuard = CloseGuard.get();
35 
36     private long mSenderPtr;
37 
38     // We keep references to the input channel and message queue objects here so that
39     // they are not GC'd while the native peer of the receiver is using them.
40     private InputChannel mInputChannel;
41     private MessageQueue mMessageQueue;
42 
nativeInit(WeakReference<InputEventSender> sender, InputChannel inputChannel, MessageQueue messageQueue)43     private static native long nativeInit(WeakReference<InputEventSender> sender,
44             InputChannel inputChannel, MessageQueue messageQueue);
nativeDispose(long senderPtr)45     private static native void nativeDispose(long senderPtr);
nativeSendKeyEvent(long senderPtr, int seq, KeyEvent event)46     private static native boolean nativeSendKeyEvent(long senderPtr, int seq, KeyEvent event);
nativeSendMotionEvent(long senderPtr, int seq, MotionEvent event)47     private static native boolean nativeSendMotionEvent(long senderPtr, int seq, MotionEvent event);
48 
49     /**
50      * Creates an input event sender bound to the specified input channel.
51      *
52      * @param inputChannel The input channel.
53      * @param looper The looper to use when invoking callbacks.
54      */
InputEventSender(InputChannel inputChannel, Looper looper)55     public InputEventSender(InputChannel inputChannel, Looper looper) {
56         if (inputChannel == null) {
57             throw new IllegalArgumentException("inputChannel must not be null");
58         }
59         if (looper == null) {
60             throw new IllegalArgumentException("looper must not be null");
61         }
62 
63         mInputChannel = inputChannel;
64         mMessageQueue = looper.getQueue();
65         mSenderPtr = nativeInit(new WeakReference<InputEventSender>(this),
66                 inputChannel, mMessageQueue);
67 
68         mCloseGuard.open("dispose");
69     }
70 
71     @Override
finalize()72     protected void finalize() throws Throwable {
73         try {
74             dispose(true);
75         } finally {
76             super.finalize();
77         }
78     }
79 
80     /**
81      * Disposes the receiver.
82      */
dispose()83     public void dispose() {
84         dispose(false);
85     }
86 
dispose(boolean finalized)87     private void dispose(boolean finalized) {
88         if (mCloseGuard != null) {
89             if (finalized) {
90                 mCloseGuard.warnIfOpen();
91             }
92             mCloseGuard.close();
93         }
94 
95         if (mSenderPtr != 0) {
96             nativeDispose(mSenderPtr);
97             mSenderPtr = 0;
98         }
99         mInputChannel = null;
100         mMessageQueue = null;
101     }
102 
103     /**
104      * Called when an input event is finished.
105      *
106      * @param seq The input event sequence number.
107      * @param handled True if the input event was handled.
108      */
onInputEventFinished(int seq, boolean handled)109     public void onInputEventFinished(int seq, boolean handled) {
110     }
111 
112     /**
113      * Sends an input event.
114      * Must be called on the same Looper thread to which the sender is attached.
115      *
116      * @param seq The input event sequence number.
117      * @param event The input event to send.
118      * @return True if the entire event was sent successfully.  May return false
119      * if the input channel buffer filled before all samples were dispatched.
120      */
sendInputEvent(int seq, InputEvent event)121     public final boolean sendInputEvent(int seq, InputEvent event) {
122         if (event == null) {
123             throw new IllegalArgumentException("event must not be null");
124         }
125         if (mSenderPtr == 0) {
126             Log.w(TAG, "Attempted to send an input event but the input event "
127                     + "sender has already been disposed.");
128             return false;
129         }
130 
131         if (event instanceof KeyEvent) {
132             return nativeSendKeyEvent(mSenderPtr, seq, (KeyEvent)event);
133         } else {
134             return nativeSendMotionEvent(mSenderPtr, seq, (MotionEvent)event);
135         }
136     }
137 
138     // Called from native code.
139     @SuppressWarnings("unused")
dispatchInputEventFinished(int seq, boolean handled)140     private void dispatchInputEventFinished(int seq, boolean handled) {
141         onInputEventFinished(seq, handled);
142     }
143 }
144