blob: 6d95ca7e86cfa5ccfd45dbcc8e2b693edab20463 [file] [log] [blame]
Paul Ramirezbe9c5442024-07-10 00:12:41 +00001/**
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 Ramirez29ee27c2024-10-02 08:18:53 +000019#include <array>
Paul Ramirezbe9c5442024-07-10 00:12:41 +000020#include <chrono>
Paul Ramirez29ee27c2024-10-02 08:18:53 +000021#include <iterator>
Paul Ramirezbe9c5442024-07-10 00:12:41 +000022#include <optional>
Paul Ramirezcf1b06e2024-08-01 17:11:58 +000023#include <vector>
Paul Ramirezbe9c5442024-07-10 00:12:41 +000024
Paul Ramirez29ee27c2024-10-02 08:18:53 +000025#include <android-base/logging.h>
26#include <ftl/mixins.h>
Paul Ramirezbe9c5442024-07-10 00:12:41 +000027#include <input/Input.h>
28#include <input/InputTransport.h>
29#include <input/RingBuffer.h>
30#include <utils/Timers.h>
31
32namespace android {
33
34/**
35 * Resampler is an interface for resampling MotionEvents. Every resampling implementation
36 * must use this interface to enable resampling inside InputConsumer's logic.
37 */
38struct Resampler {
39 virtual ~Resampler() = default;
40
41 /**
Paul Ramirez6affbdb2024-09-11 22:20:26 +000042 * Tries to resample motionEvent at frameTime. The provided frameTime must be greater than
Paul Ramirezbe9c5442024-07-10 00:12:41 +000043 * the latest sample time of motionEvent. It is not guaranteed that resampling occurs at
Paul Ramirez6affbdb2024-09-11 22:20:26 +000044 * frameTime. Interpolation may occur is futureSample is available. Otherwise, motionEvent
Paul Ramirezbe9c5442024-07-10 00:12:41 +000045 * may be resampled by another method, or not resampled at all. Furthermore, it is the
46 * implementer's responsibility to guarantee the following:
47 * - If resampling occurs, a single additional sample should be added to motionEvent. That is,
48 * if motionEvent had N samples before being passed to Resampler, then it will have N + 1
49 * samples by the end of the resampling. No other field of motionEvent should be modified.
50 * - If resampling does not occur, then motionEvent must not be modified in any way.
51 */
Paul Ramirez6affbdb2024-09-11 22:20:26 +000052 virtual void resampleMotionEvent(std::chrono::nanoseconds frameTime, MotionEvent& motionEvent,
Paul Ramirezbe9c5442024-07-10 00:12:41 +000053 const InputMessage* futureSample) = 0;
Paul Ramirezcd7488c2024-09-13 23:01:12 +000054
55 /**
56 * Returns resample latency. Resample latency is the time difference between frame time and
57 * resample time. More precisely, let frameTime and resampleTime be two timestamps, and
58 * frameTime > resampleTime. Resample latency is defined as frameTime - resampleTime.
59 */
60 virtual std::chrono::nanoseconds getResampleLatency() const = 0;
Paul Ramirezbe9c5442024-07-10 00:12:41 +000061};
62
63class LegacyResampler final : public Resampler {
64public:
65 /**
Paul Ramirez6affbdb2024-09-11 22:20:26 +000066 * Tries to resample `motionEvent` at `frameTime` by adding a resampled sample at the end of
Paul Ramirezbe9c5442024-07-10 00:12:41 +000067 * `motionEvent` with eventTime equal to `resampleTime` and pointer coordinates determined by
68 * linear interpolation or linear extrapolation. An earlier `resampleTime` will be used if
69 * extrapolation takes place and `resampleTime` is too far in the future. If `futureSample` is
70 * not null, interpolation will occur. If `futureSample` is null and there is enough historical
71 * data, LegacyResampler will extrapolate. Otherwise, no resampling takes place and
Paul Ramirez7f1efed2024-09-29 23:55:23 +000072 * `motionEvent` is unmodified. Furthermore, motionEvent is not resampled if resampleTime equals
73 * the last sample eventTime of motionEvent.
Paul Ramirezbe9c5442024-07-10 00:12:41 +000074 */
Paul Ramirez6affbdb2024-09-11 22:20:26 +000075 void resampleMotionEvent(std::chrono::nanoseconds frameTime, MotionEvent& motionEvent,
Paul Ramirezbe9c5442024-07-10 00:12:41 +000076 const InputMessage* futureSample) override;
77
Paul Ramirezcd7488c2024-09-13 23:01:12 +000078 std::chrono::nanoseconds getResampleLatency() const override;
79
Paul Ramirezbe9c5442024-07-10 00:12:41 +000080private:
81 struct Pointer {
82 PointerProperties properties;
83 PointerCoords coords;
84 };
85
Paul Ramirez29ee27c2024-10-02 08:18:53 +000086 /**
87 * Container that stores pointers as an associative array, supporting O(1) lookup by pointer id,
88 * as well as forward iteration in the order in which the pointer or pointers were inserted in
89 * the container. PointerMap has a maximum capacity equal to MAX_POINTERS.
90 */
91 class PointerMap {
92 public:
93 struct PointerId : ftl::DefaultConstructible<PointerId, int32_t>,
94 ftl::Equatable<PointerId> {
95 using DefaultConstructible::DefaultConstructible;
96 };
97
98 /**
99 * Custom iterator to enable use of range-based for loops.
100 */
101 template <typename T>
102 class iterator {
103 public:
104 using iterator_category = std::forward_iterator_tag;
105 using value_type = T;
106 using difference_type = std::ptrdiff_t;
107 using pointer = T*;
108 using reference = T&;
109
110 explicit iterator(pointer element) : mElement{element} {}
111
112 friend bool operator==(const iterator& lhs, const iterator& rhs) {
113 return lhs.mElement == rhs.mElement;
114 }
115
116 friend bool operator!=(const iterator& lhs, const iterator& rhs) {
117 return !(lhs == rhs);
118 }
119
120 iterator operator++() {
121 ++mElement;
122 return *this;
123 }
124
125 reference operator*() const { return *mElement; }
126
127 private:
128 pointer mElement;
129 };
130
131 PointerMap() {
132 idToIndex.fill(std::nullopt);
133 for (Pointer& pointer : pointers) {
134 pointer.properties.clear();
135 pointer.coords.clear();
136 }
137 }
138
139 /**
140 * Forward iterators to traverse the pointers in `pointers`. The order of the pointers is
141 * determined by the order in which they were inserted (not by id).
142 */
143 iterator<Pointer> begin() { return iterator<Pointer>{&pointers[0]}; }
144
145 iterator<const Pointer> begin() const { return iterator<const Pointer>{&pointers[0]}; }
146
147 iterator<Pointer> end() { return iterator<Pointer>{&pointers[nextPointerIndex]}; }
148
149 iterator<const Pointer> end() const {
150 return iterator<const Pointer>{&pointers[nextPointerIndex]};
151 }
152
153 /**
154 * Inserts the given pointer into the PointerMap. Precondition: The current number of
155 * contained pointers must be less than MAX_POINTERS when this function is called. It
156 * fatally logs if the user tries to insert more than MAX_POINTERS, or if pointer id is out
157 * of bounds.
158 */
159 void insert(const Pointer& pointer) {
160 LOG_IF(FATAL, nextPointerIndex >= pointers.size())
161 << "Cannot insert more than " << MAX_POINTERS << " in PointerMap.";
162 LOG_IF(FATAL, (pointer.properties.id < 0) || (pointer.properties.id > MAX_POINTER_ID))
163 << "Invalid pointer id.";
164 idToIndex[pointer.properties.id] = std::optional<size_t>{nextPointerIndex};
165 pointers[nextPointerIndex] = pointer;
166 ++nextPointerIndex;
167 }
168
169 /**
170 * Returns the pointer associated with the provided id if it exists.
171 * Otherwise, std::nullopt is returned.
172 */
173 std::optional<Pointer> find(PointerId id) const {
174 const int32_t idValue = ftl::to_underlying(id);
175 LOG_IF(FATAL, (idValue < 0) || (idValue > MAX_POINTER_ID)) << "Invalid pointer id.";
176 const std::optional<size_t> index = idToIndex[idValue];
177 return index.has_value() ? std::optional{pointers[*index]} : std::nullopt;
178 }
179
180 private:
181 /**
182 * The index at which a pointer is inserted in `pointers`. Likewise, it represents the
183 * number of pointers in PointerMap.
184 */
185 size_t nextPointerIndex{0};
186
187 /**
188 * Sequentially stores pointers. Each pointer's position is determined by the value of
189 * nextPointerIndex at insertion time.
190 */
191 std::array<Pointer, MAX_POINTERS + 1> pointers;
192
193 /**
194 * Maps each pointer id to its associated index in pointers. If no pointer with the id
195 * exists in pointers, the mapped value is std::nullopt.
196 */
197 std::array<std::optional<size_t>, MAX_POINTER_ID + 1> idToIndex;
198 };
199
Paul Ramirezbe9c5442024-07-10 00:12:41 +0000200 struct Sample {
201 std::chrono::nanoseconds eventTime;
Paul Ramirez29ee27c2024-10-02 08:18:53 +0000202 PointerMap pointerMap;
Paul Ramirezcf1b06e2024-08-01 17:11:58 +0000203
204 std::vector<PointerCoords> asPointerCoords() const {
205 std::vector<PointerCoords> pointersCoords;
Paul Ramirez29ee27c2024-10-02 08:18:53 +0000206 for (const Pointer& pointer : pointerMap) {
Paul Ramirezcf1b06e2024-08-01 17:11:58 +0000207 pointersCoords.push_back(pointer.coords);
208 }
209 return pointersCoords;
210 }
Paul Ramirezbe9c5442024-07-10 00:12:41 +0000211 };
212
213 /**
Paul Ramirezbe9c5442024-07-10 00:12:41 +0000214 * Up to two latest samples from MotionEvent. Updated every time resampleMotionEvent is called.
215 * Note: We store up to two samples in order to simplify the implementation. Although,
216 * calculations are possible with only one previous sample.
217 */
218 RingBuffer<Sample> mLatestSamples{/*capacity=*/2};
219
220 /**
Paul Ramirez29ee27c2024-10-02 08:18:53 +0000221 * Latest sample in mLatestSamples after resampling motion event.
Paul Ramirez4d3b03a2024-09-30 01:39:00 +0000222 */
223 std::optional<Sample> mLastRealSample;
224
225 /**
Paul Ramirez29ee27c2024-10-02 08:18:53 +0000226 * Latest prediction. That is, the latest extrapolated sample.
Paul Ramirez4d3b03a2024-09-30 01:39:00 +0000227 */
228 std::optional<Sample> mPreviousPrediction;
229
230 /**
Paul Ramirezcf1b06e2024-08-01 17:11:58 +0000231 * Adds up to mLatestSamples.capacity() of motionEvent's latest samples to mLatestSamples. If
Paul Ramirezbe9c5442024-07-10 00:12:41 +0000232 * motionEvent has fewer samples than mLatestSamples.capacity(), then the available samples are
Paul Ramirezcf1b06e2024-08-01 17:11:58 +0000233 * added to mLatestSamples.
Paul Ramirezbe9c5442024-07-10 00:12:41 +0000234 */
235 void updateLatestSamples(const MotionEvent& motionEvent);
236
Paul Ramirezcf1b06e2024-08-01 17:11:58 +0000237 static Sample messageToSample(const InputMessage& message);
238
239 /**
240 * Checks if auxiliary sample has the same pointer properties of target sample. That is,
241 * auxiliary pointer IDs must appear in the same order as target pointer IDs, their toolType
242 * must match and be resampleable.
243 */
244 static bool pointerPropertiesResampleable(const Sample& target, const Sample& auxiliary);
245
Paul Ramirezbe9c5442024-07-10 00:12:41 +0000246 /**
Paul Ramirez486ca6d2024-08-12 14:37:02 +0000247 * Checks if there are necessary conditions to interpolate. For example, interpolation cannot
248 * take place if samples are too far apart in time. mLatestSamples must have at least one sample
249 * when canInterpolate is invoked.
Paul Ramirezbe9c5442024-07-10 00:12:41 +0000250 */
Paul Ramirez486ca6d2024-08-12 14:37:02 +0000251 bool canInterpolate(const InputMessage& futureSample) const;
Paul Ramirezbe9c5442024-07-10 00:12:41 +0000252
253 /**
Paul Ramirez29ee27c2024-10-02 08:18:53 +0000254 * Returns a sample interpolated between the latest sample of mLatestSamples and futureMessage,
Paul Ramirez486ca6d2024-08-12 14:37:02 +0000255 * if the conditions from canInterpolate are satisfied. Otherwise, returns nullopt.
256 * mLatestSamples must have at least one sample when attemptInterpolation is called.
Paul Ramirezbe9c5442024-07-10 00:12:41 +0000257 */
Paul Ramirez486ca6d2024-08-12 14:37:02 +0000258 std::optional<Sample> attemptInterpolation(std::chrono::nanoseconds resampleTime,
Paul Ramirez29ee27c2024-10-02 08:18:53 +0000259 const InputMessage& futureMessage) const;
Paul Ramirez486ca6d2024-08-12 14:37:02 +0000260
261 /**
262 * Checks if there are necessary conditions to extrapolate. That is, there are at least two
263 * samples in mLatestSamples, and delta is bounded within a time interval.
264 */
265 bool canExtrapolate() const;
266
267 /**
268 * Returns a sample extrapolated from the two samples of mLatestSamples, if the conditions from
269 * canExtrapolate are satisfied. The returned sample either has eventTime equal to resampleTime,
270 * or an earlier time if resampleTime is too far in the future. If canExtrapolate returns false,
271 * this function returns nullopt.
272 */
273 std::optional<Sample> attemptExtrapolation(std::chrono::nanoseconds resampleTime) const;
274
Paul Ramirez4d3b03a2024-09-30 01:39:00 +0000275 /**
Paul Ramirez29ee27c2024-10-02 08:18:53 +0000276 * Iterates through motion event samples, and replaces real coordinates with resampled
277 * coordinates to avoid jerkiness in certain conditions.
Paul Ramirez4d3b03a2024-09-30 01:39:00 +0000278 */
279 void overwriteMotionEventSamples(MotionEvent& motionEvent) const;
280
281 /**
282 * Overwrites with resampled data the pointer coordinates that did not move between motion event
283 * samples, that is, both x and y values are identical to mLastRealSample.
284 */
285 void overwriteStillPointers(MotionEvent& motionEvent, size_t sampleIndex) const;
286
Paul Ramirez4679e552024-10-01 01:17:39 +0000287 /**
288 * Overwrites the pointer coordinates of a sample with event time older than
289 * that of mPreviousPrediction.
290 */
291 void overwriteOldPointers(MotionEvent& motionEvent, size_t sampleIndex) const;
292
Paul Ramirez486ca6d2024-08-12 14:37:02 +0000293 inline static void addSampleToMotionEvent(const Sample& sample, MotionEvent& motionEvent);
Paul Ramirezbe9c5442024-07-10 00:12:41 +0000294};
Paul Ramirez29ee27c2024-10-02 08:18:53 +0000295
Paul Ramirezcf1b06e2024-08-01 17:11:58 +0000296} // namespace android