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