1 /*
2  * Copyright (C) 2023 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 "accessibility_circle_drawing_manager.h"
17 #ifdef OHOS_BUILD_ENABLE_DISPLAY_MANAGER
18 #include "accessibility_display_manager.h"
19 #endif
20 #include "hilog_wrapper.h"
21 #include "pipeline/rs_recording_canvas.h"
22 #include "recording/recording_canvas.h"
23 
24 namespace OHOS {
25 namespace Accessibility {
26 
27 constexpr int32_t DEFAULT_VALUE = -1;
28 
29 constexpr int32_t OUT_CIRCLE_RADIUS = 49; // outer circle
30 constexpr int32_t PROGRESS_RADIUS = 46; // progress circle background
31 constexpr int32_t CENTER_CIRCLE_RADIUS = 6; // center circle
32 constexpr int32_t PROGRESS_STROKE_WIDTH = 2; // progress stroke
33 
34 constexpr int32_t OUT_CIRCLE_BACKGROUND_ALPHA = 64;
35 constexpr int32_t PROGRESS_BACKGROUND_ALPHA = 153;
36 constexpr int32_t CENTER_CIRCLE_BACKGROUND_ALPHA = 230;
37 constexpr int32_t PROGRESS_BAR_BACKGROUND_ALPHA = 230;
38 
39 const std::string PROGRESS_BACKGROUND_COLOR_TYPE = "#0A59F7"; // progress circle background
40 const std::string PROGRESS_COLOR_TYPE = "#FFFFFF"; // center circle
41 const std::string OUT_CIRCLE_BACKGROUND_COLOR_TYPE = "#1756C4"; // outer circle
42 
43 constexpr int32_t DEFAULT_WIDTH = 500;
44 constexpr int32_t DEFAULT_HEIGHT = 500;
45 constexpr int32_t DEFAULT_HALF = 2;
46 
47 constexpr int32_t DEFAULT_PIXEL_DENSITY = 160;
48 
49 constexpr int32_t HEXADECIMAL = 16;
50 constexpr int32_t DECIMAL = 10;
51 constexpr char CHAR_0 = '0';
52 constexpr char CHAR_9 = '9';
53 constexpr char CHAR_A = 'A';
54 constexpr char CHAR_B = 'B';
55 constexpr char CHAR_C = 'C';
56 constexpr char CHAR_D = 'D';
57 constexpr char CHAR_E = 'E';
58 constexpr char CHAR_F = 'F';
59 
60 constexpr int32_t COLOR_STRING_LENGTH = 2;
61 constexpr int32_t RED_START_INDEX = 1;
62 constexpr int32_t GREEN_START_INDEX = 3;
63 constexpr int32_t BLUE_START_INDEX = 5;
64 
65 constexpr int32_t NUMBER_0 = 0;
66 constexpr int32_t NUMBER_1 = 1;
67 constexpr int32_t NUMBER_2 = 2;
68 
69 std::shared_ptr<AccessibilityCircleDrawingManager> AccessibilityCircleDrawingManager::pointDrawMgr_ = nullptr;
70 
GetInstance()71 std::shared_ptr<AccessibilityCircleDrawingManager> AccessibilityCircleDrawingManager::GetInstance()
72 {
73     HILOG_DEBUG();
74     if (pointDrawMgr_ == nullptr) {
75         pointDrawMgr_ = std::make_shared<AccessibilityCircleDrawingManager>();
76     }
77     return pointDrawMgr_;
78 }
79 
DeleteInstance()80 void AccessibilityCircleDrawingManager::DeleteInstance()
81 {
82     HILOG_DEBUG();
83     if (pointDrawMgr_ == nullptr) {
84         HILOG_ERROR("surfaceNode_ is nullptr");
85         return;
86     }
87     pointDrawMgr_ = nullptr;
88 }
89 
AccessibilityCircleDrawingManager()90 AccessibilityCircleDrawingManager::AccessibilityCircleDrawingManager()
91 {
92     HILOG_DEBUG();
93     imageWidth_ = DEFAULT_WIDTH;
94     imageHeight_ = DEFAULT_HEIGHT;
95     half_ = DEFAULT_WIDTH / DEFAULT_HALF;
96 
97 #ifdef OHOS_BUILD_ENABLE_DISPLAY_MANAGER
98     AccessibilityDisplayManager &displayMgr = Singleton<AccessibilityDisplayManager>::GetInstance();
99     screenId_ = displayMgr.GetDefaultDisplayId(); // default screenId 0
100     auto dpi = displayMgr.GetDefaultDisplayDpi();
101     dispalyDensity_ = static_cast<float>(dpi) / DEFAULT_PIXEL_DENSITY;
102 #else
103     HILOG_DEBUG("not support display manager");
104     screenId_ = 0;
105     dispalyDensity_ = 1;
106 #endif
107 }
108 
~AccessibilityCircleDrawingManager()109 AccessibilityCircleDrawingManager::~AccessibilityCircleDrawingManager()
110 {
111     HILOG_DEBUG();
112     if (surfaceNode_ == nullptr) {
113         HILOG_ERROR("surfaceNode_ is nullptr");
114         return;
115     }
116 
117     surfaceNode_->ClearChildren();
118     surfaceNode_->DetachToDisplay(screenId_);
119     surfaceNode_ = nullptr;
120     canvasNode_ = nullptr;
121     Rosen::RSTransaction::FlushImplicitTransaction();
122 }
123 
UpdatePointerVisible(bool state)124 void AccessibilityCircleDrawingManager::UpdatePointerVisible(bool state)
125 {
126     HILOG_DEBUG("state %{public}s", state ? "true" : "false");
127     if (surfaceNode_ == nullptr) {
128         HILOG_ERROR("surfaceNode_ is nullptr");
129         return;
130     }
131 
132     surfaceNode_->SetVisible(state);
133     Rosen::RSTransaction::FlushImplicitTransaction();
134 }
135 
CreatePointerWindow(int32_t physicalX,int32_t physicalY,uint64_t screenId)136 void AccessibilityCircleDrawingManager::CreatePointerWindow(int32_t physicalX, int32_t physicalY, uint64_t screenId)
137 {
138     HILOG_DEBUG();
139     Rosen::RSSurfaceNodeConfig surfaceNodeConfig;
140     surfaceNodeConfig.SurfaceNodeName = "screen touch progress";
141     Rosen::RSSurfaceNodeType surfaceNodeType = Rosen::RSSurfaceNodeType::SELF_DRAWING_WINDOW_NODE;
142     surfaceNode_ = Rosen::RSSurfaceNode::Create(surfaceNodeConfig, surfaceNodeType);
143     if (surfaceNode_ == nullptr) {
144         HILOG_ERROR("create surfaceNode_ fail");
145         return;
146     }
147 
148     surfaceNode_->SetFrameGravity(Rosen::Gravity::RESIZE_ASPECT_FILL);
149     surfaceNode_->SetPositionZ(Rosen::RSSurfaceNode::POINTER_WINDOW_POSITION_Z);
150     surfaceNode_->SetBounds(physicalX - half_, physicalY - half_, imageWidth_, imageHeight_);
151     surfaceNode_->SetBackgroundColor(SK_ColorTRANSPARENT); // USE_ROSEN_DRAWING
152     screenId_ = screenId;
153     surfaceNode_->AttachToDisplay(screenId);
154     surfaceNode_->SetRotation(0);
155 
156     canvasNode_ = Rosen::RSCanvasNode::Create();
157     if (canvasNode_ == nullptr) {
158         HILOG_ERROR("create canvasNode_ fail");
159         return;
160     }
161 
162     surfaceNode_->AddChild(canvasNode_, DEFAULT_VALUE);
163     canvasNode_->SetBounds(0, 0, imageWidth_, imageHeight_);
164     canvasNode_->SetFrame(0, 0, imageWidth_, imageHeight_);
165     canvasNode_->SetBackgroundColor(SK_ColorTRANSPARENT); // USE_ROSEN_DRAWING
166     canvasNode_->SetCornerRadius(1);
167     canvasNode_->SetPositionZ(Rosen::RSSurfaceNode::POINTER_WINDOW_POSITION_Z);
168     canvasNode_->SetRotation(0);
169     Rosen::RSTransaction::FlushImplicitTransaction();
170 }
171 
172 #ifndef USE_ROSEN_DRAWING
DrawingProgressByOpenSource(int32_t physicalX,int32_t physicalY,int32_t angle)173 void AccessibilityCircleDrawingManager::DrawingProgressByOpenSource(int32_t physicalX, int32_t physicalY, int32_t angle)
174 {
175     HILOG_DEBUG();
176     auto canvas = static_cast<Rosen::RSRecordingCanvas *>(canvasNode_->BeginRecording(imageWidth_, imageHeight_));
177 
178     // outer circle
179     SkPaint outCirclePaint;
180     outCirclePaint.setAntiAlias(true);
181     outCirclePaint.setAlphaf(OUT_CIRCLE_BACKGROUND_ALPHA);
182 
183     std::vector<int32_t> outCircleColor = ParseColorString(OUT_CIRCLE_BACKGROUND_COLOR_TYPE);
184     outCirclePaint.setARGB(OUT_CIRCLE_BACKGROUND_ALPHA, outCircleColor[NUMBER_0], outCircleColor[NUMBER_1],
185         outCircleColor[NUMBER_2]);
186     outCirclePaint.setStyle(SkPaint::kFill_Style);
187     canvas->drawCircle(half_, half_, dispalyDensity_ * OUT_CIRCLE_RADIUS, outCirclePaint);
188 
189     // center circle
190     SkPaint centerCirclePaint;
191     centerCirclePaint.setAntiAlias(true);
192     centerCirclePaint.setAlphaf(CENTER_CIRCLE_BACKGROUND_ALPHA);
193     std::vector<int32_t> centerCircleColor = ParseColorString(PROGRESS_COLOR_TYPE);
194     centerCirclePaint.setARGB(CENTER_CIRCLE_BACKGROUND_ALPHA, centerCircleColor[NUMBER_0],
195         centerCircleColor[NUMBER_1], centerCircleColor[NUMBER_2]);
196     centerCirclePaint.setStyle(SkPaint::kFill_Style);
197     canvas->drawCircle(half_, half_, dispalyDensity_ * CENTER_CIRCLE_RADIUS, centerCirclePaint);
198 
199     // progress circle
200     SkPaint progressCirclePaint;
201     progressCirclePaint.setAntiAlias(true);
202     progressCirclePaint.setAlphaf(PROGRESS_BACKGROUND_ALPHA);
203     std::vector<int32_t> progressCircleColor = ParseColorString(PROGRESS_BACKGROUND_COLOR_TYPE);
204     progressCirclePaint.setARGB(PROGRESS_BACKGROUND_ALPHA, progressCircleColor[NUMBER_0],
205         progressCircleColor[NUMBER_1], progressCircleColor[NUMBER_2]);
206     progressCirclePaint.setStrokeWidth(PROGRESS_STROKE_WIDTH * dispalyDensity_);
207     progressCirclePaint.setStyle(SkPaint::kStroke_Style);
208     canvas->drawCircle(half_, half_, dispalyDensity_ * PROGRESS_RADIUS, progressCirclePaint);
209 
210     // progress arc
211     SkPaint progressArcPaint;
212     progressArcPaint.setAntiAlias(true);
213     progressArcPaint.setAlphaf(PROGRESS_BAR_BACKGROUND_ALPHA);
214     std::vector<int32_t> progressArcColor = ParseColorString(PROGRESS_COLOR_TYPE);
215     progressArcPaint.setARGB(PROGRESS_BAR_BACKGROUND_ALPHA, progressArcColor[NUMBER_0],
216         progressArcColor[NUMBER_1], progressArcColor[NUMBER_2]);
217     progressArcPaint.setStrokeWidth(PROGRESS_STROKE_WIDTH * dispalyDensity_);
218     progressArcPaint.setStyle(SkPaint::kStroke_Style);
219 
220     SkRect arcRect = SkRect::MakeLTRB(half_ - dispalyDensity_ * PROGRESS_RADIUS,
221         half_ - dispalyDensity_ * PROGRESS_RADIUS,
222         half_ + dispalyDensity_ * PROGRESS_RADIUS,
223         half_ + dispalyDensity_ * PROGRESS_RADIUS);
224     canvas->drawArc(arcRect, startAngle_, angle, false, progressArcPaint);
225 
226     canvasNode_->FinishRecording();
227     Rosen::RSTransaction::FlushImplicitTransaction();
228 }
229 #else
DrawingProgressByRosenDrawing(int32_t physicalX,int32_t physicalY,int32_t angle)230 void AccessibilityCircleDrawingManager::DrawingProgressByRosenDrawing(int32_t physicalX, int32_t physicalY,
231     int32_t angle)
232 {
233     HILOG_DEBUG();
234     auto canvas = canvasNode_->BeginRecording(imageWidth_, imageHeight_);
235 
236     // outer circle
237     Rosen::Drawing::Brush outCircleBrush;
238     outCircleBrush.SetAntiAlias(true);
239     outCircleBrush.SetAlphaF(OUT_CIRCLE_BACKGROUND_ALPHA);
240     std::vector<int32_t> outCircleColor = ParseColorString(OUT_CIRCLE_BACKGROUND_COLOR_TYPE);
241     outCircleBrush.SetARGB(OUT_CIRCLE_BACKGROUND_ALPHA, outCircleColor[NUMBER_0], outCircleColor[NUMBER_1],
242         outCircleColor[NUMBER_2]);
243 
244     canvas->AttachBrush(outCircleBrush);
245     canvas->DrawCircle(Rosen::Drawing::Point(half_, half_), dispalyDensity_ * OUT_CIRCLE_RADIUS);
246     canvas->DetachBrush();
247 
248     // center circle
249     Rosen::Drawing::Brush centerCircleBrush;
250     centerCircleBrush.SetAntiAlias(true);
251     centerCircleBrush.SetAlphaF(CENTER_CIRCLE_BACKGROUND_ALPHA);
252     std::vector<int32_t> centerCircleColor = ParseColorString(PROGRESS_COLOR_TYPE);
253     centerCircleBrush.SetARGB(CENTER_CIRCLE_BACKGROUND_ALPHA, centerCircleColor[NUMBER_0],
254         centerCircleColor[NUMBER_1], centerCircleColor[NUMBER_2]);
255 
256     canvas->AttachBrush(centerCircleBrush);
257     canvas->DrawCircle(Rosen::Drawing::Point(half_, half_), dispalyDensity_ * CENTER_CIRCLE_RADIUS);
258     canvas->DetachBrush();
259 
260     // progress circle
261     Rosen::Drawing::Pen progressPen;
262     progressPen.SetAntiAlias(true);
263     progressPen.SetAlphaF(PROGRESS_BACKGROUND_ALPHA);
264     std::vector<int32_t> progressCircleColor = ParseColorString(PROGRESS_BACKGROUND_COLOR_TYPE);
265     progressPen.SetARGB(PROGRESS_BACKGROUND_ALPHA, progressCircleColor[NUMBER_0],
266         progressCircleColor[NUMBER_1], progressCircleColor[NUMBER_2]);
267     progressPen.SetWidth(PROGRESS_STROKE_WIDTH * dispalyDensity_);
268 
269     canvas->AttachPen(progressPen);
270     canvas->DrawCircle(Rosen::Drawing::Point(half_, half_), dispalyDensity_ * PROGRESS_RADIUS);
271     canvas->DetachPen();
272 
273     // progress arc
274     Rosen::Drawing::Pen progressArcPen;
275     progressArcPen.SetAntiAlias(true);
276     progressArcPen.SetAlphaF(PROGRESS_BAR_BACKGROUND_ALPHA);
277     std::vector<int32_t> progressArcColor = ParseColorString(PROGRESS_COLOR_TYPE);
278     progressArcPen.SetARGB(PROGRESS_BAR_BACKGROUND_ALPHA, progressArcColor[NUMBER_0],
279         progressArcColor[NUMBER_1], progressArcColor[NUMBER_2]);
280     progressArcPen.SetWidth(PROGRESS_STROKE_WIDTH * dispalyDensity_);
281 
282     Rosen::Drawing::Rect rect(half_ - dispalyDensity_ * PROGRESS_RADIUS,
283         half_ - dispalyDensity_ * PROGRESS_RADIUS,
284         half_ + dispalyDensity_ * PROGRESS_RADIUS,
285         half_ + dispalyDensity_ * PROGRESS_RADIUS);
286     canvas->AttachPen(progressArcPen);
287     canvas->DrawArc(rect, startAngle_, angle);
288     canvas->DetachPen();
289 
290     canvasNode_->FinishRecording();
291     Rosen::RSTransaction::FlushImplicitTransaction();
292 }
293 #endif
294 
DrawingProgress(int32_t physicalX,int32_t physicalY,int32_t angle)295 void AccessibilityCircleDrawingManager::DrawingProgress(int32_t physicalX, int32_t physicalY, int32_t angle)
296 {
297 #ifndef USE_ROSEN_DRAWING
298     DrawingProgressByOpenSource(physicalX, physicalY, angle);
299 #else
300     DrawingProgressByRosenDrawing(physicalX, physicalY, angle);
301 #endif
302 }
303 
SetPointerLocation(int32_t physicalX,int32_t physicalY,uint64_t screenId)304 void AccessibilityCircleDrawingManager::SetPointerLocation(int32_t physicalX, int32_t physicalY, uint64_t screenId)
305 {
306     HILOG_DEBUG("Pointer window move, x:%{public}d, y:%{public}d", physicalX, physicalY);
307     if (surfaceNode_ != nullptr) {
308         surfaceNode_->SetBounds(physicalX - half_,
309             physicalY - half_,
310             surfaceNode_->GetStagingProperties().GetBounds().z_,
311             surfaceNode_->GetStagingProperties().GetBounds().w_);
312         screenId_ = screenId;
313         surfaceNode_->AttachToDisplay(screenId);
314         Rosen::RSTransaction::FlushImplicitTransaction();
315     }
316 
317     if (canvasNode_ != nullptr) {
318         canvasNode_->SetBounds(0,
319             0,
320             canvasNode_->GetStagingProperties().GetBounds().z_,
321             canvasNode_->GetStagingProperties().GetBounds().w_);
322         canvasNode_->SetFrame(0,
323             0,
324             canvasNode_->GetStagingProperties().GetBounds().z_,
325             canvasNode_->GetStagingProperties().GetBounds().w_);
326         Rosen::RSTransaction::FlushImplicitTransaction();
327     }
328 }
329 
DrawPointer(int32_t physicalX,int32_t physicalY,int32_t angle,uint64_t screenId,int32_t startAngle)330 void AccessibilityCircleDrawingManager::DrawPointer(int32_t physicalX, int32_t physicalY, int32_t angle,
331     uint64_t screenId, int32_t startAngle)
332 {
333     HILOG_DEBUG();
334     startAngle_ = startAngle;
335     if (surfaceNode_ != nullptr) {
336         SetPointerLocation(physicalX, physicalY, screenId);
337         DrawingProgress(physicalX, physicalY, angle);
338         UpdatePointerVisible(true);
339         HILOG_DEBUG("surfaceNode_ is existed");
340         return;
341     }
342 
343     CreatePointerWindow(physicalX, physicalY, screenId);
344     if (surfaceNode_ == nullptr) {
345         HILOG_ERROR("surfaceNode_ is nullptr");
346         return;
347     }
348 
349     DrawingProgress(physicalX, physicalY, angle);
350     UpdatePointerVisible(true);
351 }
352 
ParseStringToInteger(const std::string & color)353 int32_t AccessibilityCircleDrawingManager::ParseStringToInteger(const std::string& color)
354 {
355     int32_t val = 0;
356     int32_t base = 1;
357     if (color.size() < 1) {
358         return val;
359     }
360     for (int32_t index = static_cast<int32_t>(color.size() - 1); index >= 0; index--) {
361         if (color[index] >= CHAR_0 && color[index] <= CHAR_9) {
362             val += base * static_cast<int32_t>(color[index] - CHAR_0);
363         }
364 
365         if (color[index] == CHAR_A) {
366             val += base * static_cast<int32_t>(color[index] - CHAR_A + DECIMAL);
367         }
368 
369         if (color[index] == CHAR_B) {
370             val += base * static_cast<int32_t>(color[index] - CHAR_A + DECIMAL);
371         }
372 
373         if (color[index] == CHAR_C) {
374             val += base * static_cast<int32_t>(color[index] - CHAR_A + DECIMAL);
375         }
376 
377         if (color[index] == CHAR_D) {
378             val += base * static_cast<int32_t>(color[index] - CHAR_A + DECIMAL);
379         }
380 
381         if (color[index] == CHAR_E) {
382             val += base * static_cast<int32_t>(color[index] - CHAR_A + DECIMAL);
383         }
384 
385         if (color[index] == CHAR_F) {
386             val += base * static_cast<int32_t>(color[index] - CHAR_A + DECIMAL);
387         }
388 
389         base = base * HEXADECIMAL;
390     }
391 
392     return val;
393 }
394 
ParseColorString(const std::string & color)395 std::vector<int32_t> AccessibilityCircleDrawingManager::ParseColorString(const std::string& color)
396 {
397     std::string r = color.substr(RED_START_INDEX, COLOR_STRING_LENGTH);
398     std::string g = color.substr(GREEN_START_INDEX, COLOR_STRING_LENGTH);
399     std::string b = color.substr(BLUE_START_INDEX, COLOR_STRING_LENGTH);
400 
401     int32_t rValue = ParseStringToInteger(r);
402     int32_t gValue = ParseStringToInteger(g);
403     int32_t bValue = ParseStringToInteger(b);
404 
405     std::vector<int32_t> rgbValue = {rValue, gValue, bValue};
406     return rgbValue;
407 }
408 } // namespace Accessibility
409 } // namespace OHOS