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 std::lock_guard<std::mutex> lock(mtx_);
44 resampleTimeStamp_ = nanoTimestamp - vSyncPeriod + ONE_MS_IN_NS;
45 auto targetTimeStamp = resampleTimeStamp_;
46 std::vector<DragMoveEvent> currentEvents;
47 currentEvents.swap(moveEvents_);
48 size_t historyEventSize = historyEvents_.size();
49 if (currentEvents.empty() && historyEventSize > 0) {
50 if (historyEventSize > 1) {
51 auto event = GetInterpolatedEvent(historyEvents_.at(historyEventSize - PREVIOUS_HISTORY_EVENT),
52 historyEvents_.back(), targetTimeStamp);
53 auto resampleEvent = event.has_value() ? event.value() : historyEvents_.back();
54 historyEvents_ = currentEvents;
55 historyEvents_.emplace_back(resampleEvent);
56 return resampleEvent;
57 } else {
58 DragMoveEvent event = historyEvents_.back();
59 event.timestamp = targetTimeStamp;
60 historyEvents_ = currentEvents;
61 historyEvents_.emplace_back(event);
62 return event;
63 }
64 }
65 DragMoveEvent latestEvent = currentEvents.back();
66 auto resampleEvent = GetResampleEvent(historyEvents_, currentEvents, targetTimeStamp);
67 historyEvents_ = currentEvents;
68 return resampleEvent.has_value() ? resampleEvent.value() : latestEvent;
69 }
70
ResetParameters()71 void DragSmoothProcessor::ResetParameters()
72 {
73 std::lock_guard<std::mutex> lock(mtx_);
74 moveEvents_.clear();
75 historyEvents_.clear();
76 resampleTimeStamp_ = 0;
77 }
78
GetResampleEvent(const std::vector<DragMoveEvent> & history,const std::vector<DragMoveEvent> & current,uint64_t nanoTimestamp)79 std::optional<DragMoveEvent> DragSmoothProcessor::GetResampleEvent(const std::vector<DragMoveEvent>& history,
80 const std::vector<DragMoveEvent>& current, uint64_t nanoTimestamp)
81 {
82 auto event = Resample(history, current, nanoTimestamp);
83 DragMoveEvent nearestEvent = GetNearestEvent(current, nanoTimestamp);
84 return event.has_value() ? event.value() : nearestEvent;
85 }
86
GetNearestEvent(const std::vector<DragMoveEvent> & events,uint64_t nanoTimestamp)87 DragMoveEvent DragSmoothProcessor::GetNearestEvent(const std::vector<DragMoveEvent>& events, uint64_t nanoTimestamp)
88 {
89 DragMoveEvent nearestEvent;
90 uint64_t gap = UINT64_MAX;
91 for (const auto &event : events) {
92 if (event.timestamp == nanoTimestamp) {
93 nearestEvent = event;
94 return nearestEvent;
95 }
96 if (event.timestamp > nanoTimestamp) {
97 if (event.timestamp - nanoTimestamp < gap) {
98 gap = event.timestamp - nanoTimestamp;
99 nearestEvent = event;
100 }
101 } else {
102 if (nanoTimestamp - event.timestamp < gap) {
103 gap = nanoTimestamp - event.timestamp;
104 nearestEvent = event;
105 }
106 }
107 }
108 return nearestEvent;
109 }
110
Resample(const std::vector<DragMoveEvent> & history,const std::vector<DragMoveEvent> & current,uint64_t nanoTimestamp)111 std::optional<DragMoveEvent> DragSmoothProcessor::Resample(const std::vector<DragMoveEvent>& history,
112 const std::vector<DragMoveEvent>& current, uint64_t nanoTimestamp)
113 {
114 if (history.empty() || current.empty()) {
115 FI_HILOGW("history or current is empty, history size:%{public}zu, current size:%{public}zu,"
116 "nanoTimestamp:%{public}" PRId64, history.size(), current.size(), nanoTimestamp);
117 return std::nullopt;
118 }
119 DragMoveEvent latestEvent;
120 for (auto const &event : current) {
121 if (latestEvent.timestamp < event.timestamp) {
122 latestEvent = event;
123 }
124 }
125 if (nanoTimestamp > RESAMPLE_COORD_TIME_THRESHOLD + latestEvent.timestamp) {
126 FI_HILOGW("latestEvent is beyond the sampling range, use this this latest event, x:%{private}f, "
127 "y:%{private}f, timestamp:%{public}" PRId64 "displayId:%{public}d, sampling nanoTimestamp:%{public}" PRId64,
128 latestEvent.displayX, latestEvent.displayY, latestEvent.timestamp, latestEvent.displayId, nanoTimestamp);
129 return latestEvent;
130 }
131 auto historyAvgEvent = GetAvgCoordinate(history);
132 auto currentAvgEvent = GetAvgCoordinate(current);
133 DumpMoveEvent(history, current, historyAvgEvent, currentAvgEvent, latestEvent);
134 return GetInterpolatedEvent(historyAvgEvent, currentAvgEvent, nanoTimestamp);
135 }
136
GetInterpolatedEvent(const DragMoveEvent & historyAvgEvent,const DragMoveEvent & currentAvgEvent,uint64_t nanoTimestamp)137 std::optional<DragMoveEvent> DragSmoothProcessor::GetInterpolatedEvent(const DragMoveEvent &historyAvgEvent,
138 const DragMoveEvent ¤tAvgEvent, uint64_t nanoTimestamp)
139 {
140 if ((nanoTimestamp <= historyAvgEvent.timestamp) || (nanoTimestamp == currentAvgEvent.timestamp) ||
141 (currentAvgEvent.timestamp <= historyAvgEvent.timestamp) ||
142 ((currentAvgEvent.timestamp - historyAvgEvent.timestamp) > INTERPOLATION_THRESHOLD)) {
143 FI_HILOGW("No need linear interpolation, historyAvgEvent x:%{private}f, "
144 "y:%{private}f, timestamp:%{public}" PRId64 "displayId:%{public}d, currentAvgEvent x:%{private}f"
145 "y:%{private}f, timestamp:%{public}" PRId64 "displayId:%{public}d, nanoTimestamp: %{public}" PRId64,
146 historyAvgEvent.displayX, historyAvgEvent.displayY, historyAvgEvent.timestamp, historyAvgEvent.displayId,
147 currentAvgEvent.displayX, currentAvgEvent.displayY, currentAvgEvent.timestamp, currentAvgEvent.displayId,
148 nanoTimestamp);
149 return std::nullopt;
150 }
151 DragMoveEvent event;
152 if (nanoTimestamp < currentAvgEvent.timestamp) {
153 float alpha = static_cast<float>(nanoTimestamp - historyAvgEvent.timestamp) /
154 (currentAvgEvent.timestamp - historyAvgEvent.timestamp);
155 event.displayX = historyAvgEvent.displayX + alpha * (currentAvgEvent.displayX - historyAvgEvent.displayX);
156 event.displayY = historyAvgEvent.displayY + alpha * (currentAvgEvent.displayY - historyAvgEvent.displayY);
157 event.timestamp = nanoTimestamp;
158 event.displayId = currentAvgEvent.displayId;
159 } else if (nanoTimestamp > currentAvgEvent.timestamp) {
160 float alpha = static_cast<float>(nanoTimestamp - currentAvgEvent.timestamp) /
161 (currentAvgEvent.timestamp - historyAvgEvent.timestamp);
162 event.displayX = currentAvgEvent.displayX + alpha * (currentAvgEvent.displayX - historyAvgEvent.displayX);
163 event.displayY = currentAvgEvent.displayY + alpha * (currentAvgEvent.displayY - historyAvgEvent.displayY);
164 event.timestamp = nanoTimestamp;
165 event.displayId = currentAvgEvent.displayId;
166 }
167 return event;
168 }
169
DumpMoveEvent(const std::vector<DragMoveEvent> & history,const std::vector<DragMoveEvent> & current,const DragMoveEvent & historyAvgEvent,const DragMoveEvent & currentAvgEvent,const DragMoveEvent & latestEvent)170 void DragSmoothProcessor::DumpMoveEvent(const std::vector<DragMoveEvent>& history,
171 const std::vector<DragMoveEvent>& current, const DragMoveEvent &historyAvgEvent,
172 const DragMoveEvent ¤tAvgEvent, const DragMoveEvent &latestEvent)
173 {
174 for (const auto &event : history) {
175 FI_HILOGD("history event, x:%{private}f, y:%{private}f, timestamp:%{public}" PRId64 "displayId:%{public}d",
176 event.displayX, event.displayY, event.timestamp, event.displayId);
177 }
178 for (const auto &event : current) {
179 FI_HILOGD("current event, x:%{private}f, y:%{private}f, timestamp:%{public}" PRId64 "displayId:%{public}d",
180 event.displayX, event.displayY, event.timestamp, event.displayId);
181 }
182 FI_HILOGD("history average event, x:%{private}f, y:%{private}f, timestamp:%{public}" PRId64 "displayId:%{public}d",
183 historyAvgEvent.displayX, historyAvgEvent.displayY, historyAvgEvent.timestamp, historyAvgEvent.displayId);
184 FI_HILOGD("current average event, x:%{private}f, y:%{private}f, timestamp:%{public}" PRId64 "displayId:%{public}d",
185 currentAvgEvent.displayX, currentAvgEvent.displayY, currentAvgEvent.timestamp, currentAvgEvent.displayId);
186 FI_HILOGD("latest event, x:%{private}f, y:%{private}f, timestamp:%{public}" PRId64 "displayId:%{public}d",
187 latestEvent.displayX, latestEvent.displayY, latestEvent.timestamp, latestEvent.displayId);
188 }
189
GetAvgCoordinate(const std::vector<DragMoveEvent> & events)190 DragMoveEvent DragSmoothProcessor::GetAvgCoordinate(const std::vector<DragMoveEvent>& events)
191 {
192 DragMoveEvent avgEvent;
193 if (events.empty()) {
194 FI_HILOGW("events is empty");
195 return avgEvent;
196 }
197 int32_t i = 0;
198 uint64_t lastTime = 0;
199 for (const auto &event : events) {
200 if ((lastTime == 0) || (lastTime != event.timestamp)) {
201 avgEvent.displayX += event.displayX;
202 avgEvent.displayY += event.displayY;
203 avgEvent.timestamp += event.timestamp;
204 avgEvent.displayId = event.displayId;
205 lastTime = event.timestamp;
206 i++;
207 }
208 }
209 if (i != 0) {
210 avgEvent.displayX /= i;
211 avgEvent.displayY /= i;
212 avgEvent.timestamp /= static_cast<uint64_t>(i);
213 }
214 return avgEvent;
215 }
216 } // namespace DeviceStatus
217 } // namespace Msdp
218 } // namespace OHOS