146b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown/*
246b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown * Copyright (C) 2010 The Android Open Source Project
346b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown *
446b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown * Licensed under the Apache License, Version 2.0 (the "License");
546b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown * you may not use this file except in compliance with the License.
646b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown * You may obtain a copy of the License at
746b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown *
846b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown *      http://www.apache.org/licenses/LICENSE-2.0
946b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown *
1046b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown * Unless required by applicable law or agreed to in writing, software
1146b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown * distributed under the License is distributed on an "AS IS" BASIS,
1246b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1346b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown * See the License for the specific language governing permissions and
1446b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown * limitations under the License.
1546b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown */
1646b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown
1746b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brownpackage android.view;
1846b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown
19a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wrightimport dalvik.system.CloseGuard;
20a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright
21a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wrightimport android.os.Handler;
22a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wrightimport android.os.Looper;
23a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wrightimport android.os.MessageQueue;
24a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wrightimport android.util.Pools.Pool;
25a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wrightimport android.util.Pools.SimplePool;
26a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wrightimport android.util.SparseArray;
27a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright
28a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wrightimport java.lang.ref.WeakReference;
29a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright
3046b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown/**
3146b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown * An input queue provides a mechanism for an application to receive incoming
321e4b9f3936d6f357e89360293e05a0e16d5fa440Dianne Hackborn * input events.  Currently only usable from native code.
3346b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown */
3446b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brownpublic final class InputQueue {
35a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright    private final SparseArray<ActiveInputEvent> mActiveEventArray =
36a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright            new SparseArray<ActiveInputEvent>(20);
37a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright    private final Pool<ActiveInputEvent> mActiveInputEventPool =
38a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright            new SimplePool<ActiveInputEvent>(20);
39a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright
40a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright    private final CloseGuard mCloseGuard = CloseGuard.get();
41a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright
42a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright    private int mPtr;
43a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright
44a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright    private static native int nativeInit(WeakReference<InputQueue> weakQueue,
45a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright            MessageQueue messageQueue);
46a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright    private static native int nativeSendKeyEvent(int ptr, KeyEvent e, boolean preDispatch);
47a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright    private static native int nativeSendMotionEvent(int ptr, MotionEvent e);
48a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright    private static native void nativeDispose(int ptr);
49a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright
50a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright    /** @hide */
51a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright    public InputQueue() {
52a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright        mPtr = nativeInit(new WeakReference<InputQueue>(this), Looper.myQueue());
53a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright
54a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright        mCloseGuard.open("dispose");
55a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright    }
56a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright
57a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright    @Override
58a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright    protected void finalize() throws Throwable {
59a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright        try {
60a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright            dispose(true);
61a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright        } finally {
62a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright            super.finalize();
63a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright        }
64a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright    }
65a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright
66a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright    /** @hide */
67a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright    public void dispose() {
68a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright        dispose(false);
69a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright    }
70a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright
71a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright    /** @hide */
72a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright    public void dispose(boolean finalized) {
73a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright        if (mCloseGuard != null) {
74a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright            if (finalized) {
75a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright                mCloseGuard.warnIfOpen();
76a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright            }
77a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright            mCloseGuard.close();
78a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright        }
79a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright
80a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright        if (mPtr != 0) {
81a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright            nativeDispose(mPtr);
82a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright            mPtr = 0;
83a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright        }
84a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright    }
85a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright
86a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright    /** @hide */
87a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright    public int getNativePtr() {
88a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright        return mPtr;
89a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright    }
90a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright
91a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright    /** @hide */
92a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright    public void sendInputEvent(InputEvent e, Object token, boolean predispatch,
93a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright            FinishedInputEventCallback callback) {
94a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright        ActiveInputEvent event = obtainActiveInputEvent(token, callback);
95a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright        int id;
96a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright        if (e instanceof KeyEvent) {
97a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright            id = nativeSendKeyEvent(mPtr, (KeyEvent) e, predispatch);
98a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright        } else {
99a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright            id = nativeSendMotionEvent(mPtr, (MotionEvent) e);
100a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright        }
101a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright        mActiveEventArray.put(id, event);
102a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright    }
103a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright
104a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright    private void finishInputEvent(int id, boolean handled) {
105a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright        int index = mActiveEventArray.indexOfKey(id);
106a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright        if (index >= 0) {
107a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright            ActiveInputEvent e = mActiveEventArray.valueAt(index);
108a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright            mActiveEventArray.removeAt(index);
109a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright            e.mCallback.onFinishedInputEvent(e.mToken, handled);
110a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright            recycleActiveInputEvent(e);
111a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright        }
112a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright    }
113a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright
114a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright    private ActiveInputEvent obtainActiveInputEvent(Object token,
115a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright            FinishedInputEventCallback callback) {
116a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright        ActiveInputEvent e = mActiveInputEventPool.acquire();
117a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright        if (e == null) {
118a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright            e = new ActiveInputEvent();
119a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright        }
120a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright        e.mToken = token;
121a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright        e.mCallback = callback;
122a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright        return e;
123a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright    }
124a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright
125a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright    private void recycleActiveInputEvent(ActiveInputEvent e) {
126a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright        e.recycle();
127a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright        mActiveInputEventPool.release(e);
128a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright    }
129a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright
130a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright    private final class ActiveInputEvent {
131a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright        public Object mToken;
132a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright        public FinishedInputEventCallback mCallback;
133a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright
134a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright        public void recycle() {
135a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright            mToken = null;
136a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright            mCallback = null;
137a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright        }
138a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright    }
139a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright
140bfba7cab94cd9cf28e561159dbbe934dc83a6f0aDianne Hackborn    /**
141bfba7cab94cd9cf28e561159dbbe934dc83a6f0aDianne Hackborn     * Interface to receive notification of when an InputQueue is associated
142bfba7cab94cd9cf28e561159dbbe934dc83a6f0aDianne Hackborn     * and dissociated with a thread.
143bfba7cab94cd9cf28e561159dbbe934dc83a6f0aDianne Hackborn     */
1441e4b9f3936d6f357e89360293e05a0e16d5fa440Dianne Hackborn    public static interface Callback {
145bfba7cab94cd9cf28e561159dbbe934dc83a6f0aDianne Hackborn        /**
146bfba7cab94cd9cf28e561159dbbe934dc83a6f0aDianne Hackborn         * Called when the given InputQueue is now associated with the
147bfba7cab94cd9cf28e561159dbbe934dc83a6f0aDianne Hackborn         * thread making this call, so it can start receiving events from it.
148bfba7cab94cd9cf28e561159dbbe934dc83a6f0aDianne Hackborn         */
1491e4b9f3936d6f357e89360293e05a0e16d5fa440Dianne Hackborn        void onInputQueueCreated(InputQueue queue);
150a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright
151bfba7cab94cd9cf28e561159dbbe934dc83a6f0aDianne Hackborn        /**
152bfba7cab94cd9cf28e561159dbbe934dc83a6f0aDianne Hackborn         * Called when the given InputQueue is no longer associated with
153bfba7cab94cd9cf28e561159dbbe934dc83a6f0aDianne Hackborn         * the thread and thus not dispatching events.
154bfba7cab94cd9cf28e561159dbbe934dc83a6f0aDianne Hackborn         */
1551e4b9f3936d6f357e89360293e05a0e16d5fa440Dianne Hackborn        void onInputQueueDestroyed(InputQueue queue);
1561e4b9f3936d6f357e89360293e05a0e16d5fa440Dianne Hackborn    }
1571e4b9f3936d6f357e89360293e05a0e16d5fa440Dianne Hackborn
1581e4b9f3936d6f357e89360293e05a0e16d5fa440Dianne Hackborn    /** @hide */
159a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright    public static interface FinishedInputEventCallback {
160a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright        void onFinishedInputEvent(Object token, boolean handled);
16146b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown    }
162a44dd26a75e24cc021802288fb81f4761e47be6bMichael Wright
16346b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown}
164