diff --git a/shell/platform/ohos/BUILD.gn b/shell/platform/ohos/BUILD.gn index e9f11044a738b427b881a87b3fa7562d1c6bcf8c..9dda39bf4609d039466bc4b852347a6a2bae4dd8 100644 --- a/shell/platform/ohos/BUILD.gn +++ b/shell/platform/ohos/BUILD.gn @@ -78,7 +78,6 @@ source_set("flutter_ohos_sources") { "platform_view_ohos_delegate.h", "./accessibility/ohos_accessibility_bridge.h", "./accessibility/ohos_accessibility_features.h", - "./accessibility/ohos_accessibility_manager.h", "./accessibility/native_accessibility_channel.h", "./accessibility/ohos_accessibility_ddl.h", "./utils/ddl_utils.h", @@ -117,7 +116,6 @@ source_set("flutter_ohos_sources") { "platform_view_ohos_delegate.cpp", "./accessibility/ohos_accessibility_bridge.cpp", "./accessibility/ohos_accessibility_features.cpp", - "./accessibility/ohos_accessibility_manager.cpp", "./accessibility/native_accessibility_channel.cpp", "./accessibility/ohos_accessibility_ddl.cpp", "./utils/ohos_utils.cpp" diff --git a/shell/platform/ohos/accessibility/native_accessibility_channel.cpp b/shell/platform/ohos/accessibility/native_accessibility_channel.cpp index 68f52cf1a3144e0fffcf88db85152a58eb5ca0e7..a391b093599f2742ffdb865c973c34cb235365f5 100644 --- a/shell/platform/ohos/accessibility/native_accessibility_channel.cpp +++ b/shell/platform/ohos/accessibility/native_accessibility_channel.cpp @@ -74,7 +74,7 @@ namespace flutter { flutter::SemanticsNodeUpdates update, flutter::CustomAccessibilityActionUpdates actions) { - OhosAccessibilityBridge::GetInstance()->UpdateSemantics(update, actions); + OhosAccessibilityBridge::GetInstance()->UpdateSemantics(std::move(update), std::move(actions)); } /** diff --git a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp index 97aa8119b79c487fd9e3423ff28d0beae9e29c59..d564367082beb80c4077e9d2ef825a38fac831ad 100644 --- a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp +++ b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include "flutter/fml/logging.h" #include "flutter/shell/platform/ohos/ohos_logging.h" #include "flutter/shell/common/platform_view.h" @@ -20,6 +21,25 @@ const int32_t OhosAccessibilityBridge::OHOS_API_VERSION = OH_GetSdkApiVersion(); std::unique_ptr OhosAccessibilityBridge::bridgeInstance_ = nullptr; +/** + * 采用局部静态变量配合call-once特性,实现线程安全的单例模式 + */ +OhosAccessibilityBridge* OhosAccessibilityBridge::GetInstance() +{ + static std::once_flag onceFlag; + std::call_once(onceFlag, []() { + bridgeInstance_.reset(new OhosAccessibilityBridge()); + }); + return bridgeInstance_.get(); +} + +OhosAccessibilityBridge::OhosAccessibilityBridge() +: xcomponentId_("oh_flutter_1"), + native_shell_holder_id_(0), + isFlutterNavigated_(false), + isTouchGuideOn_(false), + isAccessibilityEnabled_(false) {} + /** * flutter无障碍相关语义树、句柄指针provider等参数 * 跟随xcomponentid显示切换,而加载对应xcomponent的语义树和provider指针 @@ -30,7 +50,10 @@ void OhosAccessibilityBridge::AccessibiltiyChangesWithXComponentId() auto xcompMap = XComponentAdapter::GetInstance()->xcomponetMap_; // 获取当前显示的xcomponetid std::string currXcompId = XComponentAdapter::GetInstance()->currentXComponentId_; - if (xcomponentId_ == currXcompId) { return; } + if (xcomponentId_ == currXcompId) { + xcomponentId_ = currXcompId; + return; + } auto it = xcompMap.find(currXcompId); if (!xcompMap.empty() && it != xcompMap.end()) { @@ -38,32 +61,14 @@ void OhosAccessibilityBridge::AccessibiltiyChangesWithXComponentId() xcomponentId_ = currXcompId; native_shell_holder_id_ = std::stoll(it->second->shellholderId_); g_flutterSemanticsTree = g_flutterSemanticsTreeXComponents[xcomponentId_]; - g_parentChildIdVec = g_parentChildIdVecXComponents[xcomponentId_]; FML_DLOG(INFO) << "AccessibiltiyChangesWithXComponentId -> xcomponentid:" << xcomponentId_; } else { xcomponentId_ = "oh_flutter_1"; g_flutterSemanticsTree = g_flutterSemanticsTreeXComponents[xcomponentId_]; - g_parentChildIdVec = g_parentChildIdVecXComponents[xcomponentId_]; FML_DLOG(INFO) << "AccessibiltiyChangesWithXComponentId -> xcomponentid:" << xcomponentId_; } } -/** - * 采用局部静态变量配合call-once特性,实现线程安全的单例模式 - */ -OhosAccessibilityBridge* OhosAccessibilityBridge::GetInstance() -{ - static std::once_flag onceFlag; - std::call_once(onceFlag, []() { - bridgeInstance_.reset(new OhosAccessibilityBridge()); - }); - return bridgeInstance_.get(); -} - -OhosAccessibilityBridge::OhosAccessibilityBridge() - : isFlutterNavigated_(false), - isAccessibilityEnabled_(false) {} - /** * 监听当前ohos平台是否开启无障碍屏幕朗读服务 */ @@ -84,20 +89,6 @@ void OhosAccessibilityBridge::OnOhosAccessibilityStateChange( } } -/** - * build the id mapping betwween parent node and its children nodes - */ -void OhosAccessibilityBridge::BuildParentChildNodeIdRelation( - const SemanticsNodeExtent& node) -{ - if (!IsNodeVisible(node)) { return; } - for (const auto& childId : node.childrenInTraversalOrder) { - auto childNode = GetFlutterSemanticsNode(childId); - if (!IsNodeVisible(childNode)) { continue; } - g_parentChildIdVec.emplace_back(std::make_pair(node.id, childId)); - } -} - /** * 从dart侧传递到c++侧的flutter无障碍语义树节点更新过程, * 路由新页面、滑动页面等操作会自动触发该语义树的更新 @@ -107,9 +98,11 @@ void OhosAccessibilityBridge::UpdateSemantics( flutter::CustomAccessibilityActionUpdates actions) { FML_DLOG(INFO) << "OhosAccessibilityBridge::UpdateSemantics()"; - std::vector updatedFlutterNodes; + std::unordered_set updatedFlutterNodes; + AccessibiltiyChangesWithXComponentId(); - // 当flutter页面状态更新(路由新页面)时,自动请求root节点组件获焦(规避滑动组件更新干扰) + // request rootNode when routes a new flutter page + // on touch guide mode (screen reader is on) if (isFlutterNavigated_) { RequestFocusWhenPageUpdate(0); isFlutterNavigated_ = false; @@ -119,41 +112,30 @@ void OhosAccessibilityBridge::UpdateSemantics( for (const auto& item : update) { // 获取当前更新的节点node const auto& node = item.second; - FML_DLOG(INFO) << "*#*#* node.id=" << node.id; // 更新扩展的SemanticsNode信息 - auto nodeEx = UpdatetSemanticsNodeExtent(node); + auto nodeEx = UpdatetSemanticsNodeExtent(std::move(node)); - // 构建flutter无障碍语义节点树 g_flutterSemanticsTree[nodeEx.id] = nodeEx; - // 构建flutter节点的父子id映射关系 - BuildParentChildNodeIdRelation(nodeEx); - - //print semantics node and flags info for debugging - GetSemanticsNodeDebugInfo(nodeEx); - GetSemanticsFlagsDebugInfo(nodeEx); if (!IsNodeVisible(nodeEx)) { continue; } - // 若当前节点为获焦 - if (IsNodeFocused(nodeEx)) { - inputFocusedNode = nodeEx; - } // 若当前节点和更新前节点信息不同,则加入更新节点数组 if (nodeEx.hadPreviousConfig) { - updatedFlutterNodes.emplace_back(nodeEx); + updatedFlutterNodes.emplace(nodeEx); FML_DLOG(INFO) << "updatedFlutterNodes -> node.id=" << nodeEx.id; } } + // calculate the global tranfom matrix and parent id for each node + ComputeGlobalTransformAndParentId(); // 将更新后的flutter语义树和父子节点id映射缓存,保存到相应的xcomponent里面 g_flutterSemanticsTreeXComponents[xcomponentId_] = g_flutterSemanticsTree; - g_parentChildIdVecXComponents[xcomponentId_] = g_parentChildIdVec; - - // 页面内容更新事件 - Flutter_SendAccessibilityAsyncEvent(0, - ArkUI_AccessibilityEventType:: - ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_PAGE_CONTENT_UPDATE); - LOGD("Flutter_SendAccessibilityAsyncEvent -> PAGE_CONTENT_UPDATE"); + + // if the screen reader starts (touch guide state is true), + // sending the a11y event and draw the green rect + Flutter_SendAccessibilityAsyncEvent( + 0, ArkUI_AccessibilityEventType::ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_PAGE_CONTENT_UPDATE); + /* 针对更新后的节点进行事件处理 */ for (auto& nodeEx: updatedFlutterNodes) { @@ -171,10 +153,12 @@ void OhosAccessibilityBridge::UpdateSemantics( // flutter滑动组件滑动处理逻辑 FlutterScrollExecution(nodeEx, _elementInfo); - // 屏幕朗读状态下双指滑动,获焦节点绿框实时跟随节点滑动 - Flutter_SendAccessibilityAsyncEvent( - static_cast(accessibilityFocusedNode.id), - ArkUI_AccessibilityEventType::ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_FOCUS_NODE_UPDATE); + // when screen reader is on and the touch guide is active + if (isTouchGuideOn_) { + Flutter_SendAccessibilityAsyncEvent( + static_cast(accessibilityFocusedNode.id), + ArkUI_AccessibilityEventType::ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_FOCUS_NODE_UPDATE); + } auto OH_ArkUI_DestoryAccessibilityElementInfo = OhosAccessibilityDDL::DLLoadDestroyElemFunc(ArkUIAccessibilityConstant::ARKUI_DESTORY_NODE); @@ -191,10 +175,6 @@ void OhosAccessibilityBridge::UpdateSemantics( ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_PAGE_CONTENT_UPDATE); } } - // calculate the global tranfomr matrix for each node - ComputeGlobalTransform(); - // 输出flutter语义树相关重要语义信息debug日志 - GetSemanticsDebugInfo(); FML_DLOG(INFO) << "=== UpdateSemantics() is finished ==="; } @@ -229,13 +209,6 @@ void OhosAccessibilityBridge::FlutterScrollExecution( nodePosition -= node.scrollExtentMin; } - if (node.HasAction(ACTIONS_::kScrollUp) || - node.HasAction(ACTIONS_::kScrollDown)) { - } else if (node.HasAction(ACTIONS_::kScrollLeft) || - node.HasAction(ACTIONS_::kScrollRight)) { - LOGD("current flutterNode has scroll up/down/left/right"); - } - // 当可滑动组件存在滑动子节点 if (node.scrollChildren > 0) { // 配置当前滑动组件的子节点总数 @@ -406,15 +379,7 @@ void OhosAccessibilityBridge::OnTooltip(std::unique_ptr& message) //获取根节点 SemanticsNodeExtent OhosAccessibilityBridge::GetFlutterRootSemanticsNode() { - if (!g_flutterSemanticsTree.size()) { - LOGE("GetFlutterRootSemanticsNode: g_flutterSemanticsTree.size()=0"); - return {}; - } - if (g_flutterSemanticsTree.find(0) == g_flutterSemanticsTree.end()) { - LOGE("GetFlutterRootSemanticsNod: g_flutterSemanticsTree has no root id"); - return {}; - } - return g_flutterSemanticsTree.at(0); + return GetFlutterSemanticsNode(0); } /** @@ -423,12 +388,11 @@ SemanticsNodeExtent OhosAccessibilityBridge::GetFlutterRootSemanticsNode() SemanticsNodeExtent OhosAccessibilityBridge::GetFlutterSemanticsNode( int32_t id) { - if (g_flutterSemanticsTree.count(id) > 0) { - return g_flutterSemanticsTree.at(id); - } else { - LOGE("GetFlutterSemanticsNode g_flutterSemanticsTree = null"); - return {}; + auto it = g_flutterSemanticsTree.find(id); + if (it != g_flutterSemanticsTree.end()) { + return it->second; } + return {}; } /** @@ -436,20 +400,16 @@ SemanticsNodeExtent OhosAccessibilityBridge::GetFlutterSemanticsNode( */ int32_t OhosAccessibilityBridge::GetParentId(int64_t elementId) { - if (!g_parentChildIdVec.size()) { - FML_DLOG(WARNING) << "OhosAccessibilityBridge::GetParentId parentChildIdMap.size()=0"; - return ARKUI_ACCESSIBILITY_ROOT_PARENT_ID; - } if (elementId == -1 || elementId == 0) { return ARKUI_ACCESSIBILITY_ROOT_PARENT_ID; } - int32_t childElementId = static_cast(elementId); - for (const auto& item : g_parentChildIdVec) { - if (item.second == childElementId) { - return item.first; - } + int32_t id = static_cast(elementId); + auto node = GetFlutterSemanticsNode(id); + if (g_flutterSemanticsTree.find(id) == g_flutterSemanticsTree.end()) { + LOGE("GetParentId: %{public}d is null", id); + return -1; } - return RET_ERROR_STATE_CODE; + return node.parentId; } /** @@ -461,57 +421,41 @@ void OhosAccessibilityBridge::SetAbsoluteScreenRect(SemanticsNodeExtent& flutter float right, float bottom) { - g_screenRectMap[flutterNode.id] = AbsoluteRect{left, top, right, bottom}; + flutterNode.absoluteRect = {left, top, right, bottom}; FML_DLOG(INFO) << "SetAbsoluteScreenRect -> id=" << flutterNode.id << ", {" << left << ", " << top << ", " << right << ", "<< bottom << "> }"; } -AbsoluteRect OhosAccessibilityBridge::GetAbsoluteScreenRect(SemanticsNodeExtent& flutterNode) -{ - if (!g_screenRectMap.empty() && g_screenRectMap.count(flutterNode.id) > 0) { - return g_screenRectMap.at(flutterNode.id); - } else { - FML_DLOG(ERROR) << "GetAbsoluteScreenRect -> flutterNodeId=" - << flutterNode.id << " is not found !"; - return {}; - } -} - -/** - * 获取flutter相对-绝对坐标映射的真实缩放系数 - */ -std::pair OhosAccessibilityBridge::GetRealScaleFactor() +const AbsoluteRect& OhosAccessibilityBridge::GetAbsoluteScreenRect( + const SemanticsNodeExtent& flutterNode) { - auto secondNode = GetFlutterSemanticsNode(1); - SkMatrix transform = secondNode.transform.asM33(); - auto scaleX = transform.get(SkMatrix::kMScaleX); - auto scaleY = transform.get(SkMatrix::kMScaleY); - return std::make_pair(scaleX, scaleY); + return flutterNode.absoluteRect; } /** * calculate the global transform matrix for each node */ -void OhosAccessibilityBridge::ComputeGlobalTransform() +void OhosAccessibilityBridge::ComputeGlobalTransformAndParentId() { std::queue semanticsQue; - auto root = GetFlutterSemanticsNode(0); - semanticsQue.push(root); - g_globalTransformMap[root.id] = root.transform; + auto rootNode = GetFlutterSemanticsNode(0); + rootNode.globalTransform = rootNode.transform; + rootNode.parentId = ARKUI_ACCESSIBILITY_ROOT_PARENT_ID; + g_flutterSemanticsTree[rootNode.id] = rootNode; + semanticsQue.push(rootNode); while (!semanticsQue.empty()) { - uint32_t queSize = semanticsQue.size(); - for (uint32_t i=0; i 0) { auto childrenIdsVec = flutterNode.childrenInTraversalOrder; - std::sort(childrenIdsVec.begin(), childrenIdsVec.end()); int64_t childNodeIds[childCount]; for (int32_t i = 0; i < childCount; i++) { childNodeIds[i] = static_cast(childrenIdsVec[i]); @@ -941,21 +864,16 @@ std::vector OhosAccessibilityBridge::GetLevelOrderTraversalTree(int32_t semanticsQue.push(root); while (!semanticsQue.empty()) { - uint32_t queSize = semanticsQue.size(); - for (uint32_t i=0; i(currNode.id)); - - std::sort(currNode.childrenInTraversalOrder.begin(), - currNode.childrenInTraversalOrder.end()); + for (const auto& childId: currNode.childrenInTraversalOrder) { auto childNode = GetFlutterSemanticsNode(childId); semanticsQue.push(childNode); } - } } return levelOrderTraversalTree; } @@ -1076,23 +994,13 @@ void OhosAccessibilityBridge::DispatchSemanticsAction( std::move(args)); } -/** - * flutter按钮节点双击跳转新页面时,发送页面更新事件 - */ -void OhosAccessibilityBridge::DoubleClickRouteToNewPage(SemanticsNodeExtent node) -{ - if (node.HasFlag(FLAGS_::kIsButton)) { - RequestFocusWhenPageUpdate(0); - } -} - /** * perform click action in accessibility status */ void OhosAccessibilityBridge::PerformClickAction( int64_t elementId, ArkUI_Accessibility_ActionType action, - SemanticsNodeExtent flutterNode) + const SemanticsNodeExtent& flutterNode) { /** Click event, sent after the UI component responds. 1 */ auto clickEventType = ArkUI_AccessibilityEventType::ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_CLICKED; @@ -1101,8 +1009,6 @@ void OhosAccessibilityBridge::PerformClickAction( << ")" << " event: click(" << clickEventType << ")"; auto flutterTapAction = ArkuiActionsToFlutterActions(action); DispatchSemanticsAction(static_cast(elementId), flutterTapAction, {}); - // double click at button-like node for pushing page update - DoubleClickRouteToNewPage(flutterNode); } /** @@ -1111,7 +1017,7 @@ void OhosAccessibilityBridge::PerformClickAction( void OhosAccessibilityBridge::PerformLongClickAction( int64_t elementId, ArkUI_Accessibility_ActionType action, - SemanticsNodeExtent flutterNode) + const SemanticsNodeExtent& flutterNode) { /** Long click event, sent after the UI component responds. 2 */ auto longClickEventType = ArkUI_AccessibilityEventType::ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_LONG_CLICKED; @@ -1129,7 +1035,7 @@ void OhosAccessibilityBridge::PerformLongClickAction( void OhosAccessibilityBridge::PerformGainFocusnAction( int64_t elementId, ArkUI_Accessibility_ActionType action, - SemanticsNodeExtent flutterNode) + const SemanticsNodeExtent& flutterNode) { // 感知获焦flutter节点 accessibilityFocusedNode = flutterNode; @@ -1158,7 +1064,7 @@ void OhosAccessibilityBridge::PerformGainFocusnAction( void OhosAccessibilityBridge::PerformClearFocusAction( int64_t elementId, ArkUI_Accessibility_ActionType action, - SemanticsNodeExtent flutterNode) + const SemanticsNodeExtent& flutterNode) { // 解析arkui的失焦 -> flutter对应节点的失焦 auto flutterLoseFocusAction = ArkuiActionsToFlutterActions(action); @@ -1179,7 +1085,7 @@ void OhosAccessibilityBridge::PerformClearFocusAction( void OhosAccessibilityBridge::PerformScrollUpAction( int64_t elementId, ArkUI_Accessibility_ActionType action, - SemanticsNodeExtent flutterNode) + SemanticsNodeExtent& flutterNode) { // flutter scroll forward with different situations if (flutterNode.HasAction(ACTIONS_::kScrollUp)) { @@ -1195,16 +1101,6 @@ void OhosAccessibilityBridge::PerformScrollUpAction( elementId, ArkUI_AccessibilityEventType::ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_SELECTED); DispatchSemanticsAction(static_cast(elementId), ACTIONS_::kIncrease, {}); } - std::string currComponetType = GetNodeComponentType(flutterNode); - if (OHOSUtils::Contains(currComponetType, SCROLL_WIDGET_NAME)) { - /** Scrolled event, sent when a scrollable component experiences a scroll event. 4096 */ - ArkUI_AccessibilityEventType scrollEventType1 = - ArkUI_AccessibilityEventType::ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_SCROLLED; - Flutter_SendAccessibilityAsyncEvent(elementId, scrollEventType1); - FML_DLOG(INFO) - << "ExecuteAccessibilityAction -> action: scroll forward(" << action - << ")" << " event: scroll forward(" << scrollEventType1 << ")"; - } } /** @@ -1213,7 +1109,7 @@ void OhosAccessibilityBridge::PerformScrollUpAction( void OhosAccessibilityBridge::PerformScrollDownAction( int64_t elementId, ArkUI_Accessibility_ActionType action, - SemanticsNodeExtent flutterNode) + SemanticsNodeExtent& flutterNode) { // flutter scroll down with different situations if (flutterNode.HasAction(ACTIONS_::kScrollDown)) { @@ -1229,24 +1125,13 @@ void OhosAccessibilityBridge::PerformScrollDownAction( elementId, ArkUI_AccessibilityEventType::ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_SELECTED); DispatchSemanticsAction(static_cast(elementId), ACTIONS_::kDecrease, {}); } - std::string currComponetType = GetNodeComponentType(flutterNode); - if (OHOSUtils::Contains(currComponetType, SCROLL_WIDGET_NAME)) { - /** Scrolled event, sent when a scrollable component experiences a - * scroll event. 4096 */ - ArkUI_AccessibilityEventType scrollEventType1 = - ArkUI_AccessibilityEventType::ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_SCROLLED; - Flutter_SendAccessibilityAsyncEvent(elementId, scrollEventType1); - FML_DLOG(INFO) - << "ExecuteAccessibilityAction -> action: scroll forward(" << action - << ")" << " event: scroll forward(" << scrollEventType1 << ")"; - } } /** * perform invalid action in accessibility status */ void OhosAccessibilityBridge::PerformClipboardAction( int64_t elementId, - ArkUI_Accessibility_ActionType action) + const ArkUI_Accessibility_ActionType& action) { if (action == ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_COPY) { FML_DLOG(INFO) << "ExecuteAccessibilityAction -> action: copy(" << action << ")"; @@ -1265,7 +1150,7 @@ void OhosAccessibilityBridge::PerformClipboardAction( void OhosAccessibilityBridge::PerformInvalidAction( int64_t elementId, ArkUI_Accessibility_ActionType action, - SemanticsNodeExtent flutterNode) + const SemanticsNodeExtent& flutterNode) { /** Invalid event. 0 */ ArkUI_AccessibilityEventType invalidEventType = @@ -1279,7 +1164,7 @@ void OhosAccessibilityBridge::PerformInvalidAction( * 设置输入框文本 */ void OhosAccessibilityBridge::PerformSetText( - SemanticsNodeExtent flutterNode, + SemanticsNodeExtent& flutterNode, ArkUI_Accessibility_ActionType action, ArkUI_AccessibilityActionArguments* actionArguments) { @@ -1306,7 +1191,7 @@ void OhosAccessibilityBridge::PerformSetText( * perform select text (from base to extent) in accessibility status */ void OhosAccessibilityBridge::PerformSelectText( - SemanticsNodeExtent flutterNode, + const SemanticsNodeExtent& flutterNode, ArkUI_Accessibility_ActionType action, ArkUI_AccessibilityActionArguments* actionArguments) { @@ -1369,7 +1254,7 @@ void OhosAccessibilityBridge::PerformSetCursorPosition( * perform custom action in accessibility status */ void OhosAccessibilityBridge::PerformCustomAction( - SemanticsNodeExtent flutterNode, + const SemanticsNodeExtent& flutterNode, ArkUI_Accessibility_ActionType action, ArkUI_AccessibilityActionArguments* actionArguments) { @@ -1381,7 +1266,8 @@ void OhosAccessibilityBridge::PerformCustomAction( /** * perform show on screen action in accessibility status */ -void OhosAccessibilityBridge::PerformShowOnScreenAction(SemanticsNodeExtent flutterNode) +void OhosAccessibilityBridge::PerformShowOnScreenAction( + const SemanticsNodeExtent& flutterNode) { if (!IsNodeShowOnScreen(flutterNode)) { DispatchSemanticsAction(flutterNode.id, ACTIONS_::kShowOnScreen, {}); @@ -1770,14 +1656,16 @@ std::string OhosAccessibilityBridge::GetNodeComponentType( /** * 判断当前节点是否为textfield文本框 */ -bool OhosAccessibilityBridge::IsTextField(SemanticsNodeExtent flutterNode) +bool OhosAccessibilityBridge::IsTextField( + const SemanticsNodeExtent& flutterNode) { return flutterNode.HasFlag(FLAGS_::kIsTextField); } /** * 判断当前节点是否为滑动条slider类型 */ -bool OhosAccessibilityBridge::IsSlider(SemanticsNodeExtent flutterNode) +bool OhosAccessibilityBridge::IsSlider( + const SemanticsNodeExtent& flutterNode) { return flutterNode.HasFlag(FLAGS_::kIsSlider); } @@ -1785,7 +1673,7 @@ bool OhosAccessibilityBridge::IsSlider(SemanticsNodeExtent flutterNode) * 判断当前flutter节点组件是否可点击 */ bool OhosAccessibilityBridge::IsNodeClickable( - SemanticsNodeExtent flutterNode) + const SemanticsNodeExtent& flutterNode) { return flutterNode.HasAction(ACTIONS_::kTap); } @@ -1793,7 +1681,7 @@ bool OhosAccessibilityBridge::IsNodeClickable( * 判断当前flutter节点组件是否可显示 */ bool OhosAccessibilityBridge::IsNodeVisible( - SemanticsNodeExtent flutterNode) + const SemanticsNodeExtent& flutterNode) { return !flutterNode.HasFlag(FLAGS_::kIsHidden); } @@ -1801,7 +1689,7 @@ bool OhosAccessibilityBridge::IsNodeVisible( * 判断当前flutter节点组件是否具备checkable属性 */ bool OhosAccessibilityBridge::IsNodeCheckable( - SemanticsNodeExtent flutterNode) + const SemanticsNodeExtent& flutterNode) { return flutterNode.HasFlag(FLAGS_::kHasCheckedState) || flutterNode.HasFlag(FLAGS_::kHasToggledState); @@ -1810,7 +1698,7 @@ bool OhosAccessibilityBridge::IsNodeCheckable( * 判断当前flutter节点组件是否checked/unchecked(checkbox、radio button) */ bool OhosAccessibilityBridge::IsNodeChecked( - SemanticsNodeExtent flutterNode) + const SemanticsNodeExtent& flutterNode) { return flutterNode.HasFlag(FLAGS_::kIsChecked) || flutterNode.HasFlag(FLAGS_::kIsToggled); @@ -1819,7 +1707,7 @@ bool OhosAccessibilityBridge::IsNodeChecked( * 判断当前flutter节点组件是否选中 */ bool OhosAccessibilityBridge::IsNodeSelected( - SemanticsNodeExtent flutterNode) + const SemanticsNodeExtent& flutterNode) { return flutterNode.HasFlag(FLAGS_::kIsSelected); } @@ -1827,7 +1715,7 @@ bool OhosAccessibilityBridge::IsNodeSelected( * 判断当前flutter节点组件是否为密码输入框 */ bool OhosAccessibilityBridge::IsNodePassword( - SemanticsNodeExtent flutterNode) + const SemanticsNodeExtent& flutterNode) { return flutterNode.HasFlag(FLAGS_::kIsTextField) && flutterNode.HasFlag(FLAGS_::kIsObscured); @@ -1836,7 +1724,7 @@ bool OhosAccessibilityBridge::IsNodePassword( * 判断当前flutter节点组件是否支持长按功能 */ bool OhosAccessibilityBridge::IsNodeHasLongPress( - SemanticsNodeExtent flutterNode) + const SemanticsNodeExtent& flutterNode) { return flutterNode.HasAction(ACTIONS_::kLongPress); } @@ -1844,7 +1732,7 @@ bool OhosAccessibilityBridge::IsNodeHasLongPress( * 判断当前flutter节点是否enabled */ bool OhosAccessibilityBridge::IsNodeEnabled( - SemanticsNodeExtent flutterNode) + const SemanticsNodeExtent& flutterNode) { return !flutterNode.HasFlag(FLAGS_::kHasEnabledState) || flutterNode.HasFlag(FLAGS_::kIsEnabled); @@ -1852,7 +1740,8 @@ bool OhosAccessibilityBridge::IsNodeEnabled( /** * 判断当前flutter节点是否在当前屏幕上显示 */ -bool OhosAccessibilityBridge::IsNodeShowOnScreen(SemanticsNodeExtent flutterNode) +bool OhosAccessibilityBridge::IsNodeShowOnScreen( + const SemanticsNodeExtent& flutterNode) { return flutterNode.HasAction(ACTIONS_::kShowOnScreen); } @@ -1894,10 +1783,6 @@ bool OhosAccessibilityBridge::IsNodeFocusable( if (node.IsPlatformViewNode()) { return true; } - // Always consider actionable nodes focusable. - if (node.actions != 0) { - return true; - } if ((node.flags & FOCUSABLE_FLAGS) != 0) { return true; } @@ -1918,7 +1803,7 @@ bool OhosAccessibilityBridge::IsNodeFocused(const SemanticsNodeExtent& flutterNo * 判断是否可滑动 */ bool OhosAccessibilityBridge::IsNodeScrollable( - SemanticsNodeExtent flutterNode) + const SemanticsNodeExtent& flutterNode) { return flutterNode.HasAction(ACTIONS_::kScrollLeft) || flutterNode.HasAction(ACTIONS_::kScrollRight) || @@ -1929,72 +1814,11 @@ bool OhosAccessibilityBridge::IsNodeScrollable( * 判断当前节点组件是否是滑动组件,如: listview, gridview等 */ bool OhosAccessibilityBridge::IsScrollableWidget( - SemanticsNodeExtent flutterNode) + const SemanticsNodeExtent& flutterNode) { return flutterNode.HasFlag(FLAGS_::kHasImplicitScrolling); } -void OhosAccessibilityBridge::AddRouteNodes( - std::vector edges, - SemanticsNodeExtent node) -{ - if (node.HasFlag(FLAGS_::kScopesRoute)) { - edges.emplace_back(node); - } - for (auto& childNodeId : node.childrenInTraversalOrder) { - auto childNode = GetFlutterSemanticsNode(childNodeId); - AddRouteNodes(edges, childNode); - } -} - -std::string OhosAccessibilityBridge::GetRouteName(SemanticsNodeExtent node) -{ - if (node.HasFlag(FLAGS_::kNamesRoute) && !node.label.empty()) { - return node.label; - } - for (auto& childNodeId : node.childrenInTraversalOrder) { - auto childNode = GetFlutterSemanticsNode(childNodeId); - std::string newName = GetRouteName(childNode); - if (!newName.empty()) { - return newName; - } - } - return ""; -} - -void OhosAccessibilityBridge::OnWindowNameChange(SemanticsNodeExtent route) -{ - std::string routeName = GetRouteName(route); - if (routeName.empty()) { - routeName = " "; - } - Flutter_SendAccessibilityAsyncEvent( - static_cast(route.id), - ArkUI_AccessibilityEventType:: - ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_PAGE_CONTENT_UPDATE); -} - -void OhosAccessibilityBridge::RemoveSemanticsNode( - SemanticsNodeExtent nodeToBeRemoved) -{ - if (!g_flutterSemanticsTree.size()) { - FML_DLOG(ERROR) << "OhosAccessibilityBridge::removeSemanticsNode -> " - "g_flutterSemanticsTree.szie()=0"; - return; - } - if (g_flutterSemanticsTree.find(nodeToBeRemoved.id) == - g_flutterSemanticsTree.end()) { - FML_DLOG(INFO) << "Attempted to remove a node that is not in the tree."; - } - int32_t nodeToBeRemovedParentId = GetParentId(nodeToBeRemoved.id); - for (auto it = g_parentChildIdVec.begin(); it != g_parentChildIdVec.end(); it++) { - if (it->first == nodeToBeRemovedParentId && - it->second == nodeToBeRemoved.id) { - g_parentChildIdVec.erase(it); - } - } -} - /** * when the system accessibility service is shut down, * clear all the flutter semantics-relevant caches like maps, vectors @@ -2002,8 +1826,6 @@ void OhosAccessibilityBridge::RemoveSemanticsNode( void OhosAccessibilityBridge::ClearFlutterSemanticsCaches() { g_flutterSemanticsTree.clear(); - g_parentChildIdVec.clear(); - g_screenRectMap.clear(); Flutter_SendAccessibilityAsyncEvent( accessibilityFocusedNode.id, ArkUI_AccessibilityEventType::ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_ACCESSIBILITY_FOCUS_CLEARED); @@ -2017,10 +1839,11 @@ SemanticsNodeExtent OhosAccessibilityBridge::UpdatetSemanticsNodeExtent( flutter::SemanticsNode node) { SemanticsNodeExtent nodeEx = SemanticsNodeExtent(); - // 获取更新前的flutter节点信息 - if (g_flutterSemanticsTree.size() > 0) { + // + if (!g_flutterSemanticsTree.empty()) { auto prevNode = GetFlutterSemanticsNode(node.id); nodeEx.hadPreviousConfig = true; + nodeEx.parentId = prevNode.parentId; nodeEx.previousFlags = prevNode.flags; nodeEx.previousActions = prevNode.actions; nodeEx.previousTextSelectionBase = prevNode.textSelectionBase; @@ -2028,26 +1851,26 @@ SemanticsNodeExtent OhosAccessibilityBridge::UpdatetSemanticsNodeExtent( nodeEx.previousScrollPosition = prevNode.scrollPosition; nodeEx.previousScrollExtentMax = prevNode.scrollExtentMax; nodeEx.previousScrollExtentMin = prevNode.scrollExtentMin; - nodeEx.previousValue = prevNode.value; - nodeEx.previousLabel = prevNode.label; + nodeEx.previousValue = std::move(prevNode.value); + nodeEx.previousLabel = std::move(prevNode.label); } + // 更新当前flutter节点信息 - nodeEx.isNull = false; - nodeEx.id = std::move(node.id); - nodeEx.flags = std::move(node.flags); - nodeEx.actions = std::move(node.actions); - nodeEx.maxValueLength = std::move(node.maxValueLength); - nodeEx.currentValueLength = std::move(node.currentValueLength); - nodeEx.textSelectionBase = std::move(node.textSelectionBase); - nodeEx.textSelectionExtent = std::move(node.textSelectionExtent); - nodeEx.platformViewId = std::move(node.platformViewId); - nodeEx.scrollChildren = std::move(node.scrollChildren); - nodeEx.scrollIndex = std::move(node.scrollIndex); - nodeEx.scrollPosition = std::move(node.scrollPosition); - nodeEx.scrollExtentMax = std::move(node.scrollExtentMax); - nodeEx.scrollExtentMin = std::move(node.scrollExtentMin); - nodeEx.elevation = std::move(node.elevation); - nodeEx.thickness = std::move(node.thickness); + nodeEx.id = node.id; + nodeEx.flags = node.flags; + nodeEx.actions = node.actions; + nodeEx.maxValueLength = node.maxValueLength; + nodeEx.currentValueLength = node.currentValueLength; + nodeEx.textSelectionBase = node.textSelectionBase; + nodeEx.textSelectionExtent = node.textSelectionExtent; + nodeEx.platformViewId = node.platformViewId; + nodeEx.scrollChildren = node.scrollChildren; + nodeEx.scrollIndex = node.scrollIndex; + nodeEx.scrollPosition = node.scrollPosition; + nodeEx.scrollExtentMax = node.scrollExtentMax; + nodeEx.scrollExtentMin = node.scrollExtentMin; + nodeEx.elevation = node.elevation; + nodeEx.thickness = node.thickness; nodeEx.label = std::move(node.label); nodeEx.labelAttributes = std::move(node.labelAttributes); nodeEx.hint = std::move(node.hint); @@ -2059,7 +1882,7 @@ SemanticsNodeExtent OhosAccessibilityBridge::UpdatetSemanticsNodeExtent( nodeEx.decreasedValue = std::move(node.decreasedValue); nodeEx.decreasedValueAttributes = std::move(node.decreasedValueAttributes); nodeEx.tooltip = std::move(node.tooltip); - nodeEx.textDirection = std::move(node.textDirection); + nodeEx.textDirection = node.textDirection; nodeEx.rect = std::move(node.rect); nodeEx.transform = std::move(node.transform); nodeEx.childrenInTraversalOrder = std::move(node.childrenInTraversalOrder); @@ -2069,11 +1892,12 @@ SemanticsNodeExtent OhosAccessibilityBridge::UpdatetSemanticsNodeExtent( } void OhosAccessibilityBridge::GetSemanticsNodeDebugInfo( - SemanticsNodeExtent node) + const SemanticsNodeExtent& node) { FML_DLOG(INFO) << "-------------------SemanticsNode------------------"; SkMatrix _transform = node.transform.asM33(); FML_DLOG(INFO) << "node.id=" << node.id; + FML_DLOG(INFO) << "node.parentId=" << node.parentId; FML_DLOG(INFO) << "node.label=" << node.label; FML_DLOG(INFO) << "node.previousLabel=" << node.previousLabel; FML_DLOG(INFO) << "node.tooltip=" << node.tooltip; @@ -2146,7 +1970,7 @@ void OhosAccessibilityBridge::GetSemanticsNodeDebugInfo( } void OhosAccessibilityBridge::GetSemanticsFlagsDebugInfo( - SemanticsNodeExtent node) + const SemanticsNodeExtent& node) { FML_DLOG(INFO) << "----------------SemanticsFlags-------------------------"; FML_DLOG(INFO) << "node.id=" << node.id; @@ -2187,7 +2011,7 @@ void OhosAccessibilityBridge::GetSemanticsFlagsDebugInfo( } void OhosAccessibilityBridge::GetCustomActionDebugInfo( - flutter::CustomAccessibilityAction customAccessibilityAction) + const flutter::CustomAccessibilityAction& customAccessibilityAction) { FML_DLOG(INFO) << "--------------CustomAccessibilityAction------------"; FML_DLOG(INFO) << "customAccessibilityAction.id=" @@ -2208,10 +2032,6 @@ void OhosAccessibilityBridge::GetSemanticsDebugInfo() FML_DLOG(INFO) << "g_flutterSemanticsTree -> {" << item.first << ", " << item.second.id << "}"; } - for (const auto& item : g_parentChildIdVec) { - FML_DLOG(INFO) << "g_parentChildIdVec -> (" << item.first << ", " - << item.second << ")"; - } //打印按层次遍历排序的flutter语义树节点id数组 std::vector levelOrderTraversalTree = GetLevelOrderTraversalTree(0); for (const auto& item: levelOrderTraversalTree) { diff --git a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h index d947b14f14b223ce5d16474c8372cf60ff4ee5bb..dd51c4553faaf0d0a74c5dd4cebbf69b7462b6ed 100644 --- a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h +++ b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h @@ -44,7 +44,6 @@ struct AbsoluteRect { }; struct SemanticsNodeExtent : flutter::SemanticsNode { - bool isNull = false; SkM44 globalTransform = SkM44{}; AbsoluteRect absoluteRect = AbsoluteRect::MakeEmpty(); int32_t parentId = -1; @@ -59,14 +58,20 @@ struct SemanticsNodeExtent : flutter::SemanticsNode { double previousScrollExtentMin = std::nan(""); std::string previousValue; std::string previousLabel; - bool HasPrevAction(SemanticsAction action) const - { + bool HasPrevAction(SemanticsAction action) const { return (previousActions & this->actions) != 0; } - bool HasPrevFlag(SemanticsFlags flag) const - { + bool HasPrevFlag(SemanticsFlags flag) const { return (previousFlags & this->flags) != 0; } + bool operator==(const SemanticsNodeExtent& other) const { + return id == other.id; + } + struct Hash { + std::size_t operator()(const SemanticsNodeExtent& obj) const { + return std::hash()(obj.id); + } + }; }; /** @@ -79,8 +84,12 @@ public: OhosAccessibilityBridge& operator=(const OhosAccessibilityBridge&) = delete; std::string xcomponentId_; - bool isFlutterNavigated_; int64_t native_shell_holder_id_; + bool isFlutterNavigated_; + bool isTouchGuideOn_; + + std::unordered_map g_flutterSemanticsTree; + std::unordered_map> g_flutterSemanticsTreeXComponents; void OnOhosAccessibilityStateChange(bool ohosAccessibilityEnabled, int64_t shellholderId); @@ -137,7 +146,7 @@ public: ArkUI_AccessibilityEventType eventType); void RelativeRectToScreenRect(SemanticsNodeExtent& node); - AbsoluteRect GetAbsoluteScreenRect(SemanticsNodeExtent& flutterNode); + const AbsoluteRect& GetAbsoluteScreenRect(const SemanticsNodeExtent& flutterNode); void SetAbsoluteScreenRect(SemanticsNodeExtent& flutterNode, float left, float top, @@ -159,15 +168,6 @@ private: std::shared_ptr nativeAccessibilityChannel_; std::shared_ptr accessibilityFeatures_; - std::unordered_map> g_flutterSemanticsTreeXComponents; - std::unordered_map>> g_parentChildIdVecXComponents; - std::unordered_map> g_screenRectMapXComponents; - - std::unordered_map g_flutterSemanticsTree; - std::vector> g_parentChildIdVec; - std::unordered_map g_screenRectMap; - std::unordered_map g_globalTransformMap; - SemanticsNodeExtent inputFocusedNode; SemanticsNodeExtent lastInputFocusedNode; SemanticsNodeExtent accessibilityFocusedNode; @@ -198,23 +198,6 @@ private: const std::string SWITCH_WIDGET_NAME = "Toggle"; const std::string SEEKBAR_WIDGET_NAME = "SeekBar"; - const std::map - ArkUI_ACTION_TYPE_MAP_ = { - {"invalid", ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_INVALID}, - {"click", ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_CLICK}, - {"long press", ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_LONG_CLICK}, - {"focus acquisition", ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_GAIN_ACCESSIBILITY_FOCUS}, - {"focus clearance", ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_CLEAR_ACCESSIBILITY_FOCUS}, - {"forward scroll", ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SCROLL_FORWARD}, - {"backward scroll", ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SCROLL_BACKWARD}, - {"copy text", ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_COPY}, - {"paste text", ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_PASTE}, - {"cut text", ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_CUT}, - {"text selection", ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SELECT_TEXT}, - {"set text", ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SET_TEXT}, - {"text cursor position setting", ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SET_CURSOR_POSITION}, - }; - static const int32_t FOCUSABLE_FLAGS = static_cast(FLAGS_::kHasCheckedState) | static_cast(FLAGS_::kIsChecked) | @@ -241,7 +224,7 @@ private: int64_t elementId); void FlutterSetElementInfoOperationActions( ArkUI_AccessibilityElementInfo* elementInfoFromList, - std::string widget_type); + const SemanticsNodeExtent& node); void BuildArkUISemanticsTree( int64_t elementId, ArkUI_AccessibilityElementInfo* elementInfoFromList, @@ -253,8 +236,7 @@ private: flutter::SemanticsAction ArkuiActionsToFlutterActions( ArkUI_Accessibility_ActionType arkui_action); - void BuildParentChildNodeIdRelation(const SemanticsNodeExtent& node); - void ComputeGlobalTransform(); + void ComputeGlobalTransformAndParentId(); void ConvertRectToGlobal(SemanticsNodeExtent& node); SkPoint ApplyTransform(SkPoint& point, const SkM44& transform); @@ -263,75 +245,66 @@ private: bool IsNodeFocusable(const SemanticsNodeExtent& flutterNode); bool IsNodeFocused(const SemanticsNodeExtent& flutterNode); - bool IsNodeCheckable(SemanticsNodeExtent flutterNode); - bool IsNodeChecked(SemanticsNodeExtent flutterNode); - bool IsNodeSelected(SemanticsNodeExtent flutterNode); - bool IsNodeClickable(SemanticsNodeExtent flutterNode); - bool IsNodeScrollable(SemanticsNodeExtent flutterNode); - bool IsNodePassword(SemanticsNodeExtent flutterNode); - bool IsNodeVisible(SemanticsNodeExtent flutterNode); - bool IsNodeEnabled(SemanticsNodeExtent flutterNode); - bool IsNodeHasLongPress(SemanticsNodeExtent flutterNode); - bool IsNodeShowOnScreen(SemanticsNodeExtent flutterNode); - - bool IsTextField(SemanticsNodeExtent flutterNode); - bool IsSlider(SemanticsNodeExtent flutterNode); - bool IsScrollableWidget(SemanticsNodeExtent flutterNode); + bool IsNodeCheckable(const SemanticsNodeExtent& flutterNode); + bool IsNodeChecked(const SemanticsNodeExtent& flutterNode); + bool IsNodeSelected(const SemanticsNodeExtent& flutterNode); + bool IsNodeClickable(const SemanticsNodeExtent& flutterNode); + bool IsNodeScrollable(const SemanticsNodeExtent& flutterNode); + bool IsNodePassword(const SemanticsNodeExtent& flutterNode); + bool IsNodeVisible(const SemanticsNodeExtent& flutterNode); + bool IsNodeEnabled(const SemanticsNodeExtent& flutterNode); + bool IsNodeHasLongPress(const SemanticsNodeExtent& flutterNode); + bool IsNodeShowOnScreen(const SemanticsNodeExtent& flutterNode); + bool IsTextField(const SemanticsNodeExtent& flutterNode); + bool IsSlider(const SemanticsNodeExtent& flutterNode); + bool IsScrollableWidget(const SemanticsNodeExtent& flutterNode); void PerformClickAction(int64_t elementId, ArkUI_Accessibility_ActionType action, - SemanticsNodeExtent flutterNode); + const SemanticsNodeExtent& flutterNode); void PerformLongClickAction(int64_t elementId, ArkUI_Accessibility_ActionType action, - SemanticsNodeExtent flutterNode); + const SemanticsNodeExtent& flutterNode); void PerformGainFocusnAction(int64_t elementId, ArkUI_Accessibility_ActionType action, - SemanticsNodeExtent flutterNode); + const SemanticsNodeExtent& flutterNode); void PerformClearFocusAction(int64_t elementId, ArkUI_Accessibility_ActionType action, - SemanticsNodeExtent flutterNode); + const SemanticsNodeExtent& flutterNode); void PerformScrollUpAction(int64_t elementId, ArkUI_Accessibility_ActionType action, - SemanticsNodeExtent flutterNode); + SemanticsNodeExtent& flutterNode); void PerformScrollDownAction(int64_t elementId, ArkUI_Accessibility_ActionType action, - SemanticsNodeExtent flutterNode); + SemanticsNodeExtent& flutterNode); void PerformClipboardAction(int64_t elementId, - ArkUI_Accessibility_ActionType action); + const ArkUI_Accessibility_ActionType& action); void PerformInvalidAction(int64_t elementId, ArkUI_Accessibility_ActionType action, - SemanticsNodeExtent flutterNode); - void PerformSetText(SemanticsNodeExtent flutterNode, + const SemanticsNodeExtent& flutterNode); + void PerformSetText(SemanticsNodeExtent& flutterNode, ArkUI_Accessibility_ActionType action, ArkUI_AccessibilityActionArguments* actionArguments); - void PerformSelectText(SemanticsNodeExtent flutterNode, + void PerformSelectText(const SemanticsNodeExtent& flutterNode, ArkUI_Accessibility_ActionType action, ArkUI_AccessibilityActionArguments* actionArguments); void PerformSetCursorPosition(SemanticsNodeExtent flutterNode, ArkUI_Accessibility_ActionType action, ArkUI_AccessibilityActionArguments* actionArguments); - void PerformCustomAction(SemanticsNodeExtent flutterNode, + void PerformCustomAction(const SemanticsNodeExtent& flutterNode, ArkUI_Accessibility_ActionType action, ArkUI_AccessibilityActionArguments* actionArguments); - void PerformShowOnScreenAction(SemanticsNodeExtent flutterNode); + void PerformShowOnScreenAction(const SemanticsNodeExtent& flutterNode); - void AddRouteNodes(std::vector edges, - SemanticsNodeExtent node); - std::string GetRouteName(SemanticsNodeExtent node); - void OnWindowNameChange(SemanticsNodeExtent route); - void RemoveSemanticsNode(SemanticsNodeExtent nodeToBeRemoved); - - void GetSemanticsNodeDebugInfo(SemanticsNodeExtent node); - void GetSemanticsFlagsDebugInfo(SemanticsNodeExtent node); + void GetSemanticsNodeDebugInfo(const SemanticsNodeExtent& node); + void GetSemanticsFlagsDebugInfo(const SemanticsNodeExtent& node); void GetCustomActionDebugInfo( - flutter::CustomAccessibilityAction customAccessibilityAction); + const flutter::CustomAccessibilityAction& customAccessibilityAction); void RequestFocusWhenPageUpdate(int32_t requestFocusId); - bool Contains(const std::string source, const std::string target); - std::pair GetRealScaleFactor(); - void DoubleClickRouteToNewPage(SemanticsNodeExtent node); void GetSemanticsDebugInfo(); void AccessibiltiyChangesWithXComponentId(); }; + } // namespace flutter #endif // OHOS_ACCESSIBILITY_BRIDGE_H diff --git a/shell/platform/ohos/accessibility/ohos_accessibility_manager.cpp b/shell/platform/ohos/accessibility/ohos_accessibility_manager.cpp deleted file mode 100644 index e6b811032418945d50b33d84b3e8d403a3704f3e..0000000000000000000000000000000000000000 --- a/shell/platform/ohos/accessibility/ohos_accessibility_manager.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2021-2024 Huawei Device Co., Ltd. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE_HW file. - */ -#include "ohos_accessibility_manager.h" - -namespace flutter { - -OhosAccessibilityManager::OhosAccessibilityManager() {} - -OhosAccessibilityManager::~OhosAccessibilityManager() {} - -/** - * 监听ohos平台是否开启无障碍屏幕朗读功能 - */ -void OhosAccessibilityManager::OnAccessibilityStateChanged( - bool ohosAccessibilityEnabled) {} - -void OhosAccessibilityManager::SetOhosAccessibilityEnabled(bool isEnabled) -{ - this->isOhosAccessibilityEnabled_ = isEnabled; -} - -bool OhosAccessibilityManager::GetOhosAccessibilityEnabled() -{ - return this->isOhosAccessibilityEnabled_; -} - -} // namespace flutter diff --git a/shell/platform/ohos/accessibility/ohos_accessibility_manager.h b/shell/platform/ohos/accessibility/ohos_accessibility_manager.h deleted file mode 100644 index 1ae56a60f9230498b9b6d47e754ab804aebe8958..0000000000000000000000000000000000000000 --- a/shell/platform/ohos/accessibility/ohos_accessibility_manager.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2021-2024 Huawei Device Co., Ltd. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE_HW file. - */ -#ifndef OHOS_ACCESSIBILITY_MANAGER_H -#define OHOS_ACCESSIBILITY_MANAGER_H -#include - -namespace flutter { -/** - * 无障碍辅助管理类 - */ -class OhosAccessibilityManager { - public: - OhosAccessibilityManager(); - ~OhosAccessibilityManager(); - - void OnAccessibilityStateChanged(bool ohosAccessibilityEnabled); - - bool GetOhosAccessibilityEnabled(); - - void SetOhosAccessibilityEnabled(bool isEnabled); - - private: - bool isOhosAccessibilityEnabled_; -}; - -} // namespace flutter - -#endif \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/cpp/types/libflutter/index.d.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/cpp/types/libflutter/index.d.ets index 99aa2d54f7ac2c33aa6685fe452d46060937387a..34524c31cc396a64cc0c1eda5a0bbe8aa8a94f57 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/cpp/types/libflutter/index.d.ets +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/cpp/types/libflutter/index.d.ets @@ -167,4 +167,6 @@ export const nativeUnicodeIsRegionalIndicatorSymbol: (code: number) => number; export const nativeGetXComponentId: (id: string) => number; -export const nativeSetDVsyncSwitch: (nativeShellHolderId: number, isEnable: boolean) => void; \ No newline at end of file +export const nativeSetDVsyncSwitch: (nativeShellHolderId: number, isEnable: boolean) => void; + +export const nativeTouchGuideStateChange: (state: Boolean) => void; diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/FlutterNapi.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/FlutterNapi.ets index 75ec3f3f3c59089553a1f107dba6427802541ef0..f4317b6bdcfbf1d648aa36b19fac3682253e9232 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/FlutterNapi.ets +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/FlutterNapi.ets @@ -370,6 +370,11 @@ export default class FlutterNapi { flutter.nativeAccessibilityStateChange(this.nativeShellHolderId!, state); } + touchGuideStateChange(state: Boolean): void { + this.ensureRunningOnMainThread(); + flutter.nativeTouchGuideStateChange(state); + } + setLocalizationPlugin(localizationPlugin: LocalizationPlugin | null): void { this.localizationPlugin = localizationPlugin; } diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterPage.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterPage.ets index 34a1148219e45656a3d31f42392e60d53e925447..04f49062a4c8effa9345028dd8d5856a437e3136 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterPage.ets +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterPage.ets @@ -9,7 +9,6 @@ import { FlutterView } from '../../view/FlutterView'; import FlutterManager from './FlutterManager'; import { DVModel, DVModelChildren, DynamicView } from '../../view/DynamicView/dynamicView'; import flutter from 'libflutter.so'; - const TAG = "FlutterPage"; export const OHOS_FLUTTER_PAGE_UPDATE = "ohos_flutter_page_update"; @@ -67,9 +66,10 @@ export struct FlutterPage { (ratioInc: boolean, ratio: number) => { if (ratioInc) { Log.i(TAG, "setOnVisibleAreaApproximateChange -> xcomponentId: " + this.viewId + - " ratioInc: " + ratioInc + " ratio: " + ratio); + " ratioInc: " + ratioInc + " ratio: " + ratio); flutter.nativeGetXComponentId(this.viewId); // 保证获取xcomponentid之后再使用无障碍 + this.flutterView?.onTouchGuideIsOpen(); this.flutterView?.onAccessibilityIsOpen(); } } @@ -173,9 +173,10 @@ export struct FlutterPage { (ratioInc: boolean, ratio: number) => { if (ratioInc) { Log.i(TAG, "setOnVisibleAreaApproximateChange -> xcomponentId: " + this.viewId + - " ratioInc: " + ratioInc + " ratio: " + ratio); + " ratioInc: " + ratioInc + " ratio: " + ratio); flutter.nativeGetXComponentId(this.viewId); // 保证获取xcomponentid之后再使用无障碍 + this.flutterView?.onTouchGuideIsOpen(); this.flutterView?.onAccessibilityIsOpen(); } } diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/view/FlutterView.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/view/FlutterView.ets index 0a6b2bcc1b76ac1a376fa7807184649a2306eb31..840ecc421a986bf3736bec5f90b4d115e179b9e8 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/view/FlutterView.ets +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/view/FlutterView.ets @@ -207,6 +207,12 @@ export class FlutterView { this.mainWindow?.on('avoidAreaChange', this.avoidAreaChangeCallback); this.mainWindow?.on('windowStatusChange', this.windowStatusChangeCallback); + // listen the touchGuideStateChange, when screen reader is on that + // the callback data of this lister event is true + accessibility.on('touchGuideStateChange', (data: boolean) => { + this.flutterEngine?.getFlutterNapi()?.touchGuideStateChange(data); + console.info(`subscribe touch guide state change, result: ${JSON.stringify(data)}`); + }); //监听系统无障碍服务状态改变 accessibility.on('accessibilityStateChange', (data: boolean) => { Log.i(TAG, `subscribe accessibility state change, result: ${JSON.stringify(data)}`); @@ -370,6 +376,9 @@ export class FlutterView { this.mainWindow?.off('windowSizeChange', this.windowSizeChangeCallback); this.mainWindow?.off('avoidAreaChange', this.avoidAreaChangeCallback); this.mainWindow?.off('windowStatusChange', this.windowStatusChangeCallback); + accessibility.off('touchGuideStateChange', (data: boolean) => { + Log.i(TAG, `subscribe touch guide state change, result: ${JSON.stringify(data)}`); + }); accessibility.off('accessibilityStateChange', (data: boolean) => { Log.i(TAG, `unsubscribe accessibility state change, result: ${JSON.stringify(data)}`); }); @@ -503,6 +512,14 @@ export class FlutterView { Log.i(TAG, `accessibility isOpen state -> ${JSON.stringify(accessibilityState)}`); } + onTouchGuideIsOpen() { + let touchGuideState: boolean = accessibility.isOpenTouchGuideSync(); + if(touchGuideState) { + this.flutterEngine?.getFlutterNapi()?.touchGuideStateChange(touchGuideState) + } + Log.i(TAG, `Touch Guide isOpen state -> ${JSON.stringify(touchGuideState)}`); + } + onAreaChange(newArea: Area | null, setFullScreen: boolean = false) { if (newArea != null) { this.viewportMetrics.physicalWidth = vp2px(newArea.width as number); diff --git a/shell/platform/ohos/library_loader.cpp b/shell/platform/ohos/library_loader.cpp index 165f9c26f6b6c55dd94acd1f54ea1c38392d49b2..f2af665a25fd6a27ed3ded9c09394837a71143cd 100644 --- a/shell/platform/ohos/library_loader.cpp +++ b/shell/platform/ohos/library_loader.cpp @@ -190,6 +190,9 @@ static napi_value Init(napi_env env, napi_value exports) { DECLARE_NAPI_FUNCTION( "nativeSetDVsyncSwitch", flutter::PlatformViewOHOSNapi::nativeSetDVsyncSwitch), + DECLARE_NAPI_FUNCTION( + "nativeTouchGuideStateChange", + flutter::PlatformViewOHOSNapi::NativeTouchGuideStateChange), }; FML_DLOG(INFO) << "Init NAPI size=" << sizeof(desc) / sizeof(desc[0]); diff --git a/shell/platform/ohos/napi/platform_view_ohos_napi.cpp b/shell/platform/ohos/napi/platform_view_ohos_napi.cpp index cfa0c2d3090003d006221772fcee25aff931f43e..ef8de8b2b4f36fd93d57cd5d6748ec11b3b3b88e 100644 --- a/shell/platform/ohos/napi/platform_view_ohos_napi.cpp +++ b/shell/platform/ohos/napi/platform_view_ohos_napi.cpp @@ -2347,4 +2347,22 @@ napi_value PlatformViewOHOSNapi::nativeSetDVsyncSwitch(napi_env env, napi_callba napi_create_int32(env, 0, &result); return result; } + +napi_value PlatformViewOHOSNapi::NativeTouchGuideStateChange(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value args[1] = {nullptr}; + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + bool touchGuideState = false; + bool ret = napi_get_value_bool(env, args[0], &touchGuideState); + if (ret != napi_ok) { + FML_DLOG(ERROR) << "NativeTouchGuideStateChange touchGuideState: " << touchGuideState; + return nullptr; + } + + OhosAccessibilityBridge::GetInstance()->isTouchGuideOn_ = touchGuideState; + FML_DLOG(INFO) << "NativeTouchGuideStateChange -> touchGuideState: " << touchGuideState; + return nullptr; +} } // namespace flutter \ No newline at end of file diff --git a/shell/platform/ohos/napi/platform_view_ohos_napi.h b/shell/platform/ohos/napi/platform_view_ohos_napi.h index 65c59694173b2b797d5876c9c84c68346b16e596..6f10aae4e1af9f34f53b6a0524a3de5e86784329 100644 --- a/shell/platform/ohos/napi/platform_view_ohos_napi.h +++ b/shell/platform/ohos/napi/platform_view_ohos_napi.h @@ -271,6 +271,10 @@ class PlatformViewOHOSNapi { napi_env env, napi_callback_info info); + static napi_value NativeTouchGuideStateChange( + napi_env env, + napi_callback_info info); + private: static napi_env env_; napi_ref ref_napi_obj_; diff --git a/shell/platform/ohos/ohos_xcomponent_adapter.cpp b/shell/platform/ohos/ohos_xcomponent_adapter.cpp index f9ef00ee506479c5e598858fd9dc193807da87e7..a7da244df798c1fe36d0d35bb63005b54e4be117 100644 --- a/shell/platform/ohos/ohos_xcomponent_adapter.cpp +++ b/shell/platform/ohos/ohos_xcomponent_adapter.cpp @@ -195,6 +195,8 @@ void OnSurfaceDestroyedCB(OH_NativeXComponent* component, void* window) { delete it->second; // 将当前要销毁的xcomponent对应的无障碍provider指针置nullptr it->second->accessibilityProvider_ = nullptr; + // delete the semantics tree of the destroyed xcomponent + OhosAccessibilityBridge::GetInstance()->g_flutterSemanticsTreeXComponents.erase(it->first); it = XComponentAdapter::GetInstance()->xcomponetMap_.erase(it); } else { ++it; diff --git a/shell/platform/ohos/platform_view_ohos.cpp b/shell/platform/ohos/platform_view_ohos.cpp index d164be8830d1d3c8d7884bb3ce8df125b3738c06..be9e82c6cc64ba346ddc87cfbc15da90aa49583f 100644 --- a/shell/platform/ohos/platform_view_ohos.cpp +++ b/shell/platform/ohos/platform_view_ohos.cpp @@ -280,7 +280,7 @@ void PlatformViewOHOS::UpdateSemantics( flutter::CustomAccessibilityActionUpdates actions) { FML_DLOG(INFO) << "PlatformViewOHOS::UpdateSemantics()"; auto nativeAccessibilityChannel_ = std::make_shared(); - nativeAccessibilityChannel_->UpdateSemantics(update, actions); + nativeAccessibilityChannel_->UpdateSemantics(std::move(update), std::move(actions)); } // |PlatformView|