/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.view; import dalvik.system.CloseGuard; import android.os.Looper; import android.os.MessageQueue; import android.util.Pools.Pool; import android.util.Pools.SimplePool; import android.util.LongSparseArray; import java.lang.ref.WeakReference; /** * An input queue provides a mechanism for an application to receive incoming * input events. Currently only usable from native code. */ public final class InputQueue { private final LongSparseArray<ActiveInputEvent> mActiveEventArray = new LongSparseArray<ActiveInputEvent>(20); private final Pool<ActiveInputEvent> mActiveInputEventPool = new SimplePool<ActiveInputEvent>(20); private final CloseGuard mCloseGuard = CloseGuard.get(); private long mPtr; private static native long nativeInit(WeakReference<InputQueue> weakQueue, MessageQueue messageQueue); private static native long nativeSendKeyEvent(long ptr, KeyEvent e, boolean preDispatch); private static native long nativeSendMotionEvent(long ptr, MotionEvent e); private static native void nativeDispose(long ptr); /** @hide */ public InputQueue() { mPtr = nativeInit(new WeakReference<InputQueue>(this), Looper.myQueue()); mCloseGuard.open("dispose"); } @Override protected void finalize() throws Throwable { try { dispose(true); } finally { super.finalize(); } } /** @hide */ public void dispose() { dispose(false); } /** @hide */ public void dispose(boolean finalized) { if (mCloseGuard != null) { if (finalized) { mCloseGuard.warnIfOpen(); } mCloseGuard.close(); } if (mPtr != 0) { nativeDispose(mPtr); mPtr = 0; } } /** @hide */ public long getNativePtr() { return mPtr; } /** @hide */ public void sendInputEvent(InputEvent e, Object token, boolean predispatch, FinishedInputEventCallback callback) { ActiveInputEvent event = obtainActiveInputEvent(token, callback); long id; if (e instanceof KeyEvent) { id = nativeSendKeyEvent(mPtr, (KeyEvent) e, predispatch); } else { id = nativeSendMotionEvent(mPtr, (MotionEvent) e); } mActiveEventArray.put(id, event); } private void finishInputEvent(long id, boolean handled) { int index = mActiveEventArray.indexOfKey(id); if (index >= 0) { ActiveInputEvent e = mActiveEventArray.valueAt(index); mActiveEventArray.removeAt(index); e.mCallback.onFinishedInputEvent(e.mToken, handled); recycleActiveInputEvent(e); } } private ActiveInputEvent obtainActiveInputEvent(Object token, FinishedInputEventCallback callback) { ActiveInputEvent e = mActiveInputEventPool.acquire(); if (e == null) { e = new ActiveInputEvent(); } e.mToken = token; e.mCallback = callback; return e; } private void recycleActiveInputEvent(ActiveInputEvent e) { e.recycle(); mActiveInputEventPool.release(e); } private final class ActiveInputEvent { public Object mToken; public FinishedInputEventCallback mCallback; public void recycle() { mToken = null; mCallback = null; } } /** * Interface to receive notification of when an InputQueue is associated * and dissociated with a thread. */ public static interface Callback { /** * Called when the given InputQueue is now associated with the * thread making this call, so it can start receiving events from it. */ void onInputQueueCreated(InputQueue queue); /** * Called when the given InputQueue is no longer associated with * the thread and thus not dispatching events. */ void onInputQueueDestroyed(InputQueue queue); } /** @hide */ public static interface FinishedInputEventCallback { void onFinishedInputEvent(Object token, boolean handled); } }