• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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