blob: 7986ceb988dbe9740422312157a90e10ac7a34e9 [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
Artur Satayevad9254c2019-12-10 17:47:54 +000019import android.compat.annotation.UnsupportedAppUsage;
Vishnu Nair5cf253192019-11-07 15:33:20 -080020import android.os.IBinder;
Jeff Brown32cbc38552011-12-01 14:01:49 -080021import android.os.Looper;
22import android.os.MessageQueue;
23import android.util.Log;
Jeff Brown072ec962012-02-07 14:46:57 -080024import android.util.SparseIntArray;
Jeff Brown32cbc38552011-12-01 14:01:49 -080025
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -070026import dalvik.system.CloseGuard;
27
Tiger Huangced251f2019-12-16 21:42:11 +080028import java.lang.ref.Reference;
Jeff Browna4ca8ea2013-04-02 18:01:38 -070029import java.lang.ref.WeakReference;
30
Jeff Brown32cbc38552011-12-01 14:01:49 -080031/**
32 * Provides a low-level mechanism for an application to receive input events.
33 * @hide
34 */
35public abstract class InputEventReceiver {
36 private static final String TAG = "InputEventReceiver";
37
38 private final CloseGuard mCloseGuard = CloseGuard.get();
39
Ashok Bhata931d5212014-01-08 14:04:51 +000040 private long mReceiverPtr;
Jeff Brown32cbc38552011-12-01 14:01:49 -080041
42 // We keep references to the input channel and message queue objects here so that
43 // they are not GC'd while the native peer of the receiver is using them.
44 private InputChannel mInputChannel;
45 private MessageQueue mMessageQueue;
46
Jeff Brown072ec962012-02-07 14:46:57 -080047 // Map from InputEvent sequence numbers to dispatcher sequence numbers.
48 private final SparseIntArray mSeqMap = new SparseIntArray();
Jeff Brown32cbc38552011-12-01 14:01:49 -080049
Ashok Bhata931d5212014-01-08 14:04:51 +000050 private static native long nativeInit(WeakReference<InputEventReceiver> receiver,
Jeff Brown32cbc38552011-12-01 14:01:49 -080051 InputChannel inputChannel, MessageQueue messageQueue);
Ashok Bhata931d5212014-01-08 14:04:51 +000052 private static native void nativeDispose(long receiverPtr);
53 private static native void nativeFinishInputEvent(long receiverPtr, int seq, boolean handled);
54 private static native boolean nativeConsumeBatchedInputEvents(long receiverPtr,
Jeff Brown771526c2012-04-27 15:13:25 -070055 long frameTimeNanos);
Jeff Brown32cbc38552011-12-01 14:01:49 -080056
57 /**
58 * Creates an input event receiver bound to the specified input channel.
59 *
60 * @param inputChannel The input channel.
61 * @param looper The looper to use when invoking callbacks.
62 */
63 public InputEventReceiver(InputChannel inputChannel, Looper looper) {
64 if (inputChannel == null) {
65 throw new IllegalArgumentException("inputChannel must not be null");
66 }
67 if (looper == null) {
68 throw new IllegalArgumentException("looper must not be null");
69 }
70
71 mInputChannel = inputChannel;
72 mMessageQueue = looper.getQueue();
Jeff Browna4ca8ea2013-04-02 18:01:38 -070073 mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this),
74 inputChannel, mMessageQueue);
Jeff Brown32cbc38552011-12-01 14:01:49 -080075
76 mCloseGuard.open("dispose");
77 }
78
79 @Override
80 protected void finalize() throws Throwable {
81 try {
Jeff Brown3e7e7f02012-08-27 14:33:53 -070082 dispose(true);
Jeff Brown32cbc38552011-12-01 14:01:49 -080083 } finally {
84 super.finalize();
85 }
86 }
87
88 /**
89 * Disposes the receiver.
Tiger Huangced251f2019-12-16 21:42:11 +080090 * Must be called on the same Looper thread to which the receiver is attached.
Jeff Brown32cbc38552011-12-01 14:01:49 -080091 */
92 public void dispose() {
Jeff Brown3e7e7f02012-08-27 14:33:53 -070093 dispose(false);
94 }
95
96 private void dispose(boolean finalized) {
Jeff Brown32cbc38552011-12-01 14:01:49 -080097 if (mCloseGuard != null) {
Jeff Brown3e7e7f02012-08-27 14:33:53 -070098 if (finalized) {
99 mCloseGuard.warnIfOpen();
100 }
Jeff Brown32cbc38552011-12-01 14:01:49 -0800101 mCloseGuard.close();
102 }
Jeff Brown3e7e7f02012-08-27 14:33:53 -0700103
Jeff Brown32cbc38552011-12-01 14:01:49 -0800104 if (mReceiverPtr != 0) {
105 nativeDispose(mReceiverPtr);
106 mReceiverPtr = 0;
107 }
Arthur Hung12a06ce2019-07-22 15:35:17 +0800108
109 if (mInputChannel != null) {
110 mInputChannel.dispose();
111 mInputChannel = null;
112 }
Jeff Brown32cbc38552011-12-01 14:01:49 -0800113 mMessageQueue = null;
Tiger Huangced251f2019-12-16 21:42:11 +0800114 Reference.reachabilityFence(this);
Jeff Brown32cbc38552011-12-01 14:01:49 -0800115 }
116
117 /**
118 * Called when an input event is received.
119 * The recipient should process the input event and then call {@link #finishInputEvent}
120 * to indicate whether the event was handled. No new input events will be received
121 * until {@link #finishInputEvent} is called.
122 *
123 * @param event The input event that was received.
124 */
Mathew Inwooda570dee2018-08-17 14:56:00 +0100125 @UnsupportedAppUsage
Siarhei Vishniakou85ddfff2018-01-31 16:49:36 -0800126 public void onInputEvent(InputEvent event) {
Jeff Brown32cbc38552011-12-01 14:01:49 -0800127 finishInputEvent(event, false);
128 }
129
130 /**
Siarhei Vishniakou3b8e8722019-09-20 16:28:12 +0100131 * Called when a focus event is received.
132 *
133 * @param hasFocus if true, the window associated with this input channel has just received
134 * focus
135 * if false, the window associated with this input channel has just lost focus
136 * @param inTouchMode if true, the device is in touch mode
137 * if false, the device is not in touch mode
138 */
139 // Called from native code.
140 public void onFocusEvent(boolean hasFocus, boolean inTouchMode) {
141 }
142
143 /**
Jeff Brown072ec962012-02-07 14:46:57 -0800144 * Called when a batched input event is pending.
145 *
146 * The batched input event will continue to accumulate additional movement
147 * samples until the recipient calls {@link #consumeBatchedInputEvents} or
148 * an event is received that ends the batch and causes it to be consumed
149 * immediately (such as a pointer up event).
150 */
151 public void onBatchedInputEventPending() {
Jeff Brown771526c2012-04-27 15:13:25 -0700152 consumeBatchedInputEvents(-1);
Jeff Brown072ec962012-02-07 14:46:57 -0800153 }
154
155 /**
Jeff Brown32cbc38552011-12-01 14:01:49 -0800156 * Finishes an input event and indicates whether it was handled.
Jeff Brown072ec962012-02-07 14:46:57 -0800157 * Must be called on the same Looper thread to which the receiver is attached.
Jeff Brown32cbc38552011-12-01 14:01:49 -0800158 *
159 * @param event The input event that was finished.
160 * @param handled True if the event was handled.
161 */
Jeff Brown072ec962012-02-07 14:46:57 -0800162 public final void finishInputEvent(InputEvent event, boolean handled) {
Jeff Brown32cbc38552011-12-01 14:01:49 -0800163 if (event == null) {
164 throw new IllegalArgumentException("event must not be null");
165 }
166 if (mReceiverPtr == 0) {
167 Log.w(TAG, "Attempted to finish an input event but the input event "
168 + "receiver has already been disposed.");
169 } else {
Jeff Brown072ec962012-02-07 14:46:57 -0800170 int index = mSeqMap.indexOfKey(event.getSequenceNumber());
171 if (index < 0) {
Jeff Brown32cbc38552011-12-01 14:01:49 -0800172 Log.w(TAG, "Attempted to finish an input event that is not in progress.");
173 } else {
Jeff Brown072ec962012-02-07 14:46:57 -0800174 int seq = mSeqMap.valueAt(index);
175 mSeqMap.removeAt(index);
176 nativeFinishInputEvent(mReceiverPtr, seq, handled);
Jeff Brown32cbc38552011-12-01 14:01:49 -0800177 }
178 }
Jeff Brown92cc2d82011-12-02 01:19:47 -0800179 event.recycleIfNeededAfterDispatch();
Jeff Brown32cbc38552011-12-01 14:01:49 -0800180 }
181
Jeff Brown072ec962012-02-07 14:46:57 -0800182 /**
183 * Consumes all pending batched input events.
184 * Must be called on the same Looper thread to which the receiver is attached.
185 *
186 * This method forces all batched input events to be delivered immediately.
187 * Should be called just before animating or drawing a new frame in the UI.
Jeff Brown771526c2012-04-27 15:13:25 -0700188 *
189 * @param frameTimeNanos The time in the {@link System#nanoTime()} time base
190 * when the current display frame started rendering, or -1 if unknown.
Michael Wright62ce65d2013-10-25 14:50:36 -0700191 *
192 * @return Whether a batch was consumed
Jeff Brown072ec962012-02-07 14:46:57 -0800193 */
Michael Wright62ce65d2013-10-25 14:50:36 -0700194 public final boolean consumeBatchedInputEvents(long frameTimeNanos) {
Jeff Brown072ec962012-02-07 14:46:57 -0800195 if (mReceiverPtr == 0) {
196 Log.w(TAG, "Attempted to consume batched input events but the input event "
197 + "receiver has already been disposed.");
198 } else {
Michael Wright62ce65d2013-10-25 14:50:36 -0700199 return nativeConsumeBatchedInputEvents(mReceiverPtr, frameTimeNanos);
Jeff Brown072ec962012-02-07 14:46:57 -0800200 }
Michael Wright62ce65d2013-10-25 14:50:36 -0700201 return false;
Jeff Brown072ec962012-02-07 14:46:57 -0800202 }
203
Vishnu Nair5cf253192019-11-07 15:33:20 -0800204 /**
205 * @return Returns a token to identify the input channel.
206 */
207 public IBinder getToken() {
208 if (mInputChannel == null) {
209 return null;
210 }
211 return mInputChannel.getToken();
212 }
213
Jeff Brown32cbc38552011-12-01 14:01:49 -0800214 // Called from native code.
215 @SuppressWarnings("unused")
Mathew Inwooda570dee2018-08-17 14:56:00 +0100216 @UnsupportedAppUsage
Siarhei Vishniakou85ddfff2018-01-31 16:49:36 -0800217 private void dispatchInputEvent(int seq, InputEvent event) {
Jeff Brown072ec962012-02-07 14:46:57 -0800218 mSeqMap.put(event.getSequenceNumber(), seq);
Siarhei Vishniakou85ddfff2018-01-31 16:49:36 -0800219 onInputEvent(event);
Jeff Brown32cbc38552011-12-01 14:01:49 -0800220 }
221
Jeff Brown072ec962012-02-07 14:46:57 -0800222 // Called from native code.
223 @SuppressWarnings("unused")
Mathew Inwooda570dee2018-08-17 14:56:00 +0100224 @UnsupportedAppUsage
Jeff Brown072ec962012-02-07 14:46:57 -0800225 private void dispatchBatchedInputEventPending() {
226 onBatchedInputEventPending();
227 }
228
Siarhei Vishniakou3b8e8722019-09-20 16:28:12 +0100229 /**
230 * Factory for InputEventReceiver
231 */
232 public interface Factory {
233 /**
234 * Create a new InputReceiver for a given inputChannel
235 */
236 InputEventReceiver createInputEventReceiver(InputChannel inputChannel, Looper looper);
Jeff Brown32cbc38552011-12-01 14:01:49 -0800237 }
238}