Siarhei Vishniakou | 2b92027 | 2024-02-27 19:49:51 -0800 | [diff] [blame] | 1 | /** |
| 2 | * Copyright 2024 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 | |
| 17 | #pragma once |
| 18 | |
Paul Ramirez | 00cf5d0 | 2024-09-05 17:10:12 +0000 | [diff] [blame^] | 19 | #include <map> |
| 20 | #include <memory> |
| 21 | #include <optional> |
| 22 | |
| 23 | #include <input/Input.h> |
Paul Ramirez | b41d38e | 2024-07-16 17:44:20 +0000 | [diff] [blame] | 24 | #include <input/InputTransport.h> |
Paul Ramirez | e2bb187 | 2024-08-12 20:21:13 +0000 | [diff] [blame] | 25 | #include <input/LooperInterface.h> |
Paul Ramirez | be9c544 | 2024-07-10 00:12:41 +0000 | [diff] [blame] | 26 | #include <input/Resampler.h> |
Siarhei Vishniakou | 2b92027 | 2024-02-27 19:49:51 -0800 | [diff] [blame] | 27 | #include <utils/Looper.h> |
Siarhei Vishniakou | 2b92027 | 2024-02-27 19:49:51 -0800 | [diff] [blame] | 28 | |
| 29 | namespace android { |
| 30 | |
| 31 | /** |
| 32 | * An interface to receive batched input events. Even if you don't want batching, you still have to |
| 33 | * use this interface, and some of the events will be batched if your implementation is slow to |
Paul Ramirez | 79655f2 | 2024-07-01 21:55:48 +0000 | [diff] [blame] | 34 | * handle the incoming input. The events received by these callbacks are never null. |
Siarhei Vishniakou | 2b92027 | 2024-02-27 19:49:51 -0800 | [diff] [blame] | 35 | */ |
| 36 | class InputConsumerCallbacks { |
| 37 | public: |
| 38 | virtual ~InputConsumerCallbacks(){}; |
Siarhei Vishniakou | 3891ec9 | 2024-03-15 13:29:57 -0700 | [diff] [blame] | 39 | virtual void onKeyEvent(std::unique_ptr<KeyEvent> event, uint32_t seq) = 0; |
| 40 | virtual void onMotionEvent(std::unique_ptr<MotionEvent> event, uint32_t seq) = 0; |
Siarhei Vishniakou | 2b92027 | 2024-02-27 19:49:51 -0800 | [diff] [blame] | 41 | /** |
| 42 | * When you receive this callback, you must (eventually) call "consumeBatchedInputEvents". |
| 43 | * If you don't want batching, then call "consumeBatchedInputEvents" immediately with |
Paul Ramirez | 00cf5d0 | 2024-09-05 17:10:12 +0000 | [diff] [blame^] | 44 | * std::nullopt requestedFrameTime to receive the pending motion event(s). |
Siarhei Vishniakou | 2b92027 | 2024-02-27 19:49:51 -0800 | [diff] [blame] | 45 | * @param pendingBatchSource the source of the pending batch. |
| 46 | */ |
| 47 | virtual void onBatchedInputEventPending(int32_t pendingBatchSource) = 0; |
Siarhei Vishniakou | 3891ec9 | 2024-03-15 13:29:57 -0700 | [diff] [blame] | 48 | virtual void onFocusEvent(std::unique_ptr<FocusEvent> event, uint32_t seq) = 0; |
| 49 | virtual void onCaptureEvent(std::unique_ptr<CaptureEvent> event, uint32_t seq) = 0; |
| 50 | virtual void onDragEvent(std::unique_ptr<DragEvent> event, uint32_t seq) = 0; |
| 51 | virtual void onTouchModeEvent(std::unique_ptr<TouchModeEvent> event, uint32_t seq) = 0; |
Siarhei Vishniakou | 2b92027 | 2024-02-27 19:49:51 -0800 | [diff] [blame] | 52 | }; |
| 53 | |
| 54 | /** |
| 55 | * Consumes input events from an input channel. |
| 56 | * |
Paul Ramirez | be9c544 | 2024-07-10 00:12:41 +0000 | [diff] [blame] | 57 | * This is a re-implementation of InputConsumer. At the moment it only supports resampling for |
| 58 | * single pointer events. A lot of the higher-level logic has been folded into this class, to make |
| 59 | * it easier to use. In the legacy class, InputConsumer, the consumption logic was partially handled |
| 60 | * in the jni layer, as well as various actions like adding the fd to the Choreographer. |
Siarhei Vishniakou | 2b92027 | 2024-02-27 19:49:51 -0800 | [diff] [blame] | 61 | * |
| 62 | * TODO(b/297226446): use this instead of "InputConsumer": |
Paul Ramirez | be9c544 | 2024-07-10 00:12:41 +0000 | [diff] [blame] | 63 | * - Add resampling for multiple pointer events. |
Siarhei Vishniakou | 2b92027 | 2024-02-27 19:49:51 -0800 | [diff] [blame] | 64 | * - Allow various resampling strategies to be specified |
| 65 | * - Delete the old "InputConsumer" and use this class instead, renaming it to "InputConsumer". |
| 66 | * - Add tracing |
| 67 | * - Update all tests to use the new InputConsumer |
| 68 | * |
| 69 | * This class is not thread-safe. We are currently allowing the constructor to run on any thread, |
| 70 | * but all of the remaining APIs should be invoked on the looper thread only. |
| 71 | */ |
| 72 | class InputConsumerNoResampling final { |
| 73 | public: |
Paul Ramirez | be9c544 | 2024-07-10 00:12:41 +0000 | [diff] [blame] | 74 | /** |
Paul Ramirez | e2bb187 | 2024-08-12 20:21:13 +0000 | [diff] [blame] | 75 | * This constructor is exclusively for test code. Any real use of InputConsumerNoResampling must |
| 76 | * use the constructor that takes an sp<Looper> parameter instead of |
| 77 | * std::shared_ptr<LooperInterface>. |
| 78 | */ |
| 79 | explicit InputConsumerNoResampling(const std::shared_ptr<InputChannel>& channel, |
| 80 | std::shared_ptr<LooperInterface> looper, |
| 81 | InputConsumerCallbacks& callbacks, |
| 82 | std::unique_ptr<Resampler> resampler); |
| 83 | |
| 84 | /** |
Paul Ramirez | be9c544 | 2024-07-10 00:12:41 +0000 | [diff] [blame] | 85 | * @param callbacks are used to interact with InputConsumerNoResampling. They're called whenever |
| 86 | * the event is ready to consume. |
| 87 | * @param looper needs to be sp and not shared_ptr because it inherits from |
| 88 | * RefBase |
| 89 | * @param resampler the resampling strategy to use. If null, no resampling will be |
| 90 | * performed. |
| 91 | */ |
Siarhei Vishniakou | 2b92027 | 2024-02-27 19:49:51 -0800 | [diff] [blame] | 92 | explicit InputConsumerNoResampling(const std::shared_ptr<InputChannel>& channel, |
Paul Ramirez | be9c544 | 2024-07-10 00:12:41 +0000 | [diff] [blame] | 93 | sp<Looper> looper, InputConsumerCallbacks& callbacks, |
| 94 | std::unique_ptr<Resampler> resampler); |
| 95 | |
Siarhei Vishniakou | 2b92027 | 2024-02-27 19:49:51 -0800 | [diff] [blame] | 96 | ~InputConsumerNoResampling(); |
| 97 | |
| 98 | /** |
| 99 | * Must be called exactly once for each event received through the callbacks. |
| 100 | */ |
| 101 | void finishInputEvent(uint32_t seq, bool handled); |
| 102 | void reportTimeline(int32_t inputEventId, nsecs_t gpuCompletedTime, nsecs_t presentTime); |
| 103 | /** |
Paul Ramirez | 00cf5d0 | 2024-09-05 17:10:12 +0000 | [diff] [blame^] | 104 | * If you want to consume all events immediately (disable batching), then you still must call |
| 105 | * this. For requestedFrameTime, use a std::nullopt. It is not guaranteed that the consumption |
| 106 | * will occur at requestedFrameTime. The resampling strategy may modify it. |
| 107 | * @param requestedFrameTime the time up to which consume the events. When there's double (or |
| 108 | * triple) buffering, you may want to not consume all events currently available, because you |
| 109 | * could be still working on an older frame, but there could already have been events that |
| 110 | * arrived that are more recent. |
Siarhei Vishniakou | 2b92027 | 2024-02-27 19:49:51 -0800 | [diff] [blame] | 111 | * @return whether any events were actually consumed |
| 112 | */ |
Paul Ramirez | 00cf5d0 | 2024-09-05 17:10:12 +0000 | [diff] [blame^] | 113 | bool consumeBatchedInputEvents(std::optional<nsecs_t> requestedFrameTime); |
| 114 | |
Siarhei Vishniakou | 2b92027 | 2024-02-27 19:49:51 -0800 | [diff] [blame] | 115 | /** |
| 116 | * Returns true when there is *likely* a pending batch or a pending event in the channel. |
| 117 | * |
| 118 | * This is only a performance hint and may return false negative results. Clients should not |
| 119 | * rely on availability of the message based on the return value. |
| 120 | */ |
| 121 | bool probablyHasInput() const; |
| 122 | |
| 123 | std::string getName() { return mChannel->getName(); } |
| 124 | |
| 125 | std::string dump() const; |
| 126 | |
| 127 | private: |
| 128 | std::shared_ptr<InputChannel> mChannel; |
Paul Ramirez | e2bb187 | 2024-08-12 20:21:13 +0000 | [diff] [blame] | 129 | std::shared_ptr<LooperInterface> mLooper; |
Siarhei Vishniakou | 2b92027 | 2024-02-27 19:49:51 -0800 | [diff] [blame] | 130 | InputConsumerCallbacks& mCallbacks; |
Paul Ramirez | be9c544 | 2024-07-10 00:12:41 +0000 | [diff] [blame] | 131 | std::unique_ptr<Resampler> mResampler; |
Siarhei Vishniakou | 2b92027 | 2024-02-27 19:49:51 -0800 | [diff] [blame] | 132 | |
| 133 | // Looper-related infrastructure |
| 134 | /** |
| 135 | * This class is needed to associate the function "handleReceiveCallback" with the provided |
| 136 | * looper. The callback sent to the looper is RefBase - based, so we can't just send a reference |
| 137 | * of this class directly to the looper. |
| 138 | */ |
| 139 | class LooperEventCallback : public LooperCallback { |
| 140 | public: |
| 141 | LooperEventCallback(std::function<int(int events)> callback) : mCallback(callback) {} |
| 142 | int handleEvent(int /*fd*/, int events, void* /*data*/) override { |
| 143 | return mCallback(events); |
| 144 | } |
| 145 | |
| 146 | private: |
| 147 | std::function<int(int events)> mCallback; |
| 148 | }; |
| 149 | sp<LooperEventCallback> mCallback; |
| 150 | /** |
| 151 | * The actual code that executes when the looper encounters available data on the InputChannel. |
| 152 | */ |
| 153 | int handleReceiveCallback(int events); |
| 154 | int mFdEvents; |
| 155 | void setFdEvents(int events); |
| 156 | |
| 157 | void ensureCalledOnLooperThread(const char* func) const; |
| 158 | |
| 159 | // Event-reading infrastructure |
| 160 | /** |
| 161 | * A fifo queue of events to be sent to the InputChannel. We can't send all InputMessages to |
| 162 | * the channel immediately when they are produced, because it's possible that the InputChannel |
| 163 | * is blocked (if the channel buffer is full). When that happens, we don't want to drop the |
| 164 | * events. Therefore, events should only be erased from the queue after they've been |
| 165 | * successfully written to the InputChannel. |
| 166 | */ |
| 167 | std::queue<InputMessage> mOutboundQueue; |
| 168 | /** |
| 169 | * Try to send all of the events in mOutboundQueue over the InputChannel. Not all events might |
| 170 | * actually get sent, because it's possible that the channel is blocked. |
| 171 | */ |
| 172 | void processOutboundEvents(); |
| 173 | |
| 174 | /** |
| 175 | * The time at which each event with the sequence number 'seq' was consumed. |
| 176 | * This data is provided in 'finishInputEvent' so that the receiving end can measure the latency |
| 177 | * This collection is populated when the event is received, and the entries are erased when the |
| 178 | * events are finished. It should not grow infinitely because if an event is not ack'd, ANR |
| 179 | * will be raised for that connection, and no further events will be posted to that channel. |
| 180 | */ |
| 181 | std::unordered_map<uint32_t /*seq*/, nsecs_t /*consumeTime*/> mConsumeTimes; |
| 182 | /** |
| 183 | * Find and return the consumeTime associated with the provided sequence number. Crashes if |
| 184 | * the provided seq number is not found. |
| 185 | */ |
| 186 | nsecs_t popConsumeTime(uint32_t seq); |
| 187 | |
| 188 | // Event reading and processing |
| 189 | /** |
| 190 | * Read all of the available events from the InputChannel |
| 191 | */ |
| 192 | std::vector<InputMessage> readAllMessages(); |
| 193 | |
| 194 | /** |
| 195 | * Send InputMessage to the corresponding InputConsumerCallbacks function. |
| 196 | * @param msg |
| 197 | */ |
| 198 | void handleMessage(const InputMessage& msg) const; |
| 199 | |
| 200 | // Batching |
| 201 | /** |
| 202 | * Batch messages that can be batched. When an unbatchable message is encountered, send it |
| 203 | * to the InputConsumerCallbacks immediately. If there are batches remaining, |
| 204 | * notify InputConsumerCallbacks. |
| 205 | */ |
| 206 | void handleMessages(std::vector<InputMessage>&& messages); |
| 207 | /** |
| 208 | * Batched InputMessages, per deviceId. |
| 209 | * For each device, we are storing a queue of batched messages. These will all be collapsed into |
Paul Ramirez | 00cf5d0 | 2024-09-05 17:10:12 +0000 | [diff] [blame^] | 210 | * a single MotionEvent (up to a specific requestedFrameTime) when the consumer calls |
Siarhei Vishniakou | 2b92027 | 2024-02-27 19:49:51 -0800 | [diff] [blame] | 211 | * `consumeBatchedInputEvents`. |
| 212 | */ |
| 213 | std::map<DeviceId, std::queue<InputMessage>> mBatches; |
| 214 | /** |
Paul Ramirez | b41d38e | 2024-07-16 17:44:20 +0000 | [diff] [blame] | 215 | * Creates a MotionEvent by consuming samples from the provided queue. If one message has |
Paul Ramirez | 00cf5d0 | 2024-09-05 17:10:12 +0000 | [diff] [blame^] | 216 | * eventTime > adjustedFrameTime, all subsequent messages in the queue will be skipped. It is |
| 217 | * assumed that messages are queued in chronological order. In other words, only events that |
| 218 | * occurred prior to the adjustedFrameTime will be consumed. |
| 219 | * @param requestedFrameTime the time up to which to consume events. |
Paul Ramirez | b41d38e | 2024-07-16 17:44:20 +0000 | [diff] [blame] | 220 | * @param messages the queue of messages to consume from |
| 221 | */ |
| 222 | std::pair<std::unique_ptr<MotionEvent>, std::optional<uint32_t>> createBatchedMotionEvent( |
Paul Ramirez | 00cf5d0 | 2024-09-05 17:10:12 +0000 | [diff] [blame^] | 223 | const nsecs_t requestedFrameTime, std::queue<InputMessage>& messages); |
| 224 | |
| 225 | /** |
| 226 | * Consumes the batched input events, optionally allowing the caller to specify a device id |
| 227 | * and/or requestedFrameTime threshold. It is not guaranteed that consumption will occur at |
| 228 | * requestedFrameTime. |
| 229 | * @param deviceId The device id from which to consume events. If std::nullopt, consumes events |
| 230 | * from any device id. |
| 231 | * @param requestedFrameTime The time up to which consume the events. If std::nullopt, consumes |
| 232 | * input events with any timestamp. |
| 233 | * @return Whether or not any events were consumed. |
| 234 | */ |
| 235 | bool consumeBatchedInputEvents(std::optional<DeviceId> deviceId, |
| 236 | std::optional<nsecs_t> requestedFrameTime); |
Paul Ramirez | b41d38e | 2024-07-16 17:44:20 +0000 | [diff] [blame] | 237 | /** |
Siarhei Vishniakou | 2b92027 | 2024-02-27 19:49:51 -0800 | [diff] [blame] | 238 | * A map from a single sequence number to several sequence numbers. This is needed because of |
| 239 | * batching. When batching is enabled, a single MotionEvent will contain several samples. Each |
| 240 | * sample came from an individual InputMessage of Type::Motion, and therefore will have to be |
| 241 | * finished individually. Therefore, when the app calls "finish" on a (possibly batched) |
| 242 | * MotionEvent, we will need to check this map in case there are multiple sequence numbers |
| 243 | * associated with a single number that the app provided. |
| 244 | * |
| 245 | * For example: |
| 246 | * Suppose we received 4 InputMessage's of type Motion, with action MOVE: |
| 247 | * InputMessage(MOVE) InputMessage(MOVE) InputMessage(MOVE) InputMessage(MOVE) |
| 248 | * seq=10 seq=11 seq=12 seq=13 |
| 249 | * The app consumed them all as a batch, which means that the app received a single MotionEvent |
| 250 | * with historySize=3 and seq = 10. |
| 251 | * |
| 252 | * This map will look like: |
| 253 | * { |
| 254 | * 10: [11, 12, 13], |
| 255 | * } |
| 256 | * So the sequence number 10 will have 3 other sequence numbers associated with it. |
| 257 | * When the app calls 'finish' for seq=10, we need to call 'finish' 4 times total, for sequence |
| 258 | * numbers 10, 11, 12, 13. The app is not aware of the sequence numbers of each sample inside |
| 259 | * the batched MotionEvent that it received. |
| 260 | */ |
| 261 | std::map<uint32_t, std::vector<uint32_t>> mBatchedSequenceNumbers; |
| 262 | }; |
| 263 | |
| 264 | } // namespace android |