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 "knuckle_dynamic_drawing_manager.h"
17 #include "image_source.h"
18
19 #include "input_windows_manager.h"
20 #include "mmi_log.h"
21 #ifndef USE_ROSEN_DRAWING
22 #include "pipeline/rs_recording_canvas.h"
23 #else
24 #include "recording/recording_canvas.h"
25 #include "ui/rs_canvas_drawing_node.h"
26 #endif // USE_ROSEN_DRAWING
27
28 #undef MMI_LOG_TAG
29 #define MMI_LOG_TAG "KnuckleDynamicDrawingManager"
30
31 namespace OHOS {
32 namespace MMI {
33 namespace {
34 const std::string IMAGE_POINTER_PENTAGRAM_PATH = "/system/etc/multimodalinput/mouse_icon/";
35 const std::string PENT_ICON_PATH = IMAGE_POINTER_PENTAGRAM_PATH + "Default.svg";
36 [[ maybe_unused ]] constexpr int32_t DENSITY_BASELINE { 160 };
37 [[ maybe_unused ]] constexpr int32_t INDEPENDENT_INNER_PIXELS { 20 };
38 [[ maybe_unused ]] constexpr int32_t INDEPENDENT_OUTER_PIXELS { 21 };
39 [[ maybe_unused ]] constexpr int32_t INDEPENDENT_WIDTH_PIXELS { 2 };
40 [[ maybe_unused ]] constexpr int32_t CALCULATE_MIDDLE { 2 };
41 constexpr int32_t DEFAULT_VALUE { -1 };
42 constexpr int32_t MAX_POINTER_COLOR { 0x00ffff };
43 constexpr int32_t TIME_DIMENSION { 1000 };
44 constexpr int32_t PATH_COLOR { 0xFFCCCCCC };
45 constexpr int32_t MIN_POINT_SIZE { 1 };
46 constexpr float PAINT_STROKE_WIDTH { 10.0f };
47 constexpr float DOUBLE { 2.0f };
48 constexpr int32_t POINT_TOTAL_SIZE { 5 };
49 constexpr int32_t POINT_SYSTEM_SIZE { 200 };
50 constexpr int32_t MAX_DIVERGENCE_NUM { 10 };
51 [[ maybe_unused ]] constexpr int32_t DEFAULT_POINTER_SIZE { 1 };
52 constexpr int32_t DESIRED_SIZE { 80 };
53 constexpr int64_t DOUBLE_CLICK_INTERVAL_TIME_SLOW { 450000 };
54 constexpr int64_t WAIT_DOUBLE_CLICK_INTERVAL_TIME { 100000 };
55 constexpr float DOUBLE_CLICK_DISTANCE_LONG_CONFIG { 96.0f };
56 [[ maybe_unused ]] constexpr float VPR_CONFIG { 3.25f };
57 constexpr int32_t POW_SQUARE { 2 };
58 constexpr int32_t IN_DRAWING_TIME { 23000 };
59 constexpr uint64_t FOLD_SCREEN_MAIN_ID { 5 };
60 constexpr std::string_view SCREEN_READ_ENABLE { "1" };
61 } // namespace
62
KnuckleDynamicDrawingManager()63 KnuckleDynamicDrawingManager::KnuckleDynamicDrawingManager()
64 {
65 InitPointerPathPaint();
66 }
67
DecodeImageToPixelMap(const std::string & imagePath)68 std::shared_ptr<OHOS::Media::PixelMap> KnuckleDynamicDrawingManager::DecodeImageToPixelMap(const std::string &imagePath)
69 {
70 CALL_DEBUG_ENTER;
71 OHOS::Media::SourceOptions opts;
72 uint32_t ret = 0;
73 auto imageSource = OHOS::Media::ImageSource::CreateImageSource(imagePath, opts, ret);
74 CHKPP(imageSource);
75 std::set<std::string> formats;
76 ret = imageSource->GetSupportedFormats(formats);
77 OHOS::Media::DecodeOptions decodeOpts;
78 decodeOpts.desiredSize = {
79 .width = DESIRED_SIZE,
80 .height = DESIRED_SIZE
81 };
82
83 decodeOpts.SVGOpts.fillColor = {.isValidColor = true, .color = MAX_POINTER_COLOR};
84 decodeOpts.SVGOpts.strokeColor = {.isValidColor = true, .color = MAX_POINTER_COLOR};
85
86 std::shared_ptr<OHOS::Media::PixelMap> pixelMap = imageSource->CreatePixelMap(decodeOpts, ret);
87 CHKPL(pixelMap);
88 return pixelMap;
89 }
90
InitPointerPathPaint()91 void KnuckleDynamicDrawingManager::InitPointerPathPaint()
92 {
93 CALL_DEBUG_ENTER;
94 pixelMap_ = DecodeImageToPixelMap(PENT_ICON_PATH);
95 CHKPV(pixelMap_);
96 if (glowTraceSystem_ == nullptr) {
97 glowTraceSystem_ = std::make_shared<KnuckleGlowTraceSystem>(POINT_SYSTEM_SIZE, pixelMap_, MAX_DIVERGENCE_NUM);
98 }
99 pointerPathPaint_.setStyle(SkPaint::Style::kStroke_Style);
100 pointerPathPaint_.setStrokeJoin(SkPaint::Join::kRound_Join);
101 pointerPathPaint_.setStrokeCap(SkPaint::Cap::kRound_Cap);
102 pointerPathPaint_.setStrokeWidth(PAINT_STROKE_WIDTH);
103 pointerPathPaint_.setAntiAlias(true);
104 }
105
UpdateTrackColors()106 void KnuckleDynamicDrawingManager::UpdateTrackColors()
107 {
108 CALL_DEBUG_ENTER;
109 pointerPathPaint_.setColor(PATH_COLOR);
110 }
111
KnuckleDynamicDrawHandler(std::shared_ptr<PointerEvent> pointerEvent,int32_t rsId)112 void KnuckleDynamicDrawingManager::KnuckleDynamicDrawHandler(std::shared_ptr<PointerEvent> pointerEvent,
113 int32_t rsId)
114 {
115 CALL_DEBUG_ENTER;
116 CHKPV(pointerEvent);
117 if (!IsSingleKnuckle(pointerEvent)) {
118 return;
119 }
120 if (rsId == DEFAULT_VALUE) {
121 rsId = pointerEvent->GetTargetDisplayId();
122 }
123 CreateTouchWindow(rsId);
124 if (CheckPointerAction(pointerEvent)) {
125 StartTouchDraw(pointerEvent);
126 }
127 }
128
IsSingleKnuckle(std::shared_ptr<PointerEvent> touchEvent)129 bool KnuckleDynamicDrawingManager::IsSingleKnuckle(std::shared_ptr<PointerEvent> touchEvent)
130 {
131 CALL_DEBUG_ENTER;
132 CHKPF(touchEvent);
133 auto id = touchEvent->GetPointerId();
134 PointerEvent::PointerItem item;
135 touchEvent->GetPointerItem(id, item);
136 auto itemToolType = item.GetToolType();
137 if (itemToolType != PointerEvent::TOOL_TYPE_KNUCKLE ||
138 touchEvent->GetPointerIds().size() != 1 || isRotate_) {
139 if (!traceControlPoints_.empty()) {
140 isStop_ = true;
141 isDrawing_ = true;
142 DestoryWindow();
143 } else if (isRotate_) {
144 isRotate_ = false;
145 if (item.GetToolType() == PointerEvent::TOOL_TYPE_KNUCKLE) {
146 return true;
147 }
148 }
149 return false;
150 }
151 return true;
152 }
153
CheckPointerAction(std::shared_ptr<PointerEvent> pointerEvent)154 bool KnuckleDynamicDrawingManager::CheckPointerAction(std::shared_ptr<PointerEvent> pointerEvent)
155 {
156 CALL_DEBUG_ENTER;
157 CHKPF(knuckleDrawMgr_);
158 if (knuckleDrawMgr_->GetScreenReadState() == SCREEN_READ_ENABLE) {
159 DestoryWindow();
160 }
161 size_t size = pointerEvent->GetPointerIds().size();
162 if (size > MIN_POINT_SIZE) {
163 pointerPath_.Reset();
164 CHKPF(glowTraceSystem_);
165 glowTraceSystem_->Clear();
166 return false;
167 }
168 switch (pointerEvent->GetPointerAction()) {
169 case PointerEvent::POINTER_ACTION_UP:
170 case PointerEvent::POINTER_ACTION_PULL_UP:
171 ProcessUpAndCancelEvent(pointerEvent);
172 break;
173 case PointerEvent::POINTER_ACTION_DOWN:
174 case PointerEvent::POINTER_ACTION_PULL_DOWN:
175 ProcessDownEvent(pointerEvent);
176 return true;
177 case PointerEvent::POINTER_ACTION_MOVE:
178 case PointerEvent::POINTER_ACTION_PULL_MOVE:
179 if (!isStop_ && !traceControlPoints_.empty()) {
180 ProcessMoveEvent(pointerEvent);
181 return true;
182 }
183 return false;
184 default:
185 return false;
186 }
187 return true;
188 }
189
StartTouchDraw(std::shared_ptr<PointerEvent> pointerEvent)190 void KnuckleDynamicDrawingManager::StartTouchDraw(std::shared_ptr<PointerEvent> pointerEvent)
191 {
192 CHKPV(pointerEvent);
193 int32_t ret = DrawGraphic(pointerEvent);
194 if (ret != RET_OK) {
195 MMI_HILOGD("Can't get enough pointers to draw");
196 return;
197 }
198 Rosen::RSTransaction::FlushImplicitTransaction();
199 }
200
ProcessUpAndCancelEvent(std::shared_ptr<PointerEvent> pointerEvent)201 void KnuckleDynamicDrawingManager::ProcessUpAndCancelEvent(std::shared_ptr<PointerEvent> pointerEvent)
202 {
203 CALL_DEBUG_ENTER;
204 CHKPV(glowTraceSystem_);
205 CHKPV(pointerEvent);
206 lastUpTime_ = pointerEvent->GetActionTime();
207 if (pointerPath_.IsValid()) {
208 auto id = pointerEvent->GetPointerId();
209 PointerEvent::PointerItem pointerItem;
210 pointerEvent->GetPointerItem(id, pointerItem);
211 auto displayXY = WIN_MGR->CalcDrawCoordinate(displayInfo_, pointerItem);
212 glowTraceSystem_->ResetDivergentPoints(displayXY.first, displayXY.second);
213 }
214 isDrawing_ = true;
215 DestoryWindow();
216 }
217
ProcessDownEvent(std::shared_ptr<PointerEvent> pointerEvent)218 void KnuckleDynamicDrawingManager::ProcessDownEvent(std::shared_ptr<PointerEvent> pointerEvent)
219 {
220 CALL_DEBUG_ENTER;
221 CHKPV(pointerEvent);
222 if (traceControlPoints_.empty()) {
223 for (int32_t i = 0; i < POINT_TOTAL_SIZE; i++) {
224 Rosen::Drawing::Point point = Rosen::Drawing::Point();
225 traceControlPoints_.emplace_back(point);
226 }
227 }
228 int64_t intervalTime = pointerEvent->GetActionTime() - lastUpTime_;
229 firstDownTime_ = pointerEvent->GetActionTime();
230 bool isTimeIntervalReady = intervalTime > 0 && intervalTime <= DOUBLE_CLICK_INTERVAL_TIME_SLOW;
231
232 UpdateTrackColors();
233 lastUpdateTimeMillis_ = pointerEvent->GetActionTime();
234 pointCounter_ = 0;
235 auto id = pointerEvent->GetPointerId();
236 PointerEvent::PointerItem pointerItem;
237 pointerEvent->GetPointerItem(id, pointerItem);
238 auto displayXY = WIN_MGR->CalcDrawCoordinate(displayInfo_, pointerItem);
239 float downToPrevDownDistance = static_cast<float>(sqrt(pow(lastDownX_ - displayXY.first, POW_SQUARE) +
240 pow(lastDownY_ - displayXY.second, POW_SQUARE)));
241 bool isDistanceReady = downToPrevDownDistance < DOUBLE_CLICK_DISTANCE_LONG_CONFIG * POW_SQUARE;
242 if (isTimeIntervalReady && isDistanceReady) {
243 MMI_HILOGE("Take a screenshot");
244 isDrawing_ = true;
245 isStop_ = true;
246 return;
247 }
248 lastDownX_ = displayXY.first;
249 lastDownY_ = displayXY.second;
250 traceControlPoints_[pointCounter_].Set(displayXY.first, displayXY.second);
251 isStop_ = false;
252 }
253
ProcessMoveEvent(std::shared_ptr<PointerEvent> pointerEvent)254 void KnuckleDynamicDrawingManager::ProcessMoveEvent(std::shared_ptr<PointerEvent> pointerEvent)
255 {
256 CALL_DEBUG_ENTER;
257 CHKPV(pointerEvent);
258 pointCounter_++;
259 if (pointCounter_ >= POINT_TOTAL_SIZE) {
260 MMI_HILOGE("traceControlPoints_ index out of size");
261 return;
262 }
263 auto id = pointerEvent->GetPointerId();
264 PointerEvent::PointerItem pointerItem;
265 pointerEvent->GetPointerItem(id, pointerItem);
266 auto displayXY = WIN_MGR->CalcDrawCoordinate(displayInfo_, pointerItem);
267 traceControlPoints_[pointCounter_].Set(displayXY.first, displayXY.second);
268 int pointIndex4 = 4;
269 bool draw = (pointerEvent->GetActionTime() - firstDownTime_) > WAIT_DOUBLE_CLICK_INTERVAL_TIME;
270 if (pointCounter_ == pointIndex4) {
271 int pointIndex0 = 0;
272 int pointIndex1 = 1;
273 int pointIndex2 = 2;
274 int pointIndex3 = 3;
275
276 traceControlPoints_[pointIndex3].Set(
277 (traceControlPoints_[pointIndex2].GetX() + traceControlPoints_[pointIndex4].GetX()) / DOUBLE,
278 (traceControlPoints_[pointIndex2].GetY() + traceControlPoints_[pointIndex4].GetY()) / DOUBLE);
279 // Add a cubic Bezier from pt[0] to pt[3] with control pointspt[1] and pt[2]
280 pointerPath_.MoveTo (traceControlPoints_[pointIndex0].GetX(), traceControlPoints_[pointIndex0].GetY());
281 pointerPath_.CubicTo(traceControlPoints_[pointIndex1].GetX(), traceControlPoints_[pointIndex1].GetY(),
282 traceControlPoints_[pointIndex2].GetX(), traceControlPoints_[pointIndex2].GetY(),
283 traceControlPoints_[pointIndex3].GetX(), traceControlPoints_[pointIndex3].GetY());
284 traceControlPoints_[pointIndex0].Set(traceControlPoints_[pointIndex3].GetX(),
285 traceControlPoints_[pointIndex3].GetY());
286 traceControlPoints_[pointIndex1].Set (traceControlPoints_[pointIndex4].GetX(),
287 traceControlPoints_[pointIndex4].GetY());
288 pointCounter_ = 1;
289 // Add glowing particles onto the last path segment that was drawn
290 int64_t now = pointerEvent->GetActionTime();
291 if (draw) {
292 CHKPV(glowTraceSystem_);
293 glowTraceSystem_->AddGlowPoints(pointerPath_, (now - lastUpdateTimeMillis_) / TIME_DIMENSION);
294 }
295 pointerPath_.Reset();
296 lastUpdateTimeMillis_ = now;
297 }
298 if (draw) {
299 glowTraceSystem_->ResetDivergentPoints(displayXY.first, displayXY.second);
300 isDrawing_ = false;
301 }
302 }
303
UpdateDisplayInfo(const OLD::DisplayInfo & displayInfo)304 void KnuckleDynamicDrawingManager::UpdateDisplayInfo(const OLD::DisplayInfo& displayInfo)
305 {
306 CALL_DEBUG_ENTER;
307 if (displayInfo_.direction != displayInfo.direction) {
308 MMI_HILOGD("DisplayInfo direction change");
309 isRotate_ = true;
310 }
311 scaleW_ = displayInfo.width > displayInfo.height ? displayInfo.width : displayInfo.height;
312 scaleH_ = displayInfo.width > displayInfo.height ? displayInfo.width : displayInfo.height;
313 displayInfo_ = displayInfo;
314 }
315
SetKnuckleDrawingManager(std::shared_ptr<KnuckleDrawingManager> knuckleDrawMgr)316 void KnuckleDynamicDrawingManager::SetKnuckleDrawingManager(std::shared_ptr<KnuckleDrawingManager> knuckleDrawMgr)
317 {
318 CALL_DEBUG_ENTER;
319 knuckleDrawMgr_ = knuckleDrawMgr;
320 }
321
DrawGraphic(std::shared_ptr<PointerEvent> pointerEvent)322 int32_t KnuckleDynamicDrawingManager::DrawGraphic(std::shared_ptr<PointerEvent> pointerEvent)
323 {
324 CALL_DEBUG_ENTER;
325 CHKPR(pointerEvent, RET_ERR);
326 CHKPR(canvasNode_, RET_ERR);
327 CHKPR(glowTraceSystem_, RET_ERR);
328 glowTraceSystem_->Update();
329 if ((pointerEvent->GetActionTime() - isInDrawingTime_) > IN_DRAWING_TIME) {
330 isInDrawingTime_ = pointerEvent->GetActionTime();
331 } else {
332 return RET_ERR;
333 }
334 #ifndef USE_ROSEN_DRAWING
335 auto canvas = static_cast<Rosen::RSRecordingCanvas *>(canvasNode_->
336 BeginRecording(scaleW_, scaleH_));
337 #else
338 auto canvas = static_cast<Rosen::ExtendRecordingCanvas *>(canvasNode_->
339 BeginRecording(scaleW_, scaleH_));
340 #endif // USE_ROSEN_DRAWING
341
342 CHKPR(canvas, RET_ERR);
343
344 if (!isDrawing_) {
345 glowTraceSystem_->Draw(canvas);
346 }
347 canvasNode_->ResetSurface(scaleW_, scaleH_);
348 canvasNode_->FinishRecording();
349 return RET_OK;
350 }
351
CreateTouchWindow(const int32_t rsId)352 void KnuckleDynamicDrawingManager::CreateTouchWindow(const int32_t rsId)
353 {
354 CALL_DEBUG_ENTER;
355 if (surfaceNode_ != nullptr) {
356 MMI_HILOGD("surfaceNode_ is already exist");
357 return;
358 }
359 Rosen::RSSurfaceNodeConfig surfaceNodeConfig;
360 surfaceNodeConfig.SurfaceNodeName = "knuckle dynamic window";
361 Rosen::RSSurfaceNodeType surfaceNodeType = Rosen::RSSurfaceNodeType::SELF_DRAWING_WINDOW_NODE;
362 surfaceNode_ = Rosen::RSSurfaceNode::Create(surfaceNodeConfig, surfaceNodeType);
363 CHKPV(surfaceNode_);
364
365 surfaceNode_->SetSnapshotSkipLayer(true);
366 surfaceNode_->SetFrameGravity(Rosen::Gravity::RESIZE_ASPECT_FILL);
367 surfaceNode_->SetPositionZ(Rosen::RSSurfaceNode::POINTER_WINDOW_POSITION_Z);
368 surfaceNode_->SetBounds(0, 0, scaleW_, scaleH_);
369 surfaceNode_->SetFrame(0, 0, scaleW_, scaleH_);
370
371 #ifndef USE_ROSEN_DRAWING
372 surfaceNode_->SetBackgroundColor(SK_ColorTRANSPARENT);
373 #else
374 surfaceNode_->SetBackgroundColor(Rosen::Drawing::Color::COLOR_TRANSPARENT);
375 #endif // USE_ROSEN_DRAWING
376
377 screenId_ = static_cast<uint64_t>(rsId);
378 surfaceNode_->SetRotation(0);
379
380 CreateCanvasNode();
381 surfaceNode_->AddChild(canvasNode_, DEFAULT_VALUE);
382 if (displayInfo_.displayMode == DisplayMode::MAIN) {
383 screenId_ = FOLD_SCREEN_MAIN_ID;
384 }
385 MMI_HILOGI("The screenId_:%{public}" PRIu64, screenId_);
386 surfaceNode_->AttachToDisplay(screenId_);
387 MMI_HILOGD("KnuckleDynamicDrawingManager screenId_:%{private}" PRIu64, screenId_);
388 CHKPV(knuckleDrawMgr_);
389 knuckleDrawMgr_->RotationCanvasNode(canvasNode_, displayInfo_);
390 CHKPV(canvasNode_);
391 canvasNode_->ResetSurface(scaleW_, scaleH_);
392 Rosen::RSTransaction::FlushImplicitTransaction();
393 }
394
CreateCanvasNode()395 void KnuckleDynamicDrawingManager::CreateCanvasNode()
396 {
397 CALL_DEBUG_ENTER;
398 canvasNode_ = Rosen::RSCanvasDrawingNode::Create();
399 CHKPV(canvasNode_);
400 canvasNode_->SetBounds(0, 0, scaleW_, scaleH_);
401 canvasNode_->SetFrame(0, 0, scaleW_, scaleH_);
402
403 #ifndef USE_ROSEN_DRAWING
404 canvasNode_->SetBackgroundColor(SK_ColorTRANSPARENT);
405 #else
406 canvasNode_->SetBackgroundColor(Rosen::Drawing::Color::COLOR_TRANSPARENT);
407 #endif // USE_ROSEN_DRAWING
408 canvasNode_->SetCornerRadius(1);
409 canvasNode_->SetPositionZ(Rosen::RSSurfaceNode::POINTER_WINDOW_POSITION_Z);
410 canvasNode_->SetRotation(0);
411 }
412
DestoryWindow()413 void KnuckleDynamicDrawingManager::DestoryWindow()
414 {
415 CALL_DEBUG_ENTER;
416 traceControlPoints_.clear();
417 pointerPath_.Reset();
418 if (glowTraceSystem_ != nullptr) {
419 glowTraceSystem_->Clear();
420 }
421 CHKPV(canvasNode_);
422 #ifndef USE_ROSEN_DRAWING
423 auto canvas = static_cast<Rosen::RSRecordingCanvas *>(canvasNode_->
424 BeginRecording(scaleW_, scaleH_));
425 #else
426 auto canvas = static_cast<Rosen::ExtendRecordingCanvas *>(canvasNode_->
427 BeginRecording(scaleW_, scaleH_));
428 #endif // USE_ROSEN_DRAWING
429 CHKPV(canvas);
430 canvas->Clear();
431 canvasNode_->FinishRecording();
432 CHKPV(surfaceNode_);
433 surfaceNode_->DetachToDisplay(screenId_);
434 surfaceNode_->RemoveChild(canvasNode_);
435 canvasNode_->ResetSurface(scaleW_, scaleH_);
436 canvasNode_.reset();
437 surfaceNode_.reset();
438 MMI_HILOGI("Detach screenId:%{public}" PRIu64, screenId_);
439 Rosen::RSTransaction::FlushImplicitTransaction();
440 }
441 } // namespace MMI
442 } // namespace OHOS
443