blob: da0c5b2150791e037f06ee2802524d9d536b0036 [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
19#include <chrono>
20#include <optional>
Paul Ramirezcf1b06e2024-08-01 17:11:58 +000021#include <vector>
Paul Ramirezbe9c5442024-07-10 00:12:41 +000022
23#include <input/Input.h>
24#include <input/InputTransport.h>
25#include <input/RingBuffer.h>
26#include <utils/Timers.h>
27
28namespace android {
29
30/**
31 * Resampler is an interface for resampling MotionEvents. Every resampling implementation
32 * must use this interface to enable resampling inside InputConsumer's logic.
33 */
34struct Resampler {
35 virtual ~Resampler() = default;
36
37 /**
Paul Ramirez6affbdb2024-09-11 22:20:26 +000038 * Tries to resample motionEvent at frameTime. The provided frameTime must be greater than
Paul Ramirezbe9c5442024-07-10 00:12:41 +000039 * the latest sample time of motionEvent. It is not guaranteed that resampling occurs at
Paul Ramirez6affbdb2024-09-11 22:20:26 +000040 * frameTime. Interpolation may occur is futureSample is available. Otherwise, motionEvent
Paul Ramirezbe9c5442024-07-10 00:12:41 +000041 * may be resampled by another method, or not resampled at all. Furthermore, it is the
42 * implementer's responsibility to guarantee the following:
43 * - If resampling occurs, a single additional sample should be added to motionEvent. That is,
44 * if motionEvent had N samples before being passed to Resampler, then it will have N + 1
45 * samples by the end of the resampling. No other field of motionEvent should be modified.
46 * - If resampling does not occur, then motionEvent must not be modified in any way.
47 */
Paul Ramirez6affbdb2024-09-11 22:20:26 +000048 virtual void resampleMotionEvent(std::chrono::nanoseconds frameTime, MotionEvent& motionEvent,
Paul Ramirezbe9c5442024-07-10 00:12:41 +000049 const InputMessage* futureSample) = 0;
Paul Ramirezcd7488c2024-09-13 23:01:12 +000050
51 /**
52 * Returns resample latency. Resample latency is the time difference between frame time and
53 * resample time. More precisely, let frameTime and resampleTime be two timestamps, and
54 * frameTime > resampleTime. Resample latency is defined as frameTime - resampleTime.
55 */
56 virtual std::chrono::nanoseconds getResampleLatency() const = 0;
Paul Ramirezbe9c5442024-07-10 00:12:41 +000057};
58
59class LegacyResampler final : public Resampler {
60public:
61 /**
Paul Ramirez6affbdb2024-09-11 22:20:26 +000062 * Tries to resample `motionEvent` at `frameTime` by adding a resampled sample at the end of
Paul Ramirezbe9c5442024-07-10 00:12:41 +000063 * `motionEvent` with eventTime equal to `resampleTime` and pointer coordinates determined by
64 * linear interpolation or linear extrapolation. An earlier `resampleTime` will be used if
65 * extrapolation takes place and `resampleTime` is too far in the future. If `futureSample` is
66 * not null, interpolation will occur. If `futureSample` is null and there is enough historical
67 * data, LegacyResampler will extrapolate. Otherwise, no resampling takes place and
Paul Ramirez7f1efed2024-09-29 23:55:23 +000068 * `motionEvent` is unmodified. Furthermore, motionEvent is not resampled if resampleTime equals
69 * the last sample eventTime of motionEvent.
Paul Ramirezbe9c5442024-07-10 00:12:41 +000070 */
Paul Ramirez6affbdb2024-09-11 22:20:26 +000071 void resampleMotionEvent(std::chrono::nanoseconds frameTime, MotionEvent& motionEvent,
Paul Ramirezbe9c5442024-07-10 00:12:41 +000072 const InputMessage* futureSample) override;
73
Paul Ramirezcd7488c2024-09-13 23:01:12 +000074 std::chrono::nanoseconds getResampleLatency() const override;
75
Paul Ramirezbe9c5442024-07-10 00:12:41 +000076private:
77 struct Pointer {
78 PointerProperties properties;
79 PointerCoords coords;
80 };
81
82 struct Sample {
83 std::chrono::nanoseconds eventTime;
Paul Ramirezcf1b06e2024-08-01 17:11:58 +000084 std::vector<Pointer> pointers;
85
86 std::vector<PointerCoords> asPointerCoords() const {
87 std::vector<PointerCoords> pointersCoords;
88 for (const Pointer& pointer : pointers) {
89 pointersCoords.push_back(pointer.coords);
90 }
91 return pointersCoords;
92 }
Paul Ramirezbe9c5442024-07-10 00:12:41 +000093 };
94
95 /**
Paul Ramirezbe9c5442024-07-10 00:12:41 +000096 * Up to two latest samples from MotionEvent. Updated every time resampleMotionEvent is called.
97 * Note: We store up to two samples in order to simplify the implementation. Although,
98 * calculations are possible with only one previous sample.
99 */
100 RingBuffer<Sample> mLatestSamples{/*capacity=*/2};
101
102 /**
Paul Ramirezcf1b06e2024-08-01 17:11:58 +0000103 * Adds up to mLatestSamples.capacity() of motionEvent's latest samples to mLatestSamples. If
Paul Ramirezbe9c5442024-07-10 00:12:41 +0000104 * motionEvent has fewer samples than mLatestSamples.capacity(), then the available samples are
Paul Ramirezcf1b06e2024-08-01 17:11:58 +0000105 * added to mLatestSamples.
Paul Ramirezbe9c5442024-07-10 00:12:41 +0000106 */
107 void updateLatestSamples(const MotionEvent& motionEvent);
108
Paul Ramirezcf1b06e2024-08-01 17:11:58 +0000109 static Sample messageToSample(const InputMessage& message);
110
111 /**
112 * Checks if auxiliary sample has the same pointer properties of target sample. That is,
113 * auxiliary pointer IDs must appear in the same order as target pointer IDs, their toolType
114 * must match and be resampleable.
115 */
116 static bool pointerPropertiesResampleable(const Sample& target, const Sample& auxiliary);
117
Paul Ramirezbe9c5442024-07-10 00:12:41 +0000118 /**
Paul Ramirez486ca6d2024-08-12 14:37:02 +0000119 * Checks if there are necessary conditions to interpolate. For example, interpolation cannot
120 * take place if samples are too far apart in time. mLatestSamples must have at least one sample
121 * when canInterpolate is invoked.
Paul Ramirezbe9c5442024-07-10 00:12:41 +0000122 */
Paul Ramirez486ca6d2024-08-12 14:37:02 +0000123 bool canInterpolate(const InputMessage& futureSample) const;
Paul Ramirezbe9c5442024-07-10 00:12:41 +0000124
125 /**
Paul Ramirez486ca6d2024-08-12 14:37:02 +0000126 * Returns a sample interpolated between the latest sample of mLatestSamples and futureSample,
127 * if the conditions from canInterpolate are satisfied. Otherwise, returns nullopt.
128 * mLatestSamples must have at least one sample when attemptInterpolation is called.
Paul Ramirezbe9c5442024-07-10 00:12:41 +0000129 */
Paul Ramirez486ca6d2024-08-12 14:37:02 +0000130 std::optional<Sample> attemptInterpolation(std::chrono::nanoseconds resampleTime,
131 const InputMessage& futureSample) const;
132
133 /**
134 * Checks if there are necessary conditions to extrapolate. That is, there are at least two
135 * samples in mLatestSamples, and delta is bounded within a time interval.
136 */
137 bool canExtrapolate() const;
138
139 /**
140 * Returns a sample extrapolated from the two samples of mLatestSamples, if the conditions from
141 * canExtrapolate are satisfied. The returned sample either has eventTime equal to resampleTime,
142 * or an earlier time if resampleTime is too far in the future. If canExtrapolate returns false,
143 * this function returns nullopt.
144 */
145 std::optional<Sample> attemptExtrapolation(std::chrono::nanoseconds resampleTime) const;
146
147 inline static void addSampleToMotionEvent(const Sample& sample, MotionEvent& motionEvent);
Paul Ramirezbe9c5442024-07-10 00:12:41 +0000148};
Paul Ramirezcf1b06e2024-08-01 17:11:58 +0000149} // namespace android