• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 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.os.MessageQueue;
20 import android.util.Slog;
21 
22 /**
23  * An input queue provides a mechanism for an application to receive incoming
24  * input events.  Currently only usable from native code.
25  */
26 public final class InputQueue {
27     private static final String TAG = "InputQueue";
28 
29     private static final boolean DEBUG = false;
30 
31     /**
32      * Interface to receive notification of when an InputQueue is associated
33      * and dissociated with a thread.
34      */
35     public static interface Callback {
36         /**
37          * Called when the given InputQueue is now associated with the
38          * thread making this call, so it can start receiving events from it.
39          */
onInputQueueCreated(InputQueue queue)40         void onInputQueueCreated(InputQueue queue);
41 
42         /**
43          * Called when the given InputQueue is no longer associated with
44          * the thread and thus not dispatching events.
45          */
onInputQueueDestroyed(InputQueue queue)46         void onInputQueueDestroyed(InputQueue queue);
47     }
48 
49     final InputChannel mChannel;
50 
51     private static final Object sLock = new Object();
52 
nativeRegisterInputChannel(InputChannel inputChannel, InputHandler inputHandler, MessageQueue messageQueue)53     private static native void nativeRegisterInputChannel(InputChannel inputChannel,
54             InputHandler inputHandler, MessageQueue messageQueue);
nativeUnregisterInputChannel(InputChannel inputChannel)55     private static native void nativeUnregisterInputChannel(InputChannel inputChannel);
nativeFinished(long finishedToken, boolean handled)56     private static native void nativeFinished(long finishedToken, boolean handled);
57 
58     /** @hide */
InputQueue(InputChannel channel)59     public InputQueue(InputChannel channel) {
60         mChannel = channel;
61     }
62 
63     /** @hide */
getInputChannel()64     public InputChannel getInputChannel() {
65         return mChannel;
66     }
67 
68     /**
69      * Registers an input channel and handler.
70      * @param inputChannel The input channel to register.
71      * @param inputHandler The input handler to input events send to the target.
72      * @param messageQueue The message queue on whose thread the handler should be invoked.
73      * @hide
74      */
registerInputChannel(InputChannel inputChannel, InputHandler inputHandler, MessageQueue messageQueue)75     public static void registerInputChannel(InputChannel inputChannel, InputHandler inputHandler,
76             MessageQueue messageQueue) {
77         if (inputChannel == null) {
78             throw new IllegalArgumentException("inputChannel must not be null");
79         }
80         if (inputHandler == null) {
81             throw new IllegalArgumentException("inputHandler must not be null");
82         }
83         if (messageQueue == null) {
84             throw new IllegalArgumentException("messageQueue must not be null");
85         }
86 
87         synchronized (sLock) {
88             if (DEBUG) {
89                 Slog.d(TAG, "Registering input channel '" + inputChannel + "'");
90             }
91 
92             nativeRegisterInputChannel(inputChannel, inputHandler, messageQueue);
93         }
94     }
95 
96     /**
97      * Unregisters an input channel.
98      * Does nothing if the channel is not currently registered.
99      * @param inputChannel The input channel to unregister.
100      * @hide
101      */
unregisterInputChannel(InputChannel inputChannel)102     public static void unregisterInputChannel(InputChannel inputChannel) {
103         if (inputChannel == null) {
104             throw new IllegalArgumentException("inputChannel must not be null");
105         }
106 
107         synchronized (sLock) {
108             if (DEBUG) {
109                 Slog.d(TAG, "Unregistering input channel '" + inputChannel + "'");
110             }
111 
112             nativeUnregisterInputChannel(inputChannel);
113         }
114     }
115 
116     @SuppressWarnings("unused")
dispatchKeyEvent(InputHandler inputHandler, KeyEvent event, long finishedToken)117     private static void dispatchKeyEvent(InputHandler inputHandler,
118             KeyEvent event, long finishedToken) {
119         FinishedCallback finishedCallback = FinishedCallback.obtain(finishedToken);
120         inputHandler.handleKey(event, finishedCallback);
121     }
122 
123     @SuppressWarnings("unused")
dispatchMotionEvent(InputHandler inputHandler, MotionEvent event, long finishedToken)124     private static void dispatchMotionEvent(InputHandler inputHandler,
125             MotionEvent event, long finishedToken) {
126         FinishedCallback finishedCallback = FinishedCallback.obtain(finishedToken);
127         inputHandler.handleMotion(event, finishedCallback);
128     }
129 
130     /**
131      * A callback that must be invoked to when finished processing an event.
132      * @hide
133      */
134     public static final class FinishedCallback {
135         private static final boolean DEBUG_RECYCLING = false;
136 
137         private static final int RECYCLE_MAX_COUNT = 4;
138 
139         private static FinishedCallback sRecycleHead;
140         private static int sRecycleCount;
141 
142         private FinishedCallback mRecycleNext;
143         private long mFinishedToken;
144 
FinishedCallback()145         private FinishedCallback() {
146         }
147 
obtain(long finishedToken)148         public static FinishedCallback obtain(long finishedToken) {
149             synchronized (sLock) {
150                 FinishedCallback callback = sRecycleHead;
151                 if (callback != null) {
152                     sRecycleHead = callback.mRecycleNext;
153                     sRecycleCount -= 1;
154                     callback.mRecycleNext = null;
155                 } else {
156                     callback = new FinishedCallback();
157                 }
158                 callback.mFinishedToken = finishedToken;
159                 return callback;
160             }
161         }
162 
finished(boolean handled)163         public void finished(boolean handled) {
164             synchronized (sLock) {
165                 if (mFinishedToken == -1) {
166                     throw new IllegalStateException("Event finished callback already invoked.");
167                 }
168 
169                 nativeFinished(mFinishedToken, handled);
170                 mFinishedToken = -1;
171 
172                 if (sRecycleCount < RECYCLE_MAX_COUNT) {
173                     mRecycleNext = sRecycleHead;
174                     sRecycleHead = this;
175                     sRecycleCount += 1;
176 
177                     if (DEBUG_RECYCLING) {
178                         Slog.d(TAG, "Recycled finished callbacks: " + sRecycleCount);
179                     }
180                 }
181             }
182         }
183     }
184 }
185