* Copyright (C) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "accessibility_circle_drawing_manager.h"
#ifdef OHOS_BUILD_ENABLE_DISPLAY_MANAGER
#include "accessibility_display_manager.h"
#endif
#include "hilog_wrapper.h"
#include "pipeline/rs_recording_canvas.h"
#include "recording/recording_canvas.h"
#include "transaction/rs_interfaces.h"
#include "modifier/rs_property.h"
namespace OHOS {
namespace Accessibility {
constexpr int32_t DEFAULT_VALUE = -1;
constexpr int32_t OUT_CIRCLE_RADIUS = 49;
constexpr int32_t PROGRESS_RADIUS = 46;
constexpr int32_t CENTER_CIRCLE_RADIUS = 6;
constexpr int32_t PROGRESS_STROKE_WIDTH = 2;
constexpr int32_t OUT_CIRCLE_BACKGROUND_ALPHA = 64;
constexpr int32_t PROGRESS_BACKGROUND_ALPHA = 153;
constexpr int32_t CENTER_CIRCLE_BACKGROUND_ALPHA = 230;
constexpr int32_t PROGRESS_BAR_BACKGROUND_ALPHA = 230;
const std::string PROGRESS_BACKGROUND_COLOR_TYPE = "#0A59F7";
const std::string PROGRESS_COLOR_TYPE = "#FFFFFF";
const std::string OUT_CIRCLE_BACKGROUND_COLOR_TYPE = "#1756C4";
constexpr int32_t DEFAULT_WIDTH = 500;
constexpr int32_t DEFAULT_HEIGHT = 500;
constexpr int32_t DEFAULT_HALF = 2;
constexpr int32_t DEFAULT_PIXEL_DENSITY = 160;
constexpr int32_t HEXADECIMAL = 16;
constexpr int32_t DECIMAL = 10;
constexpr char CHAR_0 = '0';
constexpr char CHAR_9 = '9';
constexpr char CHAR_A = 'A';
constexpr char CHAR_B = 'B';
constexpr char CHAR_C = 'C';
constexpr char CHAR_D = 'D';
constexpr char CHAR_E = 'E';
constexpr char CHAR_F = 'F';
constexpr int32_t COLOR_STRING_LENGTH = 2;
constexpr int32_t RED_START_INDEX = 1;
constexpr int32_t GREEN_START_INDEX = 3;
constexpr int32_t BLUE_START_INDEX = 5;
constexpr int32_t NUMBER_0 = 0;
constexpr int32_t NUMBER_1 = 1;
constexpr int32_t NUMBER_2 = 2;
std::shared_ptr<AccessibilityCircleDrawingManager> AccessibilityCircleDrawingManager::pointDrawMgr_ = nullptr;
std::shared_ptr<AccessibilityCircleDrawingManager> AccessibilityCircleDrawingManager::GetInstance()
{
HILOG_DEBUG();
if (pointDrawMgr_ == nullptr) {
pointDrawMgr_ = std::make_shared<AccessibilityCircleDrawingManager>();
}
return pointDrawMgr_;
}
void AccessibilityCircleDrawingManager::DeleteInstance()
{
HILOG_DEBUG();
if (pointDrawMgr_ == nullptr) {
HILOG_ERROR("surfaceNode_ is nullptr");
return;
}
pointDrawMgr_ = nullptr;
}
AccessibilityCircleDrawingManager::AccessibilityCircleDrawingManager()
{
HILOG_DEBUG();
imageWidth_ = DEFAULT_WIDTH;
imageHeight_ = DEFAULT_HEIGHT;
half_ = DEFAULT_WIDTH / DEFAULT_HALF;
#ifdef OHOS_BUILD_ENABLE_DISPLAY_MANAGER
AccessibilityDisplayManager &displayMgr = Singleton<AccessibilityDisplayManager>::GetInstance();
screenId_ = displayMgr.GetDefaultDisplayId();
auto dpi = displayMgr.GetDefaultDisplayDpi();
dispalyDensity_ = static_cast<float>(dpi) / DEFAULT_PIXEL_DENSITY;
#else
HILOG_DEBUG("not support display manager");
screenId_ = 0;
dispalyDensity_ = 1;
#endif
}
AccessibilityCircleDrawingManager::~AccessibilityCircleDrawingManager()
{
HILOG_DEBUG();
if (surfaceNode_ == nullptr) {
HILOG_ERROR("surfaceNode_ is nullptr");
return;
}
surfaceNode_->ClearChildren();
surfaceNode_->DetachToDisplay(screenId_);
surfaceNode_ = nullptr;
canvasNode_ = nullptr;
FlushImplicitTransaction();
}
void AccessibilityCircleDrawingManager::UpdatePointerVisible(bool state)
{
HILOG_DEBUG("state %{public}s", state ? "true" : "false");
if (surfaceNode_ == nullptr) {
HILOG_ERROR("surfaceNode_ is nullptr");
return;
}
surfaceNode_->SetVisible(state);
FlushImplicitTransaction();
}
void AccessibilityCircleDrawingManager::CreatePointerWindow(int32_t physicalX, int32_t physicalY, uint64_t screenId)
{
HILOG_DEBUG();
Rosen::RSSurfaceNodeConfig surfaceNodeConfig;
surfaceNodeConfig.SurfaceNodeName = "screen touch progress";
Rosen::RSSurfaceNodeType surfaceNodeType = Rosen::RSSurfaceNodeType::SELF_DRAWING_WINDOW_NODE;
auto connectToRenderObj = Rosen::RSInterfaces::GetInstance().GetConnectToRenderToken(screenId);
rsUiDirector_ = Rosen::RSUIDirector::Create(connectToRenderObj);
if (!rsUiDirector_) {
return;
}
surfaceNode_ =
Rosen::RSSurfaceNode::Create(surfaceNodeConfig, surfaceNodeType, true, false, rsUiDirector_->GetRSUIContext());
if (surfaceNode_ == nullptr) {
HILOG_ERROR("create surfaceNode_ fail");
return;
}
surfaceNode_->SetFrameGravity(Rosen::Gravity::RESIZE_ASPECT_FILL);
surfaceNode_->SetPositionZ(Rosen::RSSurfaceNode::POINTER_WINDOW_POSITION_Z);
surfaceNode_->SetBounds(physicalX - half_, physicalY - half_, imageWidth_, imageHeight_);
surfaceNode_->SetBackgroundColor(SK_ColorTRANSPARENT);
screenId_ = screenId;
surfaceNode_->AttachToDisplay(screenId);
surfaceNode_->SetRotation(0);
canvasNode_ = Rosen::RSCanvasNode::Create(false, false, rsUiDirector_->GetRSUIContext());
if (canvasNode_ == nullptr) {
HILOG_ERROR("create canvasNode_ fail");
return;
}
surfaceNode_->AddChild(canvasNode_, DEFAULT_VALUE);
canvasNode_->SetBounds(0, 0, imageWidth_, imageHeight_);
canvasNode_->SetFrame(0, 0, imageWidth_, imageHeight_);
canvasNode_->SetBackgroundColor(SK_ColorTRANSPARENT);
canvasNode_->SetCornerRadius(1);
canvasNode_->SetPositionZ(Rosen::RSSurfaceNode::POINTER_WINDOW_POSITION_Z);
canvasNode_->SetRotation(0);
FlushImplicitTransaction();
}
#ifndef USE_ROSEN_DRAWING
void AccessibilityCircleDrawingManager::DrawingProgressByOpenSource(int32_t physicalX, int32_t physicalY, int32_t angle)
{
HILOG_DEBUG();
auto canvas = static_cast<Rosen::RSRecordingCanvas *>(canvasNode_->BeginRecording(imageWidth_, imageHeight_));
SkPaint outCirclePaint;
outCirclePaint.setAntiAlias(true);
outCirclePaint.setAlphaf(OUT_CIRCLE_BACKGROUND_ALPHA);
std::vector<int32_t> outCircleColor = ParseColorString(OUT_CIRCLE_BACKGROUND_COLOR_TYPE);
outCirclePaint.setARGB(OUT_CIRCLE_BACKGROUND_ALPHA, outCircleColor[NUMBER_0], outCircleColor[NUMBER_1],
outCircleColor[NUMBER_2]);
outCirclePaint.setStyle(SkPaint::kFill_Style);
canvas->drawCircle(half_, half_, dispalyDensity_ * OUT_CIRCLE_RADIUS, outCirclePaint);
SkPaint centerCirclePaint;
centerCirclePaint.setAntiAlias(true);
centerCirclePaint.setAlphaf(CENTER_CIRCLE_BACKGROUND_ALPHA);
std::vector<int32_t> centerCircleColor = ParseColorString(PROGRESS_COLOR_TYPE);
centerCirclePaint.setARGB(CENTER_CIRCLE_BACKGROUND_ALPHA, centerCircleColor[NUMBER_0],
centerCircleColor[NUMBER_1], centerCircleColor[NUMBER_2]);
centerCirclePaint.setStyle(SkPaint::kFill_Style);
canvas->drawCircle(half_, half_, dispalyDensity_ * CENTER_CIRCLE_RADIUS, centerCirclePaint);
SkPaint progressCirclePaint;
progressCirclePaint.setAntiAlias(true);
progressCirclePaint.setAlphaf(PROGRESS_BACKGROUND_ALPHA);
std::vector<int32_t> progressCircleColor = ParseColorString(PROGRESS_BACKGROUND_COLOR_TYPE);
progressCirclePaint.setARGB(PROGRESS_BACKGROUND_ALPHA, progressCircleColor[NUMBER_0],
progressCircleColor[NUMBER_1], progressCircleColor[NUMBER_2]);
progressCirclePaint.setStrokeWidth(PROGRESS_STROKE_WIDTH * dispalyDensity_);
progressCirclePaint.setStyle(SkPaint::kStroke_Style);
canvas->drawCircle(half_, half_, dispalyDensity_ * PROGRESS_RADIUS, progressCirclePaint);
SkPaint progressArcPaint;
progressArcPaint.setAntiAlias(true);
progressArcPaint.setAlphaf(PROGRESS_BAR_BACKGROUND_ALPHA);
std::vector<int32_t> progressArcColor = ParseColorString(PROGRESS_COLOR_TYPE);
progressArcPaint.setARGB(PROGRESS_BAR_BACKGROUND_ALPHA, progressArcColor[NUMBER_0],
progressArcColor[NUMBER_1], progressArcColor[NUMBER_2]);
progressArcPaint.setStrokeWidth(PROGRESS_STROKE_WIDTH * dispalyDensity_);
progressArcPaint.setStyle(SkPaint::kStroke_Style);
SkRect arcRect = SkRect::MakeLTRB(half_ - dispalyDensity_ * PROGRESS_RADIUS,
half_ - dispalyDensity_ * PROGRESS_RADIUS,
half_ + dispalyDensity_ * PROGRESS_RADIUS,
half_ + dispalyDensity_ * PROGRESS_RADIUS);
canvas->drawArc(arcRect, startAngle_, angle, false, progressArcPaint);
canvasNode_->FinishRecording();
FlushImplicitTransaction();
}
#else
void AccessibilityCircleDrawingManager::DrawingProgressByRosenDrawing(int32_t physicalX, int32_t physicalY,
int32_t angle)
{
HILOG_DEBUG();
auto canvas = canvasNode_->BeginRecording(imageWidth_, imageHeight_);
Rosen::Drawing::Brush outCircleBrush;
outCircleBrush.SetAntiAlias(true);
outCircleBrush.SetAlphaF(OUT_CIRCLE_BACKGROUND_ALPHA);
std::vector<int32_t> outCircleColor = ParseColorString(OUT_CIRCLE_BACKGROUND_COLOR_TYPE);
outCircleBrush.SetARGB(OUT_CIRCLE_BACKGROUND_ALPHA, outCircleColor[NUMBER_0], outCircleColor[NUMBER_1],
outCircleColor[NUMBER_2]);
canvas->AttachBrush(outCircleBrush);
canvas->DrawCircle(Rosen::Drawing::Point(half_, half_), dispalyDensity_ * OUT_CIRCLE_RADIUS);
canvas->DetachBrush();
Rosen::Drawing::Brush centerCircleBrush;
centerCircleBrush.SetAntiAlias(true);
centerCircleBrush.SetAlphaF(CENTER_CIRCLE_BACKGROUND_ALPHA);
std::vector<int32_t> centerCircleColor = ParseColorString(PROGRESS_COLOR_TYPE);
centerCircleBrush.SetARGB(CENTER_CIRCLE_BACKGROUND_ALPHA, centerCircleColor[NUMBER_0],
centerCircleColor[NUMBER_1], centerCircleColor[NUMBER_2]);
canvas->AttachBrush(centerCircleBrush);
canvas->DrawCircle(Rosen::Drawing::Point(half_, half_), dispalyDensity_ * CENTER_CIRCLE_RADIUS);
canvas->DetachBrush();
Rosen::Drawing::Pen progressPen;
progressPen.SetAntiAlias(true);
progressPen.SetAlphaF(PROGRESS_BACKGROUND_ALPHA);
std::vector<int32_t> progressCircleColor = ParseColorString(PROGRESS_BACKGROUND_COLOR_TYPE);
progressPen.SetARGB(PROGRESS_BACKGROUND_ALPHA, progressCircleColor[NUMBER_0],
progressCircleColor[NUMBER_1], progressCircleColor[NUMBER_2]);
progressPen.SetWidth(PROGRESS_STROKE_WIDTH * dispalyDensity_);
canvas->AttachPen(progressPen);
canvas->DrawCircle(Rosen::Drawing::Point(half_, half_), dispalyDensity_ * PROGRESS_RADIUS);
canvas->DetachPen();
Rosen::Drawing::Pen progressArcPen;
progressArcPen.SetAntiAlias(true);
progressArcPen.SetAlphaF(PROGRESS_BAR_BACKGROUND_ALPHA);
std::vector<int32_t> progressArcColor = ParseColorString(PROGRESS_COLOR_TYPE);
progressArcPen.SetARGB(PROGRESS_BAR_BACKGROUND_ALPHA, progressArcColor[NUMBER_0],
progressArcColor[NUMBER_1], progressArcColor[NUMBER_2]);
progressArcPen.SetWidth(PROGRESS_STROKE_WIDTH * dispalyDensity_);
Rosen::Drawing::Rect rect(half_ - dispalyDensity_ * PROGRESS_RADIUS,
half_ - dispalyDensity_ * PROGRESS_RADIUS,
half_ + dispalyDensity_ * PROGRESS_RADIUS,
half_ + dispalyDensity_ * PROGRESS_RADIUS);
canvas->AttachPen(progressArcPen);
canvas->DrawArc(rect, startAngle_, angle);
canvas->DetachPen();
canvasNode_->FinishRecording();
FlushImplicitTransaction();
}
#endif
void AccessibilityCircleDrawingManager::DrawingProgress(int32_t physicalX, int32_t physicalY, int32_t angle)
{
#ifndef USE_ROSEN_DRAWING
DrawingProgressByOpenSource(physicalX, physicalY, angle);
#else
DrawingProgressByRosenDrawing(physicalX, physicalY, angle);
#endif
}
void AccessibilityCircleDrawingManager::SetPointerLocation(int32_t physicalX, int32_t physicalY, uint64_t screenId)
{
HILOG_DEBUG("Pointer window move, x:%{public}d, y:%{public}d", physicalX, physicalY);
if (surfaceNode_ != nullptr) {
surfaceNode_->SetBounds(physicalX - half_,
physicalY - half_,
surfaceNode_->GetStagingProperties().GetBounds().z_,
surfaceNode_->GetStagingProperties().GetBounds().w_);
screenId_ = screenId;
surfaceNode_->AttachToDisplay(screenId);
FlushImplicitTransaction();
}
if (canvasNode_ != nullptr) {
canvasNode_->SetBounds(0,
0,
canvasNode_->GetStagingProperties().GetBounds().z_,
canvasNode_->GetStagingProperties().GetBounds().w_);
canvasNode_->SetFrame(0,
0,
canvasNode_->GetStagingProperties().GetBounds().z_,
canvasNode_->GetStagingProperties().GetBounds().w_);
FlushImplicitTransaction();
}
}
void AccessibilityCircleDrawingManager::DrawPointer(int32_t physicalX, int32_t physicalY, int32_t angle,
uint64_t screenId, int32_t startAngle)
{
HILOG_DEBUG();
startAngle_ = startAngle;
if (surfaceNode_ != nullptr) {
SetPointerLocation(physicalX, physicalY, screenId);
DrawingProgress(physicalX, physicalY, angle);
UpdatePointerVisible(true);
HILOG_DEBUG("surfaceNode_ is existed");
return;
}
CreatePointerWindow(physicalX, physicalY, screenId);
if (surfaceNode_ == nullptr) {
HILOG_ERROR("surfaceNode_ is nullptr");
return;
}
DrawingProgress(physicalX, physicalY, angle);
UpdatePointerVisible(true);
}
int32_t AccessibilityCircleDrawingManager::ParseStringToInteger(const std::string& color)
{
int32_t val = 0;
int32_t base = 1;
if (color.size() < 1) {
return val;
}
for (int32_t index = static_cast<int32_t>(color.size() - 1); index >= 0; index--) {
if (color[index] >= CHAR_0 && color[index] <= CHAR_9) {
val += base * static_cast<int32_t>(color[index] - CHAR_0);
}
if (color[index] == CHAR_A) {
val += base * static_cast<int32_t>(color[index] - CHAR_A + DECIMAL);
}
if (color[index] == CHAR_B) {
val += base * static_cast<int32_t>(color[index] - CHAR_A + DECIMAL);
}
if (color[index] == CHAR_C) {
val += base * static_cast<int32_t>(color[index] - CHAR_A + DECIMAL);
}
if (color[index] == CHAR_D) {
val += base * static_cast<int32_t>(color[index] - CHAR_A + DECIMAL);
}
if (color[index] == CHAR_E) {
val += base * static_cast<int32_t>(color[index] - CHAR_A + DECIMAL);
}
if (color[index] == CHAR_F) {
val += base * static_cast<int32_t>(color[index] - CHAR_A + DECIMAL);
}
base = base * HEXADECIMAL;
}
return val;
}
std::vector<int32_t> AccessibilityCircleDrawingManager::ParseColorString(const std::string& color)
{
std::string r = color.substr(RED_START_INDEX, COLOR_STRING_LENGTH);
std::string g = color.substr(GREEN_START_INDEX, COLOR_STRING_LENGTH);
std::string b = color.substr(BLUE_START_INDEX, COLOR_STRING_LENGTH);
int32_t rValue = ParseStringToInteger(r);
int32_t gValue = ParseStringToInteger(g);
int32_t bValue = ParseStringToInteger(b);
std::vector<int32_t> rgbValue = {rValue, gValue, bValue};
return rgbValue;
}
void AccessibilityCircleDrawingManager::FlushImplicitTransaction()
{
if (rsUiDirector_ && rsUiDirector_->GetRSUIContext()) {
auto rsUIContext = rsUiDirector_->GetRSUIContext();
if (rsUIContext && rsUIContext->GetRSTransaction()) {
rsUIContext->GetRSTransaction()->FlushImplicitTransaction();
return;
}
}
HILOG_ERROR("FlushImplicitTransaction failed");
}
}
}