1*38e8c45fSAndroid Build Coastguard Worker /** 2*38e8c45fSAndroid Build Coastguard Worker * Copyright 2024 The Android Open Source Project 3*38e8c45fSAndroid Build Coastguard Worker * 4*38e8c45fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*38e8c45fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*38e8c45fSAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*38e8c45fSAndroid Build Coastguard Worker * 8*38e8c45fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*38e8c45fSAndroid Build Coastguard Worker * 10*38e8c45fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*38e8c45fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*38e8c45fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*38e8c45fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*38e8c45fSAndroid Build Coastguard Worker * limitations under the License. 15*38e8c45fSAndroid Build Coastguard Worker */ 16*38e8c45fSAndroid Build Coastguard Worker 17*38e8c45fSAndroid Build Coastguard Worker #pragma once 18*38e8c45fSAndroid Build Coastguard Worker 19*38e8c45fSAndroid Build Coastguard Worker #include <array> 20*38e8c45fSAndroid Build Coastguard Worker #include <chrono> 21*38e8c45fSAndroid Build Coastguard Worker #include <iterator> 22*38e8c45fSAndroid Build Coastguard Worker #include <map> 23*38e8c45fSAndroid Build Coastguard Worker #include <optional> 24*38e8c45fSAndroid Build Coastguard Worker #include <vector> 25*38e8c45fSAndroid Build Coastguard Worker 26*38e8c45fSAndroid Build Coastguard Worker #include <android-base/logging.h> 27*38e8c45fSAndroid Build Coastguard Worker #include <ftl/mixins.h> 28*38e8c45fSAndroid Build Coastguard Worker #include <input/CoordinateFilter.h> 29*38e8c45fSAndroid Build Coastguard Worker #include <input/Input.h> 30*38e8c45fSAndroid Build Coastguard Worker #include <input/InputTransport.h> 31*38e8c45fSAndroid Build Coastguard Worker #include <input/RingBuffer.h> 32*38e8c45fSAndroid Build Coastguard Worker #include <utils/Timers.h> 33*38e8c45fSAndroid Build Coastguard Worker 34*38e8c45fSAndroid Build Coastguard Worker namespace android { 35*38e8c45fSAndroid Build Coastguard Worker 36*38e8c45fSAndroid Build Coastguard Worker /** 37*38e8c45fSAndroid Build Coastguard Worker * Resampler is an interface for resampling MotionEvents. Every resampling implementation 38*38e8c45fSAndroid Build Coastguard Worker * must use this interface to enable resampling inside InputConsumer's logic. 39*38e8c45fSAndroid Build Coastguard Worker */ 40*38e8c45fSAndroid Build Coastguard Worker struct Resampler { 41*38e8c45fSAndroid Build Coastguard Worker virtual ~Resampler() = default; 42*38e8c45fSAndroid Build Coastguard Worker 43*38e8c45fSAndroid Build Coastguard Worker /** 44*38e8c45fSAndroid Build Coastguard Worker * Tries to resample motionEvent at frameTime. The provided frameTime must be greater than 45*38e8c45fSAndroid Build Coastguard Worker * the latest sample time of motionEvent. It is not guaranteed that resampling occurs at 46*38e8c45fSAndroid Build Coastguard Worker * frameTime. Interpolation may occur is futureSample is available. Otherwise, motionEvent 47*38e8c45fSAndroid Build Coastguard Worker * may be resampled by another method, or not resampled at all. Furthermore, it is the 48*38e8c45fSAndroid Build Coastguard Worker * implementer's responsibility to guarantee the following: 49*38e8c45fSAndroid Build Coastguard Worker * - If resampling occurs, a single additional sample should be added to motionEvent. That is, 50*38e8c45fSAndroid Build Coastguard Worker * if motionEvent had N samples before being passed to Resampler, then it will have N + 1 51*38e8c45fSAndroid Build Coastguard Worker * samples by the end of the resampling. No other field of motionEvent should be modified. 52*38e8c45fSAndroid Build Coastguard Worker * - If resampling does not occur, then motionEvent must not be modified in any way. 53*38e8c45fSAndroid Build Coastguard Worker */ 54*38e8c45fSAndroid Build Coastguard Worker virtual void resampleMotionEvent(std::chrono::nanoseconds frameTime, MotionEvent& motionEvent, 55*38e8c45fSAndroid Build Coastguard Worker const InputMessage* futureSample) = 0; 56*38e8c45fSAndroid Build Coastguard Worker 57*38e8c45fSAndroid Build Coastguard Worker /** 58*38e8c45fSAndroid Build Coastguard Worker * Returns resample latency. Resample latency is the time difference between frame time and 59*38e8c45fSAndroid Build Coastguard Worker * resample time. More precisely, let frameTime and resampleTime be two timestamps, and 60*38e8c45fSAndroid Build Coastguard Worker * frameTime > resampleTime. Resample latency is defined as frameTime - resampleTime. 61*38e8c45fSAndroid Build Coastguard Worker */ 62*38e8c45fSAndroid Build Coastguard Worker virtual std::chrono::nanoseconds getResampleLatency() const = 0; 63*38e8c45fSAndroid Build Coastguard Worker }; 64*38e8c45fSAndroid Build Coastguard Worker 65*38e8c45fSAndroid Build Coastguard Worker class LegacyResampler final : public Resampler { 66*38e8c45fSAndroid Build Coastguard Worker public: 67*38e8c45fSAndroid Build Coastguard Worker /** 68*38e8c45fSAndroid Build Coastguard Worker * Tries to resample `motionEvent` at `frameTime` by adding a resampled sample at the end of 69*38e8c45fSAndroid Build Coastguard Worker * `motionEvent` with eventTime equal to `resampleTime` and pointer coordinates determined by 70*38e8c45fSAndroid Build Coastguard Worker * linear interpolation or linear extrapolation. An earlier `resampleTime` will be used if 71*38e8c45fSAndroid Build Coastguard Worker * extrapolation takes place and `resampleTime` is too far in the future. If `futureSample` is 72*38e8c45fSAndroid Build Coastguard Worker * not null, interpolation will occur. If `futureSample` is null and there is enough historical 73*38e8c45fSAndroid Build Coastguard Worker * data, LegacyResampler will extrapolate. Otherwise, no resampling takes place and 74*38e8c45fSAndroid Build Coastguard Worker * `motionEvent` is unmodified. Furthermore, motionEvent is not resampled if resampleTime equals 75*38e8c45fSAndroid Build Coastguard Worker * the last sample eventTime of motionEvent. 76*38e8c45fSAndroid Build Coastguard Worker */ 77*38e8c45fSAndroid Build Coastguard Worker void resampleMotionEvent(std::chrono::nanoseconds frameTime, MotionEvent& motionEvent, 78*38e8c45fSAndroid Build Coastguard Worker const InputMessage* futureSample) override; 79*38e8c45fSAndroid Build Coastguard Worker 80*38e8c45fSAndroid Build Coastguard Worker std::chrono::nanoseconds getResampleLatency() const override; 81*38e8c45fSAndroid Build Coastguard Worker 82*38e8c45fSAndroid Build Coastguard Worker private: 83*38e8c45fSAndroid Build Coastguard Worker struct Pointer { 84*38e8c45fSAndroid Build Coastguard Worker PointerProperties properties; 85*38e8c45fSAndroid Build Coastguard Worker PointerCoords coords; 86*38e8c45fSAndroid Build Coastguard Worker }; 87*38e8c45fSAndroid Build Coastguard Worker 88*38e8c45fSAndroid Build Coastguard Worker /** 89*38e8c45fSAndroid Build Coastguard Worker * Container that stores pointers as an associative array, supporting O(1) lookup by pointer id, 90*38e8c45fSAndroid Build Coastguard Worker * as well as forward iteration in the order in which the pointer or pointers were inserted in 91*38e8c45fSAndroid Build Coastguard Worker * the container. PointerMap has a maximum capacity equal to MAX_POINTERS. 92*38e8c45fSAndroid Build Coastguard Worker */ 93*38e8c45fSAndroid Build Coastguard Worker class PointerMap { 94*38e8c45fSAndroid Build Coastguard Worker public: 95*38e8c45fSAndroid Build Coastguard Worker struct PointerId : ftl::DefaultConstructible<PointerId, int32_t>, 96*38e8c45fSAndroid Build Coastguard Worker ftl::Equatable<PointerId> { 97*38e8c45fSAndroid Build Coastguard Worker using DefaultConstructible::DefaultConstructible; 98*38e8c45fSAndroid Build Coastguard Worker }; 99*38e8c45fSAndroid Build Coastguard Worker 100*38e8c45fSAndroid Build Coastguard Worker /** 101*38e8c45fSAndroid Build Coastguard Worker * Custom iterator to enable use of range-based for loops. 102*38e8c45fSAndroid Build Coastguard Worker */ 103*38e8c45fSAndroid Build Coastguard Worker template <typename T> 104*38e8c45fSAndroid Build Coastguard Worker class iterator { 105*38e8c45fSAndroid Build Coastguard Worker public: 106*38e8c45fSAndroid Build Coastguard Worker using iterator_category = std::forward_iterator_tag; 107*38e8c45fSAndroid Build Coastguard Worker using value_type = T; 108*38e8c45fSAndroid Build Coastguard Worker using difference_type = std::ptrdiff_t; 109*38e8c45fSAndroid Build Coastguard Worker using pointer = T*; 110*38e8c45fSAndroid Build Coastguard Worker using reference = T&; 111*38e8c45fSAndroid Build Coastguard Worker iterator(pointer element)112*38e8c45fSAndroid Build Coastguard Worker explicit iterator(pointer element) : mElement{element} {} 113*38e8c45fSAndroid Build Coastguard Worker 114*38e8c45fSAndroid Build Coastguard Worker friend bool operator==(const iterator& lhs, const iterator& rhs) { 115*38e8c45fSAndroid Build Coastguard Worker return lhs.mElement == rhs.mElement; 116*38e8c45fSAndroid Build Coastguard Worker } 117*38e8c45fSAndroid Build Coastguard Worker 118*38e8c45fSAndroid Build Coastguard Worker friend bool operator!=(const iterator& lhs, const iterator& rhs) { 119*38e8c45fSAndroid Build Coastguard Worker return !(lhs == rhs); 120*38e8c45fSAndroid Build Coastguard Worker } 121*38e8c45fSAndroid Build Coastguard Worker 122*38e8c45fSAndroid Build Coastguard Worker iterator operator++() { 123*38e8c45fSAndroid Build Coastguard Worker ++mElement; 124*38e8c45fSAndroid Build Coastguard Worker return *this; 125*38e8c45fSAndroid Build Coastguard Worker } 126*38e8c45fSAndroid Build Coastguard Worker 127*38e8c45fSAndroid Build Coastguard Worker reference operator*() const { return *mElement; } 128*38e8c45fSAndroid Build Coastguard Worker 129*38e8c45fSAndroid Build Coastguard Worker private: 130*38e8c45fSAndroid Build Coastguard Worker pointer mElement; 131*38e8c45fSAndroid Build Coastguard Worker }; 132*38e8c45fSAndroid Build Coastguard Worker PointerMap()133*38e8c45fSAndroid Build Coastguard Worker PointerMap() { 134*38e8c45fSAndroid Build Coastguard Worker idToIndex.fill(std::nullopt); 135*38e8c45fSAndroid Build Coastguard Worker for (Pointer& pointer : pointers) { 136*38e8c45fSAndroid Build Coastguard Worker pointer.properties.clear(); 137*38e8c45fSAndroid Build Coastguard Worker pointer.coords.clear(); 138*38e8c45fSAndroid Build Coastguard Worker } 139*38e8c45fSAndroid Build Coastguard Worker } 140*38e8c45fSAndroid Build Coastguard Worker 141*38e8c45fSAndroid Build Coastguard Worker /** 142*38e8c45fSAndroid Build Coastguard Worker * Forward iterators to traverse the pointers in `pointers`. The order of the pointers is 143*38e8c45fSAndroid Build Coastguard Worker * determined by the order in which they were inserted (not by id). 144*38e8c45fSAndroid Build Coastguard Worker */ begin()145*38e8c45fSAndroid Build Coastguard Worker iterator<Pointer> begin() { return iterator<Pointer>{&pointers[0]}; } 146*38e8c45fSAndroid Build Coastguard Worker begin()147*38e8c45fSAndroid Build Coastguard Worker iterator<const Pointer> begin() const { return iterator<const Pointer>{&pointers[0]}; } 148*38e8c45fSAndroid Build Coastguard Worker end()149*38e8c45fSAndroid Build Coastguard Worker iterator<Pointer> end() { return iterator<Pointer>{&pointers[nextPointerIndex]}; } 150*38e8c45fSAndroid Build Coastguard Worker end()151*38e8c45fSAndroid Build Coastguard Worker iterator<const Pointer> end() const { 152*38e8c45fSAndroid Build Coastguard Worker return iterator<const Pointer>{&pointers[nextPointerIndex]}; 153*38e8c45fSAndroid Build Coastguard Worker } 154*38e8c45fSAndroid Build Coastguard Worker 155*38e8c45fSAndroid Build Coastguard Worker /** 156*38e8c45fSAndroid Build Coastguard Worker * Inserts the given pointer into the PointerMap. Precondition: The current number of 157*38e8c45fSAndroid Build Coastguard Worker * contained pointers must be less than MAX_POINTERS when this function is called. It 158*38e8c45fSAndroid Build Coastguard Worker * fatally logs if the user tries to insert more than MAX_POINTERS, or if pointer id is out 159*38e8c45fSAndroid Build Coastguard Worker * of bounds. 160*38e8c45fSAndroid Build Coastguard Worker */ insert(const Pointer & pointer)161*38e8c45fSAndroid Build Coastguard Worker void insert(const Pointer& pointer) { 162*38e8c45fSAndroid Build Coastguard Worker LOG_IF(FATAL, nextPointerIndex >= pointers.size()) 163*38e8c45fSAndroid Build Coastguard Worker << "Cannot insert more than " << MAX_POINTERS << " in PointerMap."; 164*38e8c45fSAndroid Build Coastguard Worker LOG_IF(FATAL, (pointer.properties.id < 0) || (pointer.properties.id > MAX_POINTER_ID)) 165*38e8c45fSAndroid Build Coastguard Worker << "Invalid pointer id."; 166*38e8c45fSAndroid Build Coastguard Worker idToIndex[pointer.properties.id] = std::optional<size_t>{nextPointerIndex}; 167*38e8c45fSAndroid Build Coastguard Worker pointers[nextPointerIndex] = pointer; 168*38e8c45fSAndroid Build Coastguard Worker ++nextPointerIndex; 169*38e8c45fSAndroid Build Coastguard Worker } 170*38e8c45fSAndroid Build Coastguard Worker 171*38e8c45fSAndroid Build Coastguard Worker /** 172*38e8c45fSAndroid Build Coastguard Worker * Returns the pointer associated with the provided id if it exists. 173*38e8c45fSAndroid Build Coastguard Worker * Otherwise, std::nullopt is returned. 174*38e8c45fSAndroid Build Coastguard Worker */ find(PointerId id)175*38e8c45fSAndroid Build Coastguard Worker std::optional<Pointer> find(PointerId id) const { 176*38e8c45fSAndroid Build Coastguard Worker const int32_t idValue = ftl::to_underlying(id); 177*38e8c45fSAndroid Build Coastguard Worker LOG_IF(FATAL, (idValue < 0) || (idValue > MAX_POINTER_ID)) << "Invalid pointer id."; 178*38e8c45fSAndroid Build Coastguard Worker const std::optional<size_t> index = idToIndex[idValue]; 179*38e8c45fSAndroid Build Coastguard Worker return index.has_value() ? std::optional{pointers[*index]} : std::nullopt; 180*38e8c45fSAndroid Build Coastguard Worker } 181*38e8c45fSAndroid Build Coastguard Worker 182*38e8c45fSAndroid Build Coastguard Worker private: 183*38e8c45fSAndroid Build Coastguard Worker /** 184*38e8c45fSAndroid Build Coastguard Worker * The index at which a pointer is inserted in `pointers`. Likewise, it represents the 185*38e8c45fSAndroid Build Coastguard Worker * number of pointers in PointerMap. 186*38e8c45fSAndroid Build Coastguard Worker */ 187*38e8c45fSAndroid Build Coastguard Worker size_t nextPointerIndex{0}; 188*38e8c45fSAndroid Build Coastguard Worker 189*38e8c45fSAndroid Build Coastguard Worker /** 190*38e8c45fSAndroid Build Coastguard Worker * Sequentially stores pointers. Each pointer's position is determined by the value of 191*38e8c45fSAndroid Build Coastguard Worker * nextPointerIndex at insertion time. 192*38e8c45fSAndroid Build Coastguard Worker */ 193*38e8c45fSAndroid Build Coastguard Worker std::array<Pointer, MAX_POINTERS + 1> pointers; 194*38e8c45fSAndroid Build Coastguard Worker 195*38e8c45fSAndroid Build Coastguard Worker /** 196*38e8c45fSAndroid Build Coastguard Worker * Maps each pointer id to its associated index in pointers. If no pointer with the id 197*38e8c45fSAndroid Build Coastguard Worker * exists in pointers, the mapped value is std::nullopt. 198*38e8c45fSAndroid Build Coastguard Worker */ 199*38e8c45fSAndroid Build Coastguard Worker std::array<std::optional<size_t>, MAX_POINTER_ID + 1> idToIndex; 200*38e8c45fSAndroid Build Coastguard Worker }; 201*38e8c45fSAndroid Build Coastguard Worker 202*38e8c45fSAndroid Build Coastguard Worker struct Sample { 203*38e8c45fSAndroid Build Coastguard Worker std::chrono::nanoseconds eventTime; 204*38e8c45fSAndroid Build Coastguard Worker PointerMap pointerMap; 205*38e8c45fSAndroid Build Coastguard Worker asPointerCoordsSample206*38e8c45fSAndroid Build Coastguard Worker std::vector<PointerCoords> asPointerCoords() const { 207*38e8c45fSAndroid Build Coastguard Worker std::vector<PointerCoords> pointersCoords; 208*38e8c45fSAndroid Build Coastguard Worker for (const Pointer& pointer : pointerMap) { 209*38e8c45fSAndroid Build Coastguard Worker pointersCoords.push_back(pointer.coords); 210*38e8c45fSAndroid Build Coastguard Worker } 211*38e8c45fSAndroid Build Coastguard Worker return pointersCoords; 212*38e8c45fSAndroid Build Coastguard Worker } 213*38e8c45fSAndroid Build Coastguard Worker }; 214*38e8c45fSAndroid Build Coastguard Worker 215*38e8c45fSAndroid Build Coastguard Worker /** 216*38e8c45fSAndroid Build Coastguard Worker * Up to two latest samples from MotionEvent. Updated every time resampleMotionEvent is called. 217*38e8c45fSAndroid Build Coastguard Worker * Note: We store up to two samples in order to simplify the implementation. Although, 218*38e8c45fSAndroid Build Coastguard Worker * calculations are possible with only one previous sample. 219*38e8c45fSAndroid Build Coastguard Worker */ 220*38e8c45fSAndroid Build Coastguard Worker RingBuffer<Sample> mLatestSamples{/*capacity=*/2}; 221*38e8c45fSAndroid Build Coastguard Worker 222*38e8c45fSAndroid Build Coastguard Worker /** 223*38e8c45fSAndroid Build Coastguard Worker * Latest sample in mLatestSamples after resampling motion event. 224*38e8c45fSAndroid Build Coastguard Worker */ 225*38e8c45fSAndroid Build Coastguard Worker std::optional<Sample> mLastRealSample; 226*38e8c45fSAndroid Build Coastguard Worker 227*38e8c45fSAndroid Build Coastguard Worker /** 228*38e8c45fSAndroid Build Coastguard Worker * Latest prediction. That is, the latest extrapolated sample. 229*38e8c45fSAndroid Build Coastguard Worker */ 230*38e8c45fSAndroid Build Coastguard Worker std::optional<Sample> mPreviousPrediction; 231*38e8c45fSAndroid Build Coastguard Worker 232*38e8c45fSAndroid Build Coastguard Worker /** 233*38e8c45fSAndroid Build Coastguard Worker * Adds up to mLatestSamples.capacity() of motionEvent's latest samples to mLatestSamples. If 234*38e8c45fSAndroid Build Coastguard Worker * motionEvent has fewer samples than mLatestSamples.capacity(), then the available samples are 235*38e8c45fSAndroid Build Coastguard Worker * added to mLatestSamples. 236*38e8c45fSAndroid Build Coastguard Worker */ 237*38e8c45fSAndroid Build Coastguard Worker void updateLatestSamples(const MotionEvent& motionEvent); 238*38e8c45fSAndroid Build Coastguard Worker 239*38e8c45fSAndroid Build Coastguard Worker static Sample messageToSample(const InputMessage& message); 240*38e8c45fSAndroid Build Coastguard Worker 241*38e8c45fSAndroid Build Coastguard Worker /** 242*38e8c45fSAndroid Build Coastguard Worker * Checks if auxiliary sample has the same pointer properties of target sample. That is, 243*38e8c45fSAndroid Build Coastguard Worker * auxiliary pointer IDs must appear in the same order as target pointer IDs, their toolType 244*38e8c45fSAndroid Build Coastguard Worker * must match and be resampleable. 245*38e8c45fSAndroid Build Coastguard Worker */ 246*38e8c45fSAndroid Build Coastguard Worker static bool pointerPropertiesResampleable(const Sample& target, const Sample& auxiliary); 247*38e8c45fSAndroid Build Coastguard Worker 248*38e8c45fSAndroid Build Coastguard Worker /** 249*38e8c45fSAndroid Build Coastguard Worker * Checks if there are necessary conditions to interpolate. For example, interpolation cannot 250*38e8c45fSAndroid Build Coastguard Worker * take place if samples are too far apart in time. mLatestSamples must have at least one sample 251*38e8c45fSAndroid Build Coastguard Worker * when canInterpolate is invoked. 252*38e8c45fSAndroid Build Coastguard Worker */ 253*38e8c45fSAndroid Build Coastguard Worker bool canInterpolate(const InputMessage& futureSample) const; 254*38e8c45fSAndroid Build Coastguard Worker 255*38e8c45fSAndroid Build Coastguard Worker /** 256*38e8c45fSAndroid Build Coastguard Worker * Returns a sample interpolated between the latest sample of mLatestSamples and futureMessage, 257*38e8c45fSAndroid Build Coastguard Worker * if the conditions from canInterpolate are satisfied. Otherwise, returns nullopt. 258*38e8c45fSAndroid Build Coastguard Worker * mLatestSamples must have at least one sample when attemptInterpolation is called. 259*38e8c45fSAndroid Build Coastguard Worker */ 260*38e8c45fSAndroid Build Coastguard Worker std::optional<Sample> attemptInterpolation(std::chrono::nanoseconds resampleTime, 261*38e8c45fSAndroid Build Coastguard Worker const InputMessage& futureMessage) const; 262*38e8c45fSAndroid Build Coastguard Worker 263*38e8c45fSAndroid Build Coastguard Worker /** 264*38e8c45fSAndroid Build Coastguard Worker * Checks if there are necessary conditions to extrapolate. That is, there are at least two 265*38e8c45fSAndroid Build Coastguard Worker * samples in mLatestSamples, and delta is bounded within a time interval. 266*38e8c45fSAndroid Build Coastguard Worker */ 267*38e8c45fSAndroid Build Coastguard Worker bool canExtrapolate() const; 268*38e8c45fSAndroid Build Coastguard Worker 269*38e8c45fSAndroid Build Coastguard Worker /** 270*38e8c45fSAndroid Build Coastguard Worker * Returns a sample extrapolated from the two samples of mLatestSamples, if the conditions from 271*38e8c45fSAndroid Build Coastguard Worker * canExtrapolate are satisfied. The returned sample either has eventTime equal to resampleTime, 272*38e8c45fSAndroid Build Coastguard Worker * or an earlier time if resampleTime is too far in the future. If canExtrapolate returns false, 273*38e8c45fSAndroid Build Coastguard Worker * this function returns nullopt. 274*38e8c45fSAndroid Build Coastguard Worker */ 275*38e8c45fSAndroid Build Coastguard Worker std::optional<Sample> attemptExtrapolation(std::chrono::nanoseconds resampleTime) const; 276*38e8c45fSAndroid Build Coastguard Worker 277*38e8c45fSAndroid Build Coastguard Worker /** 278*38e8c45fSAndroid Build Coastguard Worker * Iterates through motion event samples, and replaces real coordinates with resampled 279*38e8c45fSAndroid Build Coastguard Worker * coordinates to avoid jerkiness in certain conditions. 280*38e8c45fSAndroid Build Coastguard Worker */ 281*38e8c45fSAndroid Build Coastguard Worker void overwriteMotionEventSamples(MotionEvent& motionEvent) const; 282*38e8c45fSAndroid Build Coastguard Worker 283*38e8c45fSAndroid Build Coastguard Worker /** 284*38e8c45fSAndroid Build Coastguard Worker * Overwrites with resampled data the pointer coordinates that did not move between motion event 285*38e8c45fSAndroid Build Coastguard Worker * samples, that is, both x and y values are identical to mLastRealSample. 286*38e8c45fSAndroid Build Coastguard Worker */ 287*38e8c45fSAndroid Build Coastguard Worker void overwriteStillPointers(MotionEvent& motionEvent, size_t sampleIndex) const; 288*38e8c45fSAndroid Build Coastguard Worker 289*38e8c45fSAndroid Build Coastguard Worker /** 290*38e8c45fSAndroid Build Coastguard Worker * Overwrites the pointer coordinates of a sample with event time older than 291*38e8c45fSAndroid Build Coastguard Worker * that of mPreviousPrediction. 292*38e8c45fSAndroid Build Coastguard Worker */ 293*38e8c45fSAndroid Build Coastguard Worker void overwriteOldPointers(MotionEvent& motionEvent, size_t sampleIndex) const; 294*38e8c45fSAndroid Build Coastguard Worker 295*38e8c45fSAndroid Build Coastguard Worker inline static void addSampleToMotionEvent(const Sample& sample, MotionEvent& motionEvent); 296*38e8c45fSAndroid Build Coastguard Worker }; 297*38e8c45fSAndroid Build Coastguard Worker 298*38e8c45fSAndroid Build Coastguard Worker /** 299*38e8c45fSAndroid Build Coastguard Worker * Resampler that first applies the LegacyResampler resampling algorithm, then independently filters 300*38e8c45fSAndroid Build Coastguard Worker * the X and Y coordinates with a pair of One Euro filters. 301*38e8c45fSAndroid Build Coastguard Worker */ 302*38e8c45fSAndroid Build Coastguard Worker class FilteredLegacyResampler final : public Resampler { 303*38e8c45fSAndroid Build Coastguard Worker public: 304*38e8c45fSAndroid Build Coastguard Worker /** 305*38e8c45fSAndroid Build Coastguard Worker * Creates a resampler, using the given minCutoffFreq and beta to instantiate its One Euro 306*38e8c45fSAndroid Build Coastguard Worker * filters. 307*38e8c45fSAndroid Build Coastguard Worker */ 308*38e8c45fSAndroid Build Coastguard Worker explicit FilteredLegacyResampler(float minCutoffFreq, float beta); 309*38e8c45fSAndroid Build Coastguard Worker 310*38e8c45fSAndroid Build Coastguard Worker void resampleMotionEvent(std::chrono::nanoseconds requestedFrameTime, MotionEvent& motionEvent, 311*38e8c45fSAndroid Build Coastguard Worker const InputMessage* futureMessage) override; 312*38e8c45fSAndroid Build Coastguard Worker 313*38e8c45fSAndroid Build Coastguard Worker std::chrono::nanoseconds getResampleLatency() const override; 314*38e8c45fSAndroid Build Coastguard Worker 315*38e8c45fSAndroid Build Coastguard Worker private: 316*38e8c45fSAndroid Build Coastguard Worker LegacyResampler mResampler; 317*38e8c45fSAndroid Build Coastguard Worker 318*38e8c45fSAndroid Build Coastguard Worker /** 319*38e8c45fSAndroid Build Coastguard Worker * Minimum cutoff frequency of the value's low pass filter. Refer to OneEuroFilter class for a 320*38e8c45fSAndroid Build Coastguard Worker * more detailed explanation. 321*38e8c45fSAndroid Build Coastguard Worker */ 322*38e8c45fSAndroid Build Coastguard Worker const float mMinCutoffFreq; 323*38e8c45fSAndroid Build Coastguard Worker 324*38e8c45fSAndroid Build Coastguard Worker /** 325*38e8c45fSAndroid Build Coastguard Worker * Scaling factor of the adaptive cutoff frequency criterion. Refer to OneEuroFilter class for a 326*38e8c45fSAndroid Build Coastguard Worker * more detailed explanation. 327*38e8c45fSAndroid Build Coastguard Worker */ 328*38e8c45fSAndroid Build Coastguard Worker const float mBeta; 329*38e8c45fSAndroid Build Coastguard Worker 330*38e8c45fSAndroid Build Coastguard Worker /* 331*38e8c45fSAndroid Build Coastguard Worker * Note: an associative array with constant insertion and lookup times would be more efficient. 332*38e8c45fSAndroid Build Coastguard Worker * When this was implemented, there was no container with these properties. 333*38e8c45fSAndroid Build Coastguard Worker */ 334*38e8c45fSAndroid Build Coastguard Worker std::map<int32_t /*pointerId*/, CoordinateFilter> mFilteredPointers; 335*38e8c45fSAndroid Build Coastguard Worker }; 336*38e8c45fSAndroid Build Coastguard Worker 337*38e8c45fSAndroid Build Coastguard Worker } // namespace android 338