blob: c566a653da422488e02d148f2be0f19c077d694a [file] [log] [blame]
Jeff Brown32cbc38552011-12-01 14:01:49 -08001/*
2 * Copyright (C) 2011 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
17package android.view;
18
Jeff Brown32cbc38552011-12-01 14:01:49 -080019import android.os.Looper;
20import android.os.MessageQueue;
21import android.util.Log;
Jeff Brown072ec962012-02-07 14:46:57 -080022import android.util.SparseIntArray;
Jeff Brown32cbc38552011-12-01 14:01:49 -080023
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -070024import dalvik.system.CloseGuard;
25
Jeff Browna4ca8ea2013-04-02 18:01:38 -070026import java.lang.ref.WeakReference;
27
Jeff Brown32cbc38552011-12-01 14:01:49 -080028/**
29 * Provides a low-level mechanism for an application to receive input events.
30 * @hide
31 */
32public abstract class InputEventReceiver {
33 private static final String TAG = "InputEventReceiver";
34
35 private final CloseGuard mCloseGuard = CloseGuard.get();
36
Ashok Bhata931d5212014-01-08 14:04:51 +000037 private long mReceiverPtr;
Jeff Brown32cbc38552011-12-01 14:01:49 -080038
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
Jeff Brown072ec962012-02-07 14:46:57 -080044 // Map from InputEvent sequence numbers to dispatcher sequence numbers.
45 private final SparseIntArray mSeqMap = new SparseIntArray();
Jeff Brown32cbc38552011-12-01 14:01:49 -080046
Ashok Bhata931d5212014-01-08 14:04:51 +000047 private static native long nativeInit(WeakReference<InputEventReceiver> receiver,
Jeff Brown32cbc38552011-12-01 14:01:49 -080048 InputChannel inputChannel, MessageQueue messageQueue);
Ashok Bhata931d5212014-01-08 14:04:51 +000049 private static native void nativeDispose(long receiverPtr);
50 private static native void nativeFinishInputEvent(long receiverPtr, int seq, boolean handled);
51 private static native boolean nativeConsumeBatchedInputEvents(long receiverPtr,
Jeff Brown771526c2012-04-27 15:13:25 -070052 long frameTimeNanos);
Jeff Brown32cbc38552011-12-01 14:01:49 -080053
54 /**
55 * Creates an input event receiver bound to the specified input channel.
56 *
57 * @param inputChannel The input channel.
58 * @param looper The looper to use when invoking callbacks.
59 */
60 public InputEventReceiver(InputChannel inputChannel, Looper looper) {
61 if (inputChannel == null) {
62 throw new IllegalArgumentException("inputChannel must not be null");
63 }
64 if (looper == null) {
65 throw new IllegalArgumentException("looper must not be null");
66 }
67
68 mInputChannel = inputChannel;
69 mMessageQueue = looper.getQueue();
Jeff Browna4ca8ea2013-04-02 18:01:38 -070070 mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this),
71 inputChannel, mMessageQueue);
Jeff Brown32cbc38552011-12-01 14:01:49 -080072
73 mCloseGuard.open("dispose");
74 }
75
76 @Override
77 protected void finalize() throws Throwable {
78 try {
Jeff Brown3e7e7f02012-08-27 14:33:53 -070079 dispose(true);
Jeff Brown32cbc38552011-12-01 14:01:49 -080080 } finally {
81 super.finalize();
82 }
83 }
84
85 /**
86 * Disposes the receiver.
87 */
88 public void dispose() {
Jeff Brown3e7e7f02012-08-27 14:33:53 -070089 dispose(false);
90 }
91
92 private void dispose(boolean finalized) {
Jeff Brown32cbc38552011-12-01 14:01:49 -080093 if (mCloseGuard != null) {
Jeff Brown3e7e7f02012-08-27 14:33:53 -070094 if (finalized) {
95 mCloseGuard.warnIfOpen();
96 }
Jeff Brown32cbc38552011-12-01 14:01:49 -080097 mCloseGuard.close();
98 }
Jeff Brown3e7e7f02012-08-27 14:33:53 -070099
Jeff Brown32cbc38552011-12-01 14:01:49 -0800100 if (mReceiverPtr != 0) {
101 nativeDispose(mReceiverPtr);
102 mReceiverPtr = 0;
103 }
104 mInputChannel = null;
105 mMessageQueue = null;
106 }
107
108 /**
109 * Called when an input event is received.
110 * The recipient should process the input event and then call {@link #finishInputEvent}
111 * to indicate whether the event was handled. No new input events will be received
112 * until {@link #finishInputEvent} is called.
113 *
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700114 * @param displayId The display id on which input event triggered.
Jeff Brown32cbc38552011-12-01 14:01:49 -0800115 * @param event The input event that was received.
116 */
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700117 public void onInputEvent(InputEvent event, int displayId) {
Jeff Brown32cbc38552011-12-01 14:01:49 -0800118 finishInputEvent(event, false);
119 }
120
121 /**
Jeff Brown072ec962012-02-07 14:46:57 -0800122 * Called when a batched input event is pending.
123 *
124 * The batched input event will continue to accumulate additional movement
125 * samples until the recipient calls {@link #consumeBatchedInputEvents} or
126 * an event is received that ends the batch and causes it to be consumed
127 * immediately (such as a pointer up event).
128 */
129 public void onBatchedInputEventPending() {
Jeff Brown771526c2012-04-27 15:13:25 -0700130 consumeBatchedInputEvents(-1);
Jeff Brown072ec962012-02-07 14:46:57 -0800131 }
132
133 /**
Jeff Brown32cbc38552011-12-01 14:01:49 -0800134 * Finishes an input event and indicates whether it was handled.
Jeff Brown072ec962012-02-07 14:46:57 -0800135 * Must be called on the same Looper thread to which the receiver is attached.
Jeff Brown32cbc38552011-12-01 14:01:49 -0800136 *
137 * @param event The input event that was finished.
138 * @param handled True if the event was handled.
139 */
Jeff Brown072ec962012-02-07 14:46:57 -0800140 public final void finishInputEvent(InputEvent event, boolean handled) {
Jeff Brown32cbc38552011-12-01 14:01:49 -0800141 if (event == null) {
142 throw new IllegalArgumentException("event must not be null");
143 }
144 if (mReceiverPtr == 0) {
145 Log.w(TAG, "Attempted to finish an input event but the input event "
146 + "receiver has already been disposed.");
147 } else {
Jeff Brown072ec962012-02-07 14:46:57 -0800148 int index = mSeqMap.indexOfKey(event.getSequenceNumber());
149 if (index < 0) {
Jeff Brown32cbc38552011-12-01 14:01:49 -0800150 Log.w(TAG, "Attempted to finish an input event that is not in progress.");
151 } else {
Jeff Brown072ec962012-02-07 14:46:57 -0800152 int seq = mSeqMap.valueAt(index);
153 mSeqMap.removeAt(index);
154 nativeFinishInputEvent(mReceiverPtr, seq, handled);
Jeff Brown32cbc38552011-12-01 14:01:49 -0800155 }
156 }
Jeff Brown92cc2d82011-12-02 01:19:47 -0800157 event.recycleIfNeededAfterDispatch();
Jeff Brown32cbc38552011-12-01 14:01:49 -0800158 }
159
Jeff Brown072ec962012-02-07 14:46:57 -0800160 /**
161 * Consumes all pending batched input events.
162 * Must be called on the same Looper thread to which the receiver is attached.
163 *
164 * This method forces all batched input events to be delivered immediately.
165 * Should be called just before animating or drawing a new frame in the UI.
Jeff Brown771526c2012-04-27 15:13:25 -0700166 *
167 * @param frameTimeNanos The time in the {@link System#nanoTime()} time base
168 * when the current display frame started rendering, or -1 if unknown.
Michael Wright62ce65d2013-10-25 14:50:36 -0700169 *
170 * @return Whether a batch was consumed
Jeff Brown072ec962012-02-07 14:46:57 -0800171 */
Michael Wright62ce65d2013-10-25 14:50:36 -0700172 public final boolean consumeBatchedInputEvents(long frameTimeNanos) {
Jeff Brown072ec962012-02-07 14:46:57 -0800173 if (mReceiverPtr == 0) {
174 Log.w(TAG, "Attempted to consume batched input events but the input event "
175 + "receiver has already been disposed.");
176 } else {
Michael Wright62ce65d2013-10-25 14:50:36 -0700177 return nativeConsumeBatchedInputEvents(mReceiverPtr, frameTimeNanos);
Jeff Brown072ec962012-02-07 14:46:57 -0800178 }
Michael Wright62ce65d2013-10-25 14:50:36 -0700179 return false;
Jeff Brown072ec962012-02-07 14:46:57 -0800180 }
181
Jeff Brown32cbc38552011-12-01 14:01:49 -0800182 // Called from native code.
183 @SuppressWarnings("unused")
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700184 private void dispatchInputEvent(int seq, InputEvent event, int displayId) {
Jeff Brown072ec962012-02-07 14:46:57 -0800185 mSeqMap.put(event.getSequenceNumber(), seq);
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700186 onInputEvent(event, displayId);
Jeff Brown32cbc38552011-12-01 14:01:49 -0800187 }
188
Jeff Brown072ec962012-02-07 14:46:57 -0800189 // Called from native code.
190 @SuppressWarnings("unused")
191 private void dispatchBatchedInputEventPending() {
192 onBatchedInputEventPending();
193 }
194
Jeff Brown32cbc38552011-12-01 14:01:49 -0800195 public static interface Factory {
196 public InputEventReceiver createInputEventReceiver(
197 InputChannel inputChannel, Looper looper);
198 }
199}