blob: ff9c4b0868f19afed713d6e16d63901c4c0d42b5 [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>
21
22#include <input/Input.h>
23#include <input/InputTransport.h>
24#include <input/RingBuffer.h>
25#include <utils/Timers.h>
26
27namespace android {
28
29/**
30 * Resampler is an interface for resampling MotionEvents. Every resampling implementation
31 * must use this interface to enable resampling inside InputConsumer's logic.
32 */
33struct Resampler {
34 virtual ~Resampler() = default;
35
36 /**
37 * Tries to resample motionEvent at resampleTime. The provided resampleTime must be greater than
38 * the latest sample time of motionEvent. It is not guaranteed that resampling occurs at
39 * resampleTime. Interpolation may occur is futureSample is available. Otherwise, motionEvent
40 * may be resampled by another method, or not resampled at all. Furthermore, it is the
41 * implementer's responsibility to guarantee the following:
42 * - If resampling occurs, a single additional sample should be added to motionEvent. That is,
43 * if motionEvent had N samples before being passed to Resampler, then it will have N + 1
44 * samples by the end of the resampling. No other field of motionEvent should be modified.
45 * - If resampling does not occur, then motionEvent must not be modified in any way.
46 */
47 virtual void resampleMotionEvent(const std::chrono::nanoseconds resampleTime,
48 MotionEvent& motionEvent,
49 const InputMessage* futureSample) = 0;
50};
51
52class LegacyResampler final : public Resampler {
53public:
54 /**
55 * Tries to resample `motionEvent` at `resampleTime` by adding a resampled sample at the end of
56 * `motionEvent` with eventTime equal to `resampleTime` and pointer coordinates determined by
57 * linear interpolation or linear extrapolation. An earlier `resampleTime` will be used if
58 * extrapolation takes place and `resampleTime` is too far in the future. If `futureSample` is
59 * not null, interpolation will occur. If `futureSample` is null and there is enough historical
60 * data, LegacyResampler will extrapolate. Otherwise, no resampling takes place and
61 * `motionEvent` is unmodified.
62 */
63 void resampleMotionEvent(const std::chrono::nanoseconds resampleTime, MotionEvent& motionEvent,
64 const InputMessage* futureSample) override;
65
66private:
67 struct Pointer {
68 PointerProperties properties;
69 PointerCoords coords;
70 };
71
72 struct Sample {
73 std::chrono::nanoseconds eventTime;
74 Pointer pointer;
75
76 Sample(const std::chrono::nanoseconds eventTime, const PointerProperties& properties,
77 const PointerCoords& coords)
78 : eventTime{eventTime}, pointer{properties, coords} {}
79 };
80
81 /**
82 * Keeps track of the previous MotionEvent deviceId to enable comparison between the previous
83 * and the current deviceId.
84 */
85 std::optional<DeviceId> mPreviousDeviceId;
86
87 /**
88 * Up to two latest samples from MotionEvent. Updated every time resampleMotionEvent is called.
89 * Note: We store up to two samples in order to simplify the implementation. Although,
90 * calculations are possible with only one previous sample.
91 */
92 RingBuffer<Sample> mLatestSamples{/*capacity=*/2};
93
94 /**
95 * Adds up to mLatestSamples.capacity() of motionEvent's latest samples to mLatestSamples. (If
96 * motionEvent has fewer samples than mLatestSamples.capacity(), then the available samples are
97 * added to mLatestSamples.)
98 */
99 void updateLatestSamples(const MotionEvent& motionEvent);
100
101 /**
102 * May add a sample at the end of motionEvent with eventTime equal to resampleTime, and
103 * interpolated coordinates between the latest motionEvent sample and futureSample.
104 */
105 void interpolate(const std::chrono::nanoseconds resampleTime, MotionEvent& motionEvent,
106 const InputMessage& futureSample) const;
107
108 /**
109 * May add a sample at the end of motionEvent by extrapolating from the latest two samples. The
110 * added sample either has eventTime equal to resampleTime, or an earlier time if resampleTime
111 * is too far in the future.
112 */
113 void extrapolate(const std::chrono::nanoseconds resampleTime, MotionEvent& motionEvent) const;
114};
115} // namespace android