From 9051954410fb48c8dc006e72660257ee2c91279c Mon Sep 17 00:00:00 2001 From: zjxi Date: Mon, 28 Oct 2024 18:04:09 +0800 Subject: [PATCH 01/14] =?UTF-8?q?refactor:=E5=B0=81=E8=A3=85native?= =?UTF-8?q?=E6=97=A0=E9=9A=9C=E7=A2=8D=E9=80=9A=E9=81=93,=E9=99=8D?= =?UTF-8?q?=E4=BD=8Ebridge=E7=B1=BB=E4=B8=AD=E4=BB=A3=E7=A0=81=E8=80=A6?= =?UTF-8?q?=E5=90=88,=E6=96=B9=E4=BE=BF=E7=BB=B4=E6=8A=A4=E6=8B=93?= =?UTF-8?q?=E5=B1=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zjxi --- shell/platform/ohos/BUILD.gn | 2 + .../native_accessibility_channel.cpp | 92 ++++++++++++++++++ .../native_accessibility_channel.h | 54 +++++++++++ .../ohos_accessibility_bridge.cpp | 97 +++++++++++++------ .../accessibility/ohos_accessibility_bridge.h | 21 ++-- .../ohos_accessibility_features.cpp | 76 ++++++++------- .../ohos_accessibility_features.h | 30 +++--- .../ohos_accessibility_manager.cpp | 24 ++--- .../ohos_accessibility_manager.h | 15 +-- .../src/main/cpp/types/libflutter/index.d.ets | 2 +- .../main/ets/embedding/engine/FlutterNapi.ets | 3 +- .../ets/embedding/ohos/FlutterAbility.ets | 6 +- .../flutter/src/main/ets/view/FlutterView.ets | 2 +- .../ohos/napi/platform_view_ohos_napi.cpp | 64 ++++++++++-- .../ohos/napi/platform_view_ohos_napi.h | 12 ++- shell/platform/ohos/platform_view_ohos.cpp | 5 +- shell/platform/ohos/platform_view_ohos.h | 8 +- 17 files changed, 381 insertions(+), 132 deletions(-) create mode 100644 shell/platform/ohos/accessibility/native_accessibility_channel.cpp create mode 100644 shell/platform/ohos/accessibility/native_accessibility_channel.h diff --git a/shell/platform/ohos/BUILD.gn b/shell/platform/ohos/BUILD.gn index 68bd4bca43..5adde6edeb 100644 --- a/shell/platform/ohos/BUILD.gn +++ b/shell/platform/ohos/BUILD.gn @@ -88,6 +88,7 @@ source_set("flutter_ohos_sources") { "./accessibility/ohos_accessibility_bridge.h", "./accessibility/ohos_accessibility_features.h", "./accessibility/ohos_accessibility_manager.h", + "./accessibility/native_accessibility_channel.h" ] #configs += [ "//flutter/shell/platform/ohos/config:gtk" ] @@ -122,6 +123,7 @@ source_set("flutter_ohos_sources") { "./accessibility/ohos_accessibility_bridge.cpp", "./accessibility/ohos_accessibility_features.cpp", "./accessibility/ohos_accessibility_manager.cpp", + "./accessibility/native_accessibility_channel.cpp" ] # Set flag to stop headers being directly included (library users should not do this) diff --git a/shell/platform/ohos/accessibility/native_accessibility_channel.cpp b/shell/platform/ohos/accessibility/native_accessibility_channel.cpp new file mode 100644 index 0000000000..4beea68300 --- /dev/null +++ b/shell/platform/ohos/accessibility/native_accessibility_channel.cpp @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2024 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 "native_accessibility_channel.h" +#include "flutter/shell/platform/ohos/ohos_shell_holder.h" +#include "flutter/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h" + +namespace flutter { + + NativeAccessibilityChannel::NativeAccessibilityChannel() {} + + NativeAccessibilityChannel::~NativeAccessibilityChannel() {} + + /** + * 通知flutter框架ohos平台无障碍屏幕朗读已开启 + */ + void NativeAccessibilityChannel::OnOhosAccessibilityEnabled(int64_t shellHolderId) + { + FML_DLOG(INFO) << "NativeAccessibilityChannel -> OnOhosAccessibilityEnabled"; + this->SetSemanticsEnabled(shellHolderId, true); + } + + /** + * 通知flutter框架ohos平台无障碍屏幕朗读未开启 + */ + void NativeAccessibilityChannel::OnOhosAccessibilityDisabled(int64_t shellHolderId) + { + FML_DLOG(INFO) << "NativeAccessibilityChannel -> OnOhosAccessibilityDisabled"; + this->SetSemanticsEnabled(shellHolderId, false); + + auto ohosAccessibilityBridge = OhosAccessibilityBridge::GetInstance(); + ohosAccessibilityBridge->ClearFlutterSemanticsCaches(); + FML_DLOG(INFO) << "OnOhosAccessibilityDisabled -> ClearFlutterSemanticsCaches()"; + } + + /** + * Native无障碍通道传递语义感知,若开启则实时更新语义树信息 + */ + void NativeAccessibilityChannel::SetSemanticsEnabled(int64_t shellHolderId, + bool enabled) + { + FML_DLOG(INFO) << "SetSemanticsEnabled -> shellHolderId: " + << shellHolderId; + auto ohos_shell_holder = + reinterpret_cast(shellHolderId); + ohos_shell_holder->GetPlatformView()->SetSemanticsEnabled(enabled); + } + + /** + * Native无障碍通道设置无障碍特征类型,如:无障碍导航、字体加粗等 + */ + void NativeAccessibilityChannel::SetAccessibilityFeatures(int64_t shellHolderId, + int32_t flags) + { + auto ohos_shell_holder = + reinterpret_cast(shellHolderId); + ohos_shell_holder->GetPlatformView()->SetAccessibilityFeatures(flags); + } + + /** + * Native无障碍通道分发flutter屏幕语义动作,如:点击、滑动等 + */ + void NativeAccessibilityChannel::DispatchSemanticsAction( + int64_t shellHolderId, + int32_t id, + flutter::SemanticsAction action, + fml::MallocMapping args) + { + auto ohos_shell_holder = + reinterpret_cast(shellHolderId); + ohos_shell_holder->GetPlatformView()->PlatformView::DispatchSemanticsAction(id, action, fml::MallocMapping()); + } + + void NativeAccessibilityChannel::UpdateSemantics( + flutter::SemanticsNodeUpdates update, + flutter::CustomAccessibilityActionUpdates actions) + { + auto ohos_a11y_bridge = OhosAccessibilityBridge::GetInstance(); + ohos_a11y_bridge->updateSemantics(update, actions); + } +} \ No newline at end of file diff --git a/shell/platform/ohos/accessibility/native_accessibility_channel.h b/shell/platform/ohos/accessibility/native_accessibility_channel.h new file mode 100644 index 0000000000..a2e9053cfc --- /dev/null +++ b/shell/platform/ohos/accessibility/native_accessibility_channel.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2024 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. + */ +#ifndef OHOS_NATIVE_ACCESSIBILITY_CHANNEL_H +#define OHOS_NATIVE_ACCESSIBILITY_CHANNEL_H +#include "flutter/fml/mapping.h" +#include "flutter/lib/ui/semantics/semantics_node.h" +#include "flutter/lib/ui/semantics/custom_accessibility_action.h" +namespace flutter { + +class NativeAccessibilityChannel { + public: + NativeAccessibilityChannel(); + ~NativeAccessibilityChannel(); + + void OnOhosAccessibilityEnabled(int64_t shellHolderId); + + void OnOhosAccessibilityDisabled(int64_t shellHolderId); + + void SetSemanticsEnabled(int64_t shellHolderId, bool enabled); + + void SetAccessibilityFeatures(int64_t shellHolderId, int32_t flags); + + void DispatchSemanticsAction(int64_t shellHolderId, + int32_t id, + flutter::SemanticsAction action, + fml::MallocMapping args); + + void UpdateSemantics(flutter::SemanticsNodeUpdates update, + flutter::CustomAccessibilityActionUpdates actions); + +}; + +class AccessibilityDelegate { + public: + AccessibilityDelegate(); + ~AccessibilityDelegate(); + +}; + +} + +#endif \ No newline at end of file diff --git a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp index 7a8b081d9c..1b2b42df97 100644 --- a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp +++ b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd. + * Copyright (C) 2024 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 @@ -15,6 +15,7 @@ #include "ohos_accessibility_bridge.h" #include #include +#include #include "flutter/fml/logging.h" #include "flutter/shell/common/platform_view.h" #include "flutter/shell/platform/embedder/embedder.h" @@ -26,14 +27,38 @@ namespace flutter { OhosAccessibilityBridge OhosAccessibilityBridge::bridgeInstance; -OhosAccessibilityBridge::OhosAccessibilityBridge() {}; -OhosAccessibilityBridge::~OhosAccessibilityBridge() {}; +OhosAccessibilityBridge::OhosAccessibilityBridge() {} + +OhosAccessibilityBridge::~OhosAccessibilityBridge() {} OhosAccessibilityBridge* OhosAccessibilityBridge::GetInstance() { return &OhosAccessibilityBridge::bridgeInstance; } +/** + * 监听当前ohos平台是否开启无障碍屏幕朗读服务 + */ +void OhosAccessibilityBridge::OnOhosAccessibilityStateChange( + int64_t shellHolderId, + bool ohosAccessibilityEnabled) +{ + native_shell_holder_id_ = shellHolderId; + auto nativeAccessibilityChannel_ = std::make_shared(); + if (ohosAccessibilityEnabled) { + FML_DLOG(INFO) << "OnOhosAccessibilityEnabled()"; + nativeAccessibilityChannel_->OnOhosAccessibilityEnabled(native_shell_holder_id_); + } else { + FML_DLOG(INFO) << "OnOhosAccessibilityEnabled()"; + nativeAccessibilityChannel_->OnOhosAccessibilityDisabled(native_shell_holder_id_); + } +} + +void OhosAccessibilityBridge::SetNativeShellHolderId(int64_t id) +{ + this->native_shell_holder_id_ = id; +} + /** * 当页面状态更新事件,在页面转换、切换、调整大小时发送页面状态更新事件 */ @@ -144,6 +169,7 @@ void OhosAccessibilityBridge::updateSemantics( if (node.HasFlag(FLAGS_::kIsHidden)) { continue; } + // 判断flutter节点是否获焦 if (IsNodeFocusable(node)) { FML_DLOG(INFO) << "UpdateSemantics -> flutterNode is focusable, node.id=" @@ -579,7 +605,7 @@ void OhosAccessibilityBridge::ConvertChildRelativeRectToScreenRect( // 获取root节点的绝对坐标 auto _rootRect = GetAbsoluteScreenRect(0); - auto rootRight = _rootRect.second.first; + // auto rootRight = _rootRect.second.first; auto rootBottom = _rootRect.second.second; // 真实缩放系数 @@ -628,9 +654,11 @@ void OhosAccessibilityBridge::ConvertChildRelativeRectToScreenRect( << currNode.id << ", (" << newLeft << ", " << newTop << ", " << newRight << ", " << newBottom << ")}"; // 防止溢出屏幕坐标 - newTop = realParentTop - rootRight; - newBottom = realParentBottom - rootBottom; - SetAbsoluteScreenRect(currNode.id, newLeft, newTop, realParentRight, + newTop = realParentTop - rootBottom; + newBottom = realParentBottom - rootBottom; + // newTop = static_cast(newTop) % static_cast(rootBottom); + // newBottom = static_cast(newBottom) % static_cast(rootBottom); + SetAbsoluteScreenRect(currNode.id, newLeft, newTop, newRight, newBottom); } else { SetAbsoluteScreenRect(currNode.id, newLeft, newTop, newRight, newBottom); @@ -860,9 +888,9 @@ void OhosAccessibilityBridge::FlutterSetElementInfoProperties( ArkUI_AccessibleRect rect = {left, top, right, bottom}; OH_ArkUI_AccessibilityElementInfoSetScreenRect(elementInfoFromList, &rect); FML_DLOG(INFO) << "FlutterNodeToElementInfoById -> node.id= " - << flutterNode.id << " SceenRect = (" << left << ", " << top - << ", " << right << ", " << bottom << ")"; - + << flutterNode.id << " SceenRect = (" << left << ", " << top + << ", " << right << ", " << bottom << ")"; + // 配置arkui的elementinfo可操作动作属性 if (IsTextField(flutterNode)) { // 若当前flutter节点为文本输入框组件 @@ -1149,6 +1177,8 @@ int32_t OhosAccessibilityBridge::FindAccessibilityNodeInfosById( return ARKUI_ACCESSIBILITY_NATIVE_RESULT_FAILED; } + auto flutterNode = getOrCreateFlutterSemanticsNode(static_cast(elementId)); + if (mode == ArkUI_AccessibilitySearchMode:: ARKUI_ACCESSIBILITY_NATIVE_SEARCH_MODE_PREFETCH_CURRENT) { /** Search for current nodes. (mode = 0) */ @@ -1156,28 +1186,35 @@ int32_t OhosAccessibilityBridge::FindAccessibilityNodeInfosById( int64_t elementInfoCount = static_cast(flutterSemanticsTree_.size()); for (int64_t i = 1; i < elementInfoCount; i++) { - ArkUI_AccessibilityElementInfo* newElementInfo = + auto childNode = getOrCreateFlutterSemanticsNode(static_cast(i)); + if (IsNodeVisible(childNode)) { + ArkUI_AccessibilityElementInfo* newElementInfo = OH_ArkUI_AddAndGetAccessibilityElementInfo(elementList); - FlutterNodeToElementInfoById(newElementInfo, i); + FlutterNodeToElementInfoById(newElementInfo, i); + } } } else if (mode == ArkUI_AccessibilitySearchMode:: ARKUI_ACCESSIBILITY_NATIVE_SEARCH_MODE_PREFETCH_PREDECESSORS) { /** Search for parent nodes. (mode = 1) */ - FlutterNodeToElementInfoById(elementInfoFromList, elementId); - + if (IsNodeVisible(flutterNode)) { + FlutterNodeToElementInfoById(elementInfoFromList, elementId); + } } else if (mode == ArkUI_AccessibilitySearchMode:: ARKUI_ACCESSIBILITY_NATIVE_SEARCH_MODE_PREFETCH_SIBLINGS) { /** Search for sibling nodes. (mode = 2) */ - FlutterNodeToElementInfoById(elementInfoFromList, elementId); - + if (IsNodeVisible(flutterNode)) { + FlutterNodeToElementInfoById(elementInfoFromList, elementId); + } } else if (mode == ArkUI_AccessibilitySearchMode:: ARKUI_ACCESSIBILITY_NATIVE_SEARCH_MODE_PREFETCH_CHILDREN) { /** Search for child nodes at the next level. (mode = 4) */ - FlutterNodeToElementInfoById(elementInfoFromList, elementId); + if (IsNodeVisible(flutterNode)) { + FlutterNodeToElementInfoById(elementInfoFromList, elementId); + } } else if ( mode == @@ -1188,13 +1225,18 @@ int32_t OhosAccessibilityBridge::FindAccessibilityNodeInfosById( int64_t elementInfoCount = static_cast(flutterSemanticsTree_.size()); for (int64_t i = 1; i < elementInfoCount; i++) { - ArkUI_AccessibilityElementInfo* newElementInfo = + auto childNode = getOrCreateFlutterSemanticsNode(static_cast(i)); + if (IsNodeVisible(childNode)) { + ArkUI_AccessibilityElementInfo* newElementInfo = OH_ArkUI_AddAndGetAccessibilityElementInfo(elementList); - FlutterNodeToElementInfoById(newElementInfo, i); + FlutterNodeToElementInfoById(newElementInfo, i); + } } } else { - FlutterNodeToElementInfoById(elementInfoFromList, elementId); + if (IsNodeVisible(flutterNode)) { + FlutterNodeToElementInfoById(elementInfoFromList, elementId); + } } FML_DLOG(INFO) << "--- FindAccessibilityNodeInfosById is end ---"; @@ -1304,21 +1346,18 @@ flutter::SemanticsAction OhosAccessibilityBridge::ArkuiActionsToFlutterActions( } /** - * covert arkui-specific touch action to flutter-specific action - * and dispatch it from C++ to Dart + * 解析flutter语义动作,并通过NativAccessibilityChannel分发 */ void OhosAccessibilityBridge::DispatchSemanticsAction( int32_t id, flutter::SemanticsAction action, fml::MallocMapping args) { - auto ohos_shell_holder = - reinterpret_cast(nativeShellHolder_); - ohos_shell_holder->GetPlatformView()->PlatformView::DispatchSemanticsAction( - id, action, {}); - FML_DLOG(INFO) << "DispatchSemanticsAction -> shell_holder_id: " - << nativeShellHolder_ << " id: " << id - << " action: " << static_cast(action); + auto nativeAccessibilityChannel_ = std::make_shared(); + nativeAccessibilityChannel_->DispatchSemanticsAction(native_shell_holder_id_, + id, + action, + fml::MallocMapping()); } /** diff --git a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h index 602df9370b..34880ea8d6 100644 --- a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h +++ b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd. + * Copyright (C) 2024 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 @@ -12,21 +12,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - #ifndef OHOS_ACCESSIBILITY_BRIDGE_H #define OHOS_ACCESSIBILITY_BRIDGE_H #include #include #include -#include +#include #include #include #include "flutter/fml/mapping.h" #include "flutter/lib/ui/semantics/custom_accessibility_action.h" #include "flutter/lib/ui/semantics/semantics_node.h" -#include "flutter/shell/platform/ohos/accessibility/ohos_accessibility_manager.h" -#include "flutter/shell/platform/ohos/napi/platform_view_ohos_napi.h" - +#include "native_accessibility_channel.h" namespace flutter { typedef flutter::SemanticsFlags FLAGS_; @@ -69,11 +66,16 @@ class OhosAccessibilityBridge { static OhosAccessibilityBridge* GetInstance(); - bool isOhosAccessibilityEnabled_; bool IS_FLUTTER_NAVIGATE = false; - int64_t nativeShellHolder_; + int64_t native_shell_holder_id_; ArkUI_AccessibilityProvider* provider_; + void OnOhosAccessibilityStateChange( + int64_t shellHolderId, + bool ohosAccessibilityEnabled); + + void SetNativeShellHolderId(int64_t id); + void updateSemantics(flutter::SemanticsNodeUpdates update, flutter::CustomAccessibilityActionUpdates actions); @@ -143,6 +145,8 @@ class OhosAccessibilityBridge { private: static OhosAccessibilityBridge bridgeInstance; + std::shared_ptr nativeAccessibilityChannel_; + static const int32_t ROOT_NODE_ID = 0; constexpr static const double SCROLL_EXTENT_FOR_INFINITY = 100000.0; constexpr static const double SCROLL_POSITION_CAP_FOR_INFINITY = 70000.0; @@ -151,7 +155,6 @@ class OhosAccessibilityBridge { flutter::SemanticsNode lastInputFocusedNode; flutter::SemanticsNode accessibilityFocusedNode; - std::shared_ptr ax_manager_; std::vector> parentChildIdVec; std::unordered_map flutterSemanticsTree_; std::unordered_map< diff --git a/shell/platform/ohos/accessibility/ohos_accessibility_features.cpp b/shell/platform/ohos/accessibility/ohos_accessibility_features.cpp index caea517fee..3e0b16b1b7 100644 --- a/shell/platform/ohos/accessibility/ohos_accessibility_features.cpp +++ b/shell/platform/ohos/accessibility/ohos_accessibility_features.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd. + * Copyright (C) 2024 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 @@ -12,47 +12,51 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "flutter/shell/platform/ohos/accessibility/ohos_accessibility_features.h" -#include "flutter/shell/platform/ohos/ohos_shell_holder.h" +#include "ohos_accessibility_features.h" #include "flutter/fml/logging.h" +#include "flutter/shell/platform/ohos/ohos_shell_holder.h" namespace flutter { - OhosAccessibilityFeatures OhosAccessibilityFeatures::instance; +OhosAccessibilityFeatures OhosAccessibilityFeatures::instance; - OhosAccessibilityFeatures::OhosAccessibilityFeatures() {}; - OhosAccessibilityFeatures::~OhosAccessibilityFeatures() {}; - - OhosAccessibilityFeatures* OhosAccessibilityFeatures::GetInstance() { - return &OhosAccessibilityFeatures::instance; - } +OhosAccessibilityFeatures::OhosAccessibilityFeatures() {}; +OhosAccessibilityFeatures::~OhosAccessibilityFeatures() {}; - /** - * bold text for AccessibilityFeature - */ - void OhosAccessibilityFeatures::SetBoldText(double fontWeightScale, int64_t shell_holder_id) { - bool shouldBold = fontWeightScale > 1.0; +OhosAccessibilityFeatures* OhosAccessibilityFeatures::GetInstance() { + return &OhosAccessibilityFeatures::instance; +} - if (shouldBold) { - accessibilityFeatureFlags |= static_cast(flutter::AccessibilityFeatureFlag::kBoldText); - FML_DLOG(INFO) << "SetBoldText -> accessibilityFeatureFlags: "< 1.0; + + if (shouldBold) { + accessibilityFeatureFlags |= + static_cast(flutter::AccessibilityFeatureFlag::kBoldText); + FML_DLOG(INFO) << "SetBoldText -> accessibilityFeatureFlags: " + << accessibilityFeatureFlags; + } else { + accessibilityFeatureFlags &= + static_cast(flutter::AccessibilityFeatureFlag::kBoldText); + } - } else { - accessibilityFeatureFlags &= static_cast(flutter::AccessibilityFeatureFlag::kBoldText); - } + SendAccessibilityFlags(shell_holder_id); +} - SendAccessibilityFlags(shell_holder_id); - } - - /** - * send the accessibility flags to flutter dart sdk - */ - void OhosAccessibilityFeatures::SendAccessibilityFlags(int64_t shell_holder_id) { - auto ohos_shell_holder = reinterpret_cast(shell_holder_id); - ohos_shell_holder->GetPlatformView()->PlatformView::SetAccessibilityFeatures(accessibilityFeatureFlags); - FML_DLOG(INFO) << "SendAccessibilityFlags -> accessibilityFeatureFlags = " - << accessibilityFeatureFlags; - accessibilityFeatureFlags = 0; - } - -} \ No newline at end of file +/** + * send the accessibility flags to flutter dart sdk + */ +void OhosAccessibilityFeatures::SendAccessibilityFlags( + int64_t shell_holder_id) { + auto nativeAccessibilityChannel_ = std::make_shared(); + nativeAccessibilityChannel_->SetAccessibilityFeatures(shell_holder_id, accessibilityFeatureFlags); + FML_DLOG(INFO) << "SendAccessibilityFlags -> accessibilityFeatureFlags = " + << accessibilityFeatureFlags; + accessibilityFeatureFlags = 0; +} + +} // namespace flutter \ No newline at end of file diff --git a/shell/platform/ohos/accessibility/ohos_accessibility_features.h b/shell/platform/ohos/accessibility/ohos_accessibility_features.h index 093e89ce11..af271318e1 100644 --- a/shell/platform/ohos/accessibility/ohos_accessibility_features.h +++ b/shell/platform/ohos/accessibility/ohos_accessibility_features.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd. + * Copyright (C) 2024 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 @@ -16,28 +16,28 @@ #define OHOS_ACCESSIBILITY_FEATURES_H #include #include "flutter/lib/ui/window/platform_configuration.h" +#include "native_accessibility_channel.h" #include "flutter/shell/platform/ohos/napi/platform_view_ohos_napi.h" namespace flutter { class OhosAccessibilityFeatures { - public: - OhosAccessibilityFeatures(); - ~OhosAccessibilityFeatures(); + public: + OhosAccessibilityFeatures(); + ~OhosAccessibilityFeatures(); - static OhosAccessibilityFeatures* GetInstance(); + static OhosAccessibilityFeatures* GetInstance(); - void SetBoldText(double fontWeightScale, int64_t shell_holder_id); - void SendAccessibilityFlags(int64_t shell_holder_id); + void SetBoldText(double fontWeightScale, int64_t shell_holder_id); + void SendAccessibilityFlags(int64_t shell_holder_id); - private: - static OhosAccessibilityFeatures instance; + private: + static OhosAccessibilityFeatures instance; + std::shared_ptr nativeAccessibilityChannel_; - // Font weight adjustment (FontWeight.Bold - FontWeight.Normal = w700 - w400 = 300) - static const int32_t BOLD_TEXT_WEIGHT_ADJUSTMENT = 300; - int32_t accessibilityFeatureFlags = 0; + int32_t accessibilityFeatureFlags = 0; }; - -} -#endif \ No newline at end of file +} // namespace flutter + +#endif \ No newline at end of file diff --git a/shell/platform/ohos/accessibility/ohos_accessibility_manager.cpp b/shell/platform/ohos/accessibility/ohos_accessibility_manager.cpp index 9e63609765..d88a5acaf0 100644 --- a/shell/platform/ohos/accessibility/ohos_accessibility_manager.cpp +++ b/shell/platform/ohos/accessibility/ohos_accessibility_manager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd. + * Copyright (C) 2024 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 @@ -12,23 +12,25 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "flutter/shell/platform/ohos/accessibility/ohos_accessibility_manager.h" -#include "flutter/fml/logging.h" +#include "ohos_accessibility_manager.h" namespace flutter { -OhosAccessibilityManager::OhosAccessibilityManager() {}; -OhosAccessibilityManager::~OhosAccessibilityManager() {}; -void OhosAccessibilityManager::onAccessibilityStateChanged( - bool isOhosAccessibilityEnabled) {}; +OhosAccessibilityManager::OhosAccessibilityManager() {} -void OhosAccessibilityManager::setOhosAccessibilityEnabled(bool isEnabled) { - FML_DLOG(INFO) << "OhosAccessibilityManager::setOhosAccessibilityEnabled = " - << isEnabled; +OhosAccessibilityManager::~OhosAccessibilityManager() {} + +/** + * 监听ohos平台是否开启无障碍屏幕朗读功能 + */ +void OhosAccessibilityManager::OnAccessibilityStateChanged( + bool ohosAccessibilityEnabled) {} + +void OhosAccessibilityManager::SetOhosAccessibilityEnabled(bool isEnabled) { this->isOhosAccessibilityEnabled_ = isEnabled; } -bool OhosAccessibilityManager::getOhosAccessibilityEnabled() { +bool OhosAccessibilityManager::GetOhosAccessibilityEnabled() { return this->isOhosAccessibilityEnabled_; } diff --git a/shell/platform/ohos/accessibility/ohos_accessibility_manager.h b/shell/platform/ohos/accessibility/ohos_accessibility_manager.h index d32e76173e..3e37c59e0e 100644 --- a/shell/platform/ohos/accessibility/ohos_accessibility_manager.h +++ b/shell/platform/ohos/accessibility/ohos_accessibility_manager.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd. + * Copyright (C) 2024 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 @@ -14,7 +14,7 @@ */ #ifndef OHOS_ACCESSIBILITY_MANAGER_H #define OHOS_ACCESSIBILITY_MANAGER_H - +#include namespace flutter { /** @@ -25,12 +25,13 @@ class OhosAccessibilityManager { OhosAccessibilityManager(); ~OhosAccessibilityManager(); - void onAccessibilityStateChanged(bool isOhosAccessibilityEnabled); - bool getOhosAccessibilityEnabled(); - void setOhosAccessibilityEnabled(bool isEnabled); + bool isOhosAccessibilityEnabled_; + + void OnAccessibilityStateChanged(bool ohosAccessibilityEnabled); + + bool GetOhosAccessibilityEnabled(); - private: - bool isOhosAccessibilityEnabled_ = false; + void SetOhosAccessibilityEnabled(bool isEnabled); }; } // namespace flutter 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 6786bedf54..3090d45f58 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 @@ -146,7 +146,7 @@ export const nativeSetTextureBufferSize: (nativeShellHolderId: number, textureId */ export const nativeSetAccessibilityFeatures: (accessibilityFeatureFlags: number, responseId: number) => void; -export const nativeAccessibilityStateChange: (state: Boolean) => void; +export const nativeAccessibilityStateChange: (nativeShellHolderId: number, state: Boolean) => void; export const nativeAnnounce: (message: string) => 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 e95bdfbf4b..741f5a8290 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 @@ -389,7 +389,7 @@ export default class FlutterNapi { this.accessibilityDelegate.accessibilityStateChange(state); } Log.d(TAG, "accessibilityStateChange is called"); - flutter.nativeAccessibilityStateChange(state); + flutter.nativeAccessibilityStateChange(this.nativeShellHolderId!, state); } setLocalizationPlugin(localizationPlugin: LocalizationPlugin | null): void { @@ -523,6 +523,7 @@ export default class FlutterNapi { } } + //native c++ get the shell holder id getShellHolderId(): void { this.ensureRunningOnMainThread(); if (this.isAttached()) { diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterAbility.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterAbility.ets index 8a336a5297..869e9148fa 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterAbility.ets +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterAbility.ets @@ -37,7 +37,6 @@ import FlutterManager from './FlutterManager'; import { FlutterView } from '../../view/FlutterView'; import ApplicationInfoLoader from '../engine/loader/ApplicationInfoLoader'; import { accessibility } from '@kit.AccessibilityKit'; -import { AccessibilityManager } from '../../view/AccessibilityBridge'; const TAG = "FlutterAbility"; const EVENT_BACK_PRESS = 'EVENT_BACK_PRESS'; @@ -53,7 +52,6 @@ export class FlutterAbility extends UIAbility implements Host { private flutterView: FlutterView | null = null; private mainWindow?: window.Window | null; private errorManagerId:number = 0; - private accessibilityManager?: AccessibilityManager | null; getFlutterView(): FlutterView | null { return this.flutterView; @@ -116,11 +114,9 @@ export class FlutterAbility extends UIAbility implements Host { //冷启动对os是否开启无障碍服务进行查询 let accessibilityState: boolean = accessibility.isOpenAccessibilitySync(); if(accessibilityState) { - this.delegate?.getFlutterNapi()?.setSemanticsEnabled(accessibilityState); + this.delegate?.getFlutterNapi()?.accessibilityStateChange(accessibilityState); } Log.i(TAG, `accessibility isOpen state -> ${JSON.stringify(accessibilityState)}`); - - this.accessibilityManager = new AccessibilityManager(); } onDestroy() { 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 6f682d78c2..800761001d 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 @@ -154,7 +154,7 @@ export class FlutterView { //监听系统无障碍服务状态改变 accessibility.on('accessibilityStateChange', (data: boolean) => { Log.i(TAG, `subscribe accessibility state change, result: ${JSON.stringify(data)}`); - this.flutterEngine?.getFlutterNapi()?.setSemanticsEnabled(data); + this.flutterEngine?.getFlutterNapi()?.accessibilityStateChange(data); }); this.systemAvoidArea = this.mainWindow?.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM); this.navigationAvoidArea = this.mainWindow?.getWindowAvoidArea(window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR); diff --git a/shell/platform/ohos/napi/platform_view_ohos_napi.cpp b/shell/platform/ohos/napi/platform_view_ohos_napi.cpp index 18977911e5..e56df51cc5 100644 --- a/shell/platform/ohos/napi/platform_view_ohos_napi.cpp +++ b/shell/platform/ohos/napi/platform_view_ohos_napi.cpp @@ -39,6 +39,7 @@ namespace flutter { napi_env PlatformViewOHOSNapi::env_; std::vector PlatformViewOHOSNapi::system_languages; +int64_t PlatformViewOHOSNapi::napi_shell_holder_id_; /** * @brief send empty PlatformMessage @@ -507,6 +508,15 @@ napi_value PlatformViewOHOSNapi::nativeAttach(napi_env env, } } +void PlatformViewOHOSNapi::GetShellHolderId() { + FML_DLOG(INFO) << "GetShellHolderId"; + napi_status status = fml::napi::InvokeJsMethod(env_, ref_napi_obj_, + "getShellHolderId", 0, nullptr); + if (status != napi_ok) { + FML_DLOG(ERROR) << "InvokeJsMethod getShellHolderId fail "; + } +} + /** * 加载dart工程构建产物 */ @@ -1836,6 +1846,7 @@ napi_value PlatformViewOHOSNapi::nativeUpdateCustomAccessibilityActions( return nullptr; } + /** * 监听获取系统的无障碍服务是否开启 */ @@ -1843,8 +1854,8 @@ napi_value PlatformViewOHOSNapi::nativeAccessibilityStateChange( napi_env env, napi_callback_info info) { napi_status ret; - size_t argc = 1; - napi_value args[1] = {nullptr}; + size_t argc = 2; + napi_value args[2] = {nullptr}; ret = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); if (ret != napi_ok) { FML_DLOG(ERROR) << "PlatformViewOHOSNapi::nativeAccessibilityStateChange " @@ -1852,8 +1863,16 @@ napi_value PlatformViewOHOSNapi::nativeAccessibilityStateChange( << ret; return nullptr; } + int64_t shell_holder_id; + ret = napi_get_value_int64(env, args[0], &shell_holder_id); + if (ret != napi_ok) { + FML_DLOG(ERROR) << "PlatformViewOHOSNapi::nativeAccessibilityStateChange " + "napi_get_value_int64 error:" + << ret; + return nullptr; + } bool state = false; - ret = napi_get_value_bool(env, args[0], &state); + ret = napi_get_value_bool(env, args[1], &state); if (ret != napi_ok) { FML_DLOG(ERROR) << "PlatformViewOHOSNapi::nativeAccessibilityStateChange " "napi_get_value_bool error:" @@ -1864,10 +1883,12 @@ napi_value PlatformViewOHOSNapi::nativeAccessibilityStateChange( "PlatformViewOHOSNapi::nativeAccessibilityStateChange state is: " "%{public}s", (state ? "true" : "false")); - // 传递到无障碍管理类 - auto ohosAccessibilityBridge = OhosAccessibilityBridge::GetInstance(); - ohosAccessibilityBridge->isOhosAccessibilityEnabled_ = state; + //send to accessibility bridge + auto a11y_bridge = OhosAccessibilityBridge::GetInstance(); + a11y_bridge->OnOhosAccessibilityStateChange(shell_holder_id, state); + FML_DLOG(INFO) << "nativeAccessibilityStateChange: state=" << state + << " shell_holder_id=" << shell_holder_id; return nullptr; } @@ -1932,7 +1953,7 @@ napi_value PlatformViewOHOSNapi::nativeSetSemanticsEnabled(napi_env env, napi_ca //给无障碍bridge传递nativeShellHolderId auto ohosAccessibilityBridge = OhosAccessibilityBridge::GetInstance(); - ohosAccessibilityBridge->nativeShellHolder_ = shell_holder; + ohosAccessibilityBridge->native_shell_holder_id_ = shell_holder; FML_DLOG(INFO) << "PlatformViewOHOSNapi::nativeSetSemanticsEnabled -> shell_holder:"<nativeShellHolder_ = shell_holder; - FML_DLOG(INFO) << "PlatformViewOHOSNapi::nativeGetShellHolderId -> shell_holder:"< shell_holder:"<GetPlatformView()->SetSemanticsEnabled(enabled); +} + +void PlatformViewOHOSNapi::DispatchSemanticsAction( + int64_t shell_holder, + int32_t id, + flutter::SemanticsAction action, + fml::MallocMapping args) +{ + OHOS_SHELL_HOLDER->GetPlatformView()->PlatformView::DispatchSemanticsAction(id, action, fml::MallocMapping()); +} + +void PlatformViewOHOSNapi::SetAccessibilityFeatures(int64_t shell_holder, + int32_t flags) +{ + OHOS_SHELL_HOLDER->GetPlatformView()->SetAccessibilityFeatures(flags); +} + napi_value PlatformViewOHOSNapi::nativeLookupCallbackInformation(napi_env env, napi_callback_info info) { napi_value result; diff --git a/shell/platform/ohos/napi/platform_view_ohos_napi.h b/shell/platform/ohos/napi/platform_view_ohos_napi.h index f1aeac3bb5..8c576f3403 100644 --- a/shell/platform/ohos/napi/platform_view_ohos_napi.h +++ b/shell/platform/ohos/napi/platform_view_ohos_napi.h @@ -28,7 +28,6 @@ #include "flutter/shell/common/run_configuration.h" #include "flutter/shell/platform/ohos/napi_common.h" #include "napi/native_api.h" -#include "flutter/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h" #include "flutter/shell/platform/ohos/accessibility/ohos_accessibility_features.h" // class for all c++ to call js function @@ -87,6 +86,16 @@ class PlatformViewOHOSNapi { void FlutterViewOnTouchEvent(std::shared_ptr touchPacketString, int size); + /** + * accessibility-relevant interfaces + */ + void GetShellHolderId(); + void SetSemanticsEnabled(int64_t shell_hoder, bool enabled); + void SetAccessibilityFeatures(int64_t shell_hoder, int32_t flags); + void DispatchSemanticsAction(int64_t shell_hoder, + int32_t id, + flutter::SemanticsAction action, + fml::MallocMapping args); static napi_value nativeUpdateRefreshRate( napi_env env, @@ -236,6 +245,7 @@ class PlatformViewOHOSNapi { napi_ref ref_napi_obj_; static std::vector system_languages; fml::RefPtr platform_task_runner_; + static int64_t napi_shell_holder_id_; }; } // namespace flutter diff --git a/shell/platform/ohos/platform_view_ohos.cpp b/shell/platform/ohos/platform_view_ohos.cpp index 212c3274ec..9ed695758f 100644 --- a/shell/platform/ohos/platform_view_ohos.cpp +++ b/shell/platform/ohos/platform_view_ohos.cpp @@ -25,7 +25,6 @@ #include "ohos_external_texture_gl.h" #include "ohos_logging.h" #include "flutter/shell/platform/ohos/platform_view_ohos_delegate.h" - #include namespace flutter { @@ -300,8 +299,8 @@ void PlatformViewOHOS::UpdateSemantics( flutter::SemanticsNodeUpdates update, flutter::CustomAccessibilityActionUpdates actions) { FML_DLOG(INFO) << "PlatformViewOHOS::UpdateSemantics is called"; - auto ax_bridge_delegate_ = OhosAccessibilityBridge::GetInstance(); - ax_bridge_delegate_->updateSemantics(update, actions); + auto nativeAccessibilityChannel_ = std::make_shared(); + nativeAccessibilityChannel_->UpdateSemantics(update, actions); } // |PlatformView| diff --git a/shell/platform/ohos/platform_view_ohos.h b/shell/platform/ohos/platform_view_ohos.h index dac7916885..cca65a2fc5 100644 --- a/shell/platform/ohos/platform_view_ohos.h +++ b/shell/platform/ohos/platform_view_ohos.h @@ -36,7 +36,8 @@ #include "flutter/shell/platform/ohos/surface/ohos_surface.h" #include "flutter/shell/platform/ohos/vsync_waiter_ohos.h" #include "flutter/shell/platform/ohos/platform_view_ohos_delegate.h" -#include "flutter/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h" +#include "flutter/shell/platform/ohos/accessibility/native_accessibility_channel.h" + namespace flutter { class OhosSurfaceFactoryImpl : public OhosSurfaceFactory { @@ -135,6 +136,9 @@ class PlatformViewOHOS final : public PlatformView { const std::shared_ptr napi_facade_; std::shared_ptr ohos_context_; + std::shared_ptr platform_view_ohos_delegate_; + NativeAccessibilityChannel nativeAccessibilityChannel_; + std::shared_ptr ohos_surface_; std::shared_ptr platform_message_handler_; @@ -142,8 +146,6 @@ class PlatformViewOHOS final : public PlatformView { std::map> external_texture_gl_; std::map contextDatas_; - std::shared_ptr platform_view_ohos_delegate_; - std::atomic isDestroyed_; bool GetDestroyed(); -- Gitee From 9443bc48199ae0aded209b3020033deeb20aa172 Mon Sep 17 00:00:00 2001 From: zjxi Date: Wed, 30 Oct 2024 19:30:54 +0800 Subject: [PATCH 02/14] =?UTF-8?q?fix:=E6=97=A0=E9=9A=9C=E7=A2=8D=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E5=8C=96=E6=B5=8B=E8=AF=95=E8=81=94=E8=B0=83=E9=9C=80?= =?UTF-8?q?=E8=A6=81=E5=A2=9E=E5=8A=A0setcontent=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E8=8C=83=E5=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zjxi --- .../ohos/accessibility/ohos_accessibility_bridge.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp index 1b2b42df97..d1a2ddd5a6 100644 --- a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp +++ b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp @@ -45,12 +45,14 @@ void OhosAccessibilityBridge::OnOhosAccessibilityStateChange( { native_shell_holder_id_ = shellHolderId; auto nativeAccessibilityChannel_ = std::make_shared(); + if (ohosAccessibilityEnabled) { FML_DLOG(INFO) << "OnOhosAccessibilityEnabled()"; nativeAccessibilityChannel_->OnOhosAccessibilityEnabled(native_shell_holder_id_); } else { FML_DLOG(INFO) << "OnOhosAccessibilityEnabled()"; nativeAccessibilityChannel_->OnOhosAccessibilityDisabled(native_shell_holder_id_); + ClearFlutterSemanticsCaches(); } } @@ -656,8 +658,6 @@ void OhosAccessibilityBridge::ConvertChildRelativeRectToScreenRect( // 防止溢出屏幕坐标 newTop = realParentTop - rootBottom; newBottom = realParentBottom - rootBottom; - // newTop = static_cast(newTop) % static_cast(rootBottom); - // newBottom = static_cast(newBottom) % static_cast(rootBottom); SetAbsoluteScreenRect(currNode.id, newLeft, newTop, newRight, newBottom); } else { @@ -737,6 +737,7 @@ void OhosAccessibilityBridge::FlutterNodeToElementInfoById( OH_ArkUI_AccessibilityElementInfoSetClickable(elementInfoFromList, true); OH_ArkUI_AccessibilityElementInfoSetComponentType(elementInfoFromList, "root"); + OH_ArkUI_AccessibilityElementInfoSetContents(elementInfoFromList, "root_content"); return; } @@ -924,7 +925,8 @@ void OhosAccessibilityBridge::FlutterSetElementInfoProperties( text.c_str()); FML_DLOG(INFO) << "FlutterNodeToElementInfoById SetAccessibilityText = " << text; - + //set contents (same as AccessibilityText) + OH_ArkUI_AccessibilityElementInfoSetContents(elementInfoFromList, text.c_str()); std::string hint = flutterNode.hint; OH_ArkUI_AccessibilityElementInfoSetHintText(elementInfoFromList, hint.c_str()); -- Gitee From 3d34c3845ea16714ef365ce2ce8c71db8ca4ef82 Mon Sep 17 00:00:00 2001 From: zjxi Date: Wed, 30 Oct 2024 20:52:01 +0800 Subject: [PATCH 03/14] =?UTF-8?q?feat:=E5=A2=9E=E5=8A=A0=E6=97=A0=E9=9A=9C?= =?UTF-8?q?=E7=A2=8D=E9=80=9A=E9=81=93=E5=86=85=E9=83=A8=E7=B1=BB,?= =?UTF-8?q?=E4=BF=AE=E6=94=B9setcontent=E5=86=85=E5=AE=B9,=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E9=80=9A=E9=81=93=E8=81=8C=E8=B4=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zjxi --- .../native_accessibility_channel.cpp | 28 +++++++++++++++---- .../native_accessibility_channel.h | 21 ++++++++++---- .../ohos_accessibility_bridge.cpp | 4 +-- .../accessibility/ohos_accessibility_bridge.h | 3 +- .../ohos/napi/platform_view_ohos_napi.cpp | 4 +-- 5 files changed, 42 insertions(+), 18 deletions(-) diff --git a/shell/platform/ohos/accessibility/native_accessibility_channel.cpp b/shell/platform/ohos/accessibility/native_accessibility_channel.cpp index 4beea68300..1d3e8a7a3a 100644 --- a/shell/platform/ohos/accessibility/native_accessibility_channel.cpp +++ b/shell/platform/ohos/accessibility/native_accessibility_channel.cpp @@ -38,10 +38,6 @@ namespace flutter { { FML_DLOG(INFO) << "NativeAccessibilityChannel -> OnOhosAccessibilityDisabled"; this->SetSemanticsEnabled(shellHolderId, false); - - auto ohosAccessibilityBridge = OhosAccessibilityBridge::GetInstance(); - ohosAccessibilityBridge->ClearFlutterSemanticsCaches(); - FML_DLOG(INFO) << "OnOhosAccessibilityDisabled -> ClearFlutterSemanticsCaches()"; } /** @@ -50,8 +46,6 @@ namespace flutter { void NativeAccessibilityChannel::SetSemanticsEnabled(int64_t shellHolderId, bool enabled) { - FML_DLOG(INFO) << "SetSemanticsEnabled -> shellHolderId: " - << shellHolderId; auto ohos_shell_holder = reinterpret_cast(shellHolderId); ohos_shell_holder->GetPlatformView()->SetSemanticsEnabled(enabled); @@ -82,6 +76,9 @@ namespace flutter { ohos_shell_holder->GetPlatformView()->PlatformView::DispatchSemanticsAction(id, action, fml::MallocMapping()); } + /** + * 更新flutter无障碍相关语义信息 + */ void NativeAccessibilityChannel::UpdateSemantics( flutter::SemanticsNodeUpdates update, flutter::CustomAccessibilityActionUpdates actions) @@ -89,4 +86,23 @@ namespace flutter { auto ohos_a11y_bridge = OhosAccessibilityBridge::GetInstance(); ohos_a11y_bridge->updateSemantics(update, actions); } + + /** + * 设置无障碍消息处理器,通过无障碍通道发送处理dart侧传递的相关信息 + */ + void NativeAccessibilityChannel::SetAccessibilityMessageHandler( + std::shared_ptr handler) + { + this->handler = handler; + } + + /** + * 利用通道内部类AccessibilityMessageHandler处理主动播报事件 + */ + void NativeAccessibilityChannel::AccessibilityMessageHandler::Announce( + std::unique_ptr& message) + { + auto ohos_a11y_bridge = OhosAccessibilityBridge::GetInstance(); + ohos_a11y_bridge->Announce(message); + } } \ No newline at end of file diff --git a/shell/platform/ohos/accessibility/native_accessibility_channel.h b/shell/platform/ohos/accessibility/native_accessibility_channel.h index a2e9053cfc..29d6e895c4 100644 --- a/shell/platform/ohos/accessibility/native_accessibility_channel.h +++ b/shell/platform/ohos/accessibility/native_accessibility_channel.h @@ -14,6 +14,7 @@ */ #ifndef OHOS_NATIVE_ACCESSIBILITY_CHANNEL_H #define OHOS_NATIVE_ACCESSIBILITY_CHANNEL_H +#include #include "flutter/fml/mapping.h" #include "flutter/lib/ui/semantics/semantics_node.h" #include "flutter/lib/ui/semantics/custom_accessibility_action.h" @@ -40,15 +41,23 @@ class NativeAccessibilityChannel { void UpdateSemantics(flutter::SemanticsNodeUpdates update, flutter::CustomAccessibilityActionUpdates actions); -}; + class AccessibilityMessageHandler { + public: + void Announce(std::unique_ptr& message); -class AccessibilityDelegate { - public: - AccessibilityDelegate(); - ~AccessibilityDelegate(); + void OnTap(int32_t nodeId); -}; + void OnLongPress(int32_t nodeId); + void OnTooltip(std::unique_ptr& message); + }; + + void SetAccessibilityMessageHandler( + std::shared_ptr handler); + + private: + std::shared_ptr handler; +}; } #endif \ No newline at end of file diff --git a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp index d1a2ddd5a6..c6510d8cda 100644 --- a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp +++ b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp @@ -377,7 +377,7 @@ bool OhosAccessibilityBridge::IsScrollableWidget( /** * 主动播报特定文本 */ -void OhosAccessibilityBridge::announce(std::unique_ptr& message) +void OhosAccessibilityBridge::Announce(std::unique_ptr& message) { // 创建并设置屏幕朗读事件 ArkUI_AccessibilityEventInfo* announceEventInfo = @@ -737,7 +737,7 @@ void OhosAccessibilityBridge::FlutterNodeToElementInfoById( OH_ArkUI_AccessibilityElementInfoSetClickable(elementInfoFromList, true); OH_ArkUI_AccessibilityElementInfoSetComponentType(elementInfoFromList, "root"); - OH_ArkUI_AccessibilityElementInfoSetContents(elementInfoFromList, "root_content"); + OH_ArkUI_AccessibilityElementInfoSetContents(elementInfoFromList, flutterNode.label); return; } diff --git a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h index 34880ea8d6..de11c80125 100644 --- a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h +++ b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h @@ -83,9 +83,8 @@ class OhosAccessibilityBridge { flutter::SemanticsAction action, fml::MallocMapping args); - void announce(std::unique_ptr& message); + void Announce(std::unique_ptr& message); - // obtain the flutter semnatics node flutter::SemanticsNode getOrCreateFlutterSemanticsNode(int32_t id); int32_t FindAccessibilityNodeInfosById( diff --git a/shell/platform/ohos/napi/platform_view_ohos_napi.cpp b/shell/platform/ohos/napi/platform_view_ohos_napi.cpp index e56df51cc5..06a086d5db 100644 --- a/shell/platform/ohos/napi/platform_view_ohos_napi.cpp +++ b/shell/platform/ohos/napi/platform_view_ohos_napi.cpp @@ -1907,8 +1907,8 @@ napi_value PlatformViewOHOSNapi::nativeAnnounce( napi_get_value_string_utf8(env, args[0], char_array.get(), null_terminated_length, nullptr); LOGD("PlatformViewOHOSNapi::nativeAnnounce message: %{public}s", char_array.get()); - auto ohosAccessibilityBridge = OhosAccessibilityBridge::GetInstance(); - ohosAccessibilityBridge->announce(char_array); + auto handler = std::make_shared(); + handler->Announce(char_array); return nullptr; } -- Gitee From a4c84d39823ae318ff31b19ed5465e2fa90b717f Mon Sep 17 00:00:00 2001 From: zjxi Date: Fri, 1 Nov 2024 16:56:02 +0800 Subject: [PATCH 04/14] =?UTF-8?q?fix:=E4=BF=AE=E5=A4=8D=E5=8F=8D=E5=A4=8D?= =?UTF-8?q?=E5=BC=80=E5=85=B3=E5=B1=8F=E5=B9=95=E6=9C=97=E8=AF=BB=EF=BC=8C?= =?UTF-8?q?=E5=AF=BC=E8=87=B4=E7=83=AD=E5=90=AF=E5=8A=A8flutter=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2=E6=97=A0=E6=B3=95=E8=AF=86=E5=88=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zjxi --- .../ohos_accessibility_bridge.cpp | 38 +++++++++---------- .../accessibility/ohos_accessibility_bridge.h | 12 +++--- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp index c6510d8cda..b439c7e258 100644 --- a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp +++ b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp @@ -25,15 +25,21 @@ namespace flutter { -OhosAccessibilityBridge OhosAccessibilityBridge::bridgeInstance; +OhosAccessibilityBridge* OhosAccessibilityBridge::bridgeInstance = nullptr; OhosAccessibilityBridge::OhosAccessibilityBridge() {} -OhosAccessibilityBridge::~OhosAccessibilityBridge() {} - OhosAccessibilityBridge* OhosAccessibilityBridge::GetInstance() { - return &OhosAccessibilityBridge::bridgeInstance; + if(!bridgeInstance) { + bridgeInstance = new OhosAccessibilityBridge(); + } + return bridgeInstance; +} + +void OhosAccessibilityBridge::DestroyInstance() { + delete bridgeInstance; + bridgeInstance = nullptr; } /** @@ -52,7 +58,6 @@ void OhosAccessibilityBridge::OnOhosAccessibilityStateChange( } else { FML_DLOG(INFO) << "OnOhosAccessibilityEnabled()"; nativeAccessibilityChannel_->OnOhosAccessibilityDisabled(native_shell_holder_id_); - ClearFlutterSemanticsCaches(); } } @@ -342,7 +347,6 @@ SemanticsNodeExtent OhosAccessibilityBridge::SetAndGetSemanticsNodeExtent( nodeEx.childrenInHitTestOrder = std::move(node.childrenInHitTestOrder); nodeEx.customAccessibilityActions = std::move(node.customAccessibilityActions); - return nodeEx; } @@ -630,15 +634,7 @@ void OhosAccessibilityBridge::ConvertChildRelativeRectToScreenRect( newRight = realParentRight; newBottom = realParentBottom; } else { - /** - * 子节点的屏幕绝对坐标转换,包括offset偏移值计算、缩放系数变换 (初期版本) - * newLeft = (currLeft + _kMTransX) * realScaleFactor; - * newTop = (currTop + _kMTransY) * realScaleFactor; - * newRight = (currLeft + _kMTransX + currRight) * realScaleFactor; - * newBottom = (currTop + _kMTransY + currBottom) * realScaleFactor; - */ // 子节点的屏幕绝对坐标转换,包括offset偏移值计算、缩放系数变换 - // (增强版本) newLeft = (currLeft + _kMTransX) * realScaleFactor + realParentLeft; newTop = (currTop + _kMTransY) * realScaleFactor + realParentTop; newRight = @@ -717,12 +713,13 @@ void OhosAccessibilityBridge::FlutterNodeToElementInfoById( false); // 配置child节点信息 + auto flutterChildVec = flutterNode.childrenInTraversalOrder; int32_t childCount = - static_cast(flutterNode.childrenInTraversalOrder.size()); + static_cast(flutterChildVec.size()); int64_t childNodeIds[childCount]; for (int32_t i = 0; i < childCount; i++) { childNodeIds[i] = - static_cast(flutterNode.childrenInTraversalOrder[i]); + static_cast(flutterChildVec[i]); FML_DLOG(INFO) << "FlutterNodeToElementInfoById -> elementid=0 childCount=" << childCount << " childNodeIds=" << childNodeIds[i]; @@ -737,7 +734,7 @@ void OhosAccessibilityBridge::FlutterNodeToElementInfoById( OH_ArkUI_AccessibilityElementInfoSetClickable(elementInfoFromList, true); OH_ArkUI_AccessibilityElementInfoSetComponentType(elementInfoFromList, "root"); - OH_ArkUI_AccessibilityElementInfoSetContents(elementInfoFromList, flutterNode.label); + OH_ArkUI_AccessibilityElementInfoSetContents(elementInfoFromList, flutterNode.label.c_str()); return; } @@ -932,12 +929,15 @@ void OhosAccessibilityBridge::FlutterSetElementInfoProperties( hint.c_str()); // set chidren elementinfo ids + auto flutterChildVec = flutterNode.childrenInTraversalOrder; + //按照升序排列孩子数组id + std::sort(flutterChildVec.begin(), flutterChildVec.end()); int32_t childCount = - static_cast(flutterNode.childrenInTraversalOrder.size()); + static_cast(flutterChildVec.size()); int64_t childNodeIds[childCount]; for (int32_t i = 0; i < childCount; i++) { childNodeIds[i] = - static_cast(flutterNode.childrenInTraversalOrder[i]); + static_cast(flutterChildVec[i]); FML_DLOG(INFO) << "FlutterNodeToElementInfoById -> elementid=" << elementId << " childCount=" << childCount << " childNodeIds=" << childNodeIds[i]; diff --git a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h index de11c80125..e9e171c53c 100644 --- a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h +++ b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h @@ -47,7 +47,6 @@ struct AbsoluteRect { struct SemanticsNodeExtent : flutter::SemanticsNode { int32_t parentId = -1; AbsoluteRect abRect = AbsoluteRect::MakeEmpty(); - int32_t previousFlags; int32_t previousActions; int32_t previousTextSelectionBase; @@ -61,10 +60,10 @@ struct SemanticsNodeExtent : flutter::SemanticsNode { class OhosAccessibilityBridge { public: - OhosAccessibilityBridge(); - ~OhosAccessibilityBridge(); - static OhosAccessibilityBridge* GetInstance(); + static void DestroyInstance(); + OhosAccessibilityBridge(const OhosAccessibilityBridge&) = delete; + OhosAccessibilityBridge& operator=(const OhosAccessibilityBridge&) = delete; bool IS_FLUTTER_NAVIGATE = false; int64_t native_shell_holder_id_; @@ -143,7 +142,8 @@ class OhosAccessibilityBridge { void ClearFlutterSemanticsCaches(); private: - static OhosAccessibilityBridge bridgeInstance; + OhosAccessibilityBridge(); + static OhosAccessibilityBridge* bridgeInstance; std::shared_ptr nativeAccessibilityChannel_; static const int32_t ROOT_NODE_ID = 0; @@ -155,7 +155,7 @@ class OhosAccessibilityBridge { flutter::SemanticsNode accessibilityFocusedNode; std::vector> parentChildIdVec; - std::unordered_map flutterSemanticsTree_; + std::map flutterSemanticsTree_; std::unordered_map< int32_t, std::pair, std::pair>> -- Gitee From cfd4d9ce40ef1cebd5947cc91b78af6aa7cc094c Mon Sep 17 00:00:00 2001 From: zjxi Date: Fri, 1 Nov 2024 18:45:53 +0800 Subject: [PATCH 05/14] =?UTF-8?q?fix:=E5=87=8F=E5=B0=91=E9=9D=9E=E5=B1=8F?= =?UTF-8?q?=E5=B9=95=E6=98=BE=E7=A4=BA=E5=8C=BA=E5=9F=9F=E7=9A=84=E8=8A=82?= =?UTF-8?q?=E7=82=B9=E5=88=9B=E5=BB=BA=E9=81=8D=E5=8E=86=E5=BC=80=E9=94=80?= =?UTF-8?q?,=E5=A4=A7=E5=B9=85=E5=BA=A6=E6=8F=90=E5=8D=87=E5=B1=8F?= =?UTF-8?q?=E5=B9=95=E6=9C=97=E8=AF=BB=E6=BB=91=E5=8A=A8=E6=B5=81=E7=95=85?= =?UTF-8?q?=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zjxi --- .../ohos/accessibility/ohos_accessibility_bridge.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp index b439c7e258..00fc3acd23 100644 --- a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp +++ b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp @@ -177,12 +177,6 @@ void OhosAccessibilityBridge::updateSemantics( continue; } - // 判断flutter节点是否获焦 - if (IsNodeFocusable(node)) { - FML_DLOG(INFO) << "UpdateSemantics -> flutterNode is focusable, node.id=" - << node.id; - } - // 获取当前flutter节点的全部子节点数量,并构建父子节点id映射关系 int32_t childNodeCount = node.childrenInTraversalOrder.size(); for (int32_t i = 0; i < childNodeCount; i++) { @@ -1180,6 +1174,9 @@ int32_t OhosAccessibilityBridge::FindAccessibilityNodeInfosById( } auto flutterNode = getOrCreateFlutterSemanticsNode(static_cast(elementId)); + if(!IsNodeVisible(flutterNode)) { + return ARKUI_ACCESSIBILITY_NATIVE_RESULT_FAILED; + } if (mode == ArkUI_AccessibilitySearchMode:: ARKUI_ACCESSIBILITY_NATIVE_SEARCH_MODE_PREFETCH_CURRENT) { @@ -1954,6 +1951,8 @@ void OhosAccessibilityBridge::GetSemanticsFlagsDebugInfo( flutter::SemanticsNode node) { FML_DLOG(INFO) << "----------------SemanticsFlags-------------------------"; + FML_DLOG(INFO) << "node.id=" << node.id; + FML_DLOG(INFO) << "node.label=" << node.label; FML_DLOG(INFO) << "kHasCheckedState: " << node.HasFlag(FLAGS_::kHasCheckedState); FML_DLOG(INFO) << "kIsChecked:" << node.HasFlag(FLAGS_::kIsChecked); -- Gitee From 30023841f861d8f54069af7f3848792adb7cc52d Mon Sep 17 00:00:00 2001 From: zjxi Date: Mon, 4 Nov 2024 15:57:15 +0800 Subject: [PATCH 06/14] =?UTF-8?q?fix:=E8=BF=87=E6=BB=A4=E9=9D=9E=E5=B1=8F?= =?UTF-8?q?=E5=B9=95=E6=98=BE=E7=A4=BA=E7=9A=84=E8=8A=82=E7=82=B9=E5=88=9B?= =?UTF-8?q?=E5=BB=BA=E4=BB=A5=E6=8F=90=E5=8D=87=E6=80=A7=E8=83=BD,?= =?UTF-8?q?=E8=A7=A3=E5=86=B3=E6=BB=91=E5=8A=A8=E7=BB=84=E4=BB=B6=E4=B8=AD?= =?UTF-8?q?=E7=BB=BF=E6=A1=86=E5=9D=90=E6=A0=87=E6=BA=A2=E5=87=BA=E5=B1=8F?= =?UTF-8?q?=E5=B9=95bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zjxi --- .../ohos_accessibility_bridge.cpp | 760 +++++++++--------- .../accessibility/ohos_accessibility_bridge.h | 4 +- 2 files changed, 378 insertions(+), 386 deletions(-) diff --git a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp index 00fc3acd23..1bba43248d 100644 --- a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp +++ b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp @@ -50,7 +50,7 @@ void OhosAccessibilityBridge::OnOhosAccessibilityStateChange( bool ohosAccessibilityEnabled) { native_shell_holder_id_ = shellHolderId; - auto nativeAccessibilityChannel_ = std::make_shared(); + nativeAccessibilityChannel_ = std::make_shared(); if (ohosAccessibilityEnabled) { FML_DLOG(INFO) << "OnOhosAccessibilityEnabled()"; @@ -66,78 +66,6 @@ void OhosAccessibilityBridge::SetNativeShellHolderId(int64_t id) this->native_shell_holder_id_ = id; } -/** - * 当页面状态更新事件,在页面转换、切换、调整大小时发送页面状态更新事件 - */ -void OhosAccessibilityBridge::PageStateUpdate(int64_t elementId) -{ - ArkUI_AccessibilityEventInfo* pageUpdateEventInfo = - OH_ArkUI_CreateAccessibilityEventInfo(); - - ArkUI_AccessibilityElementInfo* _elementInfo = - OH_ArkUI_CreateAccessibilityElementInfo(); - - OH_ArkUI_AccessibilityEventSetEventType( - pageUpdateEventInfo, - ArkUI_AccessibilityEventType:: - ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_ACCESSIBILITY_FOCUS_CLEARED); - FlutterNodeToElementInfoById(_elementInfo, elementId); - OH_ArkUI_AccessibilityEventSetElementInfo(pageUpdateEventInfo, _elementInfo); - - auto callback = [](int32_t errorCode) { - FML_DLOG(WARNING) << "PageStateUpdate callback-> errorCode =" << errorCode; - }; - - if (provider_ == nullptr) { - FML_DLOG(ERROR) << "PageStateUpdate ->" - "AccessibilityProvider = nullptr"; - return; - } - OH_ArkUI_SendAccessibilityAsyncEvent(provider_, pageUpdateEventInfo, - callback); - - OH_ArkUI_DestoryAccessibilityEventInfo(pageUpdateEventInfo); - OH_ArkUI_DestoryAccessibilityElementInfo(_elementInfo); - - FML_DLOG(INFO) << "PageStateUpdate is end"; -} - -/** - * 特定节点的焦点请求 (当页面更新时自动请求id=0节点获焦) - */ -void OhosAccessibilityBridge::RequestFocusWhenPageUpdate() -{ - ArkUI_AccessibilityEventInfo* reqFocusEventInfo = - OH_ArkUI_CreateAccessibilityEventInfo(); - ArkUI_AccessibilityElementInfo* elementInfo = - OH_ArkUI_CreateAccessibilityElementInfo(); - - OH_ArkUI_AccessibilityEventSetEventType( - reqFocusEventInfo, - ArkUI_AccessibilityEventType:: - ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_REQUEST_ACCESSIBILITY_FOCUS); - - int32_t requestFocusId = 0; - OH_ArkUI_AccessibilityEventSetRequestFocusId(reqFocusEventInfo, - requestFocusId); - - OH_ArkUI_AccessibilityEventSetElementInfo(reqFocusEventInfo, elementInfo); - - auto callback = [](int32_t errorCode) { - FML_DLOG(WARNING) << "PageStateUpdate callback-> errorCode =" << errorCode; - }; - - if (provider_ == nullptr) { - FML_DLOG(ERROR) << "PageStateUpdate ->" - "AccessibilityProvider = nullptr"; - return; - } - OH_ArkUI_SendAccessibilityAsyncEvent(provider_, reqFocusEventInfo, callback); - - OH_ArkUI_DestoryAccessibilityEventInfo(reqFocusEventInfo); - OH_ArkUI_DestoryAccessibilityElementInfo(elementInfo); -} - /** * 从dart侧传递到c++侧的flutter无障碍语义树节点更新过程 */ @@ -161,7 +89,7 @@ void OhosAccessibilityBridge::updateSemantics( // set struct SemanticsNodeExtent auto nodeEx = SetAndGetSemanticsNodeExtent(node); - // print semantics node and flags info for debugging + //print semantics node and flags info for debugging GetSemanticsNodeDebugInfo(node); GetSemanticsFlagsDebugInfo(node); @@ -276,7 +204,7 @@ void OhosAccessibilityBridge::FlutterScrollExecution( int visibleChildren = 0; // handle hidden children at the beginning and end of the list. for (const auto& childId : node.childrenInHitTestOrder) { - auto childNode = getOrCreateFlutterSemanticsNode(childId); + auto childNode = GetFlutterSemanticsNode(childId); if (!childNode.HasFlag(FLAGS_::kIsHidden)) { visibleChildren += 1; } @@ -300,76 +228,75 @@ void OhosAccessibilityBridge::FlutterScrollExecution( } /** - * extent common struct SemanticsNode to - * derived struct SemanticsNodeExtent + * 当页面状态更新事件,在页面转换、切换、调整大小时发送页面状态更新事件 */ -SemanticsNodeExtent OhosAccessibilityBridge::SetAndGetSemanticsNodeExtent( - flutter::SemanticsNode node) +void OhosAccessibilityBridge::PageStateUpdate(int64_t elementId) { - SemanticsNodeExtent nodeEx = SemanticsNodeExtent(); - 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.label = std::move(node.label); - nodeEx.labelAttributes = std::move(node.labelAttributes); - nodeEx.hint = std::move(node.hint); - nodeEx.hintAttributes = std::move(node.hintAttributes); - nodeEx.value = std::move(node.value); - nodeEx.valueAttributes = std::move(node.valueAttributes); - nodeEx.increasedValue = std::move(node.increasedValue); - nodeEx.increasedValueAttributes = std::move(node.increasedValueAttributes); - nodeEx.decreasedValue = std::move(node.decreasedValue); - nodeEx.decreasedValueAttributes = std::move(node.decreasedValueAttributes); - nodeEx.tooltip = std::move(node.tooltip); - nodeEx.textDirection = std::move(node.textDirection); + ArkUI_AccessibilityEventInfo* pageUpdateEventInfo = + OH_ArkUI_CreateAccessibilityEventInfo(); - nodeEx.rect = std::move(node.rect); - nodeEx.transform = std::move(node.transform); - nodeEx.childrenInTraversalOrder = std::move(node.childrenInTraversalOrder); - nodeEx.childrenInHitTestOrder = std::move(node.childrenInHitTestOrder); - nodeEx.customAccessibilityActions = - std::move(node.customAccessibilityActions); - return nodeEx; -} + ArkUI_AccessibilityElementInfo* _elementInfo = + OH_ArkUI_CreateAccessibilityElementInfo(); -/** - * 判断当前节点是否已经滑动 - */ -bool OhosAccessibilityBridge::HasScrolled( - const flutter::SemanticsNode& flutterNode) -{ - return flutterNode.scrollPosition != std::nan(""); -} -/** - * 判断是否可滑动 - */ -bool OhosAccessibilityBridge::IsNodeScrollable( - flutter::SemanticsNode flutterNode) -{ - return flutterNode.HasAction(ACTIONS_::kScrollLeft) || - flutterNode.HasAction(ACTIONS_::kScrollRight) || - flutterNode.HasAction(ACTIONS_::kScrollUp) || - flutterNode.HasAction(ACTIONS_::kScrollDown); + OH_ArkUI_AccessibilityEventSetEventType( + pageUpdateEventInfo, + ArkUI_AccessibilityEventType:: + ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_ACCESSIBILITY_FOCUS_CLEARED); + FlutterNodeToElementInfoById(_elementInfo, elementId); + OH_ArkUI_AccessibilityEventSetElementInfo(pageUpdateEventInfo, _elementInfo); + + auto callback = [](int32_t errorCode) { + FML_DLOG(WARNING) << "PageStateUpdate callback-> errorCode =" << errorCode; + }; + + if (provider_ == nullptr) { + FML_DLOG(ERROR) << "PageStateUpdate ->" + "AccessibilityProvider = nullptr"; + return; + } + OH_ArkUI_SendAccessibilityAsyncEvent(provider_, pageUpdateEventInfo, + callback); + + OH_ArkUI_DestoryAccessibilityEventInfo(pageUpdateEventInfo); + OH_ArkUI_DestoryAccessibilityElementInfo(_elementInfo); + + FML_DLOG(INFO) << "PageStateUpdate is end"; } + /** - * 判断当前节点组件是否是滑动组件,如: listview, gridview等 + * 特定节点的焦点请求 (当页面更新时自动请求id=0节点获焦) */ -bool OhosAccessibilityBridge::IsScrollableWidget( - flutter::SemanticsNode flutterNode) +void OhosAccessibilityBridge::RequestFocusWhenPageUpdate() { - return flutterNode.HasFlag(FLAGS_::kHasImplicitScrolling); + ArkUI_AccessibilityEventInfo* reqFocusEventInfo = + OH_ArkUI_CreateAccessibilityEventInfo(); + ArkUI_AccessibilityElementInfo* elementInfo = + OH_ArkUI_CreateAccessibilityElementInfo(); + + OH_ArkUI_AccessibilityEventSetEventType( + reqFocusEventInfo, + ArkUI_AccessibilityEventType:: + ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_REQUEST_ACCESSIBILITY_FOCUS); + + int32_t requestFocusId = 0; + OH_ArkUI_AccessibilityEventSetRequestFocusId(reqFocusEventInfo, + requestFocusId); + + OH_ArkUI_AccessibilityEventSetElementInfo(reqFocusEventInfo, elementInfo); + + auto callback = [](int32_t errorCode) { + FML_DLOG(WARNING) << "PageStateUpdate callback-> errorCode =" << errorCode; + }; + + if (provider_ == nullptr) { + FML_DLOG(ERROR) << "PageStateUpdate ->" + "AccessibilityProvider = nullptr"; + return; + } + OH_ArkUI_SendAccessibilityAsyncEvent(provider_, reqFocusEventInfo, callback); + + OH_ArkUI_DestoryAccessibilityEventInfo(reqFocusEventInfo); + OH_ArkUI_DestoryAccessibilityElementInfo(elementInfo); } /** @@ -416,19 +343,35 @@ void OhosAccessibilityBridge::Announce(std::unique_ptr& message) return; } +//获取根节点 +flutter::SemanticsNode OhosAccessibilityBridge::GetFlutterRootSemanticsNode() +{ + if (!flutterSemanticsTree_.size()) { + FML_DLOG(ERROR) + << "GetFlutterRootSemanticsNode -> flutterSemanticsTree_.size()=0"; + return flutter::SemanticsNode{}; + } + if (flutterSemanticsTree_.find(0) == flutterSemanticsTree_.end()) { + FML_DLOG(ERROR) << "GetFlutterRootSemanticsNode -> flutterSemanticsTree_ " + "has no keys = 0"; + return flutter::SemanticsNode{}; + } + return flutterSemanticsTree_.at(0); +} + /** * 根据nodeid获取或创建flutter语义节点 */ -flutter::SemanticsNode OhosAccessibilityBridge::getOrCreateFlutterSemanticsNode( +flutter::SemanticsNode OhosAccessibilityBridge::GetFlutterSemanticsNode( int32_t id) { flutter::SemanticsNode node; if (flutterSemanticsTree_.count(id) > 0) { return flutterSemanticsTree_.at(id); - FML_DLOG(INFO) << "getOrCreateFlutterSemanticsNode get node.id=" << id; + FML_DLOG(INFO) << "GetFlutterSemanticsNode get node.id=" << id; } else { FML_DLOG(ERROR) - << "getOrCreateFlutterSemanticsNode flutterSemanticsTree_ = null" << id; + << "GetFlutterSemanticsNode flutterSemanticsTree_ = null" << id; return flutter::SemanticsNode{}; } } @@ -592,7 +535,7 @@ void OhosAccessibilityBridge::ConvertChildRelativeRectToScreenRect( // 获取当前flutter节点的父节点的相对rect int32_t parentId = GetParentId(currNode.id); - auto parentNode = getOrCreateFlutterSemanticsNode(parentId); + auto parentNode = GetFlutterSemanticsNode(parentId); auto parentRight = parentNode.rect.fRight; auto parentBottom = parentNode.rect.fBottom; @@ -603,10 +546,10 @@ void OhosAccessibilityBridge::ConvertChildRelativeRectToScreenRect( auto realParentRight = _rectPairs.second.first; auto realParentBottom = _rectPairs.second.second; - // 获取root节点的绝对坐标 + // 获取root节点的绝对坐标, 即xcomponent屏幕长宽 auto _rootRect = GetAbsoluteScreenRect(0); - // auto rootRight = _rootRect.second.first; - auto rootBottom = _rootRect.second.second; + // float rootWidth = _rootRect.second.first; + auto rootHeight = _rootRect.second.second; // 真实缩放系数 float realScaleFactor = realParentRight / parentRight * 1.0; @@ -636,7 +579,6 @@ void OhosAccessibilityBridge::ConvertChildRelativeRectToScreenRect( newBottom = (currTop + _kMTransY + currBottom) * realScaleFactor + realParentTop; } - // 若子节点rect超过父节点则跳过显示(单个屏幕显示不下,滑动再重新显示) if (newLeft < realParentLeft || newTop < realParentTop || newRight > realParentRight || newBottom > realParentBottom || @@ -645,9 +587,11 @@ void OhosAccessibilityBridge::ConvertChildRelativeRectToScreenRect( "bigger than parentRect -> { nodeId: " << currNode.id << ", (" << newLeft << ", " << newTop << ", " << newRight << ", " << newBottom << ")}"; - // 防止溢出屏幕坐标 - newTop = realParentTop - rootBottom; - newBottom = realParentBottom - rootBottom; + // 防止滑动场景下绿框坐标超出屏幕范围,进行正则化处理 + // newLeft = static_cast(newLeft) % static_cast(rootWidth); + newTop = static_cast(newTop) % static_cast(rootHeight); + // newRight = static_cast(newRight) % static_cast(rootWidth); + newBottom = static_cast(newBottom) % static_cast(rootHeight); SetAbsoluteScreenRect(currNode.id, newLeft, newTop, newRight, newBottom); } else { @@ -676,7 +620,7 @@ void OhosAccessibilityBridge::FlutterNodeToElementInfoById( if (elementId == 0 || elementId == -1) { // 获取flutter的root节点 flutter::SemanticsNode flutterNode = - getOrCreateFlutterSemanticsNode(static_cast(0)); + GetFlutterSemanticsNode(static_cast(0)); // 设置elementinfo的屏幕坐标范围 int32_t left = static_cast(flutterNode.rect.fLeft); @@ -864,7 +808,7 @@ void OhosAccessibilityBridge::FlutterSetElementInfoProperties( int64_t elementId) { flutter::SemanticsNode flutterNode = - getOrCreateFlutterSemanticsNode(static_cast(elementId)); + GetFlutterSemanticsNode(static_cast(elementId)); // set elementinfo id OH_ArkUI_AccessibilityElementInfoSetElementId(elementInfoFromList, @@ -1046,108 +990,14 @@ void OhosAccessibilityBridge::FlutterSetElementInfoProperties( } /** - * 判断当前节点是否为textfield文本框 - */ -bool OhosAccessibilityBridge::IsTextField(flutter::SemanticsNode flutterNode) -{ - return flutterNode.HasFlag(FLAGS_::kIsTextField); -} -/** - * 判断当前节点是否为滑动条slider类型 - */ -bool OhosAccessibilityBridge::IsSlider(flutter::SemanticsNode flutterNode) -{ - return flutterNode.HasFlag(FLAGS_::kIsSlider); -} -/** - * 判断当前flutter节点组件是否可点击 - */ -bool OhosAccessibilityBridge::IsNodeClickable( - flutter::SemanticsNode flutterNode) -{ - return flutterNode.HasAction(ACTIONS_::kTap) || - flutterNode.HasFlag(FLAGS_::kHasCheckedState) || - flutterNode.HasFlag(FLAGS_::kIsButton) || - flutterNode.HasFlag(FLAGS_::kIsTextField) || - flutterNode.HasFlag(FLAGS_::kIsImage) || - flutterNode.HasFlag(FLAGS_::kIsLiveRegion) || - flutterNode.HasFlag(FLAGS_::kIsMultiline) || - flutterNode.HasFlag(FLAGS_::kIsLink) || - flutterNode.HasFlag(FLAGS_::kIsSlider) || - flutterNode.HasFlag(FLAGS_::kIsKeyboardKey) || - flutterNode.HasFlag(FLAGS_::kHasToggledState) || - flutterNode.HasFlag(FLAGS_::kHasImplicitScrolling); -} -/** - * 判断当前flutter节点组件是否可显示 + * Called to obtain element information based on a specified node. + * NOTE:该arkui接口需要在系统无障碍服务开启时,才能触发调用 */ -bool OhosAccessibilityBridge::IsNodeVisible( - flutter::SemanticsNode flutterNode) -{ - return flutterNode.HasFlag(FLAGS_::kIsHidden) ? false : true; -} -/** - * 判断当前flutter节点组件是否具备checkable属性 - */ -bool OhosAccessibilityBridge::IsNodeCheckable( - flutter::SemanticsNode flutterNode) -{ - return flutterNode.HasFlag(FLAGS_::kHasCheckedState) || - flutterNode.HasFlag(FLAGS_::kHasToggledState); -} -/** - * 判断当前flutter节点组件是否checked/unchecked(checkbox、radio button) - */ -bool OhosAccessibilityBridge::IsNodeChecked( - flutter::SemanticsNode flutterNode) -{ - return flutterNode.HasFlag(FLAGS_::kIsChecked) || - flutterNode.HasFlag(FLAGS_::kIsToggled); -} -/** - * 判断当前flutter节点组件是否选中 - */ -bool OhosAccessibilityBridge::IsNodeSelected( - flutter::SemanticsNode flutterNode) -{ - return flutterNode.HasFlag(FLAGS_::kIsSelected); -} -/** - * 判断当前flutter节点组件是否为密码输入框 - */ -bool OhosAccessibilityBridge::IsNodePassword( - flutter::SemanticsNode flutterNode) -{ - return flutterNode.HasFlag(FLAGS_::kIsTextField) && - flutterNode.HasFlag(FLAGS_::kIsObscured); -} -/** - * 判断当前flutter节点组件是否支持长按功能 - */ -bool OhosAccessibilityBridge::IsNodeHasLongPress( - flutter::SemanticsNode flutterNode) -{ - return flutterNode.HasAction(ACTIONS_::kLongPress); -} -/** - * 判断当前flutter节点是否enabled - */ -bool OhosAccessibilityBridge::IsNodeEnabled( - flutter::SemanticsNode flutterNode) -{ - return !flutterNode.HasFlag(FLAGS_::kHasEnabledState) || - flutterNode.HasFlag(FLAGS_::kIsEnabled); -} - -/** - * Called to obtain element information based on a specified node. - * NOTE:该arkui接口需要在系统无障碍服务开启时,才能触发调用 - */ -int32_t OhosAccessibilityBridge::FindAccessibilityNodeInfosById( - int64_t elementId, - ArkUI_AccessibilitySearchMode mode, - int32_t requestId, - ArkUI_AccessibilityElementInfoList* elementList) +int32_t OhosAccessibilityBridge::FindAccessibilityNodeInfosById( + int64_t elementId, + ArkUI_AccessibilitySearchMode mode, + int32_t requestId, + ArkUI_AccessibilityElementInfoList* elementList) { FML_DLOG(INFO) << "#### FindAccessibilityNodeInfosById input-params ####: elementId = " @@ -1173,8 +1023,10 @@ int32_t OhosAccessibilityBridge::FindAccessibilityNodeInfosById( return ARKUI_ACCESSIBILITY_NATIVE_RESULT_FAILED; } - auto flutterNode = getOrCreateFlutterSemanticsNode(static_cast(elementId)); - if(!IsNodeVisible(flutterNode)) { + auto flutterNode = GetFlutterSemanticsNode(static_cast(elementId)); + bool VISIBLE_STATE = elementId == -1; + if (!VISIBLE_STATE && !IsNodeVisible(flutterNode)) { + FML_DLOG(INFO) << "filter hidden nodes, elementId:" << elementId; return ARKUI_ACCESSIBILITY_NATIVE_RESULT_FAILED; } @@ -1185,14 +1037,13 @@ int32_t OhosAccessibilityBridge::FindAccessibilityNodeInfosById( int64_t elementInfoCount = static_cast(flutterSemanticsTree_.size()); for (int64_t i = 1; i < elementInfoCount; i++) { - auto childNode = getOrCreateFlutterSemanticsNode(static_cast(i)); + auto childNode = GetFlutterSemanticsNode(static_cast(i)); if (IsNodeVisible(childNode)) { ArkUI_AccessibilityElementInfo* newElementInfo = OH_ArkUI_AddAndGetAccessibilityElementInfo(elementList); FlutterNodeToElementInfoById(newElementInfo, i); } } - } else if (mode == ArkUI_AccessibilitySearchMode:: ARKUI_ACCESSIBILITY_NATIVE_SEARCH_MODE_PREFETCH_PREDECESSORS) { @@ -1214,7 +1065,6 @@ int32_t OhosAccessibilityBridge::FindAccessibilityNodeInfosById( if (IsNodeVisible(flutterNode)) { FlutterNodeToElementInfoById(elementInfoFromList, elementId); } - } else if ( mode == ArkUI_AccessibilitySearchMode:: @@ -1224,126 +1074,22 @@ int32_t OhosAccessibilityBridge::FindAccessibilityNodeInfosById( int64_t elementInfoCount = static_cast(flutterSemanticsTree_.size()); for (int64_t i = 1; i < elementInfoCount; i++) { - auto childNode = getOrCreateFlutterSemanticsNode(static_cast(i)); + auto childNode = GetFlutterSemanticsNode(static_cast(i)); if (IsNodeVisible(childNode)) { ArkUI_AccessibilityElementInfo* newElementInfo = OH_ArkUI_AddAndGetAccessibilityElementInfo(elementList); FlutterNodeToElementInfoById(newElementInfo, i); } } - } else { if (IsNodeVisible(flutterNode)) { FlutterNodeToElementInfoById(elementInfoFromList, elementId); } } - FML_DLOG(INFO) << "--- FindAccessibilityNodeInfosById is end ---"; return ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL; } -/** - * Called to obtain element information based on a specified node and text - * content. - */ -int32_t OhosAccessibilityBridge::FindAccessibilityNodeInfosByText( - int64_t elementId, - const char* text, - int32_t requestId, - ArkUI_AccessibilityElementInfoList* elementList) -{ - FML_DLOG(INFO) << "=== FindAccessibilityNodeInfosByText is end ==="; - return 0; -} -int32_t OhosAccessibilityBridge::FindFocusedAccessibilityNode( - int64_t elementId, - ArkUI_AccessibilityFocusType focusType, - int32_t requestId, - ArkUI_AccessibilityElementInfo* elementinfo) -{ - FML_DLOG(INFO) << "=== FindFocusedAccessibilityNode is end ==="; - - return 0; -} -int32_t OhosAccessibilityBridge::FindNextFocusAccessibilityNode( - int64_t elementId, - ArkUI_AccessibilityFocusMoveDirection direction, - int32_t requestId, - ArkUI_AccessibilityElementInfo* elementList) { - FML_DLOG(INFO) << "=== FindNextFocusAccessibilityNode is end ==="; - return 0; -} - -int32_t OhosAccessibilityBridge::ClearFocusedFocusAccessibilityNode() -{ - FML_DLOG(INFO) << "=== ClearFocusedFocusAccessibilityNode is end ==="; - return 0; -} -int32_t OhosAccessibilityBridge::GetAccessibilityNodeCursorPosition( - int64_t elementId, - int32_t requestId, - int32_t* index) -{ - FML_DLOG(INFO) << "=== GetAccessibilityNodeCursorPosition is end ==="; - return 0; -} - -/** - * 将arkui的action类型转化为flutter的action类型 - */ -flutter::SemanticsAction OhosAccessibilityBridge::ArkuiActionsToFlutterActions( - ArkUI_Accessibility_ActionType arkui_action) -{ - switch (arkui_action) { - case ArkUI_Accessibility_ActionType:: - ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_CLICK: - return ACTIONS_::kTap; - - case ArkUI_Accessibility_ActionType:: - ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_LONG_CLICK: - return ACTIONS_::kLongPress; - - case ArkUI_Accessibility_ActionType:: - ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SCROLL_FORWARD: - return ACTIONS_::kScrollUp; - - case ArkUI_Accessibility_ActionType:: - ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SCROLL_BACKWARD: - return ACTIONS_::kScrollDown; - - case ArkUI_Accessibility_ActionType:: - ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_COPY: - return ACTIONS_::kCopy; - - case ArkUI_Accessibility_ActionType:: - ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_CUT: - return ACTIONS_::kCut; - - case ArkUI_Accessibility_ActionType:: - ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_GAIN_ACCESSIBILITY_FOCUS: - return ACTIONS_::kDidGainAccessibilityFocus; - - case ArkUI_Accessibility_ActionType:: - ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_CLEAR_ACCESSIBILITY_FOCUS: - return ACTIONS_::kDidLoseAccessibilityFocus; - - // Text selection action, requiring the setting of selectTextBegin, - // TextEnd, and TextInForward parameters to select a text - // segment in the text box. */ - case ArkUI_Accessibility_ActionType:: - ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SELECT_TEXT: - return ACTIONS_::kSetSelection; - - case ArkUI_Accessibility_ActionType:: - ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SET_TEXT: - return ACTIONS_::kSetText; - - default: - // might not match to the valid action in arkui - return ACTIONS_::kCustomAction; - } -} - /** * 解析flutter语义动作,并通过NativAccessibilityChannel分发 */ @@ -1352,7 +1098,7 @@ void OhosAccessibilityBridge::DispatchSemanticsAction( flutter::SemanticsAction action, fml::MallocMapping args) { - auto nativeAccessibilityChannel_ = std::make_shared(); + nativeAccessibilityChannel_ = std::make_shared(); nativeAccessibilityChannel_->DispatchSemanticsAction(native_shell_holder_id_, id, action, @@ -1381,7 +1127,7 @@ int32_t OhosAccessibilityBridge::ExecuteAccessibilityAction( // 获取当前elementid对应的flutter语义节点 auto flutterNode = - getOrCreateFlutterSemanticsNode(static_cast(elementId)); + GetFlutterSemanticsNode(static_cast(elementId)); // 根据当前elementid和无障碍动作类型,发送无障碍事件 switch (action) { @@ -1427,7 +1173,6 @@ int32_t OhosAccessibilityBridge::ExecuteAccessibilityAction( auto flutterGainFocusAction = ArkuiActionsToFlutterActions(action); DispatchSemanticsAction(static_cast(elementId), flutterGainFocusAction, {}); - /** Accessibility focus event, sent after the UI component responds. 32768 */ auto focusEventType = ArkUI_AccessibilityEventType:: @@ -1435,14 +1180,12 @@ int32_t OhosAccessibilityBridge::ExecuteAccessibilityAction( Flutter_SendAccessibilityAsyncEvent(elementId, focusEventType); FML_DLOG(INFO) << "ExecuteAccessibilityAction -> action: focus(" << action << ")" << " event: focus(" << focusEventType << ")"; - if (flutterNode.HasAction(ACTIONS_::kIncrease) || flutterNode.HasAction(ACTIONS_::kDecrease)) { Flutter_SendAccessibilityAsyncEvent( elementId, ArkUI_AccessibilityEventType:: ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_SELECTED); } - break; } @@ -1513,11 +1256,9 @@ int32_t OhosAccessibilityBridge::ExecuteAccessibilityAction( auto flutterScrollDownAction = ArkuiActionsToFlutterActions(action); DispatchSemanticsAction(static_cast(elementId), flutterScrollDownAction, {}); - } else if (flutterNode.HasAction(ACTIONS_::kScrollRight)) { DispatchSemanticsAction(static_cast(elementId), ACTIONS_::kScrollRight, {}); - } else if (flutterNode.HasAction(ACTIONS_::kDecrease)) { flutterNode.value = flutterNode.decreasedValue; flutterNode.valueAttributes = flutterNode.decreasedValueAttributes; @@ -1527,7 +1268,6 @@ int32_t OhosAccessibilityBridge::ExecuteAccessibilityAction( ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_SELECTED); DispatchSemanticsAction(static_cast(elementId), ACTIONS_::kDecrease, {}); - } else { } std::string currComponetType = GetNodeComponentType(flutterNode); @@ -1630,6 +1370,108 @@ int32_t OhosAccessibilityBridge::ExecuteAccessibilityAction( return ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL; } +/** + * Called to obtain element information based on a specified node and text + * content. + */ +int32_t OhosAccessibilityBridge::FindAccessibilityNodeInfosByText( + int64_t elementId, + const char* text, + int32_t requestId, + ArkUI_AccessibilityElementInfoList* elementList) +{ + FML_DLOG(INFO) << "=== FindAccessibilityNodeInfosByText is end ==="; + return 0; +} +int32_t OhosAccessibilityBridge::FindFocusedAccessibilityNode( + int64_t elementId, + ArkUI_AccessibilityFocusType focusType, + int32_t requestId, + ArkUI_AccessibilityElementInfo* elementinfo) +{ + FML_DLOG(INFO) << "=== FindFocusedAccessibilityNode is end ==="; + + return 0; +} +int32_t OhosAccessibilityBridge::FindNextFocusAccessibilityNode( + int64_t elementId, + ArkUI_AccessibilityFocusMoveDirection direction, + int32_t requestId, + ArkUI_AccessibilityElementInfo* elementList) { + FML_DLOG(INFO) << "=== FindNextFocusAccessibilityNode is end ==="; + return 0; +} + +int32_t OhosAccessibilityBridge::ClearFocusedFocusAccessibilityNode() +{ + FML_DLOG(INFO) << "=== ClearFocusedFocusAccessibilityNode is end ==="; + return 0; +} +int32_t OhosAccessibilityBridge::GetAccessibilityNodeCursorPosition( + int64_t elementId, + int32_t requestId, + int32_t* index) +{ + FML_DLOG(INFO) << "=== GetAccessibilityNodeCursorPosition is end ==="; + return 0; +} + +/** + * 将arkui的action类型转化为flutter的action类型 + */ +flutter::SemanticsAction OhosAccessibilityBridge::ArkuiActionsToFlutterActions( + ArkUI_Accessibility_ActionType arkui_action) +{ + switch (arkui_action) { + case ArkUI_Accessibility_ActionType:: + ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_CLICK: + return ACTIONS_::kTap; + + case ArkUI_Accessibility_ActionType:: + ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_LONG_CLICK: + return ACTIONS_::kLongPress; + + case ArkUI_Accessibility_ActionType:: + ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SCROLL_FORWARD: + return ACTIONS_::kScrollUp; + + case ArkUI_Accessibility_ActionType:: + ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SCROLL_BACKWARD: + return ACTIONS_::kScrollDown; + + case ArkUI_Accessibility_ActionType:: + ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_COPY: + return ACTIONS_::kCopy; + + case ArkUI_Accessibility_ActionType:: + ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_CUT: + return ACTIONS_::kCut; + + case ArkUI_Accessibility_ActionType:: + ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_GAIN_ACCESSIBILITY_FOCUS: + return ACTIONS_::kDidGainAccessibilityFocus; + + case ArkUI_Accessibility_ActionType:: + ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_CLEAR_ACCESSIBILITY_FOCUS: + return ACTIONS_::kDidLoseAccessibilityFocus; + + // Text selection action, requiring the setting of selectTextBegin, + // TextEnd, and TextInForward parameters to select a text + // segment in the text box. */ + case ArkUI_Accessibility_ActionType:: + ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SELECT_TEXT: + return ACTIONS_::kSetSelection; + + case ArkUI_Accessibility_ActionType:: + ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SET_TEXT: + return ACTIONS_::kSetText; + + default: + // might not match to the valid action in arkui + return ACTIONS_::kCustomAction; + } +} + /** * 自定义无障碍异步事件发送 */ @@ -1786,20 +1628,125 @@ std::string OhosAccessibilityBridge::GetNodeComponentType( return "Widget" + std::to_string(node.id); } -// 获取根节点 -flutter::SemanticsNode OhosAccessibilityBridge::getFlutterRootSemanticsNode() +/** + * 判断当前节点是否为textfield文本框 + */ +bool OhosAccessibilityBridge::IsTextField(flutter::SemanticsNode flutterNode) { - if (!flutterSemanticsTree_.size()) { - FML_DLOG(ERROR) - << "getFlutterRootSemanticsNode -> flutterSemanticsTree_.size()=0"; - return flutter::SemanticsNode{}; - } - if (flutterSemanticsTree_.find(0) == flutterSemanticsTree_.end()) { - FML_DLOG(ERROR) << "getFlutterRootSemanticsNode -> flutterSemanticsTree_ " - "has no keys = 0"; - return flutter::SemanticsNode{}; - } - return flutterSemanticsTree_.at(0); + return flutterNode.HasFlag(FLAGS_::kIsTextField); +} +/** + * 判断当前节点是否为滑动条slider类型 + */ +bool OhosAccessibilityBridge::IsSlider(flutter::SemanticsNode flutterNode) +{ + return flutterNode.HasFlag(FLAGS_::kIsSlider); +} +/** + * 判断当前flutter节点组件是否可点击 + */ +bool OhosAccessibilityBridge::IsNodeClickable( + flutter::SemanticsNode flutterNode) +{ + return flutterNode.HasAction(ACTIONS_::kTap) || + flutterNode.HasFlag(FLAGS_::kHasCheckedState) || + flutterNode.HasFlag(FLAGS_::kIsButton) || + flutterNode.HasFlag(FLAGS_::kIsTextField) || + flutterNode.HasFlag(FLAGS_::kIsImage) || + flutterNode.HasFlag(FLAGS_::kIsLiveRegion) || + flutterNode.HasFlag(FLAGS_::kIsMultiline) || + flutterNode.HasFlag(FLAGS_::kIsLink) || + flutterNode.HasFlag(FLAGS_::kIsSlider) || + flutterNode.HasFlag(FLAGS_::kIsKeyboardKey) || + flutterNode.HasFlag(FLAGS_::kHasToggledState) || + flutterNode.HasFlag(FLAGS_::kHasImplicitScrolling); +} +/** + * 判断当前flutter节点组件是否可显示 + */ +bool OhosAccessibilityBridge::IsNodeVisible( + flutter::SemanticsNode flutterNode) +{ + return flutterNode.HasFlag(FLAGS_::kIsHidden) ? false : true; +} +/** + * 判断当前flutter节点组件是否具备checkable属性 + */ +bool OhosAccessibilityBridge::IsNodeCheckable( + flutter::SemanticsNode flutterNode) +{ + return flutterNode.HasFlag(FLAGS_::kHasCheckedState) || + flutterNode.HasFlag(FLAGS_::kHasToggledState); +} +/** + * 判断当前flutter节点组件是否checked/unchecked(checkbox、radio button) + */ +bool OhosAccessibilityBridge::IsNodeChecked( + flutter::SemanticsNode flutterNode) +{ + return flutterNode.HasFlag(FLAGS_::kIsChecked) || + flutterNode.HasFlag(FLAGS_::kIsToggled); +} +/** + * 判断当前flutter节点组件是否选中 + */ +bool OhosAccessibilityBridge::IsNodeSelected( + flutter::SemanticsNode flutterNode) +{ + return flutterNode.HasFlag(FLAGS_::kIsSelected); +} +/** + * 判断当前flutter节点组件是否为密码输入框 + */ +bool OhosAccessibilityBridge::IsNodePassword( + flutter::SemanticsNode flutterNode) +{ + return flutterNode.HasFlag(FLAGS_::kIsTextField) && + flutterNode.HasFlag(FLAGS_::kIsObscured); +} +/** + * 判断当前flutter节点组件是否支持长按功能 + */ +bool OhosAccessibilityBridge::IsNodeHasLongPress( + flutter::SemanticsNode flutterNode) +{ + return flutterNode.HasAction(ACTIONS_::kLongPress); +} +/** + * 判断当前flutter节点是否enabled + */ +bool OhosAccessibilityBridge::IsNodeEnabled( + flutter::SemanticsNode flutterNode) +{ + return !flutterNode.HasFlag(FLAGS_::kHasEnabledState) || + flutterNode.HasFlag(FLAGS_::kIsEnabled); +} +/** + * 判断当前节点是否已经滑动 + */ +bool OhosAccessibilityBridge::HasScrolled( + const flutter::SemanticsNode& flutterNode) +{ + return flutterNode.scrollPosition != std::nan(""); +} +/** + * 判断是否可滑动 + */ +bool OhosAccessibilityBridge::IsNodeScrollable( + flutter::SemanticsNode flutterNode) +{ + return flutterNode.HasAction(ACTIONS_::kScrollLeft) || + flutterNode.HasAction(ACTIONS_::kScrollRight) || + flutterNode.HasAction(ACTIONS_::kScrollUp) || + flutterNode.HasAction(ACTIONS_::kScrollDown); +} +/** + * 判断当前节点组件是否是滑动组件,如: listview, gridview等 + */ +bool OhosAccessibilityBridge::IsScrollableWidget( + flutter::SemanticsNode flutterNode) +{ + return flutterNode.HasFlag(FLAGS_::kHasImplicitScrolling); } void OhosAccessibilityBridge::AddRouteNodes( @@ -1810,7 +1757,7 @@ void OhosAccessibilityBridge::AddRouteNodes( edges.emplace_back(node); } for (auto& childNodeId : node.childrenInTraversalOrder) { - auto childNode = getOrCreateFlutterSemanticsNode(childNodeId); + auto childNode = GetFlutterSemanticsNode(childNodeId); AddRouteNodes(edges, childNode); } } @@ -1821,7 +1768,7 @@ std::string OhosAccessibilityBridge::GetRouteName(flutter::SemanticsNode node) return node.label; } for (auto& childNodeId : node.childrenInTraversalOrder) { - auto childNode = getOrCreateFlutterSemanticsNode(childNodeId); + auto childNode = GetFlutterSemanticsNode(childNodeId); std::string newName = GetRouteName(childNode); if (!newName.empty()) { return newName; @@ -1878,6 +1825,51 @@ void OhosAccessibilityBridge::ClearFlutterSemanticsCaches() flutterNavigationVec_.clear(); } +/** + * extent common struct SemanticsNode to + * derived struct SemanticsNodeExtent + */ +SemanticsNodeExtent OhosAccessibilityBridge::SetAndGetSemanticsNodeExtent( + flutter::SemanticsNode node) +{ + SemanticsNodeExtent nodeEx = SemanticsNodeExtent(); + 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.label = std::move(node.label); + nodeEx.labelAttributes = std::move(node.labelAttributes); + nodeEx.hint = std::move(node.hint); + nodeEx.hintAttributes = std::move(node.hintAttributes); + nodeEx.value = std::move(node.value); + nodeEx.valueAttributes = std::move(node.valueAttributes); + nodeEx.increasedValue = std::move(node.increasedValue); + nodeEx.increasedValueAttributes = std::move(node.increasedValueAttributes); + 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.rect = std::move(node.rect); + nodeEx.transform = std::move(node.transform); + nodeEx.childrenInTraversalOrder = std::move(node.childrenInTraversalOrder); + nodeEx.childrenInHitTestOrder = std::move(node.childrenInHitTestOrder); + nodeEx.customAccessibilityActions = + std::move(node.customAccessibilityActions); + return nodeEx; +} + void OhosAccessibilityBridge::GetSemanticsNodeDebugInfo( flutter::SemanticsNode node) { diff --git a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h index e9e171c53c..6092e0ba2a 100644 --- a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h +++ b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h @@ -84,7 +84,7 @@ class OhosAccessibilityBridge { void Announce(std::unique_ptr& message); - flutter::SemanticsNode getOrCreateFlutterSemanticsNode(int32_t id); + flutter::SemanticsNode GetFlutterSemanticsNode(int32_t id); int32_t FindAccessibilityNodeInfosById( int64_t elementId, @@ -229,7 +229,7 @@ class OhosAccessibilityBridge { void FlutterTreeToArkuiTree( ArkUI_AccessibilityElementInfoList* elementInfoList); - flutter::SemanticsNode getFlutterRootSemanticsNode(); + flutter::SemanticsNode GetFlutterRootSemanticsNode(); std::string GetNodeComponentType(const flutter::SemanticsNode& node); flutter::SemanticsAction ArkuiActionsToFlutterActions( ArkUI_Accessibility_ActionType arkui_action); -- Gitee From 2aec3b6a2d7ddcfea284dcbdb80b0e6d3fc4ccf0 Mon Sep 17 00:00:00 2001 From: zjxi Date: Mon, 4 Nov 2024 21:09:03 +0800 Subject: [PATCH 07/14] =?UTF-8?q?feat:=E5=A2=9E=E5=8A=A0=E6=97=A0=E9=9A=9C?= =?UTF-8?q?=E7=A2=8D=E5=AF=BC=E8=88=AA=E7=89=B9=E5=BE=81=E5=8A=9F=E8=83=BD?= =?UTF-8?q?,=E4=BC=98=E5=8C=96=E9=83=A8=E5=88=86=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zjxi --- .../ohos_accessibility_bridge.cpp | 19 +++++----- .../accessibility/ohos_accessibility_bridge.h | 6 ++-- .../ohos_accessibility_features.cpp | 35 +++++++++++++------ .../ohos_accessibility_features.h | 25 ++++++++++--- .../ets/embedding/ohos/FlutterAbility.ets | 2 +- .../ohos/napi/platform_view_ohos_napi.cpp | 5 ++- 6 files changed, 62 insertions(+), 30 deletions(-) diff --git a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp index 1bba43248d..f463cf2e69 100644 --- a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp +++ b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp @@ -51,12 +51,14 @@ void OhosAccessibilityBridge::OnOhosAccessibilityStateChange( { native_shell_holder_id_ = shellHolderId; nativeAccessibilityChannel_ = std::make_shared(); + accessibilityFeatures_ = std::make_shared(); if (ohosAccessibilityEnabled) { FML_DLOG(INFO) << "OnOhosAccessibilityEnabled()"; nativeAccessibilityChannel_->OnOhosAccessibilityEnabled(native_shell_holder_id_); } else { FML_DLOG(INFO) << "OnOhosAccessibilityEnabled()"; + accessibilityFeatures_->SetAccessibleNavigation(false, native_shell_holder_id_); nativeAccessibilityChannel_->OnOhosAccessibilityDisabled(native_shell_holder_id_); } } @@ -100,11 +102,6 @@ void OhosAccessibilityBridge::updateSemantics( */ flutterSemanticsTree_[node.id] = node; - // 若当前更新节点是隐藏的,则跳过 - if (node.HasFlag(FLAGS_::kIsHidden)) { - continue; - } - // 获取当前flutter节点的全部子节点数量,并构建父子节点id映射关系 int32_t childNodeCount = node.childrenInTraversalOrder.size(); for (int32_t i = 0; i < childNodeCount; i++) { @@ -230,7 +227,7 @@ void OhosAccessibilityBridge::FlutterScrollExecution( /** * 当页面状态更新事件,在页面转换、切换、调整大小时发送页面状态更新事件 */ -void OhosAccessibilityBridge::PageStateUpdate(int64_t elementId) +void OhosAccessibilityBridge::PageStateUpdate() { ArkUI_AccessibilityEventInfo* pageUpdateEventInfo = OH_ArkUI_CreateAccessibilityEventInfo(); @@ -241,8 +238,8 @@ void OhosAccessibilityBridge::PageStateUpdate(int64_t elementId) OH_ArkUI_AccessibilityEventSetEventType( pageUpdateEventInfo, ArkUI_AccessibilityEventType:: - ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_ACCESSIBILITY_FOCUS_CLEARED); - FlutterNodeToElementInfoById(_elementInfo, elementId); + ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_PAGE_CONTENT_UPDATE); + // FlutterNodeToElementInfoById(_elementInfo, elementId); OH_ArkUI_AccessibilityEventSetElementInfo(pageUpdateEventInfo, _elementInfo); auto callback = [](int32_t errorCode) { @@ -1014,6 +1011,10 @@ int32_t OhosAccessibilityBridge::FindAccessibilityNodeInfosById( return ARKUI_ACCESSIBILITY_NATIVE_RESULT_FAILED; } + // 开启无障碍导航功能 + accessibilityFeatures_->SetAccessibleNavigation(true, + native_shell_holder_id_); + // 从elementinfolist中获取elementinfo ArkUI_AccessibilityElementInfo* elementInfoFromList = OH_ArkUI_AddAndGetAccessibilityElementInfo(elementList); @@ -1023,6 +1024,7 @@ int32_t OhosAccessibilityBridge::FindAccessibilityNodeInfosById( return ARKUI_ACCESSIBILITY_NATIVE_RESULT_FAILED; } + // 过滤非当前屏幕显示的语义节点创建、配置,防止溢出屏幕坐标绘制bug以及优化性能开销 auto flutterNode = GetFlutterSemanticsNode(static_cast(elementId)); bool VISIBLE_STATE = elementId == -1; if (!VISIBLE_STATE && !IsNodeVisible(flutterNode)) { @@ -1098,7 +1100,6 @@ void OhosAccessibilityBridge::DispatchSemanticsAction( flutter::SemanticsAction action, fml::MallocMapping args) { - nativeAccessibilityChannel_ = std::make_shared(); nativeAccessibilityChannel_->DispatchSemanticsAction(native_shell_holder_id_, id, action, diff --git a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h index 6092e0ba2a..7a669b53e4 100644 --- a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h +++ b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h @@ -24,6 +24,7 @@ #include "flutter/lib/ui/semantics/custom_accessibility_action.h" #include "flutter/lib/ui/semantics/semantics_node.h" #include "native_accessibility_channel.h" +#include "ohos_accessibility_features.h" namespace flutter { typedef flutter::SemanticsFlags FLAGS_; @@ -138,13 +139,14 @@ class OhosAccessibilityBridge { void FlutterScrollExecution( flutter::SemanticsNode node, ArkUI_AccessibilityElementInfo* elementInfoFromList); - + void ClearFlutterSemanticsCaches(); private: OhosAccessibilityBridge(); static OhosAccessibilityBridge* bridgeInstance; std::shared_ptr nativeAccessibilityChannel_; + std::shared_ptr accessibilityFeatures_; static const int32_t ROOT_NODE_ID = 0; constexpr static const double SCROLL_EXTENT_FOR_INFINITY = 100000.0; @@ -268,7 +270,7 @@ class OhosAccessibilityBridge { void GetCustomActionDebugInfo( flutter::CustomAccessibilityAction customAccessibilityAction); - void PageStateUpdate(int64_t elementId); + void PageStateUpdate(); void RequestFocusWhenPageUpdate(); bool Contains(const std::string source, const std::string target); diff --git a/shell/platform/ohos/accessibility/ohos_accessibility_features.cpp b/shell/platform/ohos/accessibility/ohos_accessibility_features.cpp index 3e0b16b1b7..f82bc0bbb8 100644 --- a/shell/platform/ohos/accessibility/ohos_accessibility_features.cpp +++ b/shell/platform/ohos/accessibility/ohos_accessibility_features.cpp @@ -18,32 +18,47 @@ namespace flutter { -OhosAccessibilityFeatures OhosAccessibilityFeatures::instance; - OhosAccessibilityFeatures::OhosAccessibilityFeatures() {}; OhosAccessibilityFeatures::~OhosAccessibilityFeatures() {}; -OhosAccessibilityFeatures* OhosAccessibilityFeatures::GetInstance() { - return &OhosAccessibilityFeatures::instance; +/** + * 无障碍特征之无障碍导航 + */ +void OhosAccessibilityFeatures::SetAccessibleNavigation( + bool isAccessibleNavigation, + int64_t shell_holder_id) +{ + if (ACCESSIBLE_NAVIGATION == isAccessibleNavigation) { + return; + } + ACCESSIBLE_NAVIGATION = isAccessibleNavigation; + if (ACCESSIBLE_NAVIGATION) { + accessibilityFeatureFlags |= + static_cast(AccessibilityFeatures::AccessibleNavigation); + FML_DLOG(INFO) << "SetAccessibleNavigation -> accessibilityFeatureFlags: " + << accessibilityFeatureFlags; + } else { + accessibilityFeatureFlags &= + ~static_cast(AccessibilityFeatures::AccessibleNavigation); + } + SendAccessibilityFlags(shell_holder_id); } /** - * bold text for AccessibilityFeature + * 无障碍特征之字体加粗 */ void OhosAccessibilityFeatures::SetBoldText(double fontWeightScale, int64_t shell_holder_id) { bool shouldBold = fontWeightScale > 1.0; - if (shouldBold) { accessibilityFeatureFlags |= - static_cast(flutter::AccessibilityFeatureFlag::kBoldText); + static_cast(AccessibilityFeatures::BoldText); FML_DLOG(INFO) << "SetBoldText -> accessibilityFeatureFlags: " << accessibilityFeatureFlags; } else { accessibilityFeatureFlags &= - static_cast(flutter::AccessibilityFeatureFlag::kBoldText); + static_cast(AccessibilityFeatures::BoldText); } - SendAccessibilityFlags(shell_holder_id); } @@ -52,7 +67,7 @@ void OhosAccessibilityFeatures::SetBoldText(double fontWeightScale, */ void OhosAccessibilityFeatures::SendAccessibilityFlags( int64_t shell_holder_id) { - auto nativeAccessibilityChannel_ = std::make_shared(); + nativeAccessibilityChannel_ = std::make_shared(); nativeAccessibilityChannel_->SetAccessibilityFeatures(shell_holder_id, accessibilityFeatureFlags); FML_DLOG(INFO) << "SendAccessibilityFlags -> accessibilityFeatureFlags = " << accessibilityFeatureFlags; diff --git a/shell/platform/ohos/accessibility/ohos_accessibility_features.h b/shell/platform/ohos/accessibility/ohos_accessibility_features.h index af271318e1..1163180d65 100644 --- a/shell/platform/ohos/accessibility/ohos_accessibility_features.h +++ b/shell/platform/ohos/accessibility/ohos_accessibility_features.h @@ -18,26 +18,41 @@ #include "flutter/lib/ui/window/platform_configuration.h" #include "native_accessibility_channel.h" #include "flutter/shell/platform/ohos/napi/platform_view_ohos_napi.h" - namespace flutter { class OhosAccessibilityFeatures { public: OhosAccessibilityFeatures(); ~OhosAccessibilityFeatures(); + + bool ACCESSIBLE_NAVIGATION = false; - static OhosAccessibilityFeatures* GetInstance(); - + void SetAccessibleNavigation(bool isAccessibleNavigation, + int64_t shell_holder_id); void SetBoldText(double fontWeightScale, int64_t shell_holder_id); + void SendAccessibilityFlags(int64_t shell_holder_id); private: - static OhosAccessibilityFeatures instance; std::shared_ptr nativeAccessibilityChannel_; - int32_t accessibilityFeatureFlags = 0; }; +/** + * 无障碍特征枚举类(flutter平台通用) + * 注意:必须同src/flutter/lib/ui/window/platform_configuration.h + * 中的`AccessibilityFeatureFlag`枚举类保持一致 + */ +enum AccessibilityFeatures : int32_t { + AccessibleNavigation = 1 << 0, + InvertColors = 1 << 1, + DisableAnimations = 1 << 2, + BoldText = 1 << 3, + ReduceMotion = 1 << 4, + HighContrast = 1 << 5, + OnOffSwitchLabels = 1 << 6, +}; + } // namespace flutter #endif \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterAbility.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterAbility.ets index 869e9148fa..cac6460d74 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterAbility.ets +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterAbility.ets @@ -387,7 +387,7 @@ export class FlutterAbility extends UIAbility implements Host { .send(); //热启动生命周期内,实时监听系统设置环境改变并实时发送相应信息 //实时获取系统字体加粗系数 - this.delegate?.getFlutterNapi()?.setFontWeightScale(config.fontWeightScale == undefined? 0 : config.fontWeightScale); + this.delegate?.getFlutterNapi()?.setFontWeightScale(config.fontWeightScale == undefined? 1.0 : config.fontWeightScale); Log.i(TAG, 'fontWeightScale: ' + JSON.stringify(config.fontWeightScale)); if (config.language != '') { diff --git a/shell/platform/ohos/napi/platform_view_ohos_napi.cpp b/shell/platform/ohos/napi/platform_view_ohos_napi.cpp index 06a086d5db..990cd80f88 100644 --- a/shell/platform/ohos/napi/platform_view_ohos_napi.cpp +++ b/shell/platform/ohos/napi/platform_view_ohos_napi.cpp @@ -1981,9 +1981,8 @@ napi_value PlatformViewOHOSNapi::nativeSetFontWeightScale(napi_env env, napi_cal << ret; return nullptr; } - // accessibility features get the params - auto ohosAccessibilityFeatures = OhosAccessibilityFeatures::GetInstance(); - ohosAccessibilityFeatures->SetBoldText(fontWeightScale, shell_holder); + auto accessibilityFeatures = std::make_shared(); + accessibilityFeatures->SetBoldText(fontWeightScale, shell_holder); FML_DLOG(INFO) << "PlatformViewOHOSNapi::nativeSetFontWeightScale -> shell_holder: " << shell_holder << " fontWeightScale: "<< fontWeightScale; -- Gitee From 89eb30994048c713dbc95d7affe5529079e50bfa Mon Sep 17 00:00:00 2001 From: zjxi Date: Tue, 5 Nov 2024 17:19:39 +0800 Subject: [PATCH 08/14] =?UTF-8?q?refactor:=E5=B0=81=E8=A3=85=E6=9E=84?= =?UTF-8?q?=E5=BB=BAarkui=E6=97=A0=E9=9A=9C=E7=A2=8D=E8=AF=AD=E4=B9=89?= =?UTF-8?q?=E6=A0=91=E4=BB=A3=E7=A0=81=E9=80=BB=E8=BE=91,=E5=87=8F?= =?UTF-8?q?=E5=B0=91=E5=86=97=E4=BD=99=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zjxi --- .../ohos_accessibility_bridge.cpp | 71 ++++++++++--------- .../accessibility/ohos_accessibility_bridge.h | 4 ++ 2 files changed, 40 insertions(+), 35 deletions(-) diff --git a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp index f463cf2e69..dfee673775 100644 --- a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp +++ b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp @@ -545,7 +545,7 @@ void OhosAccessibilityBridge::ConvertChildRelativeRectToScreenRect( // 获取root节点的绝对坐标, 即xcomponent屏幕长宽 auto _rootRect = GetAbsoluteScreenRect(0); - // float rootWidth = _rootRect.second.first; + float rootWidth = _rootRect.second.first; auto rootHeight = _rootRect.second.second; // 真实缩放系数 @@ -585,9 +585,9 @@ void OhosAccessibilityBridge::ConvertChildRelativeRectToScreenRect( << currNode.id << ", (" << newLeft << ", " << newTop << ", " << newRight << ", " << newBottom << ")}"; // 防止滑动场景下绿框坐标超出屏幕范围,进行正则化处理 - // newLeft = static_cast(newLeft) % static_cast(rootWidth); + newLeft = static_cast(newLeft) % static_cast(rootWidth); newTop = static_cast(newTop) % static_cast(rootHeight); - // newRight = static_cast(newRight) % static_cast(rootWidth); + newRight = static_cast(newRight) % static_cast(rootWidth); newBottom = static_cast(newBottom) % static_cast(rootHeight); SetAbsoluteScreenRect(currNode.id, newLeft, newTop, newRight, newBottom); @@ -612,8 +612,8 @@ void OhosAccessibilityBridge::FlutterNodeToElementInfoById( "elementInfoFromList is null"; return; } - - /** NOTE: when elementId == 0 || elementId == -1 */ + FML_DLOG(INFO) << "FlutterNodeToElementInfoById elementId = " << elementId; + // 当elementId = -1或0时,创建root节点 if (elementId == 0 || elementId == -1) { // 获取flutter的root节点 flutter::SemanticsNode flutterNode = @@ -670,15 +670,10 @@ void OhosAccessibilityBridge::FlutterNodeToElementInfoById( OH_ArkUI_AccessibilityElementInfoSetComponentType(elementInfoFromList, "root"); OH_ArkUI_AccessibilityElementInfoSetContents(elementInfoFromList, flutterNode.label.c_str()); - return; + } else { + //当elementId >= 1时,根据flutter节点信息配置elementinfo无障碍属性 + FlutterSetElementInfoProperties(elementInfoFromList, elementId); } - - /** NOTE: when elementId >= 1 */ - FML_DLOG(INFO) << "FlutterNodeToElementInfoById elementId = " << elementId; - - // 根据flutter节点信息配置elementinfo无障碍属性 - FlutterSetElementInfoProperties(elementInfoFromList, elementId); - FML_DLOG(INFO) << "=== OhosAccessibilityBridge::FlutterNodeToElementInfoById is end ==="; } @@ -986,6 +981,32 @@ void OhosAccessibilityBridge::FlutterSetElementInfoProperties( false); } +/** + * 创建并配置完整arkui无障碍语义树 + */ +void OhosAccessibilityBridge::BuildArkUISemanticsTree( + int64_t elementId, + ArkUI_AccessibilityElementInfo* elementInfoFromList, + ArkUI_AccessibilityElementInfoList* elementList) +{ + //配置root节点信息 + FlutterNodeToElementInfoById(elementInfoFromList, elementId); + //获取flutter无障碍语义树的节点总数 + int64_t elementInfoCount = + static_cast(flutterSemanticsTree_.size()); + //创建并配置节点id >= 1的全部节点 + for (int64_t i = elementId + 1; i < elementInfoCount; i++) { + auto childNode = GetFlutterSemanticsNode(static_cast(i)); + //当节点为隐藏状态时,自动规避 + if (IsNodeVisible(childNode)) { + ArkUI_AccessibilityElementInfo* newElementInfo = + OH_ArkUI_AddAndGetAccessibilityElementInfo(elementList); + //配置当前子节点信息 + FlutterNodeToElementInfoById(newElementInfo, i); + } + } +} + /** * Called to obtain element information based on a specified node. * NOTE:该arkui接口需要在系统无障碍服务开启时,才能触发调用 @@ -1035,17 +1056,7 @@ int32_t OhosAccessibilityBridge::FindAccessibilityNodeInfosById( if (mode == ArkUI_AccessibilitySearchMode:: ARKUI_ACCESSIBILITY_NATIVE_SEARCH_MODE_PREFETCH_CURRENT) { /** Search for current nodes. (mode = 0) */ - FlutterNodeToElementInfoById(elementInfoFromList, elementId); - int64_t elementInfoCount = - static_cast(flutterSemanticsTree_.size()); - for (int64_t i = 1; i < elementInfoCount; i++) { - auto childNode = GetFlutterSemanticsNode(static_cast(i)); - if (IsNodeVisible(childNode)) { - ArkUI_AccessibilityElementInfo* newElementInfo = - OH_ArkUI_AddAndGetAccessibilityElementInfo(elementList); - FlutterNodeToElementInfoById(newElementInfo, i); - } - } + BuildArkUISemanticsTree(elementId, elementInfoFromList, elementList); } else if (mode == ArkUI_AccessibilitySearchMode:: ARKUI_ACCESSIBILITY_NATIVE_SEARCH_MODE_PREFETCH_PREDECESSORS) { @@ -1072,17 +1083,7 @@ int32_t OhosAccessibilityBridge::FindAccessibilityNodeInfosById( ArkUI_AccessibilitySearchMode:: ARKUI_ACCESSIBILITY_NATIVE_SEARCH_MODE_PREFETCH_RECURSIVE_CHILDREN) { /** Search for all child nodes. (mode = 8) */ - FlutterNodeToElementInfoById(elementInfoFromList, elementId); - int64_t elementInfoCount = - static_cast(flutterSemanticsTree_.size()); - for (int64_t i = 1; i < elementInfoCount; i++) { - auto childNode = GetFlutterSemanticsNode(static_cast(i)); - if (IsNodeVisible(childNode)) { - ArkUI_AccessibilityElementInfo* newElementInfo = - OH_ArkUI_AddAndGetAccessibilityElementInfo(elementList); - FlutterNodeToElementInfoById(newElementInfo, i); - } - } + BuildArkUISemanticsTree(elementId, elementInfoFromList, elementList); } else { if (IsNodeVisible(flutterNode)) { FlutterNodeToElementInfoById(elementInfoFromList, elementId); diff --git a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h index 7a669b53e4..64d717a7a9 100644 --- a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h +++ b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h @@ -230,6 +230,10 @@ class OhosAccessibilityBridge { std::string widget_type); void FlutterTreeToArkuiTree( ArkUI_AccessibilityElementInfoList* elementInfoList); + void BuildArkUISemanticsTree( + int64_t elementId, + ArkUI_AccessibilityElementInfo* elementInfoFromList, + ArkUI_AccessibilityElementInfoList* elementList); flutter::SemanticsNode GetFlutterRootSemanticsNode(); std::string GetNodeComponentType(const flutter::SemanticsNode& node); -- Gitee From 552b40d63400539dda72b384432c2610a45088fc Mon Sep 17 00:00:00 2001 From: zjxi Date: Thu, 7 Nov 2024 11:03:30 +0800 Subject: [PATCH 09/14] =?UTF-8?q?feat:=E5=A2=9E=E5=8A=A0=E6=94=B9=E8=BF=9B?= =?UTF-8?q?=E7=89=88=E5=B1=82=E6=AC=A1=E9=81=8D=E5=8E=86=E7=AE=97=E6=B3=95?= =?UTF-8?q?=E6=9E=84=E5=BB=BAarkui=E6=A0=91,=E4=BB=A5=E6=8E=A5=E5=85=A5Hyp?= =?UTF-8?q?ium=E5=92=8CUIViewer=E8=87=AA=E5=8A=A8=E5=8C=96=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E6=A1=86=E6=9E=B6,=E5=AE=9E=E7=8E=B0flutter=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=E6=A0=91=E7=9A=84=E5=8F=AF=E8=A7=86=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zjxi --- .../ohos_accessibility_bridge.cpp | 136 ++++++++---------- .../accessibility/ohos_accessibility_bridge.h | 5 +- 2 files changed, 66 insertions(+), 75 deletions(-) diff --git a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp index dfee673775..e0836cecbb 100644 --- a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp +++ b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp @@ -54,10 +54,8 @@ void OhosAccessibilityBridge::OnOhosAccessibilityStateChange( accessibilityFeatures_ = std::make_shared(); if (ohosAccessibilityEnabled) { - FML_DLOG(INFO) << "OnOhosAccessibilityEnabled()"; nativeAccessibilityChannel_->OnOhosAccessibilityEnabled(native_shell_holder_id_); } else { - FML_DLOG(INFO) << "OnOhosAccessibilityEnabled()"; accessibilityFeatures_->SetAccessibleNavigation(false, native_shell_holder_id_); nativeAccessibilityChannel_->OnOhosAccessibilityDisabled(native_shell_holder_id_); } @@ -75,7 +73,7 @@ void OhosAccessibilityBridge::updateSemantics( flutter::SemanticsNodeUpdates update, flutter::CustomAccessibilityActionUpdates actions) { - FML_DLOG(INFO) << ("OhosAccessibilityBridge::updateSemantics is called"); + FML_DLOG(INFO) << ("OhosAccessibilityBridge::UpdateSemantics()"); // 当flutter页面更新时,自动请求id=0节点组件获焦(滑动组件除外) if (IS_FLUTTER_NAVIGATE) { @@ -147,6 +145,11 @@ void OhosAccessibilityBridge::updateSemantics( << item.second << ")"; } + //打印按层次遍历排序的flutter语义树节点id数组 + std::vector levelOrderTraversalTree = GetLevelOrderTraversalTree(0); + for (const auto& item: levelOrderTraversalTree) { + FML_DLOG(INFO) << "LevelOrderTraversalTree: { " << item << " }"; + } FML_DLOG(INFO) << "=== UpdateSemantics is end ==="; } @@ -225,27 +228,20 @@ void OhosAccessibilityBridge::FlutterScrollExecution( } /** - * 当页面状态更新事件,在页面转换、切换、调整大小时发送页面状态更新事件 + * 当页面内容/状态更新事件,在页面转换、切换、调整大小时发送页面状态更新事件 */ -void OhosAccessibilityBridge::PageStateUpdate() +void OhosAccessibilityBridge::FlutterPageUpdate( + ArkUI_AccessibilityEventType eventType) { ArkUI_AccessibilityEventInfo* pageUpdateEventInfo = OH_ArkUI_CreateAccessibilityEventInfo(); - ArkUI_AccessibilityElementInfo* _elementInfo = - OH_ArkUI_CreateAccessibilityElementInfo(); - OH_ArkUI_AccessibilityEventSetEventType( - pageUpdateEventInfo, - ArkUI_AccessibilityEventType:: - ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_PAGE_CONTENT_UPDATE); - // FlutterNodeToElementInfoById(_elementInfo, elementId); - OH_ArkUI_AccessibilityEventSetElementInfo(pageUpdateEventInfo, _elementInfo); + pageUpdateEventInfo, eventType); auto callback = [](int32_t errorCode) { FML_DLOG(WARNING) << "PageStateUpdate callback-> errorCode =" << errorCode; }; - if (provider_ == nullptr) { FML_DLOG(ERROR) << "PageStateUpdate ->" "AccessibilityProvider = nullptr"; @@ -253,9 +249,7 @@ void OhosAccessibilityBridge::PageStateUpdate() } OH_ArkUI_SendAccessibilityAsyncEvent(provider_, pageUpdateEventInfo, callback); - OH_ArkUI_DestoryAccessibilityEventInfo(pageUpdateEventInfo); - OH_ArkUI_DestoryAccessibilityElementInfo(_elementInfo); FML_DLOG(INFO) << "PageStateUpdate is end"; } @@ -422,12 +416,12 @@ void OhosAccessibilityBridge::FlutterTreeToArkuiTree( } // 设置孩子节点 - int32_t childCount = - static_cast(flutterNode.childrenInTraversalOrder.size()); + int32_t childCount = flutterNode.childrenInTraversalOrder.size(); + 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(flutterNode.childrenInTraversalOrder[i]); + childNodeIds[i] = static_cast(childrenIdsVec[i]); FML_DLOG(INFO) << "FlutterTreeToArkuiTree flutterNode.id= " << flutterNode.id << " childCount= " << childCount << " childNodeId=" << childNodeIds[i]; @@ -648,13 +642,12 @@ void OhosAccessibilityBridge::FlutterNodeToElementInfoById( false); // 配置child节点信息 - auto flutterChildVec = flutterNode.childrenInTraversalOrder; - int32_t childCount = - static_cast(flutterChildVec.size()); + int32_t childCount = flutterNode.childrenInTraversalOrder.size(); + 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(flutterChildVec[i]); + childNodeIds[i] = static_cast(childrenIdsVec[i]); FML_DLOG(INFO) << "FlutterNodeToElementInfoById -> elementid=0 childCount=" << childCount << " childNodeIds=" << childNodeIds[i]; @@ -859,15 +852,12 @@ void OhosAccessibilityBridge::FlutterSetElementInfoProperties( hint.c_str()); // set chidren elementinfo ids - auto flutterChildVec = flutterNode.childrenInTraversalOrder; - //按照升序排列孩子数组id - std::sort(flutterChildVec.begin(), flutterChildVec.end()); - int32_t childCount = - static_cast(flutterChildVec.size()); + int32_t childCount = flutterNode.childrenInTraversalOrder.size(); + 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(flutterChildVec[i]); + childNodeIds[i] = static_cast(childrenIdsVec[i]); FML_DLOG(INFO) << "FlutterNodeToElementInfoById -> elementid=" << elementId << " childCount=" << childCount << " childNodeIds=" << childNodeIds[i]; @@ -981,6 +971,37 @@ void OhosAccessibilityBridge::FlutterSetElementInfoProperties( false); } +/** + * 将flutter无障碍语义树的转化为层次遍历顺序存储, + * 并按该顺序构建arkui语义树,以实现DevEco Testing + * UIViewer、Hypium自动化测试工具对flutter组件树的可视化 + */ +std::vector OhosAccessibilityBridge::GetLevelOrderTraversalTree(int32_t rootId) +{ + std::vector levelOrderTraversalTree; + std::queue semanticsQue; + + auto root = GetFlutterSemanticsNode(rootId); + 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(auto& childId: currNode.childrenInTraversalOrder) { + auto childNode = GetFlutterSemanticsNode(childId); + semanticsQue.push(childNode); + } + } + } + return levelOrderTraversalTree; +} + /** * 创建并配置完整arkui无障碍语义树 */ @@ -992,17 +1013,18 @@ void OhosAccessibilityBridge::BuildArkUISemanticsTree( //配置root节点信息 FlutterNodeToElementInfoById(elementInfoFromList, elementId); //获取flutter无障碍语义树的节点总数 - int64_t elementInfoCount = - static_cast(flutterSemanticsTree_.size()); + auto levelOrderTreeVec = GetLevelOrderTraversalTree(0); + int64_t elementInfoCount = levelOrderTreeVec.size(); //创建并配置节点id >= 1的全部节点 - for (int64_t i = elementId + 1; i < elementInfoCount; i++) { - auto childNode = GetFlutterSemanticsNode(static_cast(i)); + for (int64_t i = 1; i < elementInfoCount; i++) { + int64_t levelOrderId = levelOrderTreeVec[i]; + auto newNode = GetFlutterSemanticsNode(levelOrderId); //当节点为隐藏状态时,自动规避 - if (IsNodeVisible(childNode)) { + if (IsNodeVisible(newNode)) { ArkUI_AccessibilityElementInfo* newElementInfo = OH_ArkUI_AddAndGetAccessibilityElementInfo(elementList); //配置当前子节点信息 - FlutterNodeToElementInfoById(newElementInfo, i); + FlutterNodeToElementInfoById(newElementInfo, levelOrderId); } } } @@ -1085,9 +1107,7 @@ int32_t OhosAccessibilityBridge::FindAccessibilityNodeInfosById( /** Search for all child nodes. (mode = 8) */ BuildArkUISemanticsTree(elementId, elementInfoFromList, elementList); } else { - if (IsNodeVisible(flutterNode)) { - FlutterNodeToElementInfoById(elementInfoFromList, elementId); - } + FlutterNodeToElementInfoById(elementInfoFromList, elementId); } FML_DLOG(INFO) << "--- FindAccessibilityNodeInfosById is end ---"; return ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL; @@ -1142,14 +1162,12 @@ int32_t OhosAccessibilityBridge::ExecuteAccessibilityAction( Flutter_SendAccessibilityAsyncEvent(elementId, clickEventType); FML_DLOG(INFO) << "ExecuteAccessibilityAction -> action: click(" << action << ")" << " event: click(" << clickEventType << ")"; - // 解析arkui的屏幕点击 -> flutter对应节点的屏幕点击 auto flutterTapAction = ArkuiActionsToFlutterActions(action); DispatchSemanticsAction(static_cast(elementId), flutterTapAction, {}); break; } - /** Response to a long click. 32 */ case ArkUI_Accessibility_ActionType:: ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_LONG_CLICK: { @@ -1160,14 +1178,12 @@ int32_t OhosAccessibilityBridge::ExecuteAccessibilityAction( FML_DLOG(INFO) << "ExecuteAccessibilityAction -> action: longclick(" << action << ")" << " event: longclick(" << longClickEventType << ")"; - // 解析arkui的屏幕动作 -> flutter对应节点的屏幕动作 auto flutterLongPressAction = ArkuiActionsToFlutterActions(action); DispatchSemanticsAction(static_cast(elementId), flutterLongPressAction, {}); break; } - /** Accessibility focus acquisition. 64 */ case ArkUI_Accessibility_ActionType:: ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_GAIN_ACCESSIBILITY_FOCUS: { @@ -1175,8 +1191,7 @@ int32_t OhosAccessibilityBridge::ExecuteAccessibilityAction( auto flutterGainFocusAction = ArkuiActionsToFlutterActions(action); DispatchSemanticsAction(static_cast(elementId), flutterGainFocusAction, {}); - /** Accessibility focus event, sent after the UI component responds. 32768 - */ + // Accessibility focus event, sent after the UI component responds. 32768 auto focusEventType = ArkUI_AccessibilityEventType:: ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_ACCESSIBILITY_FOCUSED; Flutter_SendAccessibilityAsyncEvent(elementId, focusEventType); @@ -1190,7 +1205,6 @@ int32_t OhosAccessibilityBridge::ExecuteAccessibilityAction( } break; } - /** Accessibility focus clearance. 128 */ case ArkUI_Accessibility_ActionType:: ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_CLEAR_ACCESSIBILITY_FOCUS: { @@ -1198,7 +1212,6 @@ int32_t OhosAccessibilityBridge::ExecuteAccessibilityAction( auto flutterLoseFocusAction = ArkuiActionsToFlutterActions(action); DispatchSemanticsAction(static_cast(elementId), flutterLoseFocusAction, {}); - /** Accessibility focus cleared event, sent after the UI component * responds. 65536 */ auto clearFocusEventType = ArkUI_AccessibilityEventType:: @@ -1209,7 +1222,6 @@ int32_t OhosAccessibilityBridge::ExecuteAccessibilityAction( << clearFocusEventType << ")"; break; } - /** Forward scroll action. 256 */ case ArkUI_Accessibility_ActionType:: ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SCROLL_FORWARD: { @@ -1218,21 +1230,18 @@ int32_t OhosAccessibilityBridge::ExecuteAccessibilityAction( auto flutterScrollUpAction = ArkuiActionsToFlutterActions(action); DispatchSemanticsAction(static_cast(elementId), flutterScrollUpAction, {}); - } else if (flutterNode.HasAction(ACTIONS_::kScrollLeft)) { DispatchSemanticsAction(static_cast(elementId), ACTIONS_::kScrollLeft, {}); - } else if (flutterNode.HasAction(ACTIONS_::kIncrease)) { flutterNode.value = flutterNode.increasedValue; flutterNode.valueAttributes = flutterNode.increasedValueAttributes; - + Flutter_SendAccessibilityAsyncEvent( elementId, ArkUI_AccessibilityEventType:: ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_SELECTED); DispatchSemanticsAction(static_cast(elementId), ACTIONS_::kIncrease, {}); - } else { } std::string currComponetType = GetNodeComponentType(flutterNode); @@ -1249,7 +1258,6 @@ int32_t OhosAccessibilityBridge::ExecuteAccessibilityAction( } break; } - /** Backward scroll action. 512 */ case ArkUI_Accessibility_ActionType:: ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SCROLL_BACKWARD: { @@ -1287,7 +1295,6 @@ int32_t OhosAccessibilityBridge::ExecuteAccessibilityAction( } break; } - /** Copy action for text content. 1024 */ case ArkUI_Accessibility_ActionType:: ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_COPY: { @@ -1297,7 +1304,6 @@ int32_t OhosAccessibilityBridge::ExecuteAccessibilityAction( {}); break; } - /** Paste action for text content. 2048 */ case ArkUI_Accessibility_ActionType:: ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_PASTE: { @@ -1307,7 +1313,6 @@ int32_t OhosAccessibilityBridge::ExecuteAccessibilityAction( {}); break; } - /** Cut action for text content. 4096 */ case ArkUI_Accessibility_ActionType:: ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_CUT: @@ -1316,7 +1321,6 @@ int32_t OhosAccessibilityBridge::ExecuteAccessibilityAction( DispatchSemanticsAction(static_cast(elementId), ACTIONS_::kCut, {}); break; - /** Text selection action, requiring the setting of selectTextBegin, * TextEnd, and TextInForward parameters to select a text * segment in the text box. 8192 */ @@ -1328,7 +1332,6 @@ int32_t OhosAccessibilityBridge::ExecuteAccessibilityAction( PerformSelectText(flutterNode, action, actionArguments); break; } - /** Text content setting action. 16384 */ case ArkUI_Accessibility_ActionType:: ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SET_TEXT: { @@ -1338,7 +1341,6 @@ int32_t OhosAccessibilityBridge::ExecuteAccessibilityAction( PerformSetText(flutterNode, action, actionArguments); break; } - /** Cursor position setting action. 1048576 */ case ArkUI_Accessibility_ActionType:: ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SET_CURSOR_POSITION: { @@ -1348,7 +1350,6 @@ int32_t OhosAccessibilityBridge::ExecuteAccessibilityAction( // 当前os接口不支持该功能,不影响正常屏幕朗读 break; } - /** Invalid action. 0 */ case ArkUI_Accessibility_ActionType:: ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_INVALID: { @@ -1362,7 +1363,6 @@ int32_t OhosAccessibilityBridge::ExecuteAccessibilityAction( << invalidEventType << ")"; break; } - default: { /** custom semantics action */ } @@ -1581,34 +1581,27 @@ std::string OhosAccessibilityBridge::GetNodeComponentType( if (node.HasFlag(FLAGS_::kIsButton)) { return "Button"; } - if (node.HasFlag(FLAGS_::kIsTextField)) { // arkui没有textfield,这里直接透传或者传递textinput return "TextField"; } - if (node.HasFlag(FLAGS_::kIsMultiline)) { // arkui没有多行文本textfield,这里直接透传 return "TextArea"; } - if (node.HasFlag(FLAGS_::kIsLink)) { return "Link"; } - if (node.HasFlag(FLAGS_::kIsSlider) || node.HasAction(ACTIONS_::kIncrease) || node.HasAction(ACTIONS_::kDecrease)) { return "Slider"; } - if (node.HasFlag(FLAGS_::kIsHeader)) { return "Header"; } - if (node.HasFlag(FLAGS_::kIsImage)) { return "Image"; } - if (node.HasFlag(FLAGS_::kHasCheckedState)) { if (node.HasFlag(FLAGS_::kIsInMutuallyExclusiveGroup)) { // arkui没有RadioButton,这里透传为RadioButton @@ -1617,16 +1610,13 @@ std::string OhosAccessibilityBridge::GetNodeComponentType( return "Checkbox"; } } - if (node.HasFlag(FLAGS_::kHasToggledState)) { // arkui没有ToggleSwitch,这里透传为Toggle return "ToggleSwitch"; } - if ((!node.label.empty() || !node.tooltip.empty() || !node.hint.empty())) { return "Text"; } - return "Widget" + std::to_string(node.id); } diff --git a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h index 64d717a7a9..1eedd1be56 100644 --- a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h +++ b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h @@ -234,7 +234,8 @@ class OhosAccessibilityBridge { int64_t elementId, ArkUI_AccessibilityElementInfo* elementInfoFromList, ArkUI_AccessibilityElementInfoList* elementList); - + + std::vector GetLevelOrderTraversalTree(int32_t rootId); flutter::SemanticsNode GetFlutterRootSemanticsNode(); std::string GetNodeComponentType(const flutter::SemanticsNode& node); flutter::SemanticsAction ArkuiActionsToFlutterActions( @@ -274,7 +275,7 @@ class OhosAccessibilityBridge { void GetCustomActionDebugInfo( flutter::CustomAccessibilityAction customAccessibilityAction); - void PageStateUpdate(); + void FlutterPageUpdate(ArkUI_AccessibilityEventType eventType); void RequestFocusWhenPageUpdate(); bool Contains(const std::string source, const std::string target); -- Gitee From 52b369ffc829216b48dd6068bec3d04c7b18885a Mon Sep 17 00:00:00 2001 From: zjxi Date: Wed, 13 Nov 2024 12:14:50 +0800 Subject: [PATCH 10/14] =?UTF-8?q?fix:=E5=AE=8C=E5=96=84=E6=8C=87=E9=92=88?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E5=8F=98=E9=87=8F=E9=94=80=E6=AF=81=E5=90=8E?= =?UTF-8?q?=E8=B5=8B=E5=80=BC=E4=B8=BA=E7=A9=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zjxi --- .../ohos/accessibility/ohos_accessibility_bridge.cpp | 9 ++++++++- .../ohos/accessibility/ohos_accessibility_bridge.h | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp index e0836cecbb..faa3c40dd8 100644 --- a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp +++ b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp @@ -118,6 +118,7 @@ void OhosAccessibilityBridge::updateSemantics( FlutterScrollExecution(node, _elementInfo); OH_ArkUI_DestoryAccessibilityElementInfo(_elementInfo); + _elementInfo = nullptr; } // 判断是否触发liveRegion活动区,当前节点是否活跃(暂不影响正常功能) @@ -250,6 +251,7 @@ void OhosAccessibilityBridge::FlutterPageUpdate( OH_ArkUI_SendAccessibilityAsyncEvent(provider_, pageUpdateEventInfo, callback); OH_ArkUI_DestoryAccessibilityEventInfo(pageUpdateEventInfo); + pageUpdateEventInfo = nullptr; FML_DLOG(INFO) << "PageStateUpdate is end"; } @@ -287,7 +289,9 @@ void OhosAccessibilityBridge::RequestFocusWhenPageUpdate() OH_ArkUI_SendAccessibilityAsyncEvent(provider_, reqFocusEventInfo, callback); OH_ArkUI_DestoryAccessibilityEventInfo(reqFocusEventInfo); + reqFocusEventInfo = nullptr; OH_ArkUI_DestoryAccessibilityElementInfo(elementInfo); + elementInfo = nullptr; } /** @@ -330,6 +334,7 @@ void OhosAccessibilityBridge::Announce(std::unique_ptr& message) OH_ArkUI_SendAccessibilityAsyncEvent(provider_, announceEventInfo, callback); OH_ArkUI_DestoryAccessibilityEventInfo(announceEventInfo); + announceEventInfo = nullptr; return; } @@ -993,7 +998,7 @@ std::vector OhosAccessibilityBridge::GetLevelOrderTraversalTree(int32_t std::sort(currNode.childrenInTraversalOrder.begin(), currNode.childrenInTraversalOrder.end()); - for(auto& childId: currNode.childrenInTraversalOrder) { + for (auto& childId: currNode.childrenInTraversalOrder) { auto childNode = GetFlutterSemanticsNode(childId); semanticsQue.push(childNode); } @@ -1525,7 +1530,9 @@ void OhosAccessibilityBridge::Flutter_SendAccessibilityAsyncEvent( // 7.销毁新创建的elementinfo, eventinfo OH_ArkUI_DestoryAccessibilityElementInfo(_elementInfo); + _elementInfo = nullptr; OH_ArkUI_DestoryAccessibilityEventInfo(eventInfo); + eventInfo = nullptr; FML_DLOG(INFO) << "OhosAccessibilityBridge::Flutter_SendAccessibilityAsyncEvent is end"; diff --git a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h index 1eedd1be56..c8a04b45f6 100644 --- a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h +++ b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h @@ -234,7 +234,7 @@ class OhosAccessibilityBridge { int64_t elementId, ArkUI_AccessibilityElementInfo* elementInfoFromList, ArkUI_AccessibilityElementInfoList* elementList); - + std::vector GetLevelOrderTraversalTree(int32_t rootId); flutter::SemanticsNode GetFlutterRootSemanticsNode(); std::string GetNodeComponentType(const flutter::SemanticsNode& node); -- Gitee From af008ef3b2385fcd291d735093ccaf67a04d3475 Mon Sep 17 00:00:00 2001 From: zjxi Date: Wed, 13 Nov 2024 15:47:52 +0800 Subject: [PATCH 11/14] =?UTF-8?q?feat:=E5=AE=8C=E5=96=84flutter=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=E7=B1=BB=E5=9E=8B=E8=8E=B7=E5=8F=96=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?,=E5=AF=B9=E6=8E=A5hypium=E8=87=AA=E5=8A=A8=E5=8C=96=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E6=A1=86=E6=9E=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zjxi --- .../ohos_accessibility_bridge.cpp | 19 +++++-- .../accessibility/ohos_accessibility_bridge.h | 54 +++++++++++++++++++ 2 files changed, 68 insertions(+), 5 deletions(-) diff --git a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp index faa3c40dd8..3aac3fcfd7 100644 --- a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp +++ b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp @@ -1589,11 +1589,9 @@ std::string OhosAccessibilityBridge::GetNodeComponentType( return "Button"; } if (node.HasFlag(FLAGS_::kIsTextField)) { - // arkui没有textfield,这里直接透传或者传递textinput return "TextField"; } if (node.HasFlag(FLAGS_::kIsMultiline)) { - // arkui没有多行文本textfield,这里直接透传 return "TextArea"; } if (node.HasFlag(FLAGS_::kIsLink)) { @@ -1607,7 +1605,7 @@ std::string OhosAccessibilityBridge::GetNodeComponentType( return "Header"; } if (node.HasFlag(FLAGS_::kIsImage)) { - return "Image"; + return "ImageView"; } if (node.HasFlag(FLAGS_::kHasCheckedState)) { if (node.HasFlag(FLAGS_::kIsInMutuallyExclusiveGroup)) { @@ -1618,8 +1616,19 @@ std::string OhosAccessibilityBridge::GetNodeComponentType( } } if (node.HasFlag(FLAGS_::kHasToggledState)) { - // arkui没有ToggleSwitch,这里透传为Toggle - return "ToggleSwitch"; + return "Switch"; + } + if (node.HasFlag(FLAGS_::kHasImplicitScrolling)) { + if (node.HasAction(ACTIONS_::kScrollLeft) || + node.HasAction(ACTIONS_::kScrollRight)) { + return "HorizontalScrollView"; + } else { + return "ScrollView"; + } + } + if (node.HasAction(ACTIONS_::kIncrease) || + node.HasAction(ACTIONS_::kDecrease)) { + return "SeekBar"; } if ((!node.label.empty() || !node.tooltip.empty() || !node.hint.empty())) { return "Text"; diff --git a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h index c8a04b45f6..2b0f0fdc3c 100644 --- a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h +++ b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h @@ -281,5 +281,59 @@ class OhosAccessibilityBridge { bool Contains(const std::string source, const std::string target); }; +enum class AccessibilityAction : int32_t { + kTap = 1 << 0, + kLongPress = 1 << 1, + kScrollLeft = 1 << 2, + kScrollRight = 1 << 3, + kScrollUp = 1 << 4, + kScrollDown = 1 << 5, + kIncrease = 1 << 6, + kDecrease = 1 << 7, + kShowOnScreen = 1 << 8, + kMoveCursorForwardByCharacter = 1 << 9, + kMoveCursorBackwardByCharacter = 1 << 10, + kSetSelection = 1 << 11, + kCopy = 1 << 12, + kCut = 1 << 13, + kPaste = 1 << 14, + kDidGainAccessibilityFocus = 1 << 15, + kDidLoseAccessibilityFocus = 1 << 16, + kCustomAction = 1 << 17, + kDismiss = 1 << 18, + kMoveCursorForwardByWord = 1 << 19, + kMoveCursorBackwardByWord = 1 << 20, + kSetText = 1 << 21, +}; + +enum class AccessibilityFlags : int32_t { + kHasCheckedState = 1 << 0, + kIsChecked = 1 << 1, + kIsSelected = 1 << 2, + kIsButton = 1 << 3, + kIsTextField = 1 << 4, + kIsFocused = 1 << 5, + kHasEnabledState = 1 << 6, + kIsEnabled = 1 << 7, + kIsInMutuallyExclusiveGroup = 1 << 8, + kIsHeader = 1 << 9, + kIsObscured = 1 << 10, + kScopesRoute = 1 << 11, + kNamesRoute = 1 << 12, + kIsHidden = 1 << 13, + kIsImage = 1 << 14, + kIsLiveRegion = 1 << 15, + kHasToggledState = 1 << 16, + kIsToggled = 1 << 17, + kHasImplicitScrolling = 1 << 18, + kIsMultiline = 1 << 19, + kIsReadOnly = 1 << 20, + kIsFocusable = 1 << 21, + kIsLink = 1 << 22, + kIsSlider = 1 << 23, + kIsKeyboardKey = 1 << 24, + kIsCheckStateMixed = 1 << 25, +}; + } // namespace flutter #endif // OHOS_ACCESSIBILITY_BRIDGE_H -- Gitee From 5f5c0997168dafcd4158b0b9cad2c0c743ee68b5 Mon Sep 17 00:00:00 2001 From: zjxi Date: Thu, 14 Nov 2024 16:12:06 +0800 Subject: [PATCH 12/14] =?UTF-8?q?refactor:=E5=A2=9E=E5=8A=A0=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E8=A7=84=E8=8C=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zjxi --- .../ohos/accessibility/ohos_accessibility_manager.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/shell/platform/ohos/accessibility/ohos_accessibility_manager.cpp b/shell/platform/ohos/accessibility/ohos_accessibility_manager.cpp index d88a5acaf0..e9b1499f70 100644 --- a/shell/platform/ohos/accessibility/ohos_accessibility_manager.cpp +++ b/shell/platform/ohos/accessibility/ohos_accessibility_manager.cpp @@ -26,11 +26,13 @@ OhosAccessibilityManager::~OhosAccessibilityManager() {} void OhosAccessibilityManager::OnAccessibilityStateChanged( bool ohosAccessibilityEnabled) {} -void OhosAccessibilityManager::SetOhosAccessibilityEnabled(bool isEnabled) { +void OhosAccessibilityManager::SetOhosAccessibilityEnabled(bool isEnabled) +{ this->isOhosAccessibilityEnabled_ = isEnabled; } -bool OhosAccessibilityManager::GetOhosAccessibilityEnabled() { +bool OhosAccessibilityManager::GetOhosAccessibilityEnabled() +{ return this->isOhosAccessibilityEnabled_; } -- Gitee From 56fee94b47f2d2fc295f4b6e16dc7272a8a3d6ed Mon Sep 17 00:00:00 2001 From: zjxi Date: Fri, 15 Nov 2024 12:14:50 +0800 Subject: [PATCH 13/14] =?UTF-8?q?feat:=E5=A2=9E=E5=8A=A0capi=E5=87=BD?= =?UTF-8?q?=E6=95=B0=E8=B0=83=E7=94=A8=E7=9A=84=E5=AE=89=E5=85=A8=E6=A3=80?= =?UTF-8?q?=E6=9F=A5=E5=8A=9F=E8=83=BD,=E4=BC=98=E5=8C=96=E9=83=A8?= =?UTF-8?q?=E5=88=86=E5=86=85=E5=AD=98=E5=AE=89=E5=85=A8=E5=86=99=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zjxi --- .../ohos_accessibility_bridge.cpp | 447 +++++++++++------- .../accessibility/ohos_accessibility_bridge.h | 11 +- 2 files changed, 281 insertions(+), 177 deletions(-) diff --git a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp index 3aac3fcfd7..2baf359b2b 100644 --- a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp +++ b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp @@ -17,18 +17,28 @@ #include #include #include "flutter/fml/logging.h" +#include "flutter/shell/platform/ohos/ohos_logging.h" #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" +#define ARKUI_SUCCEED_CODE 0 +#define ARKUI_FAILED_CODE -1 +#define ARKUI_BAD_PARAM_CODE -2 +#define ARKUI_OOM_CODE -3 +#define ARKUI_ACCESSIBILITY_CALL_CHECK(X) \ + do { \ + int32_t ret = X; \ + if (ret != ARKUI_SUCCEED_CODE) { \ + LOGE("Failed arkui a11y function call, error code:%{public}d", ret); \ + } \ + } while (false) \ + namespace flutter { - OhosAccessibilityBridge* OhosAccessibilityBridge::bridgeInstance = nullptr; -OhosAccessibilityBridge::OhosAccessibilityBridge() {} - OhosAccessibilityBridge* OhosAccessibilityBridge::GetInstance() { if(!bridgeInstance) { @@ -42,6 +52,7 @@ void OhosAccessibilityBridge::DestroyInstance() { bridgeInstance = nullptr; } +OhosAccessibilityBridge::OhosAccessibilityBridge() {} /** * 监听当前ohos平台是否开启无障碍屏幕朗读服务 */ @@ -93,6 +104,10 @@ void OhosAccessibilityBridge::updateSemantics( GetSemanticsNodeDebugInfo(node); GetSemanticsFlagsDebugInfo(node); + // if (!IsNodeVisible(node)) { + // continue; + // } + /** * 构建flutter无障碍语义节点树 * NOTE: 若使用flutterSemanticsTree_.insert({node.id, node})方式 @@ -110,7 +125,7 @@ void OhosAccessibilityBridge::updateSemantics( } // 当滑动节点产生滑动,并执行滑动处理 - if (HasScrolled(node)) { + if (HasScrolled(node) && IsNodeVisible(node)) { ArkUI_AccessibilityElementInfo* _elementInfo = OH_ArkUI_CreateAccessibilityElementInfo(); @@ -121,11 +136,12 @@ void OhosAccessibilityBridge::updateSemantics( _elementInfo = nullptr; } - // 判断是否触发liveRegion活动区,当前节点是否活跃(暂不影响正常功能) + // 判断是否触发liveRegion活动区,当前节点是否活跃 if (node.HasFlag(FLAGS_::kIsLiveRegion)) { FML_DLOG(INFO) - << "UpdateSemantics -> flutterNode is kIsLiveRegion, node.id=" - << node.id; + << "UpdateSemantics -> LiveRegion, node.id=" << node.id; + FlutterPageUpdate(ArkUI_AccessibilityEventType:: + ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_PAGE_CONTENT_UPDATE); } } @@ -194,12 +210,16 @@ void OhosAccessibilityBridge::FlutterScrollExecution( if (node.scrollChildren > 0) { // 配置当前滑动组件的子节点总数 int32_t itemCount = node.scrollChildren; - OH_ArkUI_AccessibilityElementInfoSetItemCount(elementInfoFromList, - itemCount); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetItemCount( + elementInfoFromList, itemCount) + ); // 设置当前页面可见的起始滑动index int32_t startItemIndex = node.scrollIndex; - OH_ArkUI_AccessibilityElementInfoSetStartItemIndex(elementInfoFromList, - startItemIndex); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetStartItemIndex(elementInfoFromList, + startItemIndex) + ); // 计算当前滑动位置页面的可见子滑动节点数量 int visibleChildren = 0; @@ -212,19 +232,22 @@ void OhosAccessibilityBridge::FlutterScrollExecution( } // 当可见滑动子节点数量超过滑动组件总子节点数量 if (node.scrollIndex + visibleChildren > node.scrollChildren) { - FML_DLOG(ERROR) + FML_DLOG(WARNING) << "FlutterScrollExecution -> Scroll index is out of bounds"; } // 当滑动击中子节点数量为0 if (!node.childrenInHitTestOrder.size()) { - FML_DLOG(ERROR) << "FlutterScrollExecution -> Had scrollChildren but no " - "childrenInHitTestOrder"; + FML_DLOG(WARNING) << "FlutterScrollExecution -> Had scrollChildren but no " + "childrenInHitTestOrder"; } // 设置当前页面可见的末尾滑动index int32_t endItemIndex = node.scrollIndex + visibleChildren - 1; - OH_ArkUI_AccessibilityElementInfoSetEndItemIndex(elementInfoFromList, - endItemIndex); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetEndItemIndex(elementInfoFromList, + endItemIndex) + ); + } } @@ -234,26 +257,26 @@ void OhosAccessibilityBridge::FlutterScrollExecution( void OhosAccessibilityBridge::FlutterPageUpdate( ArkUI_AccessibilityEventType eventType) { + if (provider_ == nullptr) { + FML_DLOG(ERROR) << "PageStateUpdate ->" + "AccessibilityProvider = nullptr"; + return; + } ArkUI_AccessibilityEventInfo* pageUpdateEventInfo = OH_ArkUI_CreateAccessibilityEventInfo(); - OH_ArkUI_AccessibilityEventSetEventType( - pageUpdateEventInfo, eventType); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityEventSetEventType(pageUpdateEventInfo, eventType) + ); auto callback = [](int32_t errorCode) { FML_DLOG(WARNING) << "PageStateUpdate callback-> errorCode =" << errorCode; }; - if (provider_ == nullptr) { - FML_DLOG(ERROR) << "PageStateUpdate ->" - "AccessibilityProvider = nullptr"; - return; - } + OH_ArkUI_SendAccessibilityAsyncEvent(provider_, pageUpdateEventInfo, callback); OH_ArkUI_DestoryAccessibilityEventInfo(pageUpdateEventInfo); pageUpdateEventInfo = nullptr; - - FML_DLOG(INFO) << "PageStateUpdate is end"; } /** @@ -261,31 +284,35 @@ void OhosAccessibilityBridge::FlutterPageUpdate( */ void OhosAccessibilityBridge::RequestFocusWhenPageUpdate() { + if (provider_ == nullptr) { + FML_DLOG(ERROR) << "RequestFocusWhenPageUpdate ->" + "AccessibilityProvider = nullptr"; + return; + } ArkUI_AccessibilityEventInfo* reqFocusEventInfo = OH_ArkUI_CreateAccessibilityEventInfo(); ArkUI_AccessibilityElementInfo* elementInfo = OH_ArkUI_CreateAccessibilityElementInfo(); - OH_ArkUI_AccessibilityEventSetEventType( - reqFocusEventInfo, - ArkUI_AccessibilityEventType:: - ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_REQUEST_ACCESSIBILITY_FOCUS); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityEventSetEventType( + reqFocusEventInfo, + ArkUI_AccessibilityEventType:: + ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_REQUEST_ACCESSIBILITY_FOCUS) + ); int32_t requestFocusId = 0; - OH_ArkUI_AccessibilityEventSetRequestFocusId(reqFocusEventInfo, - requestFocusId); - - OH_ArkUI_AccessibilityEventSetElementInfo(reqFocusEventInfo, elementInfo); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityEventSetRequestFocusId(reqFocusEventInfo, + requestFocusId) + ); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityEventSetElementInfo(reqFocusEventInfo, elementInfo) + ); auto callback = [](int32_t errorCode) { FML_DLOG(WARNING) << "PageStateUpdate callback-> errorCode =" << errorCode; }; - - if (provider_ == nullptr) { - FML_DLOG(ERROR) << "PageStateUpdate ->" - "AccessibilityProvider = nullptr"; - return; - } OH_ArkUI_SendAccessibilityAsyncEvent(provider_, reqFocusEventInfo, callback); OH_ArkUI_DestoryAccessibilityEventInfo(reqFocusEventInfo); @@ -299,38 +326,31 @@ void OhosAccessibilityBridge::RequestFocusWhenPageUpdate() */ void OhosAccessibilityBridge::Announce(std::unique_ptr& message) { + if (provider_ == nullptr) { + FML_DLOG(ERROR) << "announce ->" + "AccessibilityProvider = nullptr"; + return; + } // 创建并设置屏幕朗读事件 ArkUI_AccessibilityEventInfo* announceEventInfo = OH_ArkUI_CreateAccessibilityEventInfo(); - int32_t ret1 = OH_ArkUI_AccessibilityEventSetEventType( - announceEventInfo, - ArkUI_AccessibilityEventType:: - ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_ANNOUNCE_FOR_ACCESSIBILITY); - if (ret1 != 0) { - FML_DLOG(INFO) << "OhosAccessibilityBridge::announce " - "OH_ArkUI_AccessibilityEventSetEventType failed"; - return; - } - int32_t ret2 = OH_ArkUI_AccessibilityEventSetTextAnnouncedForAccessibility( - announceEventInfo, message.get()); - if (ret2 != 0) { - FML_DLOG(INFO) - << "OhosAccessibilityBridge::announce " - "OH_ArkUI_AccessibilityEventSetTextAnnouncedForAccessibility failed"; - return; - } - FML_DLOG(INFO) << ("OhosAccessibilityBridge::announce message: ") + + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityEventSetEventType( + announceEventInfo, + ArkUI_AccessibilityEventType:: + ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_ANNOUNCE_FOR_ACCESSIBILITY) + ); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityEventSetTextAnnouncedForAccessibility( + announceEventInfo, message.get()) + ); + FML_DLOG(INFO) << ("announce -> message: ") << (message.get()); auto callback = [](int32_t errorCode) { FML_DLOG(WARNING) << "announce callback-> errorCode =" << errorCode; }; - - if (provider_ == nullptr) { - FML_DLOG(ERROR) << "announce ->" - "AccessibilityProvider = nullptr"; - return; - } OH_ArkUI_SendAccessibilityAsyncEvent(provider_, announceEventInfo, callback); OH_ArkUI_DestoryAccessibilityEventInfo(announceEventInfo); @@ -368,7 +388,7 @@ flutter::SemanticsNode OhosAccessibilityBridge::GetFlutterSemanticsNode( } else { FML_DLOG(ERROR) << "GetFlutterSemanticsNode flutterSemanticsTree_ = null" << id; - return flutter::SemanticsNode{}; + return {}; } } @@ -401,23 +421,29 @@ void OhosAccessibilityBridge::FlutterTreeToArkuiTree( int32_t right = static_cast(flutterNode.rect.fRight); int32_t bottom = static_cast(flutterNode.rect.fBottom); ArkUI_AccessibleRect rect = {left, top, right, bottom}; - OH_ArkUI_AccessibilityElementInfoSetScreenRect(elementInfo, &rect); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetScreenRect(elementInfo, &rect) + ); // 设置elementinfo的action类型 std::string widget_type = GetNodeComponentType(flutterNode); FlutterSetElementInfoOperationActions(elementInfo, widget_type); // 设置elementid - OH_ArkUI_AccessibilityElementInfoSetElementId(elementInfo, flutterNode.id); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetElementId(elementInfo, flutterNode.id) + ); // 设置父节点id int32_t parentId = GetParentId(flutterNode.id); if (flutterNode.id == 0) { - OH_ArkUI_AccessibilityElementInfoSetParentId(elementInfo, -2100000); - FML_DLOG(INFO) << "FlutterTreeToArkuiTree parent.id= " << parentId; + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetParentId(elementInfo, ARKUI_ACCESSIBILITY_ROOT_PARENT_ID) + ); } else { - OH_ArkUI_AccessibilityElementInfoSetParentId(elementInfo, parentId); - FML_DLOG(INFO) << "FlutterTreeToArkuiTree parent.id= " << parentId; + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetParentId(elementInfo, parentId) + ); } // 设置孩子节点 @@ -431,29 +457,38 @@ void OhosAccessibilityBridge::FlutterTreeToArkuiTree( << flutterNode.id << " childCount= " << childCount << " childNodeId=" << childNodeIds[i]; } - OH_ArkUI_AccessibilityElementInfoSetChildNodeIds(elementInfo, childCount, - childNodeIds); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetChildNodeIds(elementInfo, + childCount, + childNodeIds) + ); // 配置常用属性,force to true for debugging - OH_ArkUI_AccessibilityElementInfoSetCheckable(elementInfo, true); - OH_ArkUI_AccessibilityElementInfoSetFocusable(elementInfo, true); - OH_ArkUI_AccessibilityElementInfoSetVisible(elementInfo, true); - OH_ArkUI_AccessibilityElementInfoSetEnabled(elementInfo, true); - OH_ArkUI_AccessibilityElementInfoSetClickable(elementInfo, true); - + ARKUI_ACCESSIBILITY_CALL_CHECK(OH_ArkUI_AccessibilityElementInfoSetCheckable(elementInfo, true)); + ARKUI_ACCESSIBILITY_CALL_CHECK(OH_ArkUI_AccessibilityElementInfoSetFocusable(elementInfo, true)); + ARKUI_ACCESSIBILITY_CALL_CHECK(OH_ArkUI_AccessibilityElementInfoSetVisible(elementInfo, true)); + ARKUI_ACCESSIBILITY_CALL_CHECK(OH_ArkUI_AccessibilityElementInfoSetEnabled(elementInfo, true)); + ARKUI_ACCESSIBILITY_CALL_CHECK(OH_ArkUI_AccessibilityElementInfoSetClickable(elementInfo, true)); + // 设置组件类型 std::string componentTypeName = GetNodeComponentType(flutterNode); - OH_ArkUI_AccessibilityElementInfoSetComponentType( - elementInfo, componentTypeName.c_str()); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetComponentType( + elementInfo, componentTypeName.c_str()) + ); std::string contents = componentTypeName + "_content"; - OH_ArkUI_AccessibilityElementInfoSetContents(elementInfo, contents.c_str()); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetContents(elementInfo, contents.c_str()) + ); // 设置无障碍相关属性 - OH_ArkUI_AccessibilityElementInfoSetAccessibilityText( - elementInfo, flutterNode.label.c_str()); - OH_ArkUI_AccessibilityElementInfoSetAccessibilityLevel(elementInfo, "yes"); - OH_ArkUI_AccessibilityElementInfoSetAccessibilityGroup(elementInfo, false); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetAccessibilityText( + elementInfo, flutterNode.label.c_str()) + ); + ARKUI_ACCESSIBILITY_CALL_CHECK(OH_ArkUI_AccessibilityElementInfoSetAccessibilityLevel(elementInfo, "yes")); + ARKUI_ACCESSIBILITY_CALL_CHECK(OH_ArkUI_AccessibilityElementInfoSetAccessibilityGroup(elementInfo, false)); } FML_DLOG(INFO) << "FlutterTreeToArkuiTree is end"; } @@ -463,18 +498,21 @@ void OhosAccessibilityBridge::FlutterTreeToArkuiTree( */ int32_t OhosAccessibilityBridge::GetParentId(int64_t elementId) { - int32_t childElementId = static_cast(elementId); if (!parentChildIdVec.size()) { FML_DLOG(INFO) << "OhosAccessibilityBridge::GetParentId parentChildIdMap.size()=0"; - return -2100000; + return ARKUI_ACCESSIBILITY_ROOT_PARENT_ID; + } + if (elementId == -1) { + return ARKUI_ACCESSIBILITY_ROOT_PARENT_ID; } + int32_t childElementId = static_cast(elementId); for (const auto& item : parentChildIdVec) { if (item.second == childElementId) { return item.first; } } - return -2100000; + return RET_ERROR_STATE_CODE; } /** @@ -532,6 +570,10 @@ void OhosAccessibilityBridge::ConvertChildRelativeRectToScreenRect( // 获取当前flutter节点的父节点的相对rect int32_t parentId = GetParentId(currNode.id); auto parentNode = GetFlutterSemanticsNode(parentId); + // if (parentNode == ) { + // LOGE("ConvertChildRelativeRectToScreenRect -> GetFlutterSemanticsNode + // parentNode = null, parentId:%{public}d", parentId); + // } auto parentRight = parentNode.rect.fRight; auto parentBottom = parentNode.rect.fBottom; @@ -549,7 +591,10 @@ void OhosAccessibilityBridge::ConvertChildRelativeRectToScreenRect( // 真实缩放系数 float realScaleFactor = realParentRight / parentRight * 1.0; - float newLeft, newTop, newRight, newBottom; + float newLeft; + float newTop; + float newRight; + float newBottom; if (_kMScaleX > 1 && _kMScaleY > 1) { // 子节点相对父节点进行变化(缩放、 平移) @@ -563,13 +608,13 @@ void OhosAccessibilityBridge::ConvertChildRelativeRectToScreenRect( // 若当前节点的相对坐标与父亲节点的相对坐标值相同,则直接继承坐标值 if (currRight == parentRight && currBottom == parentBottom) { newLeft = realParentLeft; - newTop = realParentTop; - newRight = realParentRight; + newTop = realParentTop; + newRight = realParentRight; newBottom = realParentBottom; } else { // 子节点的屏幕绝对坐标转换,包括offset偏移值计算、缩放系数变换 newLeft = (currLeft + _kMTransX) * realScaleFactor + realParentLeft; - newTop = (currTop + _kMTransY) * realScaleFactor + realParentTop; + newTop = (currTop + _kMTransY) * realScaleFactor + realParentTop; newRight = (currLeft + _kMTransX + currRight) * realScaleFactor + realParentLeft; newBottom = @@ -585,8 +630,8 @@ void OhosAccessibilityBridge::ConvertChildRelativeRectToScreenRect( << ", " << newRight << ", " << newBottom << ")}"; // 防止滑动场景下绿框坐标超出屏幕范围,进行正则化处理 newLeft = static_cast(newLeft) % static_cast(rootWidth); - newTop = static_cast(newTop) % static_cast(rootHeight); - newRight = static_cast(newRight) % static_cast(rootWidth); + newTop = static_cast(newTop) % static_cast(rootHeight); + newRight = static_cast(newRight) % static_cast(rootWidth); newBottom = static_cast(newBottom) % static_cast(rootHeight); SetAbsoluteScreenRect(currNode.id, newLeft, newTop, newRight, newBottom); @@ -624,7 +669,11 @@ void OhosAccessibilityBridge::FlutterNodeToElementInfoById( int32_t right = static_cast(flutterNode.rect.fRight); int32_t bottom = static_cast(flutterNode.rect.fBottom); ArkUI_AccessibleRect rect = {left, top, right, bottom}; - OH_ArkUI_AccessibilityElementInfoSetScreenRect(elementInfoFromList, &rect); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetScreenRect( + elementInfoFromList, &rect) + ); + // 设置root节点的屏幕绝对坐标rect SetAbsoluteScreenRect(0, left, top, right, bottom); @@ -633,18 +682,29 @@ void OhosAccessibilityBridge::FlutterNodeToElementInfoById( FlutterSetElementInfoOperationActions(elementInfoFromList, widget_type); // 根据flutternode信息配置对应的elementinfo - OH_ArkUI_AccessibilityElementInfoSetElementId(elementInfoFromList, 0); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetElementId(elementInfoFromList, 0) + ); + // NOTE: arkui无障碍子系统强制设置root的父节点id = -2100000 (严禁更改) - OH_ArkUI_AccessibilityElementInfoSetParentId(elementInfoFromList, -2100000); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetParentId( + elementInfoFromList, ARKUI_ACCESSIBILITY_ROOT_PARENT_ID) + ); + // 设置无障碍播报文本 - OH_ArkUI_AccessibilityElementInfoSetAccessibilityText( - elementInfoFromList, flutterNode.label.empty() - ? flutterNode.hint.c_str() - : flutterNode.label.c_str()); - OH_ArkUI_AccessibilityElementInfoSetAccessibilityLevel(elementInfoFromList, - "yes"); - OH_ArkUI_AccessibilityElementInfoSetAccessibilityGroup(elementInfoFromList, - false); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetAccessibilityText( + elementInfoFromList, flutterNode.label.empty() ? flutterNode.hint.c_str() : flutterNode.label.c_str()) + ); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetAccessibilityLevel( + elementInfoFromList, "yes") + ); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetAccessibilityGroup( + elementInfoFromList, false) + ); // 配置child节点信息 int32_t childCount = flutterNode.childrenInTraversalOrder.size(); @@ -657,17 +717,18 @@ void OhosAccessibilityBridge::FlutterNodeToElementInfoById( << "FlutterNodeToElementInfoById -> elementid=0 childCount=" << childCount << " childNodeIds=" << childNodeIds[i]; } - OH_ArkUI_AccessibilityElementInfoSetChildNodeIds(elementInfoFromList, - childCount, childNodeIds); - + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetChildNodeIds( + elementInfoFromList, childCount, childNodeIds) + ); + // 配置root节点常用属性 - OH_ArkUI_AccessibilityElementInfoSetFocusable(elementInfoFromList, true); - OH_ArkUI_AccessibilityElementInfoSetVisible(elementInfoFromList, true); - OH_ArkUI_AccessibilityElementInfoSetEnabled(elementInfoFromList, true); - OH_ArkUI_AccessibilityElementInfoSetClickable(elementInfoFromList, true); - OH_ArkUI_AccessibilityElementInfoSetComponentType(elementInfoFromList, - "root"); - OH_ArkUI_AccessibilityElementInfoSetContents(elementInfoFromList, flutterNode.label.c_str()); + ARKUI_ACCESSIBILITY_CALL_CHECK(OH_ArkUI_AccessibilityElementInfoSetFocusable(elementInfoFromList, true)); + ARKUI_ACCESSIBILITY_CALL_CHECK(OH_ArkUI_AccessibilityElementInfoSetVisible(elementInfoFromList, true)); + ARKUI_ACCESSIBILITY_CALL_CHECK(OH_ArkUI_AccessibilityElementInfoSetEnabled(elementInfoFromList, true)); + ARKUI_ACCESSIBILITY_CALL_CHECK(OH_ArkUI_AccessibilityElementInfoSetClickable(elementInfoFromList, true)); + ARKUI_ACCESSIBILITY_CALL_CHECK(OH_ArkUI_AccessibilityElementInfoSetComponentType(elementInfoFromList, "root")); + ARKUI_ACCESSIBILITY_CALL_CHECK(OH_ArkUI_AccessibilityElementInfoSetContents(elementInfoFromList, flutterNode.label.c_str())); } else { //当elementId >= 1时,根据flutter节点信息配置elementinfo无障碍属性 FlutterSetElementInfoProperties(elementInfoFromList, elementId); @@ -737,9 +798,10 @@ void OhosAccessibilityBridge::FlutterSetElementInfoOperationActions( ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SET_CURSOR_POSITION; actions[9].description = "光标位置设置"; - OH_ArkUI_AccessibilityElementInfoSetOperationActions( - elementInfoFromList, actionTypeNum, actions); - + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetOperationActions( + elementInfoFromList, actionTypeNum, actions) + ); } else if (widget_type == "scrollable") { // if node is a scrollable component int32_t actionTypeNum = 5; @@ -765,9 +827,10 @@ void OhosAccessibilityBridge::FlutterSetElementInfoOperationActions( ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SCROLL_BACKWARD; actions[4].description = "向下滑动"; - OH_ArkUI_AccessibilityElementInfoSetOperationActions( - elementInfoFromList, actionTypeNum, actions); - + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetOperationActions( + elementInfoFromList, actionTypeNum, actions) + ); } else { // set common component action types int32_t actionTypeNum = 3; @@ -785,8 +848,10 @@ void OhosAccessibilityBridge::FlutterSetElementInfoOperationActions( ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_CLICK; actions[2].description = "点击动作"; - OH_ArkUI_AccessibilityElementInfoSetOperationActions( - elementInfoFromList, actionTypeNum, actions); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetOperationActions( + elementInfoFromList, actionTypeNum, actions) + ); } } @@ -801,8 +866,11 @@ void OhosAccessibilityBridge::FlutterSetElementInfoProperties( GetFlutterSemanticsNode(static_cast(elementId)); // set elementinfo id - OH_ArkUI_AccessibilityElementInfoSetElementId(elementInfoFromList, - flutterNode.id); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetElementId(elementInfoFromList, + flutterNode.id) + ); + // convert relative rect to absolute rect ConvertChildRelativeRectToScreenRect(flutterNode); auto rectPairs = GetAbsoluteScreenRect(flutterNode.id); @@ -812,7 +880,9 @@ void OhosAccessibilityBridge::FlutterSetElementInfoProperties( int32_t right = rectPairs.second.first; int32_t bottom = rectPairs.second.second; ArkUI_AccessibleRect rect = {left, top, right, bottom}; - OH_ArkUI_AccessibilityElementInfoSetScreenRect(elementInfoFromList, &rect); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetScreenRect(elementInfoFromList, &rect) + ); FML_DLOG(INFO) << "FlutterNodeToElementInfoById -> node.id= " << flutterNode.id << " SceenRect = (" << left << ", " << top << ", " << right << ", " << bottom << ")"; @@ -834,27 +904,29 @@ void OhosAccessibilityBridge::FlutterSetElementInfoProperties( // set current elementinfo parent id int32_t parentId = GetParentId(elementId); - if (parentId < 0) { - FML_DLOG(ERROR) - << "FlutterNodeToElementInfoById GetParentId is null, assigned to " - << parentId; - OH_ArkUI_AccessibilityElementInfoSetParentId(elementInfoFromList, parentId); - } else { - OH_ArkUI_AccessibilityElementInfoSetParentId(elementInfoFromList, parentId); - FML_DLOG(INFO) << "FlutterNodeToElementInfoById GetParentId = " << parentId; - } + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetParentId(elementInfoFromList, parentId) + ); + FML_DLOG(INFO) << "FlutterNodeToElementInfoById GetParentId = " << parentId; + // set accessibility text for announcing std::string text = flutterNode.label; - OH_ArkUI_AccessibilityElementInfoSetAccessibilityText(elementInfoFromList, - text.c_str()); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetAccessibilityText(elementInfoFromList, + text.c_str()) + ); FML_DLOG(INFO) << "FlutterNodeToElementInfoById SetAccessibilityText = " << text; //set contents (same as AccessibilityText) - OH_ArkUI_AccessibilityElementInfoSetContents(elementInfoFromList, text.c_str()); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetContents(elementInfoFromList, text.c_str()) + ); std::string hint = flutterNode.hint; - OH_ArkUI_AccessibilityElementInfoSetHintText(elementInfoFromList, - hint.c_str()); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetHintText(elementInfoFromList, + hint.c_str()) + ); // set chidren elementinfo ids int32_t childCount = flutterNode.childrenInTraversalOrder.size(); @@ -867,45 +939,59 @@ void OhosAccessibilityBridge::FlutterSetElementInfoProperties( << " childCount=" << childCount << " childNodeIds=" << childNodeIds[i]; } - OH_ArkUI_AccessibilityElementInfoSetChildNodeIds(elementInfoFromList, - childCount, childNodeIds); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetChildNodeIds(elementInfoFromList, + childCount, childNodeIds) + ); /** * 根据当前flutter节点的SemanticsFlags特性,配置对应的elmentinfo属性 */ // 判断当前节点是否可点击 if (IsNodeClickable(flutterNode)) { - OH_ArkUI_AccessibilityElementInfoSetClickable(elementInfoFromList, true); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetClickable(elementInfoFromList, true) + ); FML_DLOG(INFO) << "flutterNode.id=" << flutterNode.id << " OH_ArkUI_AccessibilityElementInfoSetClickable -> true"; } // 判断当前节点是否可获焦点 if (IsNodeFocusable(flutterNode)) { - OH_ArkUI_AccessibilityElementInfoSetFocusable(elementInfoFromList, true); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetFocusable(elementInfoFromList, true) + ); FML_DLOG(INFO) << "flutterNode.id=" << flutterNode.id << " OH_ArkUI_AccessibilityElementInfoSetFocusable -> true"; } // 判断当前节点是否为密码输入框 if (IsNodePassword(flutterNode)) { - OH_ArkUI_AccessibilityElementInfoSetIsPassword(elementInfoFromList, true); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetIsPassword(elementInfoFromList, true) + ); FML_DLOG(INFO) << "flutterNode.id=" << flutterNode.id << " OH_ArkUI_AccessibilityElementInfoSetIsPassword -> true"; } // 判断当前节点是否具备checkable状态 (如:checkbox, radio button) if (IsNodeCheckable(flutterNode)) { - OH_ArkUI_AccessibilityElementInfoSetCheckable(elementInfoFromList, true); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetCheckable(elementInfoFromList, true) + ); FML_DLOG(INFO) << "flutterNode.id=" << flutterNode.id << " OH_ArkUI_AccessibilityElementInfoSetCheckable -> true"; } // 判断当前节点(check box/radio button)是否checked/unchecked if (IsNodeChecked(flutterNode)) { - OH_ArkUI_AccessibilityElementInfoSetChecked(elementInfoFromList, true); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetChecked(elementInfoFromList, true) + ); FML_DLOG(INFO) << "flutterNode.id=" << flutterNode.id << " OH_ArkUI_AccessibilityElementInfoSetChecked -> true"; } // 判断当前节点组件是否可显示 if (IsNodeVisible(flutterNode)) { - OH_ArkUI_AccessibilityElementInfoSetVisible(elementInfoFromList, true); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetVisible(elementInfoFromList, true) + ); FML_DLOG(INFO) << "flutterNode.id=" << flutterNode.id << " OH_ArkUI_AccessibilityElementInfoSetVisible -> true"; } @@ -917,13 +1003,17 @@ void OhosAccessibilityBridge::FlutterSetElementInfoProperties( } // 判断当前节点组件是否可滑动 if (IsNodeScrollable(flutterNode)) { - OH_ArkUI_AccessibilityElementInfoSetScrollable(elementInfoFromList, true); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetScrollable(elementInfoFromList, true) + ); FML_DLOG(INFO) << "flutterNode.id=" << flutterNode.id << " OH_ArkUI_AccessibilityElementInfoSetScrollable -> true"; } // 判断当前节点组件是否可编辑(文本输入框) if (IsTextField(flutterNode)) { - OH_ArkUI_AccessibilityElementInfoSetEditable(elementInfoFromList, true); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetEditable(elementInfoFromList, true) + ); FML_DLOG(INFO) << "flutterNode.id=" << flutterNode.id << " OH_ArkUI_AccessibilityElementInfoSetEditable -> true"; } @@ -934,15 +1024,18 @@ void OhosAccessibilityBridge::FlutterSetElementInfoProperties( } // 判断当前节点组件是否支持长按 if (IsNodeHasLongPress(flutterNode)) { - OH_ArkUI_AccessibilityElementInfoSetLongClickable(elementInfoFromList, - true); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetLongClickable(elementInfoFromList, true) + ); FML_DLOG(INFO) << "flutterNode.id=" << flutterNode.id << " OH_ArkUI_AccessibilityElementInfoSetLongClickable -> true"; } // 判断当前节点组件是否enabled if (IsNodeEnabled(flutterNode)) { - OH_ArkUI_AccessibilityElementInfoSetEnabled(elementInfoFromList, true); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetEnabled(elementInfoFromList, true) + ); FML_DLOG(INFO) << "flutterNode.id=" << flutterNode.id << " OH_ArkUI_AccessibilityElementInfoSetEnabled -> true"; } @@ -953,11 +1046,14 @@ void OhosAccessibilityBridge::FlutterSetElementInfoProperties( << componentTypeName; // flutter节点对应elementinfo所属的组件类型(如:root, button,text等) if (elementId == 0) { - OH_ArkUI_AccessibilityElementInfoSetComponentType(elementInfoFromList, - "root"); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetComponentType(elementInfoFromList, "root") + ); } else { - OH_ArkUI_AccessibilityElementInfoSetComponentType( - elementInfoFromList, componentTypeName.c_str()); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetComponentType(elementInfoFromList, + componentTypeName.c_str()) + ); } FML_DLOG(INFO) << "FlutterNodeToElementInfoById SetComponentType: " << componentTypeName; @@ -969,11 +1065,13 @@ void OhosAccessibilityBridge::FlutterSetElementInfoProperties( * “no”:当前组件不可被无障碍辅助服务所识别 * “no-hide-descendants”:当前组件及其所有子组件不可被无障碍辅助服务所识别 */ - OH_ArkUI_AccessibilityElementInfoSetAccessibilityLevel(elementInfoFromList, - "yes"); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetAccessibilityLevel(elementInfoFromList, "yes"); + ); // 无障碍组,设置为true时表示该组件及其所有子组件为一整个可以选中的组件,无障碍服务将不再关注其子组件内容。默认值:false - OH_ArkUI_AccessibilityElementInfoSetAccessibilityGroup(elementInfoFromList, - false); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetAccessibilityGroup(elementInfoFromList, false); + ); } /** @@ -1060,8 +1158,9 @@ int32_t OhosAccessibilityBridge::FindAccessibilityNodeInfosById( } // 开启无障碍导航功能 - accessibilityFeatures_->SetAccessibleNavigation(true, - native_shell_holder_id_); + if(elementId == -1 || elementId == 0) { + accessibilityFeatures_->SetAccessibleNavigation(true, native_shell_holder_id_); + } // 从elementinfolist中获取elementinfo ArkUI_AccessibilityElementInfo* elementInfoFromList = @@ -1486,6 +1585,11 @@ void OhosAccessibilityBridge::Flutter_SendAccessibilityAsyncEvent( int64_t elementId, ArkUI_AccessibilityEventType eventType) { + if (provider_ == nullptr) { + FML_DLOG(ERROR) << "Flutter_SendAccessibilityAsyncEvent " + "AccessibilityProvider = nullptr"; + return; + } // 1.创建eventInfo对象 ArkUI_AccessibilityEventInfo* eventInfo = OH_ArkUI_CreateAccessibilityEventInfo(); @@ -1503,15 +1607,17 @@ void OhosAccessibilityBridge::Flutter_SendAccessibilityAsyncEvent( if (eventType == ArkUI_AccessibilityEventType:: ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_ACCESSIBILITY_FOCUSED) { - OH_ArkUI_AccessibilityElementInfoSetAccessibilityFocused(_elementInfo, - true); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetAccessibilityFocused(_elementInfo, + true) + ); } // 3.设置发送事件,如配置获焦、失焦、点击、滑动事件 - OH_ArkUI_AccessibilityEventSetEventType(eventInfo, eventType); + ARKUI_ACCESSIBILITY_CALL_CHECK(OH_ArkUI_AccessibilityEventSetEventType(eventInfo, eventType)); // 4.将eventinfo事件和当前elementinfo进行绑定 - OH_ArkUI_AccessibilityEventSetElementInfo(eventInfo, _elementInfo); + ARKUI_ACCESSIBILITY_CALL_CHECK(OH_ArkUI_AccessibilityEventSetElementInfo(eventInfo, _elementInfo)); // 5.调用接口发送到ohos侧 auto callback = [](int32_t errorCode) { @@ -1521,11 +1627,6 @@ void OhosAccessibilityBridge::Flutter_SendAccessibilityAsyncEvent( }; // 6.发送event到OH侧 - if (provider_ == nullptr) { - FML_DLOG(ERROR) << "Flutter_SendAccessibilityAsyncEvent " - "AccessibilityProvider = nullptr"; - return; - } OH_ArkUI_SendAccessibilityAsyncEvent(provider_, eventInfo, callback); // 7.销毁新创建的elementinfo, eventinfo @@ -1605,7 +1706,7 @@ std::string OhosAccessibilityBridge::GetNodeComponentType( return "Header"; } if (node.HasFlag(FLAGS_::kIsImage)) { - return "ImageView"; + return "Image"; } if (node.HasFlag(FLAGS_::kHasCheckedState)) { if (node.HasFlag(FLAGS_::kIsInMutuallyExclusiveGroup)) { diff --git a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h index 2b0f0fdc3c..17d58b92d1 100644 --- a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h +++ b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h @@ -25,15 +25,12 @@ #include "flutter/lib/ui/semantics/semantics_node.h" #include "native_accessibility_channel.h" #include "ohos_accessibility_features.h" + namespace flutter { typedef flutter::SemanticsFlags FLAGS_; typedef flutter::SemanticsAction ACTIONS_; -typedef flutter::SemanticsNode FLUTTER_NODE_; -/** - * flutter和ohos的无障碍服务桥接 - */ struct AbsoluteRect { float left; float top; @@ -59,6 +56,9 @@ struct SemanticsNodeExtent : flutter::SemanticsNode { std::string previousLabel; }; +/** + * flutter和ohos的无障碍服务桥接 + */ class OhosAccessibilityBridge { public: static OhosAccessibilityBridge* GetInstance(); @@ -148,6 +148,9 @@ class OhosAccessibilityBridge { std::shared_ptr nativeAccessibilityChannel_; std::shared_ptr accessibilityFeatures_; + // arkui的root节点的父节点id + static const int32_t ARKUI_ACCESSIBILITY_ROOT_PARENT_ID = -2100000; + static const int32_t RET_ERROR_STATE_CODE = -999; static const int32_t ROOT_NODE_ID = 0; constexpr static const double SCROLL_EXTENT_FOR_INFINITY = 100000.0; constexpr static const double SCROLL_POSITION_CAP_FOR_INFINITY = 70000.0; -- Gitee From 7425a8f6e23de4c4f258c317a8ed7ac71d6d5779 Mon Sep 17 00:00:00 2001 From: zjxi Date: Fri, 15 Nov 2024 17:46:02 +0800 Subject: [PATCH 14/14] =?UTF-8?q?refactor:=E4=BC=98=E5=8C=96=E9=83=A8?= =?UTF-8?q?=E5=88=86=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zjxi --- .../ohos_accessibility_bridge.cpp | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp index 2baf359b2b..3875792883 100644 --- a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp +++ b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp @@ -104,10 +104,6 @@ void OhosAccessibilityBridge::updateSemantics( GetSemanticsNodeDebugInfo(node); GetSemanticsFlagsDebugInfo(node); - // if (!IsNodeVisible(node)) { - // continue; - // } - /** * 构建flutter无障碍语义节点树 * NOTE: 若使用flutterSemanticsTree_.insert({node.id, node})方式 @@ -365,12 +361,12 @@ flutter::SemanticsNode OhosAccessibilityBridge::GetFlutterRootSemanticsNode() if (!flutterSemanticsTree_.size()) { FML_DLOG(ERROR) << "GetFlutterRootSemanticsNode -> flutterSemanticsTree_.size()=0"; - return flutter::SemanticsNode{}; + return {}; } if (flutterSemanticsTree_.find(0) == flutterSemanticsTree_.end()) { FML_DLOG(ERROR) << "GetFlutterRootSemanticsNode -> flutterSemanticsTree_ " "has no keys = 0"; - return flutter::SemanticsNode{}; + return {}; } return flutterSemanticsTree_.at(0); } @@ -570,10 +566,6 @@ void OhosAccessibilityBridge::ConvertChildRelativeRectToScreenRect( // 获取当前flutter节点的父节点的相对rect int32_t parentId = GetParentId(currNode.id); auto parentNode = GetFlutterSemanticsNode(parentId); - // if (parentNode == ) { - // LOGE("ConvertChildRelativeRectToScreenRect -> GetFlutterSemanticsNode - // parentNode = null, parentId:%{public}d", parentId); - // } auto parentRight = parentNode.rect.fRight; auto parentBottom = parentNode.rect.fBottom; @@ -621,9 +613,13 @@ void OhosAccessibilityBridge::ConvertChildRelativeRectToScreenRect( (currTop + _kMTransY + currBottom) * realScaleFactor + realParentTop; } // 若子节点rect超过父节点则跳过显示(单个屏幕显示不下,滑动再重新显示) - if (newLeft < realParentLeft || newTop < realParentTop || - newRight > realParentRight || newBottom > realParentBottom || - newLeft >= newRight || newTop >= newBottom) { + const bool IS_OVER_SCREEN_AREA = newLeft < realParentLeft || + newTop < realParentTop || + newRight > realParentRight || + newBottom > realParentBottom || + newLeft >= newRight || + newTop >= newBottom; + if (IS_OVER_SCREEN_AREA) { FML_DLOG(ERROR) << "ConvertChildRelativeRectToScreenRect childRect is " "bigger than parentRect -> { nodeId: " << currNode.id << ", (" << newLeft << ", " << newTop @@ -1096,7 +1092,7 @@ std::vector OhosAccessibilityBridge::GetLevelOrderTraversalTree(int32_t std::sort(currNode.childrenInTraversalOrder.begin(), currNode.childrenInTraversalOrder.end()); - for (auto& childId: currNode.childrenInTraversalOrder) { + for (const auto& childId: currNode.childrenInTraversalOrder) { auto childNode = GetFlutterSemanticsNode(childId); semanticsQue.push(childNode); } -- Gitee