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 dalvik.system.CloseGuard; 20 21 import android.os.Looper; 22 import android.os.MessageQueue; 23 import android.util.Pools.Pool; 24 import android.util.Pools.SimplePool; 25 import android.util.LongSparseArray; 26 27 import java.lang.ref.WeakReference; 28 29 /** 30 * An input queue provides a mechanism for an application to receive incoming 31 * input events. Currently only usable from native code. 32 */ 33 public final class InputQueue { 34 private final LongSparseArray<ActiveInputEvent> mActiveEventArray = 35 new LongSparseArray<ActiveInputEvent>(20); 36 private final Pool<ActiveInputEvent> mActiveInputEventPool = 37 new SimplePool<ActiveInputEvent>(20); 38 39 private final CloseGuard mCloseGuard = CloseGuard.get(); 40 41 private long mPtr; 42 nativeInit(WeakReference<InputQueue> weakQueue, MessageQueue messageQueue)43 private static native long nativeInit(WeakReference<InputQueue> weakQueue, 44 MessageQueue messageQueue); nativeSendKeyEvent(long ptr, KeyEvent e, boolean preDispatch)45 private static native long nativeSendKeyEvent(long ptr, KeyEvent e, boolean preDispatch); nativeSendMotionEvent(long ptr, MotionEvent e)46 private static native long nativeSendMotionEvent(long ptr, MotionEvent e); nativeDispose(long ptr)47 private static native void nativeDispose(long ptr); 48 49 /** @hide */ InputQueue()50 public InputQueue() { 51 mPtr = nativeInit(new WeakReference<InputQueue>(this), Looper.myQueue()); 52 53 mCloseGuard.open("dispose"); 54 } 55 56 @Override finalize()57 protected void finalize() throws Throwable { 58 try { 59 dispose(true); 60 } finally { 61 super.finalize(); 62 } 63 } 64 65 /** @hide */ dispose()66 public void dispose() { 67 dispose(false); 68 } 69 70 /** @hide */ dispose(boolean finalized)71 public void dispose(boolean finalized) { 72 if (mCloseGuard != null) { 73 if (finalized) { 74 mCloseGuard.warnIfOpen(); 75 } 76 mCloseGuard.close(); 77 } 78 79 if (mPtr != 0) { 80 nativeDispose(mPtr); 81 mPtr = 0; 82 } 83 } 84 85 /** @hide */ getNativePtr()86 public long getNativePtr() { 87 return mPtr; 88 } 89 90 /** @hide */ sendInputEvent(InputEvent e, Object token, boolean predispatch, FinishedInputEventCallback callback)91 public void sendInputEvent(InputEvent e, Object token, boolean predispatch, 92 FinishedInputEventCallback callback) { 93 ActiveInputEvent event = obtainActiveInputEvent(token, callback); 94 long id; 95 if (e instanceof KeyEvent) { 96 id = nativeSendKeyEvent(mPtr, (KeyEvent) e, predispatch); 97 } else { 98 id = nativeSendMotionEvent(mPtr, (MotionEvent) e); 99 } 100 mActiveEventArray.put(id, event); 101 } 102 finishInputEvent(long id, boolean handled)103 private void finishInputEvent(long id, boolean handled) { 104 int index = mActiveEventArray.indexOfKey(id); 105 if (index >= 0) { 106 ActiveInputEvent e = mActiveEventArray.valueAt(index); 107 mActiveEventArray.removeAt(index); 108 e.mCallback.onFinishedInputEvent(e.mToken, handled); 109 recycleActiveInputEvent(e); 110 } 111 } 112 obtainActiveInputEvent(Object token, FinishedInputEventCallback callback)113 private ActiveInputEvent obtainActiveInputEvent(Object token, 114 FinishedInputEventCallback callback) { 115 ActiveInputEvent e = mActiveInputEventPool.acquire(); 116 if (e == null) { 117 e = new ActiveInputEvent(); 118 } 119 e.mToken = token; 120 e.mCallback = callback; 121 return e; 122 } 123 recycleActiveInputEvent(ActiveInputEvent e)124 private void recycleActiveInputEvent(ActiveInputEvent e) { 125 e.recycle(); 126 mActiveInputEventPool.release(e); 127 } 128 129 private final class ActiveInputEvent { 130 public Object mToken; 131 public FinishedInputEventCallback mCallback; 132 recycle()133 public void recycle() { 134 mToken = null; 135 mCallback = null; 136 } 137 } 138 139 /** 140 * Interface to receive notification of when an InputQueue is associated 141 * and dissociated with a thread. 142 */ 143 public static interface Callback { 144 /** 145 * Called when the given InputQueue is now associated with the 146 * thread making this call, so it can start receiving events from it. 147 */ onInputQueueCreated(InputQueue queue)148 void onInputQueueCreated(InputQueue queue); 149 150 /** 151 * Called when the given InputQueue is no longer associated with 152 * the thread and thus not dispatching events. 153 */ onInputQueueDestroyed(InputQueue queue)154 void onInputQueueDestroyed(InputQueue queue); 155 } 156 157 /** @hide */ 158 public static interface FinishedInputEventCallback { onFinishedInputEvent(Object token, boolean handled)159 void onFinishedInputEvent(Object token, boolean handled); 160 } 161 162 } 163