blob: ed8492e482c7bfe8375bc930fc047b090f02915d [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
Mathew Inwooda570dee2018-08-17 14:56:00 +010019import android.annotation.UnsupportedAppUsage;
Jeff Brown32cbc38552011-12-01 14:01:49 -080020import android.os.Looper;
21import android.os.MessageQueue;
22import android.util.Log;
Jeff Brown072ec962012-02-07 14:46:57 -080023import android.util.SparseIntArray;
Jeff Brown32cbc38552011-12-01 14:01:49 -080024
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -070025import dalvik.system.CloseGuard;
26
Jeff Browna4ca8ea2013-04-02 18:01:38 -070027import java.lang.ref.WeakReference;
28
Jeff Brown32cbc38552011-12-01 14:01:49 -080029/**
30 * Provides a low-level mechanism for an application to receive input events.
31 * @hide
32 */
33public abstract class InputEventReceiver {
34 private static final String TAG = "InputEventReceiver";
35
36 private final CloseGuard mCloseGuard = CloseGuard.get();
37
Ashok Bhata931d5212014-01-08 14:04:51 +000038 private long mReceiverPtr;
Jeff Brown32cbc38552011-12-01 14:01:49 -080039
40 // We keep references to the input channel and message queue objects here so that
41 // they are not GC'd while the native peer of the receiver is using them.
42 private InputChannel mInputChannel;
43 private MessageQueue mMessageQueue;
44
Jeff Brown072ec962012-02-07 14:46:57 -080045 // Map from InputEvent sequence numbers to dispatcher sequence numbers.
46 private final SparseIntArray mSeqMap = new SparseIntArray();
Jeff Brown32cbc38552011-12-01 14:01:49 -080047
Ashok Bhata931d5212014-01-08 14:04:51 +000048 private static native long nativeInit(WeakReference<InputEventReceiver> receiver,
Jeff Brown32cbc38552011-12-01 14:01:49 -080049 InputChannel inputChannel, MessageQueue messageQueue);
Ashok Bhata931d5212014-01-08 14:04:51 +000050 private static native void nativeDispose(long receiverPtr);
51 private static native void nativeFinishInputEvent(long receiverPtr, int seq, boolean handled);
52 private static native boolean nativeConsumeBatchedInputEvents(long receiverPtr,
Jeff Brown771526c2012-04-27 15:13:25 -070053 long frameTimeNanos);
Jeff Brown32cbc38552011-12-01 14:01:49 -080054
55 /**
56 * Creates an input event receiver bound to the specified input channel.
57 *
58 * @param inputChannel The input channel.
59 * @param looper The looper to use when invoking callbacks.
60 */
61 public InputEventReceiver(InputChannel inputChannel, Looper looper) {
62 if (inputChannel == null) {
63 throw new IllegalArgumentException("inputChannel must not be null");
64 }
65 if (looper == null) {
66 throw new IllegalArgumentException("looper must not be null");
67 }
68
69 mInputChannel = inputChannel;
70 mMessageQueue = looper.getQueue();
Jeff Browna4ca8ea2013-04-02 18:01:38 -070071 mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this),
72 inputChannel, mMessageQueue);
Jeff Brown32cbc38552011-12-01 14:01:49 -080073
74 mCloseGuard.open("dispose");
75 }
76
77 @Override
78 protected void finalize() throws Throwable {
79 try {
Jeff Brown3e7e7f02012-08-27 14:33:53 -070080 dispose(true);
Jeff Brown32cbc38552011-12-01 14:01:49 -080081 } finally {
82 super.finalize();
83 }
84 }
85
86 /**
87 * Disposes the receiver.
88 */
89 public void dispose() {
Jeff Brown3e7e7f02012-08-27 14:33:53 -070090 dispose(false);
91 }
92
93 private void dispose(boolean finalized) {
Jeff Brown32cbc38552011-12-01 14:01:49 -080094 if (mCloseGuard != null) {
Jeff Brown3e7e7f02012-08-27 14:33:53 -070095 if (finalized) {
96 mCloseGuard.warnIfOpen();
97 }
Jeff Brown32cbc38552011-12-01 14:01:49 -080098 mCloseGuard.close();
99 }
Jeff Brown3e7e7f02012-08-27 14:33:53 -0700100
Jeff Brown32cbc38552011-12-01 14:01:49 -0800101 if (mReceiverPtr != 0) {
102 nativeDispose(mReceiverPtr);
103 mReceiverPtr = 0;
104 }
Arthur Hung12a06ce2019-07-22 15:35:17 +0800105
106 if (mInputChannel != null) {
107 mInputChannel.dispose();
108 mInputChannel = null;
109 }
Jeff Brown32cbc38552011-12-01 14:01:49 -0800110 mMessageQueue = null;
111 }
112
113 /**
114 * Called when an input event is received.
115 * The recipient should process the input event and then call {@link #finishInputEvent}
116 * to indicate whether the event was handled. No new input events will be received
117 * until {@link #finishInputEvent} is called.
118 *
119 * @param event The input event that was received.
120 */
Mathew Inwooda570dee2018-08-17 14:56:00 +0100121 @UnsupportedAppUsage
Siarhei Vishniakou85ddfff2018-01-31 16:49:36 -0800122 public void onInputEvent(InputEvent event) {
Jeff Brown32cbc38552011-12-01 14:01:49 -0800123 finishInputEvent(event, false);
124 }
125
126 /**
Jeff Brown072ec962012-02-07 14:46:57 -0800127 * Called when a batched input event is pending.
128 *
129 * The batched input event will continue to accumulate additional movement
130 * samples until the recipient calls {@link #consumeBatchedInputEvents} or
131 * an event is received that ends the batch and causes it to be consumed
132 * immediately (such as a pointer up event).
133 */
134 public void onBatchedInputEventPending() {
Jeff Brown771526c2012-04-27 15:13:25 -0700135 consumeBatchedInputEvents(-1);
Jeff Brown072ec962012-02-07 14:46:57 -0800136 }
137
138 /**
Jeff Brown32cbc38552011-12-01 14:01:49 -0800139 * Finishes an input event and indicates whether it was handled.
Jeff Brown072ec962012-02-07 14:46:57 -0800140 * Must be called on the same Looper thread to which the receiver is attached.
Jeff Brown32cbc38552011-12-01 14:01:49 -0800141 *
142 * @param event The input event that was finished.
143 * @param handled True if the event was handled.
144 */
Jeff Brown072ec962012-02-07 14:46:57 -0800145 public final void finishInputEvent(InputEvent event, boolean handled) {
Jeff Brown32cbc38552011-12-01 14:01:49 -0800146 if (event == null) {
147 throw new IllegalArgumentException("event must not be null");
148 }
149 if (mReceiverPtr == 0) {
150 Log.w(TAG, "Attempted to finish an input event but the input event "
151 + "receiver has already been disposed.");
152 } else {
Jeff Brown072ec962012-02-07 14:46:57 -0800153 int index = mSeqMap.indexOfKey(event.getSequenceNumber());
154 if (index < 0) {
Jeff Brown32cbc38552011-12-01 14:01:49 -0800155 Log.w(TAG, "Attempted to finish an input event that is not in progress.");
156 } else {
Jeff Brown072ec962012-02-07 14:46:57 -0800157 int seq = mSeqMap.valueAt(index);
158 mSeqMap.removeAt(index);
159 nativeFinishInputEvent(mReceiverPtr, seq, handled);
Jeff Brown32cbc38552011-12-01 14:01:49 -0800160 }
161 }
Jeff Brown92cc2d82011-12-02 01:19:47 -0800162 event.recycleIfNeededAfterDispatch();
Jeff Brown32cbc38552011-12-01 14:01:49 -0800163 }
164
Jeff Brown072ec962012-02-07 14:46:57 -0800165 /**
166 * Consumes all pending batched input events.
167 * Must be called on the same Looper thread to which the receiver is attached.
168 *
169 * This method forces all batched input events to be delivered immediately.
170 * Should be called just before animating or drawing a new frame in the UI.
Jeff Brown771526c2012-04-27 15:13:25 -0700171 *
172 * @param frameTimeNanos The time in the {@link System#nanoTime()} time base
173 * when the current display frame started rendering, or -1 if unknown.
Michael Wright62ce65d2013-10-25 14:50:36 -0700174 *
175 * @return Whether a batch was consumed
Jeff Brown072ec962012-02-07 14:46:57 -0800176 */
Michael Wright62ce65d2013-10-25 14:50:36 -0700177 public final boolean consumeBatchedInputEvents(long frameTimeNanos) {
Jeff Brown072ec962012-02-07 14:46:57 -0800178 if (mReceiverPtr == 0) {
179 Log.w(TAG, "Attempted to consume batched input events but the input event "
180 + "receiver has already been disposed.");
181 } else {
Michael Wright62ce65d2013-10-25 14:50:36 -0700182 return nativeConsumeBatchedInputEvents(mReceiverPtr, frameTimeNanos);
Jeff Brown072ec962012-02-07 14:46:57 -0800183 }
Michael Wright62ce65d2013-10-25 14:50:36 -0700184 return false;
Jeff Brown072ec962012-02-07 14:46:57 -0800185 }
186
Jeff Brown32cbc38552011-12-01 14:01:49 -0800187 // Called from native code.
188 @SuppressWarnings("unused")
Mathew Inwooda570dee2018-08-17 14:56:00 +0100189 @UnsupportedAppUsage
Siarhei Vishniakou85ddfff2018-01-31 16:49:36 -0800190 private void dispatchInputEvent(int seq, InputEvent event) {
Jeff Brown072ec962012-02-07 14:46:57 -0800191 mSeqMap.put(event.getSequenceNumber(), seq);
Siarhei Vishniakou85ddfff2018-01-31 16:49:36 -0800192 onInputEvent(event);
Jeff Brown32cbc38552011-12-01 14:01:49 -0800193 }
194
Jeff Brown072ec962012-02-07 14:46:57 -0800195 // Called from native code.
196 @SuppressWarnings("unused")
Mathew Inwooda570dee2018-08-17 14:56:00 +0100197 @UnsupportedAppUsage
Jeff Brown072ec962012-02-07 14:46:57 -0800198 private void dispatchBatchedInputEventPending() {
199 onBatchedInputEventPending();
200 }
201
Jeff Brown32cbc38552011-12-01 14:01:49 -0800202 public static interface Factory {
203 public InputEventReceiver createInputEventReceiver(
204 InputChannel inputChannel, Looper looper);
205 }
206}