• 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 "mmi_log.h"
20 #ifndef USE_ROSEN_DRAWING
21 #include "pipeline/rs_recording_canvas.h"
22 #else
23 #include "recording/recording_canvas.h"
24 #include "ui/rs_canvas_drawing_node.h"
25 #endif // USE_ROSEN_DRAWING
26 #include "touch_drawing_manager.h"
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)112 void KnuckleDynamicDrawingManager::KnuckleDynamicDrawHandler(std::shared_ptr<PointerEvent> pointerEvent)
113 {
114     CALL_DEBUG_ENTER;
115     CHKPV(pointerEvent);
116     if (!IsSingleKnuckle(pointerEvent)) {
117         return;
118     }
119     auto displayId = pointerEvent->GetTargetDisplayId();
120     CreateTouchWindow(displayId);
121     if (CheckPointerAction(pointerEvent)) {
122         StartTouchDraw(pointerEvent);
123     }
124 }
125 
IsSingleKnuckle(std::shared_ptr<PointerEvent> touchEvent)126 bool KnuckleDynamicDrawingManager::IsSingleKnuckle(std::shared_ptr<PointerEvent> touchEvent)
127 {
128     CALL_DEBUG_ENTER;
129     CHKPF(touchEvent);
130     auto id = touchEvent->GetPointerId();
131     PointerEvent::PointerItem item;
132     touchEvent->GetPointerItem(id, item);
133     auto itemToolType = item.GetToolType();
134     if (itemToolType != PointerEvent::TOOL_TYPE_KNUCKLE ||
135         touchEvent->GetPointerIds().size() != 1 || isRotate_) {
136         if (!traceControlPoints_.empty()) {
137             isStop_ = true;
138             isDrawing_ = true;
139             DestoryWindow();
140         } else if (isRotate_) {
141             isRotate_ = false;
142             if (item.GetToolType() == PointerEvent::TOOL_TYPE_KNUCKLE) {
143                 return true;
144             }
145         }
146         return false;
147     }
148     return true;
149 }
150 
CheckPointerAction(std::shared_ptr<PointerEvent> pointerEvent)151 bool KnuckleDynamicDrawingManager::CheckPointerAction(std::shared_ptr<PointerEvent> pointerEvent)
152 {
153     CALL_DEBUG_ENTER;
154     CHKPF(knuckleDrawMgr_);
155     if (knuckleDrawMgr_->GetScreenReadState() == SCREEN_READ_ENABLE) {
156         DestoryWindow();
157     }
158     size_t size = pointerEvent->GetPointerIds().size();
159     if (size > MIN_POINT_SIZE) {
160         pointerPath_.Reset();
161         CHKPF(glowTraceSystem_);
162         glowTraceSystem_->Clear();
163         return false;
164     }
165     switch (pointerEvent->GetPointerAction()) {
166         case PointerEvent::POINTER_ACTION_UP:
167         case PointerEvent::POINTER_ACTION_PULL_UP:
168             ProcessUpAndCancelEvent(pointerEvent);
169             break;
170         case PointerEvent::POINTER_ACTION_DOWN:
171         case PointerEvent::POINTER_ACTION_PULL_DOWN:
172             ProcessDownEvent(pointerEvent);
173             return true;
174         case PointerEvent::POINTER_ACTION_MOVE:
175         case PointerEvent::POINTER_ACTION_PULL_MOVE:
176             if (!isStop_ && !traceControlPoints_.empty()) {
177                 ProcessMoveEvent(pointerEvent);
178                 return true;
179             }
180             return false;
181         default:
182             return false;
183     }
184     return true;
185 }
186 
StartTouchDraw(std::shared_ptr<PointerEvent> pointerEvent)187 void KnuckleDynamicDrawingManager::StartTouchDraw(std::shared_ptr<PointerEvent> pointerEvent)
188 {
189     CHKPV(pointerEvent);
190     int32_t ret = DrawGraphic(pointerEvent);
191     if (ret != RET_OK) {
192         MMI_HILOGD("Can't get enough pointers to draw");
193         return;
194     }
195     Rosen::RSTransaction::FlushImplicitTransaction();
196 }
197 
ProcessUpAndCancelEvent(std::shared_ptr<PointerEvent> pointerEvent)198 void KnuckleDynamicDrawingManager::ProcessUpAndCancelEvent(std::shared_ptr<PointerEvent> pointerEvent)
199 {
200     CALL_DEBUG_ENTER;
201     CHKPV(glowTraceSystem_);
202     CHKPV(pointerEvent);
203     lastUpTime_ = pointerEvent->GetActionTime();
204     if (pointerPath_.IsValid()) {
205         auto id = pointerEvent->GetPointerId();
206         PointerEvent::PointerItem pointerItem;
207         pointerEvent->GetPointerItem(id, pointerItem);
208         auto displayXY = TOUCH_DRAWING_MGR->CalcDrawCoordinate(displayInfo_, pointerItem);
209         glowTraceSystem_->ResetDivergentPoints(displayXY.first, displayXY.second);
210     }
211     isDrawing_ = true;
212     DestoryWindow();
213 }
214 
ProcessDownEvent(std::shared_ptr<PointerEvent> pointerEvent)215 void KnuckleDynamicDrawingManager::ProcessDownEvent(std::shared_ptr<PointerEvent> pointerEvent)
216 {
217     CALL_DEBUG_ENTER;
218     CHKPV(pointerEvent);
219     if (traceControlPoints_.empty()) {
220         for (int32_t i = 0; i < POINT_TOTAL_SIZE; i++) {
221             Rosen::Drawing::Point point = Rosen::Drawing::Point();
222             traceControlPoints_.emplace_back(point);
223         }
224     }
225     int64_t intervalTime = pointerEvent->GetActionTime() - lastUpTime_;
226     firstDownTime_ = pointerEvent->GetActionTime();
227     bool isTimeIntervalReady = intervalTime > 0 && intervalTime <= DOUBLE_CLICK_INTERVAL_TIME_SLOW;
228 
229     UpdateTrackColors();
230     lastUpdateTimeMillis_ = pointerEvent->GetActionTime();
231     pointCounter_ = 0;
232     auto id = pointerEvent->GetPointerId();
233     PointerEvent::PointerItem pointerItem;
234     pointerEvent->GetPointerItem(id, pointerItem);
235     auto displayXY = TOUCH_DRAWING_MGR->CalcDrawCoordinate(displayInfo_, pointerItem);
236     float downToPrevDownDistance = static_cast<float>(sqrt(pow(lastDownX_ - displayXY.first, POW_SQUARE) +
237         pow(lastDownY_ - displayXY.second, POW_SQUARE)));
238     bool isDistanceReady = downToPrevDownDistance < DOUBLE_CLICK_DISTANCE_LONG_CONFIG * POW_SQUARE;
239     if (isTimeIntervalReady && isDistanceReady) {
240         MMI_HILOGE("Take a screenshot");
241         isDrawing_ = true;
242         isStop_ = true;
243         return;
244     }
245     lastDownX_ = displayXY.first;
246     lastDownY_ = displayXY.second;
247     traceControlPoints_[pointCounter_].Set(displayXY.first, displayXY.second);
248     isStop_ = false;
249 }
250 
ProcessMoveEvent(std::shared_ptr<PointerEvent> pointerEvent)251 void KnuckleDynamicDrawingManager::ProcessMoveEvent(std::shared_ptr<PointerEvent> pointerEvent)
252 {
253     CALL_DEBUG_ENTER;
254     CHKPV(pointerEvent);
255     pointCounter_++;
256     if (pointCounter_ >= POINT_TOTAL_SIZE) {
257         MMI_HILOGE("traceControlPoints_ index out of size");
258         return;
259     }
260     auto id = pointerEvent->GetPointerId();
261     PointerEvent::PointerItem pointerItem;
262     pointerEvent->GetPointerItem(id, pointerItem);
263     auto displayXY = TOUCH_DRAWING_MGR->CalcDrawCoordinate(displayInfo_, pointerItem);
264     traceControlPoints_[pointCounter_].Set(displayXY.first, displayXY.second);
265     int pointIndex4 = 4;
266     bool draw = (pointerEvent->GetActionTime() - firstDownTime_) > WAIT_DOUBLE_CLICK_INTERVAL_TIME;
267     if (pointCounter_ == pointIndex4) {
268         int pointIndex0 = 0;
269         int pointIndex1 = 1;
270         int pointIndex2 = 2;
271         int pointIndex3 = 3;
272 
273         traceControlPoints_[pointIndex3].Set(
274             (traceControlPoints_[pointIndex2].GetX() + traceControlPoints_[pointIndex4].GetX()) / DOUBLE,
275             (traceControlPoints_[pointIndex2].GetY() + traceControlPoints_[pointIndex4].GetY()) / DOUBLE);
276         // Add a cubic Bezier from pt[0] to pt[3] with control pointspt[1] and pt[2]
277         pointerPath_.MoveTo (traceControlPoints_[pointIndex0].GetX(), traceControlPoints_[pointIndex0].GetY());
278         pointerPath_.CubicTo(traceControlPoints_[pointIndex1].GetX(), traceControlPoints_[pointIndex1].GetY(),
279             traceControlPoints_[pointIndex2].GetX(), traceControlPoints_[pointIndex2].GetY(),
280             traceControlPoints_[pointIndex3].GetX(), traceControlPoints_[pointIndex3].GetY());
281         traceControlPoints_[pointIndex0].Set(traceControlPoints_[pointIndex3].GetX(),
282             traceControlPoints_[pointIndex3].GetY());
283         traceControlPoints_[pointIndex1].Set (traceControlPoints_[pointIndex4].GetX(),
284             traceControlPoints_[pointIndex4].GetY());
285         pointCounter_ = 1;
286         // Add glowing particles onto the last path segment that was drawn
287         int64_t now = pointerEvent->GetActionTime();
288         if (draw) {
289             glowTraceSystem_->AddGlowPoints(pointerPath_, (now - lastUpdateTimeMillis_) / TIME_DIMENSION);
290         }
291         pointerPath_.Reset();
292         lastUpdateTimeMillis_ = now;
293     }
294     if (draw) {
295         glowTraceSystem_->ResetDivergentPoints(displayXY.first, displayXY.second);
296         isDrawing_ = false;
297     }
298 }
299 
UpdateDisplayInfo(const DisplayInfo & displayInfo)300 void KnuckleDynamicDrawingManager::UpdateDisplayInfo(const DisplayInfo& displayInfo)
301 {
302     CALL_DEBUG_ENTER;
303     if (displayInfo_.direction != displayInfo.direction) {
304         MMI_HILOGD("DisplayInfo direction change");
305         isRotate_ = true;
306     }
307     scaleW_ = displayInfo.width > displayInfo.height ? displayInfo.width : displayInfo.height;
308     scaleH_ = displayInfo.width > displayInfo.height ? displayInfo.width : displayInfo.height;
309     displayInfo_ = displayInfo;
310 }
311 
SetKnuckleDrawingManager(std::shared_ptr<KnuckleDrawingManager> knuckleDrawMgr)312 void KnuckleDynamicDrawingManager::SetKnuckleDrawingManager(std::shared_ptr<KnuckleDrawingManager> knuckleDrawMgr)
313 {
314     CALL_DEBUG_ENTER;
315     knuckleDrawMgr_ = knuckleDrawMgr;
316 }
317 
DrawGraphic(std::shared_ptr<PointerEvent> pointerEvent)318 int32_t KnuckleDynamicDrawingManager::DrawGraphic(std::shared_ptr<PointerEvent> pointerEvent)
319 {
320     CALL_DEBUG_ENTER;
321     CHKPR(pointerEvent, RET_ERR);
322     CHKPR(canvasNode_, RET_ERR);
323     glowTraceSystem_->Update();
324     if ((pointerEvent->GetActionTime() - isInDrawingTime_) > IN_DRAWING_TIME) {
325         isInDrawingTime_ = pointerEvent->GetActionTime();
326     } else {
327         return RET_ERR;
328     }
329 #ifndef USE_ROSEN_DRAWING
330     auto canvas = static_cast<Rosen::RSRecordingCanvas *>(canvasNode_->
331         BeginRecording(scaleW_, scaleH_));
332 #else
333     auto canvas = static_cast<Rosen::ExtendRecordingCanvas *>(canvasNode_->
334         BeginRecording(scaleW_, scaleH_));
335 #endif // USE_ROSEN_DRAWING
336 
337     CHKPR(canvas, RET_ERR);
338 
339     if (!isDrawing_) {
340         glowTraceSystem_->Draw(canvas);
341     }
342     canvasNode_->ResetSurface(scaleW_, scaleH_);
343     canvasNode_->FinishRecording();
344     return RET_OK;
345 }
346 
CreateTouchWindow(const int32_t displayId)347 void KnuckleDynamicDrawingManager::CreateTouchWindow(const int32_t displayId)
348 {
349     CALL_DEBUG_ENTER;
350     if (surfaceNode_ != nullptr) {
351         MMI_HILOGD("surfaceNode_ is already exist");
352         return;
353     }
354     Rosen::RSSurfaceNodeConfig surfaceNodeConfig;
355     surfaceNodeConfig.SurfaceNodeName = "knuckle dynamic window";
356     Rosen::RSSurfaceNodeType surfaceNodeType = Rosen::RSSurfaceNodeType::SELF_DRAWING_WINDOW_NODE;
357     surfaceNode_ = Rosen::RSSurfaceNode::Create(surfaceNodeConfig, surfaceNodeType);
358     CHKPV(surfaceNode_);
359 
360     surfaceNode_->SetSnapshotSkipLayer(true);
361     surfaceNode_->SetFrameGravity(Rosen::Gravity::RESIZE_ASPECT_FILL);
362     surfaceNode_->SetPositionZ(Rosen::RSSurfaceNode::POINTER_WINDOW_POSITION_Z);
363     surfaceNode_->SetBounds(0, 0, scaleW_, scaleH_);
364     surfaceNode_->SetFrame(0, 0, scaleW_, scaleH_);
365 
366 #ifndef USE_ROSEN_DRAWING
367     surfaceNode_->SetBackgroundColor(SK_ColorTRANSPARENT);
368 #else
369     surfaceNode_->SetBackgroundColor(Rosen::Drawing::Color::COLOR_TRANSPARENT);
370 #endif // USE_ROSEN_DRAWING
371 
372     screenId_ = static_cast<uint64_t>(displayId);
373     surfaceNode_->SetRotation(0);
374 
375     CreateCanvasNode();
376     surfaceNode_->AddChild(canvasNode_, DEFAULT_VALUE);
377     if (displayInfo_.displayMode == DisplayMode::MAIN) {
378         screenId_ = FOLD_SCREEN_MAIN_ID;
379     }
380     MMI_HILOGI("The screenId_:%{public}" PRIu64, screenId_);
381     surfaceNode_->AttachToDisplay(screenId_);
382     CHKPV(knuckleDrawMgr_);
383     knuckleDrawMgr_->RotationCanvasNode(canvasNode_, displayInfo_);
384     canvasNode_->ResetSurface(scaleW_, scaleH_);
385     Rosen::RSTransaction::FlushImplicitTransaction();
386 }
387 
CreateCanvasNode()388 void KnuckleDynamicDrawingManager::CreateCanvasNode()
389 {
390     CALL_DEBUG_ENTER;
391     canvasNode_ = Rosen::RSCanvasDrawingNode::Create();
392     CHKPV(canvasNode_);
393     canvasNode_->SetBounds(0, 0, scaleW_, scaleH_);
394     canvasNode_->SetFrame(0, 0, scaleW_, scaleH_);
395 
396 #ifndef USE_ROSEN_DRAWING
397     canvasNode_->SetBackgroundColor(SK_ColorTRANSPARENT);
398 #else
399     canvasNode_->SetBackgroundColor(Rosen::Drawing::Color::COLOR_TRANSPARENT);
400 #endif // USE_ROSEN_DRAWING
401     canvasNode_->SetCornerRadius(1);
402     canvasNode_->SetPositionZ(Rosen::RSSurfaceNode::POINTER_WINDOW_POSITION_Z);
403     canvasNode_->SetRotation(0);
404 }
405 
DestoryWindow()406 void KnuckleDynamicDrawingManager::DestoryWindow()
407 {
408     CALL_DEBUG_ENTER;
409     traceControlPoints_.clear();
410     pointerPath_.Reset();
411     if (glowTraceSystem_ != nullptr) {
412         glowTraceSystem_->Clear();
413     }
414     CHKPV(canvasNode_);
415 #ifndef USE_ROSEN_DRAWING
416     auto canvas = static_cast<Rosen::RSRecordingCanvas *>(canvasNode_->
417         BeginRecording(scaleW_, scaleH_));
418 #else
419     auto canvas = static_cast<Rosen::ExtendRecordingCanvas *>(canvasNode_->
420         BeginRecording(scaleW_, scaleH_));
421 #endif // USE_ROSEN_DRAWING
422     CHKPV(canvas);
423     canvas->Clear();
424     canvasNode_->FinishRecording();
425     CHKPV(surfaceNode_);
426     surfaceNode_->DetachToDisplay(screenId_);
427     surfaceNode_->RemoveChild(canvasNode_);
428     canvasNode_->ResetSurface(scaleW_, scaleH_);
429     canvasNode_.reset();
430     surfaceNode_.reset();
431     Rosen::RSTransaction::FlushImplicitTransaction();
432 }
433 } // namespace MMI
434 } // namespace OHOS
435