diff --git a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp index dbb1a076e9f5bad61c48d76558c3fe68aef5513d..16f9d4b7b6714fe3c6ae9de2a5a3473194c8fa00 100644 --- a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp +++ b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp @@ -21,8 +21,6 @@ #include "flutter/shell/common/platform_view.h" #include "flutter/shell/platform/embedder/embedder.h" #include "flutter/shell/platform/ohos/ohos_shell_holder.h" -#include "third_party/skia/include/core/SkMatrix.h" -#include "third_party/skia/include/core/SkScalar.h" #include "flutter/shell/platform/ohos/ohos_xcomponent_adapter.h" namespace flutter { @@ -31,6 +29,34 @@ const int32_t OhosAccessibilityBridge::OHOS_API_VERSION = OH_GetSdkApiVersion(); std::unique_ptr OhosAccessibilityBridge::bridgeInstance_ = nullptr; +/** + * flutter无障碍相关语义树、句柄指针provider等参数 + * 跟随xcomponentid显示切换,而加载对应xcomponent的语义树和provider指针 + * @NOTE: 当屏幕同时显示多个xcomponent时,无法通过聚焦事件而触发xcomponentid改变 + */ +void OhosAccessibilityBridge::AccessibiltiyChangesWithXComponentId() +{ + auto xcompMap = XComponentAdapter::GetInstance()->xcomponetMap_; + // 获取当前显示的xcomponetid + std::string currXcompId = XComponentAdapter::GetInstance()->currentXComponentId_; + if (xcomponentId_ == currXcompId) { return; } + + auto it = xcompMap.find(currXcompId); + if (!xcompMap.empty() && it != xcompMap.end()) { + // 更新xcompid,shellholderId,provider指针 + 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特性,实现线程安全的单例模式 */ @@ -44,7 +70,7 @@ OhosAccessibilityBridge* OhosAccessibilityBridge::GetInstance() } OhosAccessibilityBridge::OhosAccessibilityBridge() - : isFlutterNavigated_(false), provider_(nullptr), + : isFlutterNavigated_(false), isAccessibilityEnabled_(false) {} /** @@ -54,7 +80,7 @@ void OhosAccessibilityBridge::OnOhosAccessibilityStateChange( bool ohosAccessibilityEnabled, int64_t shellholderId) { native_shell_holder_id_ = shellholderId; - provider_ = XComponentAdapter::GetInstance()->accessibilityProvider_; + AccessibiltiyChangesWithXComponentId(); nativeAccessibilityChannel_ = std::make_shared(); accessibilityFeatures_ = std::make_shared(); @@ -67,9 +93,18 @@ void OhosAccessibilityBridge::OnOhosAccessibilityStateChange( } } -void OhosAccessibilityBridge::SetNativeShellHolderId(int64_t id) +/** + * build the id mapping betwween parent node and its children nodes + */ +void OhosAccessibilityBridge::BuildParentChildNodeIdRelation( + const SemanticsNodeExtent& node) { - this->native_shell_holder_id_ = id; + 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)); + } } /** @@ -81,14 +116,10 @@ void OhosAccessibilityBridge::UpdateSemantics( flutter::CustomAccessibilityActionUpdates actions) { FML_DLOG(INFO) << "OhosAccessibilityBridge::UpdateSemantics()"; - provider_ = XComponentAdapter::GetInstance()->accessibilityProvider_; std::vector updatedFlutterNodes; // 当flutter页面状态更新(路由新页面)时,自动请求root节点组件获焦(规避滑动组件更新干扰) if (isFlutterNavigated_) { - Flutter_SendAccessibilityAsyncEvent(0, - ArkUI_AccessibilityEventType:: - ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_PAGE_STATE_UPDATE); RequestFocusWhenPageUpdate(0); isFlutterNavigated_ = false; } @@ -97,16 +128,20 @@ 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); + // 构建flutter无障碍语义节点树 + g_flutterSemanticsTree[nodeEx.id] = nodeEx; + // 构建flutter节点的父子id映射关系 + BuildParentChildNodeIdRelation(nodeEx); + //print semantics node and flags info for debugging GetSemanticsNodeDebugInfo(nodeEx); GetSemanticsFlagsDebugInfo(nodeEx); - // 构建flutter无障碍语义节点树 - g_flutterSemanticsTree[nodeEx.id] = nodeEx; + if (!IsNodeVisible(nodeEx)) { continue; } // 若当前节点为获焦 if (IsNodeFocused(nodeEx)) { @@ -115,15 +150,14 @@ void OhosAccessibilityBridge::UpdateSemantics( // 若当前节点和更新前节点信息不同,则加入更新节点数组 if (nodeEx.hadPreviousConfig) { updatedFlutterNodes.emplace_back(nodeEx); - } - - // 获取当前flutter节点的全部子节点数量,并构建父子节点id映射关系 - int32_t childNodeCount = nodeEx.childrenInTraversalOrder.size(); - for (int32_t i = 0; i < childNodeCount; i++) { - g_parentChildIdVec.emplace_back(std::make_pair(nodeEx.id, nodeEx.childrenInTraversalOrder[i])); + FML_DLOG(INFO) << "updatedFlutterNodes -> node.id=" << nodeEx.id; } } + // 将更新后的flutter语义树和父子节点id映射缓存,保存到相应的xcomponent里面 + g_flutterSemanticsTreeXComponents[xcomponentId_] = g_flutterSemanticsTree; + g_parentChildIdVecXComponents[xcomponentId_] = g_parentChildIdVec; + // 页面内容更新事件 Flutter_SendAccessibilityAsyncEvent(0, ArkUI_AccessibilityEventType:: @@ -131,10 +165,12 @@ void OhosAccessibilityBridge::UpdateSemantics( LOGD("Flutter_SendAccessibilityAsyncEvent -> PAGE_CONTENT_UPDATE"); /* 针对更新后的节点进行事件处理 */ - for (const auto& nodeEx: updatedFlutterNodes) { + for (auto& nodeEx: updatedFlutterNodes) { + FML_DLOG(INFO) << "*#*#* updated node.id=" << nodeEx.id; + // 当滑动节点产生滑动,并执行滑动处理 if (HasScrolled(nodeEx)) { - LOGD("UpdateSemantics -> has scrolled"); + LOGD("UpdateSemantics -> nodeId = %{public}d has scrolled", nodeEx.id); auto OH_ArkUI_CreateAccessibilityElementInfo = OhosAccessibilityDDL::DLLoadCreateElemInfoFunc(ArkUIAccessibilityConstant::ARKUI_CREATE_NODE); CHECK_DLL_NULL_PTR(OH_ArkUI_CreateAccessibilityElementInfo); @@ -156,16 +192,16 @@ void OhosAccessibilityBridge::UpdateSemantics( _elementInfo = nullptr; } - // 判断是否触发liveRegion活动区,当前节点是否活跃 + // 判断是否触发liveRegion活动区,当前节点是否活跃 nodeEx.HasFlag(FLAGS_::kIsLiveRegion) if (nodeEx.HasFlag(FLAGS_::kIsLiveRegion) && HasChangedLabel(nodeEx)) { - FML_DLOG(INFO) << "UpdateSemantics -> page content update, nodeEx.id=" << nodeEx.id; + FML_DLOG(INFO) << "liveRegion -> page content update, nodeEx.id=" << nodeEx.id; Flutter_SendAccessibilityAsyncEvent(static_cast(nodeEx.id), ArkUI_AccessibilityEventType:: ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_PAGE_CONTENT_UPDATE); - LOGD("Flutter_SendAccessibilityAsyncEvent -> PAGE_CONTENT_UPDATE"); } } - + // calculate the global tranfomr matrix for each node + ComputeGlobalTransform(); // 输出flutter语义树相关重要语义信息debug日志 GetSemanticsDebugInfo(); FML_DLOG(INFO) << "=== UpdateSemantics() is finished ==="; @@ -205,7 +241,7 @@ void OhosAccessibilityBridge::FlutterScrollExecution( if (node.HasAction(ACTIONS_::kScrollUp) || node.HasAction(ACTIONS_::kScrollDown)) { } else if (node.HasAction(ACTIONS_::kScrollLeft) || - node.HasAction(ACTIONS_::kScrollRight)) { + node.HasAction(ACTIONS_::kScrollRight)) { LOGD("current flutterNode has scroll up/down/left/right"); } @@ -270,7 +306,8 @@ void OhosAccessibilityBridge::FlutterScrollExecution( void OhosAccessibilityBridge::RequestFocusWhenPageUpdate(int32_t requestFocusId) { if (OHOS_API_VERSION < 13) { return; } - provider_ = XComponentAdapter::GetInstance()->accessibilityProvider_; + std::lock_guard lock(XComponentAdapter::GetInstance()->mutex_); + auto provider_ = XComponentAdapter::GetInstance()->GetAccessibilityProvider(xcomponentId_); CHECK_NULL_PTR_RET_VOID(provider_, RequestFocusWhenPageUpdate); auto OH_ArkUI_CreateAccessibilityEventInfo = @@ -462,68 +499,66 @@ std::pair OhosAccessibilityBridge::GetRealScaleFactor() } /** - * flutter语义树中相对坐标系转化为屏幕绝对坐标的映射算法实现 - * NOTE:目前暂未考虑旋转、透视场景,不影响屏幕朗读功能 - * (SkMatrix::kMSkewX, SkMatrix::kMSkewY, SkMatrix::kMPersp0, - * SkMatrix::kMPersp1, SkMatrix::kMPersp2) + * calculate the global transform matrix for each node */ -void OhosAccessibilityBridge::FlutterRelativeRectToScreenRect( - SemanticsNodeExtent currNode) -{ - // 获取当前flutter节点的相对rect - auto [currLeft, currTop, currRight, currBottom] = currNode.rect; - - // 获取当前flutter节点的缩放、平移、透视等矩阵坐标转换以下矩阵坐标变换参数 - SkMatrix transform = currNode.transform.asM33(); - auto _kMScaleX = transform.get(SkMatrix::kMScaleX); - auto _kMTransX = transform.get(SkMatrix::kMTransX); - auto _kMScaleY = transform.get(SkMatrix::kMScaleY); - auto _kMTransY = transform.get(SkMatrix::kMTransY); - - // 获取当前flutter节点的父节点的相对rect - int32_t parentId = GetParentId(currNode.id); - auto parentNode = GetFlutterSemanticsNode(parentId); - if (g_flutterSemanticsTree.find(parentId) == g_flutterSemanticsTree.end()) { - LOGE("FlutterRelativeRectToScreenRect: GetFlutterSemanticsNode id=%{public}d null", parentId); - } - - // 获取当前flutter节点的父节点的绝对坐标 - auto [realParentLeft, realParentTop, realParentRight, realParentBottom] = GetAbsoluteScreenRect(parentNode); - - //获取root节点的绝对坐标 - auto rootNode = GetFlutterSemanticsNode(0); - auto rootRect = GetAbsoluteScreenRect(rootNode); - auto rootWidth = rootRect.right; - auto rootHeight = rootRect.bottom; - - // 获取真实缩放系数 - auto [realScaleXFactor, realScaleYFactor] = GetRealScaleFactor(); - - // 更新后的节点屏幕坐标,子节点的屏幕绝对坐标转换,包括offset偏移值计算、缩放系数变换 - bool isRectScaleChanged = _kMScaleX > 1 && _kMScaleY > 1; - float newLeft = isRectScaleChanged ? - currLeft + _kMTransX * _kMScaleX : (currLeft + _kMTransX) * realScaleXFactor + realParentLeft; - float newTop = isRectScaleChanged ? - currTop + _kMTransY * _kMScaleY : (currTop + _kMTransY) * realScaleYFactor + realParentTop; - float newRight = isRectScaleChanged ? - currRight * _kMScaleX : newLeft + currRight * realScaleXFactor; - float newBottom = isRectScaleChanged ? - currBottom * _kMScaleY : newTop + currBottom * realScaleYFactor; - - // 若子节点rect超过父节点则跳过显示(单个屏幕显示不下,滑动再重新显示) - const bool isExceedScreeArea = newLeft < realParentLeft || newTop < realParentTop || - newRight > realParentRight || newBottom > realParentBottom || - newLeft >= newRight || newTop >= newBottom || - newRight > rootWidth || newBottom > rootHeight; - if (isExceedScreeArea) { - FML_DLOG(WARNING) << "RelativeRectToScreenRect -> childRect exceeds parentRect {Id: " - << currNode.id << ", (" << newLeft << ", " << newTop - << ", " << newRight << ", " << newBottom << ")}"; - // 防止滑动场景下绿框坐标超出屏幕范围,进行正则化处理 - SetAbsoluteScreenRect(currNode, rootWidth, rootHeight, 0, 0); - } else { - SetAbsoluteScreenRect(currNode, newLeft, newTop, newRight, newBottom); +void OhosAccessibilityBridge::ComputeGlobalTransform() +{ + std::queue semanticsQue; + + auto root = GetFlutterSemanticsNode(0); + semanticsQue.push(root); + g_globalTransformMap[root.id] = root.transform; + + while (!semanticsQue.empty()) { + uint32_t queSize = semanticsQue.size(); + for (uint32_t i=0; i Transformed points can't make a rect "; + } + globalRect.setBounds(points, 4); + + SetAbsoluteScreenRect(node, globalRect.left(), globalRect.top(), + globalRect.right(), globalRect.bottom()); } /** @@ -655,7 +690,7 @@ void OhosAccessibilityBridge::FlutterSetElementInfoProperties( rect = {static_cast(left), static_cast(top), static_cast(right), static_cast(bottom)}; } else { // 若当前节点为id >= 1的节点 - FlutterRelativeRectToScreenRect(flutterNode); + RelativeRectToScreenRect(flutterNode); auto [left, top, right, bottom] = GetAbsoluteScreenRect(flutterNode); rect = {static_cast(left), static_cast(top), static_cast(right), static_cast(bottom)}; @@ -889,7 +924,8 @@ void OhosAccessibilityBridge::FlutterSetElementInfoProperties( OhosAccessibilityDDL::DLLoadSetElemStringFunc(ArkUIAccessibilityConstant::ARKUI_SET_A11Y_LEVEL); CHECK_DLL_NULL_PTR(OH_ArkUI_AccessibilityElementInfoSetAccessibilityLevel); ARKUI_ACCESSIBILITY_CALL_CHECK( - OH_ArkUI_AccessibilityElementInfoSetAccessibilityLevel(elementInfoFromList, "yes"); + OH_ArkUI_AccessibilityElementInfoSetAccessibilityLevel( + elementInfoFromList, componentTypeName != OTHER_WIDGET_NAME ? "yes" : "no"); ); // 无障碍组,设置为true时表示该组件及其所有子组件为一整个可以选中的组件,无障碍服务将不再关注其子组件内容。默认值:false auto OH_ArkUI_AccessibilityElementInfoSetAccessibilityGroup = @@ -917,6 +953,7 @@ std::vector OhosAccessibilityBridge::GetLevelOrderTraversalTree(int32_t uint32_t queSize = semanticsQue.size(); for (uint32_t i=0; i(currNode.id)); @@ -924,6 +961,7 @@ std::vector OhosAccessibilityBridge::GetLevelOrderTraversalTree(int32_t currNode.childrenInTraversalOrder.end()); for (const auto& childId: currNode.childrenInTraversalOrder) { auto childNode = GetFlutterSemanticsNode(childId); + semanticsQue.push(childNode); } } @@ -978,6 +1016,8 @@ int32_t OhosAccessibilityBridge::FindAccessibilityNodeInfosById( << elementId << " mode=" << mode; CHECK_NULL_PTR_WITH_RET(elementList, FindAccessibilityNodeInfosById); + AccessibiltiyChangesWithXComponentId(); + if (g_flutterSemanticsTree.size() == 0) { FML_DLOG(INFO) << "FindAccessibilityNodeInfosById g_flutterSemanticsTree is null"; @@ -1370,6 +1410,8 @@ int32_t OhosAccessibilityBridge::ExecuteAccessibilityAction( << elementId << " action=" << action; CHECK_NULL_PTR_WITH_RET(actionArguments, ExecuteAccessibilityAction); + AccessibiltiyChangesWithXComponentId(); + // 获取当前elementid对应的flutter语义节点 auto flutterNode = GetFlutterSemanticsNode(static_cast(elementId)); if (!g_flutterSemanticsTree.count(flutterNode.id)) { @@ -1565,7 +1607,9 @@ void OhosAccessibilityBridge::Flutter_SendAccessibilityAnnounceEvent( ArkUI_AccessibilityEventType eventType) { if (OHOS_API_VERSION < 13) { return; } - provider_ = XComponentAdapter::GetInstance()->accessibilityProvider_; + AccessibiltiyChangesWithXComponentId(); + std::lock_guard lock(XComponentAdapter::GetInstance()->mutex_); + auto provider_ = XComponentAdapter::GetInstance()->GetAccessibilityProvider(xcomponentId_); CHECK_NULL_PTR_RET_VOID(provider_, Flutter_SendAccessibilityAnnounceEvent); // 创建并设置屏幕朗读事件 @@ -1614,7 +1658,9 @@ void OhosAccessibilityBridge::Flutter_SendAccessibilityAsyncEvent( ArkUI_AccessibilityEventType eventType) { if (OHOS_API_VERSION < 13) { return; } - provider_ = XComponentAdapter::GetInstance()->accessibilityProvider_; + AccessibiltiyChangesWithXComponentId(); + std::lock_guard lock(XComponentAdapter::GetInstance()->mutex_); + auto provider_ = XComponentAdapter::GetInstance()->GetAccessibilityProvider(xcomponentId_); CHECK_NULL_PTR_RET_VOID(provider_, Flutter_SendAccessibilityAsyncEvent); // 创建eventInfo对象 @@ -1967,6 +2013,10 @@ 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); + accessibilityFocusedNode = {}; } /** diff --git a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h index f4e03364ce919ed2d80743e5c48c986d4257616e..673f762d3770743aa4f7f97d9455651c058778dd 100644 --- a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h +++ b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h @@ -30,6 +30,9 @@ #include "ohos_accessibility_ddl.h" #include "flutter/shell/platform/ohos/utils/ohos_utils.h" #include "flutter/shell/platform/ohos/utils/arkui_accessibility_constant.h" +#include "third_party/skia/include/core/SkMatrix.h" +#include "third_party/skia/include/core/SkScalar.h" +#include "third_party/skia/include/core/SkPoint.h" namespace flutter { typedef flutter::SemanticsFlags FLAGS_; @@ -43,9 +46,15 @@ struct AbsoluteRect { static constexpr AbsoluteRect MakeEmpty() { return AbsoluteRect{0.0, 0.0, 0.0, 0.0}; } + static constexpr AbsoluteRect MakeRect( + float left, float top, float right, float bottom) { + return AbsoluteRect{left, top, right, bottom}; + } + }; struct SemanticsNodeExtent : flutter::SemanticsNode { bool isNull = false; + SkM44 globalTransform = SkM44{}; AbsoluteRect absoluteRect = AbsoluteRect::MakeEmpty(); int32_t parentId = -1; bool hadPreviousConfig = false; @@ -78,14 +87,12 @@ public: OhosAccessibilityBridge(const OhosAccessibilityBridge&) = delete; OhosAccessibilityBridge& operator=(const OhosAccessibilityBridge&) = delete; + std::string xcomponentId_; bool isFlutterNavigated_; int64_t native_shell_holder_id_; - ArkUI_AccessibilityProvider* provider_; void OnOhosAccessibilityStateChange(bool ohosAccessibilityEnabled, int64_t shellholderId); - void SetNativeShellHolderId(int64_t id); - void UpdateSemantics(flutter::SemanticsNodeUpdates update, flutter::CustomAccessibilityActionUpdates actions); @@ -138,7 +145,7 @@ public: std::unique_ptr& message, ArkUI_AccessibilityEventType eventType); - void FlutterRelativeRectToScreenRect(SemanticsNodeExtent node); + void RelativeRectToScreenRect(SemanticsNodeExtent& node); AbsoluteRect GetAbsoluteScreenRect(SemanticsNodeExtent& flutterNode); void SetAbsoluteScreenRect(SemanticsNodeExtent& flutterNode, float left, @@ -161,9 +168,14 @@ 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; @@ -250,6 +262,11 @@ private: flutter::SemanticsAction ArkuiActionsToFlutterActions( ArkUI_Accessibility_ActionType arkui_action); + void BuildParentChildNodeIdRelation(const SemanticsNodeExtent& node); + void ComputeGlobalTransform(); + void ConvertRectToGlobal(SemanticsNodeExtent& node); + SkPoint ApplyTransform(SkPoint& point, const SkM44& transform); + bool HasScrolled(const SemanticsNodeExtent& flutterNode); bool HasChangedLabel(const SemanticsNodeExtent& flutterNode); 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 5b9025f5af372f923a519cc37854472e98aedba6..257b1e7225cbe643d6c2efd0d98703fc45f89acb 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 @@ -179,4 +179,6 @@ export const nativeUnicodeIsVariationSelector: (code: number) => number; 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 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 f109e10a491a96afc62248e840a0b22ef5ecd3bd..9b5a1033fda51ced8e5c7f0b45f0f7ebc1075b51 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 @@ -17,7 +17,7 @@ import Log from '../../util/Log'; 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"; @@ -57,7 +57,19 @@ export struct FlutterPage { .onLoad((context) => { this.flutterView?.onSurfaceCreated() Log.d(TAG, "XComponent onLoad "); - this.flutterView?.onAccessibilityIsOpen() + // 当xcomponent窗口部分显示或完全隐藏时触发回调 + this.getUIContext()?.getAttachedFrameNodeById(this.viewId)?.commonEvent.setOnVisibleAreaApproximateChange( + { ratios: [0.0, 1.0], expectedUpdateInterval: 0 }, + (ratioInc: boolean, ratio: number) => { + if (ratioInc) { + Log.i(TAG, "setOnVisibleAreaApproximateChange -> xcomponentId: " + this.viewId + + " ratioInc: " + ratioInc + " ratio: " + ratio); + flutter.nativeGetXComponentId(this.viewId); + // 保证获取xcomponentid之后再使用无障碍 + this.flutterView?.onAccessibilityIsOpen(); + } + } + ) }) .onDestroy(() => { Log.d(TAG, "XComponent onDestroy "); @@ -138,7 +150,19 @@ export struct FlutterPage { .onLoad((context) => { this.flutterView?.onSurfaceCreated() Log.d(TAG, "XComponent onLoad "); - this.flutterView?.onAccessibilityIsOpen() + // 当xcomponent窗口部分显示或完全隐藏时触发回调 + this.getUIContext()?.getAttachedFrameNodeById(this.viewId)?.commonEvent.setOnVisibleAreaApproximateChange( + { ratios: [0.0, 1.0], expectedUpdateInterval: 0 }, + (ratioInc: boolean, ratio: number) => { + if (ratioInc) { + Log.i(TAG, "setOnVisibleAreaApproximateChange -> xcomponentId: " + this.viewId + + " ratioInc: " + ratioInc + " ratio: " + ratio); + flutter.nativeGetXComponentId(this.viewId); + // 保证获取xcomponentid之后再使用无障碍 + this.flutterView?.onAccessibilityIsOpen(); + } + } + ) }) .onDestroy(() => { Log.d(TAG, "XComponent onDestroy "); diff --git a/shell/platform/ohos/library_loader.cpp b/shell/platform/ohos/library_loader.cpp index 4e66c4d3f24c24e6da7258c0b4c38178eb529724..51e4e24ee967ea80500aeebbca38ca15b86463a5 100644 --- a/shell/platform/ohos/library_loader.cpp +++ b/shell/platform/ohos/library_loader.cpp @@ -193,6 +193,9 @@ static napi_value Init(napi_env env, napi_value exports) { DECLARE_NAPI_FUNCTION( "nativeUnicodeIsRegionalIndicatorSymbol", flutter::PlatformViewOHOSNapi::nativeUnicodeIsRegionalIndicatorSymbol), + DECLARE_NAPI_FUNCTION( + "nativeGetXComponentId", + flutter::PlatformViewOHOSNapi::nativeGetXComponentId), DECLARE_NAPI_FUNCTION( "nativeSetDVsyncSwitch", flutter::PlatformViewOHOSNapi::nativeSetDVsyncSwitch), diff --git a/shell/platform/ohos/napi/platform_view_ohos_napi.cpp b/shell/platform/ohos/napi/platform_view_ohos_napi.cpp index 085f68daf02bc833ff5688cfcb53be31e996a755..51271961a8a6497bc9d7d7f2f58dbb7d4cb4db85 100644 --- a/shell/platform/ohos/napi/platform_view_ohos_napi.cpp +++ b/shell/platform/ohos/napi/platform_view_ohos_napi.cpp @@ -2297,6 +2297,25 @@ napi_value PlatformViewOHOSNapi::nativeUnicodeIsRegionalIndicatorSymbol(napi_env return result; } +napi_value PlatformViewOHOSNapi::nativeGetXComponentId(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); + + std::string xcomponentId; + bool ret = fml::napi::GetString(env, args[0], xcomponentId); + if (ret != napi_ok) { + FML_DLOG(ERROR) << "nativeGetXComponentId xcomponentId: " << xcomponentId; + return nullptr; + } + // obtain the current visible xcomponent id from the ets callback event + XComponentAdapter::GetInstance()->currentXComponentId_ = xcomponentId; + FML_DLOG(ERROR) << "nativeGetXComponentId -> xcomponentId: " << xcomponentId; + return nullptr; +} + + napi_value PlatformViewOHOSNapi::nativeSetDVsyncSwitch(napi_env env, napi_callback_info info) { size_t argc = 2; diff --git a/shell/platform/ohos/napi/platform_view_ohos_napi.h b/shell/platform/ohos/napi/platform_view_ohos_napi.h index 0d1017d8482545e701bbc1e5202321cb4cc13935..c003d5f3df21026cbaa33a24e63db810317c70ee 100644 --- a/shell/platform/ohos/napi/platform_view_ohos_napi.h +++ b/shell/platform/ohos/napi/platform_view_ohos_napi.h @@ -272,6 +272,10 @@ class PlatformViewOHOSNapi { napi_env env, napi_callback_info info); + static napi_value nativeGetXComponentId( + napi_env env, + napi_callback_info info); + static napi_value nativeSetDVsyncSwitch( napi_env env, napi_callback_info info); diff --git a/shell/platform/ohos/ohos_xcomponent_adapter.cpp b/shell/platform/ohos/ohos_xcomponent_adapter.cpp index 4789d210103e9a2a14dc78a3a2705403422def7f..a35325b3db34c3633bd29d74c43a83e1c7ccd84e 100644 --- a/shell/platform/ohos/ohos_xcomponent_adapter.cpp +++ b/shell/platform/ohos/ohos_xcomponent_adapter.cpp @@ -195,12 +195,15 @@ void OnSurfaceChangedCB(OH_NativeXComponent* component, void* window) { } void OnSurfaceDestroyedCB(OH_NativeXComponent* component, void* window) { + std::lock_guard lock(XComponentAdapter::GetInstance()->mutex_); for(auto it = XComponentAdapter::GetInstance()->xcomponetMap_.begin(); it != XComponentAdapter::GetInstance()->xcomponetMap_.end();) { if(it->second->nativeXComponent_ == component) { it->second->OnSurfaceDestroyed(component, window); delete it->second; + // 将当前要销毁的xcomponent对应的无障碍provider指针置nullptr + it->second->accessibilityProvider_ = nullptr; it = XComponentAdapter::GetInstance()->xcomponetMap_.erase(it); } else { ++it; @@ -364,6 +367,16 @@ void XComponentBase::DetachFlutterEngine() { isEngineAttached_ = false; } +ArkUI_AccessibilityProvider* XComponentAdapter::GetAccessibilityProvider(const std::string& xcompId) +{ + auto it = xcomponetMap_.find(xcompId); + if (it != xcomponetMap_.end()) { + return it->second->accessibilityProvider_; + } else { + return nullptr; + } +} + void XComponentBase::RegisterArkUIAccessibilityService(OH_NativeXComponent* nativeXComponent) { BindAccessibilityProviderCallback(); @@ -385,8 +398,11 @@ void XComponentBase::RegisterArkUIAccessibilityService(OH_NativeXComponent* nati OH_ArkUI_AccessibilityProviderRegisterCallback(a11yProvider, &accessibilityProviderCallback_) ); - XComponentAdapter::GetInstance()->accessibilityProvider_ = a11yProvider; - + std::lock_guard lock(XComponentAdapter::GetInstance()->mutex_); + auto* base = XComponentAdapter::GetInstance()->xcomponetMap_[id_]; + base->accessibilityProvider_ = a11yProvider; + base->nativeXComponent_ = nativeXComponent; + FML_DLOG(INFO) << "RegisterArkUIAccessibilityService is finished"; } @@ -397,9 +413,8 @@ void XComponentBase::SetNativeXComponent(OH_NativeXComponent* nativeXComponent){ OH_NativeXComponent_RegisterCallback(nativeXComponent_, &callback_); OH_NativeXComponent_RegisterMouseEventCallback(nativeXComponent_, &mouseCallback_); // register the OH_ArkUI accessibility callbacks - if (OH_GetSdkApiVersion() >= 13) { - RegisterArkUIAccessibilityService(nativeXComponent_); - } + if (OH_GetSdkApiVersion() < 13) { return; } + RegisterArkUIAccessibilityService(nativeXComponent_); } } @@ -456,7 +471,6 @@ void XComponentBase::OnSurfaceChanged(OH_NativeXComponent* component, void* wind void XComponentBase::OnSurfaceDestroyed(OH_NativeXComponent* component, void* window) { window_ = nullptr; - XComponentAdapter::GetInstance()->accessibilityProvider_ = nullptr; LOGD("XComponentManger::OnSurfaceDestroyed"); if (isEngineAttached_) { PlatformViewOHOSNapi::SurfaceDestroyed(std::stoll(shellholderId_)); diff --git a/shell/platform/ohos/ohos_xcomponent_adapter.h b/shell/platform/ohos/ohos_xcomponent_adapter.h index 7698e3a8f2cb44c9be00d65370badaad71ae55e3..632e9d216d8b3118a563793d352b03f0ac8177fd 100644 --- a/shell/platform/ohos/ohos_xcomponent_adapter.h +++ b/shell/platform/ohos/ohos_xcomponent_adapter.h @@ -20,7 +20,7 @@ #include #include #include - +#include #include "flutter/shell/platform/ohos/ohos_touch_processor.h" #include "flutter/shell/platform/ohos/napi/platform_view_ohos_napi.h" #include "napi/native_api.h" @@ -51,7 +51,8 @@ public: void OnDispatchMouseEvent(OH_NativeXComponent* component, void* window); void OnDispatchMouseWheelEvent(mouseWheelEvent event); - void RegisterArkUIAccessibilityService(OH_NativeXComponent* nativeXComponent); + void RegisterArkUIAccessibilityService( + OH_NativeXComponent* nativeXComponent); OH_NativeXComponent_TouchEvent touchEvent_; OH_NativeXComponent_Callback callback_; @@ -68,7 +69,6 @@ public: uint64_t height_; OhosTouchProcessor ohosTouchProcessor_; ArkUI_AccessibilityProvider* accessibilityProvider_; - }; class XComponentAdapter { @@ -83,9 +83,12 @@ class XComponentAdapter { void DetachFlutterEngine(std::string& id); void OnMouseWheel(std::string& id, mouseWheelEvent event); + ArkUI_AccessibilityProvider* GetAccessibilityProvider(const std::string& xcompId); + public: std::map xcomponetMap_; - ArkUI_AccessibilityProvider* accessibilityProvider_; + std::string currentXComponentId_; + std::mutex mutex_; private: static XComponentAdapter mXComponentAdapter;