1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "drag_smooth_processor.h"
17
18 #include <utility>
19
20 #include "devicestatus_common.h"
21 #include "include/util.h"
22
23 #undef LOG_TAG
24 #define LOG_TAG "DragSmoothProcessor"
25
26 namespace OHOS {
27 namespace Msdp {
28 namespace DeviceStatus {
29 namespace {
30 constexpr uint64_t ONE_MS_IN_NS { 1 * 1000 * 1000 }; // 1ms
31 constexpr int32_t RESAMPLE_COORD_TIME_THRESHOLD { 20 * 1000 * 1000 }; // 20ms
32 constexpr uint64_t INTERPOLATION_THRESHOLD { 100 * 1000 * 1000 }; // 100ms
33 constexpr size_t PREVIOUS_HISTORY_EVENT { 2 };
34 }
InsertEvent(const DragMoveEvent & event)35 void DragSmoothProcessor::InsertEvent(const DragMoveEvent &event)
36 {
37 std::lock_guard<std::mutex> lock(mtx_);
38 moveEvents_.emplace_back(event);
39 }
40
SmoothMoveEvent(uint64_t nanoTimestamp,uint64_t vSyncPeriod)41 DragMoveEvent DragSmoothProcessor::SmoothMoveEvent(uint64_t nanoTimestamp, uint64_t vSyncPeriod)
42 {
43 resampleTimeStamp_ = nanoTimestamp - vSyncPeriod + ONE_MS_IN_NS;
44 auto targetTimeStamp = resampleTimeStamp_;
45 std::vector<DragMoveEvent> currentEvents;
46 {
47 std::lock_guard<std::mutex> lock(mtx_);
48 currentEvents.swap(moveEvents_);
49 }
50 size_t historyEventSize = historyEvents_.size();
51 if (currentEvents.empty() && historyEventSize > 0) {
52 if (historyEventSize > 1) {
53 auto event = GetInterpolatedEvent(historyEvents_.at(historyEventSize - PREVIOUS_HISTORY_EVENT),
54 historyEvents_.back(), targetTimeStamp);
55 auto resampleEvent = event.has_value() ? event.value() : historyEvents_.back();
56 historyEvents_ = currentEvents;
57 historyEvents_.emplace_back(resampleEvent);
58 return resampleEvent;
59 } else {
60 DragMoveEvent event = historyEvents_.back();
61 event.timestamp = targetTimeStamp;
62 historyEvents_ = currentEvents;
63 historyEvents_.emplace_back(event);
64 return event;
65 }
66 }
67 DragMoveEvent latestEvent = currentEvents.back();
68 auto resampleEvent = GetResampleEvent(historyEvents_, currentEvents, targetTimeStamp);
69 historyEvents_ = currentEvents;
70 return resampleEvent.has_value() ? resampleEvent.value() : latestEvent;
71 }
72
ResetParameters()73 void DragSmoothProcessor::ResetParameters()
74 {
75 std::lock_guard<std::mutex> lock(mtx_);
76 moveEvents_.clear();
77 historyEvents_.clear();
78 resampleTimeStamp_ = 0;
79 }
80
GetResampleEvent(const std::vector<DragMoveEvent> & history,const std::vector<DragMoveEvent> & current,uint64_t nanoTimestamp)81 std::optional<DragMoveEvent> DragSmoothProcessor::GetResampleEvent(const std::vector<DragMoveEvent>& history,
82 const std::vector<DragMoveEvent>& current, uint64_t nanoTimestamp)
83 {
84 auto event = Resample(history, current, nanoTimestamp);
85 DragMoveEvent nearestEvent = GetNearestEvent(current, nanoTimestamp);
86 return event.has_value() ? event.value() : nearestEvent;
87 }
88
GetNearestEvent(const std::vector<DragMoveEvent> & events,uint64_t nanoTimestamp)89 DragMoveEvent DragSmoothProcessor::GetNearestEvent(const std::vector<DragMoveEvent>& events, uint64_t nanoTimestamp)
90 {
91 DragMoveEvent nearestEvent;
92 uint64_t gap = UINT64_MAX;
93 for (const auto &event : events) {
94 if (event.timestamp == nanoTimestamp) {
95 nearestEvent = event;
96 return nearestEvent;
97 }
98 if (event.timestamp > nanoTimestamp) {
99 if (event.timestamp - nanoTimestamp < gap) {
100 gap = event.timestamp - nanoTimestamp;
101 nearestEvent = event;
102 }
103 } else {
104 if (nanoTimestamp - event.timestamp < gap) {
105 gap = nanoTimestamp - event.timestamp;
106 nearestEvent = event;
107 }
108 }
109 }
110 return nearestEvent;
111 }
112
Resample(const std::vector<DragMoveEvent> & history,const std::vector<DragMoveEvent> & current,uint64_t nanoTimestamp)113 std::optional<DragMoveEvent> DragSmoothProcessor::Resample(const std::vector<DragMoveEvent>& history,
114 const std::vector<DragMoveEvent>& current, uint64_t nanoTimestamp)
115 {
116 if (history.empty() || current.empty()) {
117 FI_HILOGW("history or current is empty, history size:%{public}zu, current size:%{public}zu,"
118 "nanoTimestamp:%{public}" PRId64, history.size(), current.size(), nanoTimestamp);
119 return std::nullopt;
120 }
121 DragMoveEvent latestEvent;
122 for (auto const &event : current) {
123 if (latestEvent.timestamp < event.timestamp) {
124 latestEvent = event;
125 }
126 }
127 if (nanoTimestamp > RESAMPLE_COORD_TIME_THRESHOLD + latestEvent.timestamp) {
128 FI_HILOGW("latestEvent is beyond the sampling range, use this this latest event, x:%{private}f, "
129 "y:%{private}f, timestamp:%{public}" PRId64 "displayId:%{public}d, sampling nanoTimestamp:%{public}" PRId64,
130 latestEvent.displayX, latestEvent.displayY, latestEvent.timestamp, latestEvent.displayId, nanoTimestamp);
131 return latestEvent;
132 }
133 auto historyAvgEvent = GetAvgCoordinate(history);
134 auto currentAvgEvent = GetAvgCoordinate(current);
135 DumpMoveEvent(history, current, historyAvgEvent, currentAvgEvent, latestEvent);
136 return GetInterpolatedEvent(historyAvgEvent, currentAvgEvent, nanoTimestamp);
137 }
138
GetInterpolatedEvent(const DragMoveEvent & historyAvgEvent,const DragMoveEvent & currentAvgEvent,uint64_t nanoTimestamp)139 std::optional<DragMoveEvent> DragSmoothProcessor::GetInterpolatedEvent(const DragMoveEvent &historyAvgEvent,
140 const DragMoveEvent ¤tAvgEvent, uint64_t nanoTimestamp)
141 {
142 if ((nanoTimestamp <= historyAvgEvent.timestamp) || (nanoTimestamp == currentAvgEvent.timestamp) ||
143 (currentAvgEvent.timestamp <= historyAvgEvent.timestamp) ||
144 ((currentAvgEvent.timestamp - historyAvgEvent.timestamp) > INTERPOLATION_THRESHOLD)) {
145 FI_HILOGW("No need linear interpolation, historyAvgEvent x:%{private}f, "
146 "y:%{private}f, timestamp:%{public}" PRId64 "displayId:%{public}d, currentAvgEvent x:%{private}f"
147 "y:%{private}f, timestamp:%{public}" PRId64 "displayId:%{public}d, nanoTimestamp: %{public}" PRId64,
148 historyAvgEvent.displayX, historyAvgEvent.displayY, historyAvgEvent.timestamp, historyAvgEvent.displayId,
149 currentAvgEvent.displayX, currentAvgEvent.displayY, currentAvgEvent.timestamp, currentAvgEvent.displayId,
150 nanoTimestamp);
151 return std::nullopt;
152 }
153 DragMoveEvent event;
154 if (nanoTimestamp < currentAvgEvent.timestamp) {
155 float alpha = static_cast<float>(nanoTimestamp - historyAvgEvent.timestamp) /
156 (currentAvgEvent.timestamp - historyAvgEvent.timestamp);
157 event.displayX = historyAvgEvent.displayX + alpha * (currentAvgEvent.displayX - historyAvgEvent.displayX);
158 event.displayY = historyAvgEvent.displayY + alpha * (currentAvgEvent.displayY - historyAvgEvent.displayY);
159 event.timestamp = nanoTimestamp;
160 event.displayId = currentAvgEvent.displayId;
161 } else if (nanoTimestamp > currentAvgEvent.timestamp) {
162 float alpha = static_cast<float>(nanoTimestamp - currentAvgEvent.timestamp) /
163 (currentAvgEvent.timestamp - historyAvgEvent.timestamp);
164 event.displayX = currentAvgEvent.displayX + alpha * (currentAvgEvent.displayX - historyAvgEvent.displayX);
165 event.displayY = currentAvgEvent.displayY + alpha * (currentAvgEvent.displayY - historyAvgEvent.displayY);
166 event.timestamp = nanoTimestamp;
167 event.displayId = currentAvgEvent.displayId;
168 }
169 return event;
170 }
171
DumpMoveEvent(const std::vector<DragMoveEvent> & history,const std::vector<DragMoveEvent> & current,const DragMoveEvent & historyAvgEvent,const DragMoveEvent & currentAvgEvent,const DragMoveEvent & latestEvent)172 void DragSmoothProcessor::DumpMoveEvent(const std::vector<DragMoveEvent>& history,
173 const std::vector<DragMoveEvent>& current, const DragMoveEvent &historyAvgEvent,
174 const DragMoveEvent ¤tAvgEvent, const DragMoveEvent &latestEvent)
175 {
176 for (const auto &event : history) {
177 FI_HILOGD("history event, x:%{private}f, y:%{private}f, timestamp:%{public}" PRId64 "displayId:%{public}d",
178 event.displayX, event.displayY, event.timestamp, event.displayId);
179 }
180 for (const auto &event : current) {
181 FI_HILOGD("current event, x:%{private}f, y:%{private}f, timestamp:%{public}" PRId64 "displayId:%{public}d",
182 event.displayX, event.displayY, event.timestamp, event.displayId);
183 }
184 FI_HILOGD("history average event, x:%{private}f, y:%{private}f, timestamp:%{public}" PRId64 "displayId:%{public}d",
185 historyAvgEvent.displayX, historyAvgEvent.displayY, historyAvgEvent.timestamp, historyAvgEvent.displayId);
186 FI_HILOGD("current average event, x:%{private}f, y:%{private}f, timestamp:%{public}" PRId64 "displayId:%{public}d",
187 currentAvgEvent.displayX, currentAvgEvent.displayY, currentAvgEvent.timestamp, currentAvgEvent.displayId);
188 FI_HILOGD("latest event, x:%{private}f, y:%{private}f, timestamp:%{public}" PRId64 "displayId:%{public}d",
189 latestEvent.displayX, latestEvent.displayY, latestEvent.timestamp, latestEvent.displayId);
190 }
191
GetAvgCoordinate(const std::vector<DragMoveEvent> & events)192 DragMoveEvent DragSmoothProcessor::GetAvgCoordinate(const std::vector<DragMoveEvent>& events)
193 {
194 DragMoveEvent avgEvent;
195 if (events.empty()) {
196 FI_HILOGW("events is empty");
197 return avgEvent;
198 }
199 int32_t i = 0;
200 uint64_t lastTime = 0;
201 for (const auto &event : events) {
202 if ((lastTime == 0) || (lastTime != event.timestamp)) {
203 avgEvent.displayX += event.displayX;
204 avgEvent.displayY += event.displayY;
205 avgEvent.timestamp += event.timestamp;
206 avgEvent.displayId = event.displayId;
207 lastTime = event.timestamp;
208 i++;
209 }
210 }
211 if (i != 0) {
212 avgEvent.displayX /= i;
213 avgEvent.displayY /= i;
214 avgEvent.timestamp /= static_cast<uint64_t>(i);
215 }
216 return avgEvent;
217 }
218 } // namespace DeviceStatus
219 } // namespace Msdp
220 } // namespace OHOS