diff --git a/.gitee/PULL_REQUEST_TEMPLATE.zh-CN.md b/.gitee/PULL_REQUEST_TEMPLATE.zh-CN.md new file mode 100644 index 0000000000000000000000000000000000000000..ff5ca685ed662c4d9cf5e468ad914ac4c251603e --- /dev/null +++ b/.gitee/PULL_REQUEST_TEMPLATE.zh-CN.md @@ -0,0 +1,24 @@ +**IssueNo**: + +**Description**: +(提交描述) + +**Feature or Bugfix**: +- [ ] Feature +- [ ] Bugfix + +**Binary Source**: +- [ ] No +- [ ] yes + +**预测试**: +- [ ] Pass +- [ ] Fail +- [ ] 评估不涉及 + +**合入前自检**: +- [ ] 不涉及性能或已进行性能测试且无性能劣化。 +- [ ] 符合对应的编码规范。 +- [ ] 不涉及文档更新,或已更新了文档。 +- [ ] 针对可测试性要求,已增加必要的自测用例、合理的日志记录或Trace信息。 +- [ ] 不存在非法的文件引入,包括图片和代码等。 \ No newline at end of file diff --git a/attachment/repos/dart.patch0 b/attachment/repos/dart.patch0 index 8094cc2e317d80592662f557836994999c0b947c..6eb95a2a1a9638a11685a3b3ddf11824d166bc14 100644 --- a/attachment/repos/dart.patch0 +++ b/attachment/repos/dart.patch0 @@ -76,7 +76,7 @@ index 33be98fc0aa..eda146a0580 100644 String? _authCode; diff --git a/pkg/vm/lib/transformations/ffi/abi.dart b/pkg/vm/lib/transformations/ffi/abi.dart -index cc2d86bafd7..e703419eed7 100644 +index cc2d86bafd7..47368356a2e 100644 --- a/pkg/vm/lib/transformations/ffi/abi.dart +++ b/pkg/vm/lib/transformations/ffi/abi.dart @@ -40,6 +40,7 @@ enum _OS { @@ -87,48 +87,83 @@ index cc2d86bafd7..e703419eed7 100644 } /// An application binary interface (ABI). -@@ -71,6 +72,9 @@ class Abi { - /// The application binary interface for Fuchsia on the X64 architecture. - static const fuchsiaX64 = _fuchsiaX64; +@@ -65,6 +66,15 @@ class Abi { + /// The application binary interface for android on the X64 architecture. + static const androidX64 = _androidX64; ++ /// The application binary interface for Ohos on the X64 architecture. ++ static const ohosArm = _ohosArm; ++ ++ /// The application binary interface for Ohos on the X64 architecture. ++ static const ohosArm64 = _ohosArm64; ++ + /// The application binary interface for Ohos on the X64 architecture. + static const ohosX64 = _ohosX64; + - /// The application binary interface for iOS on the Arm architecture. - static const iosArm = _iosArm; + /// The application binary interface for Fuchsia on the Arm64 architecture. + static const fuchsiaArm64 = _fuchsiaArm64; -@@ -131,6 +135,7 @@ class Abi { +@@ -129,6 +139,9 @@ class Abi { + androidArm64, + androidIA32, androidX64, ++ ohosArm, ++ ohosArm64, ++ ohosX64, fuchsiaArm64, fuchsiaX64, -+ ohosX64, iosArm, - iosArm64, - iosX64, -@@ -176,6 +181,7 @@ class Abi { +@@ -174,6 +187,9 @@ class Abi { + static const _androidArm64 = Abi._(_Architecture.arm64, _OS.android); + static const _androidIA32 = Abi._(_Architecture.ia32, _OS.android); static const _androidX64 = Abi._(_Architecture.x64, _OS.android); ++ static const _ohosArm = Abi._(_Architecture.arm, _OS.ohos); ++ static const _ohosArm64 = Abi._(_Architecture.arm64, _OS.ohos); ++ static const _ohosX64 = Abi._(_Architecture.x64, _OS.ohos); static const _fuchsiaArm64 = Abi._(_Architecture.arm64, _OS.fuchsia); static const _fuchsiaX64 = Abi._(_Architecture.x64, _OS.fuchsia); -+ static const _ohosX64 = Abi._(_Architecture.x64, _OS.ohos); static const _iosArm = Abi._(_Architecture.arm, _OS.ios); - static const _iosArm64 = Abi._(_Architecture.arm64, _OS.ios); - static const _iosX64 = Abi._(_Architecture.x64, _OS.ios); -@@ -200,6 +206,7 @@ const Map abiNames = { +@@ -198,6 +214,9 @@ const Map abiNames = { + Abi.androidArm64: 'androidArm64', + Abi.androidIA32: 'androidIA32', Abi.androidX64: 'androidX64', ++ Abi.ohosArm: 'ohosArm', ++ Abi.ohosArm64: 'ohosArm64', ++ Abi.ohosX64: 'ohosX64', Abi.fuchsiaArm64: 'fuchsiaArm64', Abi.fuchsiaX64: 'fuchsiaX64', -+ Abi.ohosX64: 'ohosX64', Abi.iosArm: 'iosArm', - Abi.iosArm64: 'iosArm64', - Abi.iosX64: 'iosX64', -@@ -239,6 +246,7 @@ const Map> nonSizeAlignment = { +@@ -239,6 +258,8 @@ const Map> nonSizeAlignment = { // _wordSize64 Abi.androidArm64: _wordSize64, Abi.androidX64: _wordSize64, ++ Abi.ohosArm64: _wordSize64, + Abi.ohosX64: _wordSize64, Abi.fuchsiaArm64: _wordSize64, Abi.fuchsiaX64: _wordSize64, Abi.iosArm64: _wordSize64, +@@ -256,6 +277,7 @@ const Map> nonSizeAlignment = { + Abi.linuxIA32: _wordSize32Align32, + // _wordSize32Align64 + Abi.androidArm: _wordSize32Align64, ++ Abi.ohosArm: _wordSize32Align64, + Abi.linuxArm: _wordSize32Align64, + Abi.linuxRiscv32: _wordSize32Align64, + Abi.windowsIA32: _wordSize32Align64, +diff --git a/pkg/vm/testcases/transformations/ffi/abi_specific_int.dart b/pkg/vm/testcases/transformations/ffi/abi_specific_int.dart +index f926b9d46c1..a72516ac911 100644 +--- a/pkg/vm/testcases/transformations/ffi/abi_specific_int.dart ++++ b/pkg/vm/testcases/transformations/ffi/abi_specific_int.dart +@@ -9,6 +9,9 @@ import 'dart:ffi'; + Abi.androidArm64: Uint32(), + Abi.androidIA32: Uint32(), + Abi.androidX64: Uint32(), ++ Abi.ohosArm: Uint32(), ++ Abi.ohosArm64: Uint32(), ++ Abi.ohosX64: Uint32(), + Abi.fuchsiaArm64: Uint64(), + Abi.fuchsiaX64: Uint32(), + Abi.iosArm: Uint32(), diff --git a/runtime/BUILD.gn b/runtime/BUILD.gn index 13bfd0a724b..042b6a45f7e 100644 --- a/runtime/BUILD.gn @@ -7674,166 +7709,234 @@ index b7e5be3eab5..8a8f873f6c5 100644 bool _isAllowedOrigin(String origin) { Uri uri; +diff --git a/sdk/lib/_internal/vm/lib/ffi_patch.dart b/sdk/lib/_internal/vm/lib/ffi_patch.dart +index 4e719feb5d4..df1aecdb4f8 100644 +--- a/sdk/lib/_internal/vm/lib/ffi_patch.dart ++++ b/sdk/lib/_internal/vm/lib/ffi_patch.dart +@@ -27,6 +27,9 @@ int get _intPtrSize => (const [ + 8, // androidArm64, + 4, // androidIA32, + 8, // androidX64, ++ 4, // ohosArm, ++ 8, // ohosArm64, ++ 8, // ohosX64, + 8, // fuchsiaArm64, + 8, // fuchsiaX64, + 4, // iosArm, diff --git a/sdk/lib/ffi/abi.dart b/sdk/lib/ffi/abi.dart -index e6f08b37d25..5af605a8764 100644 +index e6f08b37d25..342c5c63c22 100644 --- a/sdk/lib/ffi/abi.dart +++ b/sdk/lib/ffi/abi.dart -@@ -34,6 +34,9 @@ class Abi { - /// The application binary interface for Fuchsia on the X64 architecture. - static const fuchsiaX64 = _fuchsiaX64; +@@ -28,6 +28,15 @@ class Abi { + /// The application binary interface for android on the X64 architecture. + static const androidX64 = _androidX64; -+ /// The application binary interface for Ohos on the X64 architecture. ++ /// The application binary interface for android on the X64 architecture. ++ static const ohosArm = _ohosArm; ++ ++ /// The application binary interface for android on the X64 architecture. ++ static const ohosArm64 = _ohosArm64; ++ ++ /// The application binary interface for android on the X64 architecture. + static const ohosX64 = _ohosX64; + - /// The application binary interface for iOS on the Arm architecture. - static const iosArm = _iosArm; + /// The application binary interface for Fuchsia on the Arm64 architecture. + static const fuchsiaArm64 = _fuchsiaArm64; -@@ -94,6 +97,7 @@ class Abi { +@@ -92,6 +101,9 @@ class Abi { + androidArm64, + androidIA32, androidX64, ++ ohosArm, ++ ohosArm64, ++ ohosX64, fuchsiaArm64, fuchsiaX64, -+ ohosX64, iosArm, - iosArm64, - iosX64, -@@ -136,6 +140,7 @@ class Abi { +@@ -134,6 +146,9 @@ class Abi { + static const _androidArm64 = Abi._(_Architecture.arm64, _OS.android); + static const _androidIA32 = Abi._(_Architecture.ia32, _OS.android); static const _androidX64 = Abi._(_Architecture.x64, _OS.android); ++ static const _ohosArm = Abi._(_Architecture.arm, _OS.ohos); ++ static const _ohosArm64 = Abi._(_Architecture.arm64, _OS.ohos); ++ static const _ohosX64 = Abi._(_Architecture.x64, _OS.ohos); static const _fuchsiaArm64 = Abi._(_Architecture.arm64, _OS.fuchsia); static const _fuchsiaX64 = Abi._(_Architecture.x64, _OS.fuchsia); -+ static const _ohosX64 = Abi._(_Architecture.x64, _OS.ohos); static const _iosArm = Abi._(_Architecture.arm, _OS.ios); - static const _iosArm64 = Abi._(_Architecture.arm64, _OS.ios); - static const _iosX64 = Abi._(_Architecture.x64, _OS.ios); -@@ -170,4 +175,5 @@ enum _OS { +@@ -170,4 +185,5 @@ enum _OS { linux, macos, windows, + ohos, } +diff --git a/sdk/lib/ffi/abi_specific.dart b/sdk/lib/ffi/abi_specific.dart +index 61eb867be17..8aff498845a 100644 +--- a/sdk/lib/ffi/abi_specific.dart ++++ b/sdk/lib/ffi/abi_specific.dart +@@ -24,6 +24,9 @@ part of dart.ffi; + /// Abi.androidArm64: Uint64(), + /// Abi.androidIA32: Uint32(), + /// Abi.androidX64: Uint64(), ++/// Abi.ohosArm: Uint32(), ++/// Abi.ohosArm64: Uint64(), ++/// Abi.ohosX64: Uint64(), + /// Abi.fuchsiaArm64: Uint64(), + /// Abi.fuchsiaX64: Uint64(), + /// Abi.iosArm: Uint32(), diff --git a/sdk/lib/ffi/c_type.dart b/sdk/lib/ffi/c_type.dart -index ee358c2f79d..1f9e629beb9 100644 +index ee358c2f79d..e87207e9e4b 100644 --- a/sdk/lib/ffi/c_type.dart +++ b/sdk/lib/ffi/c_type.dart -@@ -29,6 +29,7 @@ part of dart.ffi; +@@ -27,6 +27,9 @@ part of dart.ffi; + Abi.androidArm64: Uint8(), + Abi.androidIA32: Int8(), Abi.androidX64: Int8(), ++ Abi.ohosArm: Uint8(), ++ Abi.ohosArm64: Uint8(), ++ Abi.ohosX64: Int8(), Abi.fuchsiaArm64: Uint8(), Abi.fuchsiaX64: Int8(), -+ Abi.ohosX64: Int8(), Abi.iosArm: Int8(), - Abi.iosArm64: Int8(), - Abi.iosX64: Int8(), -@@ -66,6 +67,7 @@ class Char extends AbiSpecificInteger { +@@ -64,6 +67,9 @@ class Char extends AbiSpecificInteger { + Abi.androidArm64: Int8(), + Abi.androidIA32: Int8(), Abi.androidX64: Int8(), ++ Abi.ohosArm: Int8(), ++ Abi.ohosArm64: Int8(), ++ Abi.ohosX64: Int8(), Abi.fuchsiaArm64: Int8(), Abi.fuchsiaX64: Int8(), -+ Abi.ohosX64: Int8(), Abi.iosArm: Int8(), - Abi.iosArm64: Int8(), - Abi.iosX64: Int8(), -@@ -103,6 +105,7 @@ class SignedChar extends AbiSpecificInteger { +@@ -101,6 +107,9 @@ class SignedChar extends AbiSpecificInteger { + Abi.androidArm64: Uint8(), + Abi.androidIA32: Uint8(), Abi.androidX64: Uint8(), ++ Abi.ohosArm: Uint8(), ++ Abi.ohosArm64: Uint8(), ++ Abi.ohosX64: Uint8(), Abi.fuchsiaArm64: Uint8(), Abi.fuchsiaX64: Uint8(), -+ Abi.ohosX64: Uint8(), Abi.iosArm: Uint8(), - Abi.iosArm64: Uint8(), - Abi.iosX64: Uint8(), -@@ -140,6 +143,7 @@ class UnsignedChar extends AbiSpecificInteger { +@@ -138,6 +147,9 @@ class UnsignedChar extends AbiSpecificInteger { + Abi.androidArm64: Int16(), + Abi.androidIA32: Int16(), Abi.androidX64: Int16(), ++ Abi.ohosArm: Int16(), ++ Abi.ohosArm64: Int16(), ++ Abi.ohosX64: Int16(), Abi.fuchsiaArm64: Int16(), Abi.fuchsiaX64: Int16(), -+ Abi.ohosX64: Int16(), Abi.iosArm: Int16(), - Abi.iosArm64: Int16(), - Abi.iosX64: Int16(), -@@ -177,6 +181,7 @@ class Short extends AbiSpecificInteger { +@@ -175,6 +187,9 @@ class Short extends AbiSpecificInteger { + Abi.androidArm64: Uint16(), + Abi.androidIA32: Uint16(), Abi.androidX64: Uint16(), ++ Abi.ohosArm: Uint16(), ++ Abi.ohosArm64: Uint16(), ++ Abi.ohosX64: Uint16(), Abi.fuchsiaArm64: Uint16(), Abi.fuchsiaX64: Uint16(), -+ Abi.ohosX64: Uint16(), Abi.iosArm: Uint16(), - Abi.iosArm64: Uint16(), - Abi.iosX64: Uint16(), -@@ -214,6 +219,7 @@ class UnsignedShort extends AbiSpecificInteger { +@@ -212,6 +227,9 @@ class UnsignedShort extends AbiSpecificInteger { + Abi.androidArm64: Int32(), + Abi.androidIA32: Int32(), Abi.androidX64: Int32(), ++ Abi.ohosArm: Int32(), ++ Abi.ohosArm64: Int32(), ++ Abi.ohosX64: Int32(), Abi.fuchsiaArm64: Int32(), Abi.fuchsiaX64: Int32(), -+ Abi.ohosX64: Int32(), Abi.iosArm: Int32(), - Abi.iosArm64: Int32(), - Abi.iosX64: Int32(), -@@ -251,6 +257,7 @@ class Int extends AbiSpecificInteger { +@@ -249,6 +267,9 @@ class Int extends AbiSpecificInteger { + Abi.androidArm64: Uint32(), + Abi.androidIA32: Uint32(), Abi.androidX64: Uint32(), ++ Abi.ohosArm: Uint32(), ++ Abi.ohosArm64: Uint32(), ++ Abi.ohosX64: Uint32(), Abi.fuchsiaArm64: Uint32(), Abi.fuchsiaX64: Uint32(), -+ Abi.ohosX64: Uint32(), Abi.iosArm: Uint32(), - Abi.iosArm64: Uint32(), - Abi.iosX64: Uint32(), -@@ -289,6 +296,7 @@ class UnsignedInt extends AbiSpecificInteger { +@@ -287,6 +308,9 @@ class UnsignedInt extends AbiSpecificInteger { + Abi.androidArm64: Int64(), + Abi.androidIA32: Int32(), Abi.androidX64: Int64(), ++ Abi.ohosArm: Int32(), ++ Abi.ohosArm64: Int64(), ++ Abi.ohosX64: Int64(), Abi.fuchsiaArm64: Int64(), Abi.fuchsiaX64: Int64(), -+ Abi.ohosX64: Int64(), Abi.iosArm: Int32(), - Abi.iosArm64: Int64(), - Abi.iosX64: Int64(), -@@ -327,6 +335,7 @@ class Long extends AbiSpecificInteger { +@@ -325,6 +349,9 @@ class Long extends AbiSpecificInteger { + Abi.androidArm64: Uint64(), + Abi.androidIA32: Uint32(), Abi.androidX64: Uint64(), ++ Abi.ohosArm: Uint32(), ++ Abi.ohosArm64: Uint64(), ++ Abi.ohosX64: Uint64(), Abi.fuchsiaArm64: Uint64(), Abi.fuchsiaX64: Uint64(), -+ Abi.ohosX64: Uint64(), Abi.iosArm: Uint32(), - Abi.iosArm64: Uint64(), - Abi.iosX64: Uint64(), -@@ -364,6 +373,7 @@ class UnsignedLong extends AbiSpecificInteger { +@@ -362,6 +389,9 @@ class UnsignedLong extends AbiSpecificInteger { + Abi.androidArm64: Int64(), + Abi.androidIA32: Int64(), Abi.androidX64: Int64(), ++ Abi.ohosArm: Int64(), ++ Abi.ohosArm64: Int64(), ++ Abi.ohosX64: Int64(), Abi.fuchsiaArm64: Int64(), Abi.fuchsiaX64: Int64(), -+ Abi.ohosX64: Int64(), Abi.iosArm: Int64(), - Abi.iosArm64: Int64(), - Abi.iosX64: Int64(), -@@ -401,6 +411,7 @@ class LongLong extends AbiSpecificInteger { +@@ -399,6 +429,9 @@ class LongLong extends AbiSpecificInteger { + Abi.androidArm64: Uint64(), + Abi.androidIA32: Uint64(), Abi.androidX64: Uint64(), ++ Abi.ohosArm: Uint64(), ++ Abi.ohosArm64: Uint64(), ++ Abi.ohosX64: Uint64(), Abi.fuchsiaArm64: Uint64(), Abi.fuchsiaX64: Uint64(), -+ Abi.ohosX64: Uint64(), Abi.iosArm: Uint64(), - Abi.iosArm64: Uint64(), - Abi.iosX64: Uint64(), -@@ -433,6 +444,7 @@ class UnsignedLongLong extends AbiSpecificInteger { +@@ -431,6 +464,9 @@ class UnsignedLongLong extends AbiSpecificInteger { + Abi.androidArm64: Int64(), + Abi.androidIA32: Int32(), Abi.androidX64: Int64(), ++ Abi.ohosArm: Int32(), ++ Abi.ohosArm64: Int64(), ++ Abi.ohosX64: Int64(), Abi.fuchsiaArm64: Int64(), Abi.fuchsiaX64: Int64(), -+ Abi.ohosX64: Int64(), Abi.iosArm: Int32(), - Abi.iosArm64: Int64(), - Abi.iosX64: Int64(), -@@ -466,6 +478,7 @@ class IntPtr extends AbiSpecificInteger { +@@ -464,6 +500,9 @@ class IntPtr extends AbiSpecificInteger { + Abi.androidArm64: Uint64(), + Abi.androidIA32: Uint32(), Abi.androidX64: Uint64(), ++ Abi.ohosArm: Uint32(), ++ Abi.ohosArm64: Uint64(), ++ Abi.ohosX64: Uint64(), Abi.fuchsiaArm64: Uint64(), Abi.fuchsiaX64: Uint64(), -+ Abi.ohosX64: Uint64(), Abi.iosArm: Uint32(), - Abi.iosArm64: Uint64(), - Abi.iosX64: Uint64(), -@@ -499,6 +512,7 @@ class UintPtr extends AbiSpecificInteger { +@@ -497,6 +536,9 @@ class UintPtr extends AbiSpecificInteger { + Abi.androidArm64: Uint64(), + Abi.androidIA32: Uint32(), Abi.androidX64: Uint64(), ++ Abi.ohosArm: Uint32(), ++ Abi.ohosArm64: Uint64(), ++ Abi.ohosX64: Uint64(), Abi.fuchsiaArm64: Uint64(), Abi.fuchsiaX64: Uint64(), -+ Abi.ohosX64: Uint64(), Abi.iosArm: Uint32(), - Abi.iosArm64: Uint64(), - Abi.iosX64: Uint64(), -@@ -535,6 +549,7 @@ class Size extends AbiSpecificInteger { +@@ -533,6 +575,9 @@ class Size extends AbiSpecificInteger { + Abi.androidArm64: Uint32(), + Abi.androidIA32: Uint32(), Abi.androidX64: Uint32(), ++ Abi.ohosArm: Uint32(), ++ Abi.ohosArm64: Uint32(), ++ Abi.ohosX64: Uint32(), Abi.fuchsiaArm64: Uint32(), Abi.fuchsiaX64: Int32(), -+ Abi.ohosX64: Int32(), Abi.iosArm: Int32(), - Abi.iosArm64: Int32(), - Abi.iosX64: Int32(), diff --git a/sdk_args.gni b/sdk_args.gni index 4b2a1e4ea63..a864344ee8d 100644 --- a/sdk_args.gni diff --git a/attachment/repos/skia.patch b/attachment/repos/skia.patch index adad9f220a0bb691d29b861f077f901cf4df36aa..d4edec37a968bc6a36153cc1ed14c9229629bd8b 100644 --- a/attachment/repos/skia.patch +++ b/attachment/repos/skia.patch @@ -7,7 +7,7 @@ index ebbd898ec9..015bb75414 100644 # Skia public API, generally provided by :skia. config("skia_public") { - include_dirs = [ "." ] -+ include_dirs = [ ".", ++ include_dirs = [ ".", + "//third_part/khronos/", ] defines = [] @@ -1131,7 +1131,7 @@ index 0000000000..0e5e0829b6 +} diff --git a/src/ports/skia_ohos/FontConfig_ohos.cpp b/src/ports/skia_ohos/FontConfig_ohos.cpp new file mode 100644 -index 0000000000..2dfc1348c1 +index 0000000000..ea5c8ecf84 --- /dev/null +++ b/src/ports/skia_ohos/FontConfig_ohos.cpp @@ -0,0 +1,1312 @@ @@ -1141,7 +1141,7 @@ index 0000000000..2dfc1348c1 + +#include "FontConfig_ohos.h" + -+#include ++#include +#include +#include +#include @@ -1659,7 +1659,7 @@ index 0000000000..2dfc1348c1 + return logErrInfo(ERROR_CONFIG_MISSING_TAG, "alias"); + } + // "adjust", "variation" - optional -+ const char* tags[] = {"alias", "adjust", "variations", "index"}; ++ const char* tags[] = {"alias", "adjust", "font-variations", "index"}; + std::vector aliasSet; + std::vector adjustSet; + std::vector variationSet; @@ -1824,7 +1824,7 @@ index 0000000000..2dfc1348c1 + bool hasIndex = false; + bool hasVariations = false; + for (unsigned int i = 0; i < members.size(); i++) { -+ if (members[i] == "variations") { ++ if (members[i] == "font-variations") { + hasVariations = true; + } else if (members[i] == "index") { + hasIndex = true; @@ -1842,7 +1842,7 @@ index 0000000000..2dfc1348c1 + SkString lang = SkString(key); + SkString familyName = SkString(root[key].asCString()); + if (hasVariations) { -+ key = "variations"; ++ key = "font-variations"; + if (root[key].isArray()) { + const Json::Value& varArr = root[key]; + std::vector variationSet; @@ -1850,7 +1850,7 @@ index 0000000000..2dfc1348c1 + if (varArr[i].isObject()) { + parseVariation(varArr[i], variationSet); + } else { -+ SkString text = SkString("variations#"); ++ SkString text = SkString("font-variations#"); + text.appendU32(i + 1); + (void) logErrInfo(ERROR_CONFIG_INVALID_VALUE_TYPE, text.c_str(), + Json::objectValue, varArr[i].type()); @@ -1881,7 +1881,7 @@ index 0000000000..2dfc1348c1 + return NO_ERROR; +} + -+/*! To parse an item of 'variations' attribute ++/*! To parse an item of 'font-variations' attribute + * \param root the root node of an item in 'variations' list + * \param[out] variationSet the value of VariationInfo is written to and returned to the caller + * \return NO_ERROR successful @@ -3718,10 +3718,10 @@ index 0000000000..f80e920de0 +#endif /* SKTYPEFACE_OHOS_H */ diff --git a/src/ports/skia_ohos/config/fontconfig.json b/src/ports/skia_ohos/config/fontconfig.json new file mode 100644 -index 0000000000..ec225a188e +index 0000000000..2c5458bc6b --- /dev/null +++ b/src/ports/skia_ohos/config/fontconfig.json -@@ -0,0 +1,76 @@ +@@ -0,0 +1,1373 @@ +{ + "fontdir": ["/system/fonts/"], + "generic": [ @@ -3757,6 +3757,26 @@ index 0000000000..ec225a188e + { + "weight": 200, "to": 900 + } ++ ], ++ "font-variations": [ ++ { ++ "weight": 100, "wght": 100 ++ }, ++ { ++ "weight": 300, "wght": 247 ++ }, ++ { ++ "weight": 400, "wght": 400 ++ }, ++ { ++ "weight": 500, "wght": 500 ++ }, ++ { ++ "weight": 700, "wght": 706 ++ }, ++ { ++ "weight": 900, "wght": 844 ++ } + ] + }, + { @@ -3765,6 +3785,26 @@ index 0000000000..ec225a188e + { + "HarmonyOS-Sans-Condensed": 0 + } ++ ], ++ "font-variations": [ ++ { ++ "weight": 100, "wght": 100 ++ }, ++ { ++ "weight": 300, "wght": 247 ++ }, ++ { ++ "weight": 400, "wght": 400 ++ }, ++ { ++ "weight": 500, "wght": 500 ++ }, ++ { ++ "weight": 700, "wght": 706 ++ }, ++ { ++ "weight": 900, "wght": 844 ++ } + ] + }, + { @@ -3774,27 +3814,1284 @@ index 0000000000..ec225a188e + "HarmonyOS-Sans-Digit": 0 + } + ] ++ }, ++ { ++ "family": "Noto Serif", ++ "alias": [ ++ { ++ "serif": 0 ++ } ++ ] ++ }, ++ { ++ "family": "Noto Sans Mono", ++ "alias": [ ++ { ++ "monospace": 400 ++ } ++ ] + } + ], + "fallback": [ + { + "": [ + { ++ "und-Zsye": "HMOS Color Emoji" ++ }, ++ { ++ "": "Noto Sans" ++ }, ++ { ++ "font-variations": [ ++ { ++ "weight": 100, "wght": 100 ++ }, ++ { ++ "weight": 300, "wght": 247 ++ }, ++ { ++ "weight": 400, "wght": 400 ++ }, ++ { ++ "weight": 500, "wght": 500 ++ }, ++ { ++ "weight": 700, "wght": 706 ++ }, ++ { ++ "weight": 900, "wght": 844 ++ } ++ ], ++ "und-Arab": "HarmonyOS Sans Naskh Arabic UI" ++ }, ++ { ++ "und-Ethi": "Noto Sans Ethiopic" ++ }, ++ { ++ "und-Hebr": "Noto Sans Hebrew" ++ }, ++ { ++ "und-Thai": "Noto Sans Thai" ++ }, ++ { ++ "und-Armn": "Noto Sans Armenian" ++ }, ++ { ++ "und-Geor,und-Geok": "Noto Sans Georgian" ++ }, ++ { ++ "und-Deva": "Noto Sans Devanagari" ++ }, ++ { ++ "und-Gujr": "Noto Sans Gujarati" ++ }, ++ { ++ "und-Guru": "Noto Sans Gurmukhi" ++ }, ++ { ++ "und-Taml": "Noto Sans Tamil" ++ }, ++ { ++ "und-Mlym": "Noto Sans Malayalam" ++ }, ++ { ++ "und-Beng": "Noto Sans Bengali" ++ }, ++ { ++ "und-Telu": "Noto Sans Telugu" ++ }, ++ { ++ "und-Knda": "Noto Sans Kannada" ++ }, ++ { ++ "und-Orya": "Noto Sans Oriya" ++ }, ++ { ++ "und-Sinh": "Noto Sans Sinhala" ++ }, ++ { ++ "und-Khmr": "Noto Sans Khmer" ++ }, ++ { ++ "und-Laoo": "Noto Sans Lao" ++ }, ++ { ++ "und-Mymr": "Noto Sans Myanmar" ++ }, ++ { ++ "und-Thaa": "Noto Sans Thaana" ++ }, ++ { ++ "und-Cham": "Noto Sans Cham" ++ }, ++ { ++ "und-Ahom": "Noto Serif Ahom" ++ }, ++ { ++ "und-Adlm": "Noto Sans Adlam" ++ }, ++ { ++ "und-Avst": "Noto Sans Avestan" ++ }, ++ { ++ "und-Bali": "Noto Sans Balinese" ++ }, ++ { ++ "und-Bamu": "Noto Sans Bamum" ++ }, ++ { ++ "und-Batk": "Noto Sans Batak" ++ }, ++ { ++ "und-Brah": "Noto Sans Brahmi" ++ }, ++ { ++ "und-Bugi": "Noto Sans Buginese" ++ }, ++ { ++ "und-Buhd": "Noto Sans Buhid" ++ }, ++ { ++ "und-Cans": "Noto Sans Canadian Aboriginal" ++ }, ++ { ++ "und-Cari": "Noto Sans Carian" ++ }, ++ { ++ "und-Cakm": "Noto Sans Chakma" ++ }, ++ { ++ "und-Cher": "Noto Sans Cherokee" ++ }, ++ { ++ "und-Copt": "Noto Sans Coptic" ++ }, ++ { ++ "und-Xsux": "Noto Sans Cuneiform" ++ }, ++ { ++ "und-Cprt": "Noto Sans Cypriot" ++ }, ++ { ++ "und-Dsrt": "Noto Sans Deseret" ++ }, ++ { ++ "und-Egyp": "Noto Sans Egyptian Hieroglyphs" ++ }, ++ { ++ "und-Elba": "Noto Sans Elbasan" ++ }, ++ { ++ "und-Glag": "Noto Sans Glagolitic" ++ }, ++ { ++ "und-Goth": "Noto Sans Gothic" ++ }, ++ { ++ "und-Hano": "Noto Sans Hanunoo" ++ }, ++ { ++ "und-Armi": "Noto Sans Imperial Aramaic" ++ }, ++ { ++ "und-Phli": "Noto Sans Inscriptional Pahlavi" ++ }, ++ { ++ "und-Prti": "Noto Sans Inscriptional Parthian" ++ }, ++ { ++ "und-Java": "Noto Sans Javanese" ++ }, ++ { ++ "und-Kthi": "Noto Sans Kaithi" ++ }, ++ { ++ "und-Kali": "Noto Sans Kayah Li" ++ }, ++ { ++ "und-Khar": "Noto Sans Kharoshthi" ++ }, ++ { ++ "und-Lepc": "Noto Sans Lepcha" ++ }, ++ { ++ "und-Limb": "Noto Sans Limbu" ++ }, ++ { ++ "und-Linb": "Noto Sans Linear B" ++ }, ++ { ++ "und-Lisu": "Noto Sans Lisu" ++ }, ++ { ++ "und-Lyci": "Noto Sans Lycian" ++ }, ++ { ++ "und-Lydi": "Noto Sans Lydian" ++ }, ++ { ++ "und-Mand": "Noto Sans Mandaic" ++ }, ++ { ++ "und-Mtei": "Noto Sans Meetei Mayek" ++ }, ++ { ++ "und-Talu": "Noto Sans New Tai Lue" ++ }, ++ { ++ "und-Nkoo": "Noto Sans NKo" ++ }, ++ { ++ "und-Ogam": "Noto Sans Ogham" ++ }, ++ { ++ "und-Olck": "Noto Sans Ol Chiki" ++ }, ++ { ++ "und-Ital": "Noto Sans Old Italic" ++ }, ++ { ++ "und-Xpeo": "Noto Sans Old Persian" ++ }, ++ { ++ "und-Sarb": "Noto Sans Old South Arabian" ++ }, ++ { ++ "und-Orkh": "Noto Sans Old Turkic" ++ }, ++ { ++ "und-Osge": "Noto Sans Osage" ++ }, ++ { ++ "und-Osma": "Noto Sans Osmanya" ++ }, ++ { ++ "und-Phnx": "Noto Sans Phoenician" ++ }, ++ { ++ "und-Rjng": "Noto Sans Rejang" ++ }, ++ { ++ "und-Runr": "Noto Sans Runic" ++ }, ++ { ++ "und-Samr": "Noto Sans Samaritan" ++ }, ++ { ++ "und-Saur": "Noto Sans Saurashtra" ++ }, ++ { ++ "und-Shaw": "Noto Sans Shavian" ++ }, ++ { ++ "und-Sund": "Noto Sans Sundanese" ++ }, ++ { ++ "und-Sylo": "Noto Sans Syloti Nagri" ++ }, ++ { ++ "und-Syrn": "Noto Sans Syriac Eastern" ++ }, ++ { ++ "und-Syrj": "Noto Sans Syriac Western" ++ }, ++ { ++ "und-Tglg": "Noto Sans Tagalog" ++ }, ++ { ++ "und-Tagb": "Noto Sans Tagbanwa" ++ }, ++ { ++ "und-Lana": "Noto Sans Tai Tham" ++ }, ++ { ++ "und-Tavt": "Noto Sans Tai Viet" ++ }, ++ { ++ "und-Tibt": "Noto Serif Tibetan" ++ }, ++ { ++ "und-Tfng": "Noto Sans Tifinagh" ++ }, ++ { ++ "und-Ugar": "Noto Sans Ugaritic" ++ }, ++ { ++ "und-Vaii": "Noto Sans Vai" ++ }, ++ { ++ "font-variations": [ ++ { ++ "weight": 100, "wght": 100 ++ }, ++ { ++ "weight": 300, "wght": 247 ++ }, ++ { ++ "weight": 400, "wght": 400 ++ }, ++ { ++ "weight": 500, "wght": 500 ++ }, ++ { ++ "weight": 600, "wght": 603 ++ }, ++ { ++ "weight": 700, "wght": 706 ++ }, ++ { ++ "weight": 900, "wght": 844 ++ } ++ ], + "zh-Hans": "HarmonyOS Sans SC" + }, + { ++ "font-variations": [ ++ { ++ "weight": 100, "wght": 100 ++ }, ++ { ++ "weight": 300, "wght": 247 ++ }, ++ { ++ "weight": 400, "wght": 400 ++ }, ++ { ++ "weight": 500, "wght": 500 ++ }, ++ { ++ "weight": 700, "wght": 706 ++ }, ++ { ++ "weight": 900, "wght": 844 ++ } ++ ], + "zh-Hant": "HarmonyOS Sans TC" + }, + { -+ "und-Arab": "HarmonyOS Sans Naskh Arabic UI" ++ "ja": "Noto Sans CJK JP" + }, + { -+ "ja": "Noto Sans JP" ++ "ko": "Noto Sans CJK JP" + }, + { -+ "ko": "Noto Sans KR" -+ } -+ ] ++ "und-Zsye": "HMOS Color Emoji Flags" ++ }, ++ { ++ "und-Zsym": "Noto Sans Symbols" ++ }, ++ { ++ "und-Zsym": "Noto Sans Symbols 2" ++ }, ++ { ++ "und-Tale": "Noto Sans Tai Le" ++ }, ++ { ++ "und-Yiii": "Noto Sans Yi" ++ }, ++ { ++ "und-Mong": "Noto Sans Mongolian" ++ }, ++ { ++ "und-Phag": "Noto Sans Phags-Pa" ++ }, ++ { ++ "und-Hluw": "Noto Sans Anatolian Hieroglyphs" ++ }, ++ { ++ "und-Bass": "Noto Sans Bassa Vah" ++ }, ++ { ++ "und-Bhks": "Noto Sans Bhaiksuki" ++ }, ++ { ++ "und-Hatr": "Noto Sans Hatran" ++ }, ++ { ++ "und-Lina": "Noto Sans Linear A" ++ }, ++ { ++ "und-Mani": "Noto Sans Manichaean" ++ }, ++ { ++ "und-Marc": "Noto Sans Marchen" ++ }, ++ { ++ "und-Merc": "Noto Sans Meroitic" ++ }, ++ { ++ "und-Plrd": "Noto Sans Miao" ++ }, ++ { ++ "und-Mroo": "Noto Sans Mro" ++ }, ++ { ++ "und-Mult": "Noto Sans Multani" ++ }, ++ { ++ "und-Nbat": "Noto Sans Nabataean" ++ }, ++ { ++ "und-Newa": "Noto Sans Newa" ++ }, ++ { ++ "und-Narb": "Noto Sans Old North Arabian" ++ }, ++ { ++ "und-Perm": "Noto Sans Old Permic" ++ }, ++ { ++ "und-Hmng": "Noto Sans Pahawh Hmong" ++ }, ++ { ++ "und-Palm": "Noto Sans Palmyrene" ++ }, ++ { ++ "und-Pauc": "Noto Sans Pau Cin Hau" ++ }, ++ { ++ "und-Shrd": "Noto Sans Sharada" ++ }, ++ { ++ "und-Sora": "Noto Sans Sora Sompeng" ++ }, ++ { ++ "und-Gong": "Noto Sans Gunjala Gondi" ++ }, ++ { ++ "und-Rohg": "Noto Sans Hanifi Rohingya" ++ }, ++ { ++ "und-Khoj": "Noto Sans Khojki" ++ }, ++ { ++ "und-Gonm": "Noto Sans Masaram Gondi" ++ }, ++ { ++ "und-Wcho": "Noto Sans Wancho" ++ }, ++ { ++ "und-Wara": "Noto Sans Warang Citi" ++ }, ++ { ++ "und-Gran": "Noto Sans Grantha" ++ }, ++ { ++ "und-Modi": "Noto Sans Modi" ++ }, ++ { ++ "und-Dogr": "Noto Serif Dogra" ++ }, ++ { ++ "und-Medf": "Noto Sans Medefaidrin" ++ }, ++ { ++ "und-Soyo": "Noto Sans Soyombo" ++ }, ++ { ++ "und-Takr": "Noto Sans Takri" ++ }, ++ { ++ "und-Yezi": "Noto Serif Yezidi" ++ }, ++ { ++ "und-Zsym": "HM Symbol" ++ }, ++ { ++ "und-Math": "Noto Sans Math" ++ } ++ ] ++ } ++ ], ++ "font_file_map" : [ ++ { ++ "DejaVuMathTeXGyre-Regular": "DejaVuMathTeXGyre.ttf" ++ }, ++ { ++ "FTSymbol": "FTSymbol.ttf" ++ }, ++ { ++ "FTToken": "FTToken.ttf" ++ }, ++ { ++ "FTToken2": "FTToken2.ttf" ++ }, ++ { ++ "FTToken3": "FTToken3.ttf" ++ }, ++ { ++ "FTTokens": "FTTokens.ttf" ++ }, ++ { ++ "方正仿宋-简": "FZFangS-SC.ttf" ++ }, ++ { ++ "FZFangS-SC": "FZFangS-SC.ttf" ++ }, ++ { ++ "方正仿宋-繁": "FZFangS-TC.ttf" ++ }, ++ { ++ "FZFangS-TC": "FZFangS-TC.ttf" ++ }, ++ { ++ "FZHeiT-SC Bold": "FZHeiT-SC-Bold.ttf" ++ }, ++ { ++ "FZHeiT-SC Light": "FZHeiT-SC-Light.ttf" ++ }, ++ { ++ "FZHeiT-SC": "FZHeiT-SC-Regular.ttf" ++ }, ++ { ++ "FZHeiT-TC Bold": "FZHeiT-TC-Bold.ttf" ++ }, ++ { ++ "方正黑體-繁 Bold": "FZHeiT-TC-Bold.ttf" ++ }, ++ { ++ "FZHeiT-TC Light": "FZHeiT-TC-Light.ttf" ++ }, ++ { ++ "方正黑體-繁 Light": "FZHeiT-TC-Light.ttf" ++ }, ++ { ++ "FZHeiT-TC": "FZHeiT-TC-Regular.ttf" ++ }, ++ { ++ "方正黑體-繁": "FZHeiT-TC-Regular.ttf" ++ }, ++ { ++ "方正楷体-简": "FZKaiT-SC.ttf" ++ }, ++ { ++ "FZKaiT-SC": "FZKaiT-SC.ttf" ++ }, ++ { ++ "方正楷體-繁": "FZKaiT-TC.ttf" ++ }, ++ { ++ "FZKaiT-TC": "FZKaiT-TC.ttf" ++ }, ++ { ++ "方正隶体-简": "FZLiT-SC.ttf" ++ }, ++ { ++ "FZLiT-SC": "FZLiT-SC.ttf" ++ }, ++ { ++ "方正隸變-繁": "FZLiB-TC.ttf" ++ }, ++ { ++ "FZLiB-TC": "FZLiB-TC.ttf" ++ }, ++ { ++ "方正隶书-简": "FZLiS-SC.ttf" ++ }, ++ { ++ "FZLiS-SC": "FZLiS-SC.ttf" ++ }, ++ { ++ "方正隸書-繁": "FZLiS-TC.ttf" ++ }, ++ { ++ "FZLiS-TC": "FZLiS-TC.ttf" ++ }, ++ { ++ "方正喵呜-简": "FZMiaoW-SC.ttf" ++ }, ++ { ++ "FZMiaoW-SC": "FZMiaoW-SC.ttf" ++ }, ++ { ++ "方正喵體-繁": "FZMiaoT-TC.ttf" ++ }, ++ { ++ "FZMiaoT-TC": "FZMiaoT-TC.ttf" ++ }, ++ { ++ "方正手书-简": "FZShouS-SC.ttf" ++ }, ++ { ++ "FZShouS-SC": "FZShouS-SC.ttf" ++ }, ++ { ++ "方正手書-繁": "FZShouS-TC.ttf" ++ }, ++ { ++ "FZShouS-TC": "FZShouS-TC.ttf" ++ }, ++ { ++ "方正书宋-简": "FZShuS-SC.ttf" ++ }, ++ { ++ "FZShuS-SC": "FZShuS-SC.ttf" ++ }, ++ { ++ "方正書宋-繁": "FZShuS-TC.ttf" ++ }, ++ { ++ "FZShuS-TC": "FZShuS-TC.ttf" ++ }, ++ { ++ "方正小标宋-简": "FZXiaoBS-SC.ttf" ++ }, ++ { ++ "FZXiaoBS-SC": "FZXiaoBS-SC.ttf" ++ }, ++ { ++ "方正小標宋-繁": "FZXiaoBS-TC.ttf" ++ }, ++ { ++ "FZXiaoBS-TC": "FZXiaoBS-TC.ttf" ++ }, ++ { ++ "方正行楷-简": "FZXingK-SC.ttf" ++ }, ++ { ++ "FZXingK-SC": "FZXingK-SC.ttf" ++ }, ++ { ++ "方正行楷-繁": "FZXingK-TC.ttf" ++ }, ++ { ++ "FZXingK-TC": "FZXingK-TC.ttf" ++ }, ++ { ++ "FZYuanT-SC Bold": "FZYuanT-SC-Bold.ttf" ++ }, ++ { ++ "FZYuanT-SC Light": "FZYuanT-SC-Light.ttf" ++ }, ++ { ++ "FZYuanT-SC": "FZYuanT-SC-Regular.ttf" ++ }, ++ { ++ "FZYuanT-TC Bold": "FZYuanT-TC-Bold.ttf" ++ }, ++ { ++ "方正圓體-繁 Bold": "FZYuanT-TC-Bold.ttf" ++ }, ++ { ++ "FZYuanT-TC Light": "FZYuanT-TC-Light.ttf" ++ }, ++ { ++ "方正圓體-繁 Light": "FZYuanT-TC-Light.ttf" ++ }, ++ { ++ "FZYuanT-TC": "FZYuanT-TC-Regular.ttf" ++ }, ++ { ++ "方正圓體-繁": "FZYuanT-TC-Regular.ttf" ++ }, ++ { ++ "HMOS Color Emoji": "HMOSColorEmojiCompat.ttf" ++ }, ++ { ++ "HMOS Color Emoji Flags": "HMOSColorEmojiFlags.ttf" ++ }, ++ { ++ "HM Symbol Regular": "HMSymbolVF.ttf" ++ }, ++ { ++ "HarmonyOS Sans": "HarmonyOS_Sans.ttf" ++ }, ++ { ++ "HarmonyOS Sans Condensed": "HarmonyOS_Sans_Condensed.ttf" ++ }, ++ { ++ "HarmonyOS Sans Condensed Italic": "HarmonyOS_Sans_Condensed_Italic.ttf" ++ }, ++ { ++ "HarmonyOS Sans Digit": "HarmonyOS_Sans_Digit.ttf" ++ }, ++ { ++ "HarmonyOS Sans Digit": "HarmonyOS_Sans_Digit_Medium.ttf" ++ }, ++ { ++ "HarmonyOS Sans Italic": "HarmonyOS_Sans_Italic.ttf" ++ }, ++ { ++ "HarmonyOS Sans Naskh Arabic": "HarmonyOS_Sans_Naskh_Arabic.ttf" ++ }, ++ { ++ "HarmonyOS Sans Naskh Arabic UI": "HarmonyOS_Sans_Naskh_Arabic_UI.ttf" ++ }, ++ { ++ "HarmonyOS Sans SC": "HarmonyOS_Sans_SC.ttf" ++ }, ++ { ++ "HarmonyOS Sans TC": "HarmonyOS_Sans_TC.ttf" ++ }, ++ { ++ "Noto Sans Adlam Regular": "NotoSansAdlam[wght].ttf" ++ }, ++ { ++ "Noto Sans Anatolian Hieroglyphs Regular": "NotoSansAnatolianHieroglyphs-Regular.ttf" ++ }, ++ { ++ "Noto Sans Armenian Regular": "NotoSansArmenian[wdth,wght].ttf" ++ }, ++ { ++ "Noto Sans Avestan Regular": "NotoSansAvestan-Regular.ttf" ++ }, ++ { ++ "Noto Sans Balinese Regular": "NotoSansBalinese[wght].ttf" ++ }, ++ { ++ "Noto Sans Bamum Regular": "NotoSansBamum[wght].ttf" ++ }, ++ { ++ "Noto Sans Bassa Vah Regular": "NotoSansBassaVah[wght].ttf" ++ }, ++ { ++ "Noto Sans Batak Regular": "NotoSansBatak-Regular.ttf" ++ }, ++ { ++ "Noto Sans Bengali UI Bold": "NotoSansBengaliUI-Bold.ttf" ++ }, ++ { ++ "Noto Sans Bengali UI Medium": "NotoSansBengaliUI-Medium.ttf" ++ }, ++ { ++ "Noto Sans Bengali UI Regular": "NotoSansBengaliUI-Regular.ttf" ++ }, ++ { ++ "Noto Sans Bengali UI SemiBold": "NotoSansBengaliUI-SemiBold.ttf" ++ }, ++ { ++ "Noto Sans Bengali Regular": "NotoSansBengali[wdth,wght].ttf" ++ }, ++ { ++ "Noto Sans Bhaiksuki Regular": "NotoSansBhaiksuki-Regular.ttf" ++ }, ++ { ++ "Noto Sans Brahmi Regular": "NotoSansBrahmi-Regular.ttf" ++ }, ++ { ++ "Noto Sans Buginese Regular": "NotoSansBuginese-Regular.ttf" ++ }, ++ { ++ "Noto Sans Buhid Regular": "NotoSansBuhid-Regular.ttf" ++ }, ++ { ++ "Noto Sans CJK JP": "NotoSansCJK-Regular.ttc" ++ }, ++ { ++ "Noto Sans Canadian Aboriginal Regular": "NotoSansCanadianAboriginal[wght].ttf" ++ }, ++ { ++ "Noto Sans Carian Regular": "NotoSansCarian-Regular.ttf" ++ }, ++ { ++ "Noto Sans Chakma Regular": "NotoSansChakma-Regular.ttf" ++ }, ++ { ++ "Noto Sans Cham Regular": "NotoSansCham[wght].ttf" ++ }, ++ { ++ "Noto Sans Cherokee Regular": "NotoSansCherokee[wght].ttf" ++ }, ++ { ++ "Noto Sans Coptic Regular": "NotoSansCoptic-Regular.ttf" ++ }, ++ { ++ "Noto Sans Cuneiform Regular": "NotoSansCuneiform-Regular.ttf" ++ }, ++ { ++ "Noto Sans Cypriot Regular": "NotoSansCypriot-Regular.ttf" ++ }, ++ { ++ "Noto Sans Deseret Regular": "NotoSansDeseret-Regular.ttf" ++ }, ++ { ++ "Noto Sans Devanagari UI Bold": "NotoSansDevanagariUI-Bold.ttf" ++ }, ++ { ++ "Noto Sans Devanagari UI Medium": "NotoSansDevanagariUI-Medium.ttf" ++ }, ++ { ++ "Noto Sans Devanagari UI Regular": "NotoSansDevanagariUI-Regular.ttf" ++ }, ++ { ++ "Noto Sans Devanagari UI SemiBold": "NotoSansDevanagariUI-SemiBold.ttf" ++ }, ++ { ++ "Noto Sans Devanagari Regular": "NotoSansDevanagari[wdth,wght].ttf" ++ }, ++ { ++ "Noto Sans Egyptian Hieroglyphs Regular": "NotoSansEgyptianHieroglyphs-Regular.ttf" ++ }, ++ { ++ "Noto Sans Elbasan Regular": "NotoSansElbasan-Regular.ttf" ++ }, ++ { ++ "Noto Sans Ethiopic Regular": "NotoSansEthiopic[wdth,wght].ttf" ++ }, ++ { ++ "Noto Sans Georgian Regular": "NotoSansGeorgian[wdth,wght].ttf" ++ }, ++ { ++ "Noto Sans Glagolitic Regular": "NotoSansGlagolitic-Regular.ttf" ++ }, ++ { ++ "Noto Sans Gothic Regular": "NotoSansGothic-Regular.ttf" ++ }, ++ { ++ "Noto Sans Grantha Regular": "NotoSansGrantha-Regular.ttf" ++ }, ++ { ++ "Noto Sans Gujarati UI Bold": "NotoSansGujaratiUI-Bold.ttf" ++ }, ++ { ++ "Noto Sans Gujarati UI Regular": "NotoSansGujaratiUI-Regular.ttf" ++ }, ++ { ++ "Noto Sans Gujarati Regular": "NotoSansGujarati[wdth,wght].ttf" ++ }, ++ { ++ "Noto Sans Gunjala Gondi Regular": "NotoSansGunjalaGondi[wght].ttf" ++ }, ++ { ++ "Noto Sans Gurmukhi UI Bold": "NotoSansGurmukhiUI-Bold.ttf" ++ }, ++ { ++ "Noto Sans Gurmukhi UI Medium": "NotoSansGurmukhiUI-Medium.ttf" ++ }, ++ { ++ "Noto Sans Gurmukhi UI Regular": "NotoSansGurmukhiUI-Regular.ttf" ++ }, ++ { ++ "Noto Sans Gurmukhi UI SemiBold": "NotoSansGurmukhiUI-SemiBold.ttf" ++ }, ++ { ++ "Noto Sans Gurmukhi Regular": "NotoSansGurmukhi[wdth,wght].ttf" ++ }, ++ { ++ "Noto Sans Hanifi Rohingya Regular": "NotoSansHanifiRohingya[wght].ttf" ++ }, ++ { ++ "Noto Sans Hanunoo Regular": "NotoSansHanunoo-Regular.ttf" ++ }, ++ { ++ "Noto Sans Hatran Regular": "NotoSansHatran-Regular.ttf" ++ }, ++ { ++ "Noto Sans Hebrew Regular": "NotoSansHebrew[wdth,wght].ttf" ++ }, ++ { ++ "Noto Sans Imperial Aramaic Regular": "NotoSansImperialAramaic-Regular.ttf" ++ }, ++ { ++ "Noto Sans Inscriptional Pahlavi Regular": "NotoSansInscriptionalPahlavi-Regular.ttf" ++ }, ++ { ++ "Noto Sans Inscriptional Parthian Regular": "NotoSansInscriptionalParthian-Regular.ttf" ++ }, ++ { ++ "Noto Sans Javanese Regular": "NotoSansJavanese[wght].ttf" ++ }, ++ { ++ "Noto Sans Kaithi Regular": "NotoSansKaithi-Regular.ttf" ++ }, ++ { ++ "Noto Sans Kannada UI Bold": "NotoSansKannadaUI-Bold.ttf" ++ }, ++ { ++ "Noto Sans Kannada UI Medium": "NotoSansKannadaUI-Medium.ttf" ++ }, ++ { ++ "Noto Sans Kannada UI Regular": "NotoSansKannadaUI-Regular.ttf" ++ }, ++ { ++ "Noto Sans Kannada UI SemiBold": "NotoSansKannadaUI-SemiBold.ttf" ++ }, ++ { ++ "Noto Sans Kannada Regular": "NotoSansKannada[wdth,wght].ttf" ++ }, ++ { ++ "Noto Sans Kayah Li Regular": "NotoSansKayahLi[wght].ttf" ++ }, ++ { ++ "Noto Sans Kharoshthi Regular": "NotoSansKharoshthi-Regular.ttf" ++ }, ++ { ++ "Noto Sans Khmer Regular": "NotoSansKhmer[wdth,wght].ttf" ++ }, ++ { ++ "Noto Sans Khojki Regular": "NotoSansKhojki-Regular.ttf" ++ }, ++ { ++ "Noto Sans Lao Regular": "NotoSansLao[wdth,wght].ttf" ++ }, ++ { ++ "Noto Sans Lepcha Regular": "NotoSansLepcha-Regular.ttf" ++ }, ++ { ++ "Noto Sans Limbu Regular": "NotoSansLimbu-Regular.ttf" ++ }, ++ { ++ "Noto Sans Linear A Regular": "NotoSansLinearA-Regular.ttf" ++ }, ++ { ++ "Noto Sans Linear B Regular": "NotoSansLinearB-Regular.ttf" ++ }, ++ { ++ "Noto Sans Lisu Regular": "NotoSansLisu[wght].ttf" ++ }, ++ { ++ "Noto Sans Lycian Regular": "NotoSansLycian-Regular.ttf" ++ }, ++ { ++ "Noto Sans Lydian Regular": "NotoSansLydian-Regular.ttf" ++ }, ++ { ++ "Noto Sans Malayalam UI Bold": "NotoSansMalayalamUI-Bold.ttf" ++ }, ++ { ++ "Noto Sans Malayalam UI Medium": "NotoSansMalayalamUI-Medium.ttf" ++ }, ++ { ++ "Noto Sans Malayalam UI Regular": "NotoSansMalayalamUI-Regular.ttf" ++ }, ++ { ++ "Noto Sans Malayalam UI SemiBold": "NotoSansMalayalamUI-SemiBold.ttf" ++ }, ++ { ++ "Noto Sans Malayalam Regular": "NotoSansMalayalam[wdth,wght].ttf" ++ }, ++ { ++ "Noto Sans Mandaic Regular": "NotoSansMandaic-Regular.ttf" ++ }, ++ { ++ "Noto Sans Manichaean Regular": "NotoSansManichaean-Regular.ttf" ++ }, ++ { ++ "Noto Sans Marchen Regular": "NotoSansMarchen-Regular.ttf" ++ }, ++ { ++ "Noto Sans Masaram Gondi Regular": "NotoSansMasaramGondi-Regular.ttf" ++ }, ++ { ++ "Noto Sans Medefaidrin Regular": "NotoSansMedefaidrin[wght].ttf" ++ }, ++ { ++ "Noto Sans Meetei Mayek Regular": "NotoSansMeeteiMayek[wght].ttf" ++ }, ++ { ++ "Noto Sans Meroitic Regular": "NotoSansMeroitic-Regular.ttf" ++ }, ++ { ++ "Noto Sans Miao Regular": "NotoSansMiao-Regular.ttf" ++ }, ++ { ++ "Noto Sans Modi Regular": "NotoSansModi-Regular.ttf" ++ }, ++ { ++ "Noto Sans Mongolian Regular": "NotoSansMongolian-Regular.ttf" ++ }, ++ { ++ "Noto Sans Mono Regular": "NotoSansMono[wdth,wght].ttf" ++ }, ++ { ++ "Noto Sans Mro Regular": "NotoSansMro-Regular.ttf" ++ }, ++ { ++ "Noto Sans Multani Regular": "NotoSansMultani-Regular.ttf" ++ }, ++ { ++ "Noto Sans Myanmar Regular": "NotoSansMyanmar[wdth,wght].ttf" ++ }, ++ { ++ "Noto Sans NKo Regular": "NotoSansNKo-Regular.ttf" ++ }, ++ { ++ "Noto Sans Nabataean Regular": "NotoSansNabataean-Regular.ttf" ++ }, ++ { ++ "Noto Sans New Tai Lue Regular": "NotoSansNewTaiLue[wght].ttf" ++ }, ++ { ++ "Noto Sans Newa Regular": "NotoSansNewa-Regular.ttf" ++ }, ++ { ++ "Noto Sans Ogham Regular": "NotoSansOgham-Regular.ttf" ++ }, ++ { ++ "Noto Sans Ol Chiki Regular": "NotoSansOlChiki[wght].ttf" ++ }, ++ { ++ "Noto Sans Old Italic Regular": "NotoSansOldItalic-Regular.ttf" ++ }, ++ { ++ "Noto Sans Old North Arabian Regular": "NotoSansOldNorthArabian-Regular.ttf" ++ }, ++ { ++ "Noto Sans Old Permic Regular": "NotoSansOldPermic-Regular.ttf" ++ }, ++ { ++ "Noto Sans Old Persian Regular": "NotoSansOldPersian-Regular.ttf" ++ }, ++ { ++ "Noto Sans Old South Arabian Regular": "NotoSansOldSouthArabian-Regular.ttf" ++ }, ++ { ++ "Noto Sans Old Turkic Regular": "NotoSansOldTurkic-Regular.ttf" ++ }, ++ { ++ "Noto Sans Oriya Regular": "NotoSansOriya[wdth,wght].ttf" ++ }, ++ { ++ "Noto Sans Osage Regular": "NotoSansOsage-Regular.ttf" ++ }, ++ { ++ "Noto Sans Osmanya Regular": "NotoSansOsmanya-Regular.ttf" ++ }, ++ { ++ "Noto Sans Pahawh Hmong Regular": "NotoSansPahawhHmong-Regular.ttf" ++ }, ++ { ++ "Noto Sans Palmyrene Regular": "NotoSansPalmyrene-Regular.ttf" ++ }, ++ { ++ "Noto Sans Pau Cin Hau Regular": "NotoSansPauCinHau-Regular.ttf" ++ }, ++ { ++ "Noto Sans Phags-Pa Regular": "NotoSansPhags-Pa-Regular.ttf" ++ }, ++ { ++ "Noto Sans Phoenician Regular": "NotoSansPhoenician-Regular.ttf" ++ }, ++ { ++ "Noto Sans Rejang Regular": "NotoSansRejang-Regular.ttf" ++ }, ++ { ++ "Noto Sans Runic Regular": "NotoSansRunic-Regular.ttf" ++ }, ++ { ++ "Noto Sans Samaritan Regular": "NotoSansSamaritan-Regular.ttf" ++ }, ++ { ++ "Noto Sans Saurashtra Regular": "NotoSansSaurashtra-Regular.ttf" ++ }, ++ { ++ "Noto Sans Sharada Regular": "NotoSansSharada-Regular.ttf" ++ }, ++ { ++ "Noto Sans Shavian Regular": "NotoSansShavian-Regular.ttf" ++ }, ++ { ++ "Noto Sans Sinhala UI Bold": "NotoSansSinhalaUI-Bold.ttf" ++ }, ++ { ++ "Noto Sans Sinhala UI Medium": "NotoSansSinhalaUI-Medium.ttf" ++ }, ++ { ++ "Noto Sans Sinhala UI Regular": "NotoSansSinhalaUI-Regular.ttf" ++ }, ++ { ++ "Noto Sans Sinhala UI SemiBold": "NotoSansSinhalaUI-SemiBold.ttf" ++ }, ++ { ++ "Noto Sans Sinhala Regular": "NotoSansSinhala[wdth,wght].ttf" ++ }, ++ { ++ "Noto Sans Sora Sompeng Regular": "NotoSansSoraSompeng[wght].ttf" ++ }, ++ { ++ "Noto Sans Soyombo Regular": "NotoSansSoyombo-Regular.ttf" ++ }, ++ { ++ "Noto Sans Sundanese Regular": "NotoSansSundanese[wght].ttf" ++ }, ++ { ++ "Noto Sans Syloti Nagri Regular": "NotoSansSylotiNagri-Regular.ttf" ++ }, ++ { ++ "Noto Sans Symbols Regular": "NotoSansSymbols-Regular.ttf" ++ }, ++ { ++ "Noto Sans Symbols 2 Regular": "NotoSansSymbols2-Regular.ttf" ++ }, ++ { ++ "Noto Sans Syriac Eastern Regular": "NotoSansSyriacEastern[wght].ttf" ++ }, ++ { ++ "Noto Sans Syriac Western Regular": "NotoSansSyriacWestern[wght].ttf" ++ }, ++ { ++ "Noto Sans Tagalog Regular": "NotoSansTagalog-Regular.ttf" ++ }, ++ { ++ "Noto Sans Tagbanwa Regular": "NotoSansTagbanwa-Regular.ttf" ++ }, ++ { ++ "Noto Sans Tai Le Regular": "NotoSansTaiLe-Regular.ttf" ++ }, ++ { ++ "Noto Sans Tai Tham Regular": "NotoSansTaiTham[wght].ttf" ++ }, ++ { ++ "Noto Sans Tai Viet Regular": "NotoSansTaiViet-Regular.ttf" ++ }, ++ { ++ "Noto Sans Takri Regular": "NotoSansTakri-Regular.ttf" ++ }, ++ { ++ "Noto Sans Tamil UI Bold": "NotoSansTamilUI-Bold.ttf" ++ }, ++ { ++ "Noto Sans Tamil UI Medium": "NotoSansTamilUI-Medium.ttf" ++ }, ++ { ++ "Noto Sans Tamil UI Regular": "NotoSansTamilUI-Regular.ttf" ++ }, ++ { ++ "Noto Sans Tamil UI SemiBold": "NotoSansTamilUI-SemiBold.ttf" ++ }, ++ { ++ "Noto Sans Tamil Regular": "NotoSansTamil[wdth,wght].ttf" ++ }, ++ { ++ "Noto Sans Telugu UI Bold": "NotoSansTeluguUI-Bold.ttf" ++ }, ++ { ++ "Noto Sans Telugu UI Medium": "NotoSansTeluguUI-Medium.ttf" ++ }, ++ { ++ "Noto Sans Telugu UI Regular": "NotoSansTeluguUI-Regular.ttf" ++ }, ++ { ++ "Noto Sans Telugu UI SemiBold": "NotoSansTeluguUI-SemiBold.ttf" ++ }, ++ { ++ "Noto Sans Telugu Regular": "NotoSansTelugu[wdth,wght].ttf" ++ }, ++ { ++ "Noto Sans Thaana Regular": "NotoSansThaana[wght].ttf" ++ }, ++ { ++ "Noto Sans Thai Regular": "NotoSansThai[wdth,wght].ttf" ++ }, ++ { ++ "Noto Sans Tifinagh Regular": "NotoSansTifinagh-Regular.ttf" ++ }, ++ { ++ "Noto Sans Ugaritic Regular": "NotoSansUgaritic-Regular.ttf" ++ }, ++ { ++ "Noto Sans Vai Regular": "NotoSansVai-Regular.ttf" ++ }, ++ { ++ "Noto Sans Wancho Regular": "NotoSansWancho-Regular.ttf" ++ }, ++ { ++ "Noto Sans Warang Citi Regular": "NotoSansWarangCiti-Regular.ttf" ++ }, ++ { ++ "Noto Sans Yi Regular": "NotoSansYi-Regular.ttf" ++ }, ++ { ++ "Noto Sans Regular": "NotoSans[wdth,wght].ttf" ++ }, ++ { ++ "Noto Serif Ahom Regular": "NotoSerifAhom-Regular.ttf" ++ }, ++ { ++ "Noto Serif Armenian Regular": "NotoSerifArmenian[wdth,wght].ttf" ++ }, ++ { ++ "Noto Serif Bengali Regular": "NotoSerifBengali[wdth,wght].ttf" ++ }, ++ { ++ "Noto Serif CJK JP": "NotoSerifCJK-Regular.ttc" ++ }, ++ { ++ "Noto Serif Devanagari Regular": "NotoSerifDevanagari[wdth,wght].ttf" ++ }, ++ { ++ "Noto Serif Dogra Regular": "NotoSerifDogra-Regular.ttf" ++ }, ++ { ++ "Noto Serif Ethiopic Regular": "NotoSerifEthiopic[wdth,wght].ttf" ++ }, ++ { ++ "Noto Serif Georgian Regular": "NotoSerifGeorgian[wdth,wght].ttf" ++ }, ++ { ++ "Noto Serif Gujarati Regular": "NotoSerifGujarati[wght].ttf" ++ }, ++ { ++ "Noto Serif Gurmukhi Regular": "NotoSerifGurmukhi[wght].ttf" ++ }, ++ { ++ "Noto Serif Hebrew Regular": "NotoSerifHebrew[wdth,wght].ttf" ++ }, ++ { ++ "Noto Serif Kannada Regular": "NotoSerifKannada[wght].ttf" ++ }, ++ { ++ "Noto Serif Khmer Regular": "NotoSerifKhmer[wdth,wght].ttf" ++ }, ++ { ++ "Noto Serif Lao Regular": "NotoSerifLao[wdth,wght].ttf" ++ }, ++ { ++ "Noto Serif Malayalam Regular": "NotoSerifMalayalam[wght].ttf" ++ }, ++ { ++ "Noto Serif Myanmar Regular": "NotoSerifMyanmar[wdth,wght].ttf" ++ }, ++ { ++ "Noto Serif Sinhala Regular": "NotoSerifSinhala[wdth,wght].ttf" ++ }, ++ { ++ "Noto Serif Tamil Regular": "NotoSerifTamil[wdth,wght].ttf" ++ }, ++ { ++ "Noto Serif Telugu Regular": "NotoSerifTelugu[wght].ttf" ++ }, ++ { ++ "Noto Serif Thai Regular": "NotoSerifThai[wdth,wght].ttf" ++ }, ++ { ++ "Noto Serif Tibetan Regular": "NotoSerifTibetan[wght].ttf" ++ }, ++ { ++ "Noto Serif Yezidi Regular": "NotoSerifYezidi[wght].ttf" ++ }, ++ { ++ "Noto Serif Regular": "NotoSerif[wdth,wght].ttf" ++ }, ++ { ++ "Noto Sans Regular": "Roboto-Regular.ttf" ++ }, ++ { ++ "Noto Sans Math Regular": "NotoSansMath-Regular.ttf" ++ }, ++ { ++ "FangS-SC": "FangS-SC.ttf" ++ }, ++ { ++ "仿宋-简": "FangS-SC.ttf" ++ }, ++ { ++ "FT Thymes Regular": "FTThymes-Regular.ttf" ++ }, ++ { ++ "HeiT-SC": "HeiT-SC-Regular.ttf" ++ }, ++ { ++ "ShuS-SC ": "ShuS-SC.ttf" ++ }, ++ { ++ "书宋-简": "ShuS-SC.ttf" ++ }, ++ { ++ "KaiT-SC": "KaiT-SC.ttf" ++ }, ++ { ++ "楷体-简": "KaiT-SC.ttf" + } + ] +} @@ -3812,6 +5109,3 @@ index fca2f34ded..65955a7041 100644 OutputStream* rawOut = fOut; StringStream body; fOut = &body; --- -2.25.1 - diff --git a/attachment/scripts/ohos.py b/attachment/scripts/ohos.py index d60c405775fcb9c163d2784360cc1b7097be03d3..acf42ab53f248de834f88d40052467505f9b7baa 100644 --- a/attachment/scripts/ohos.py +++ b/attachment/scripts/ohos.py @@ -298,7 +298,7 @@ def zipFiles(buildInfo, useZip2=False, args=any): prefixInZip = os.path.join("src", "out", outputName) excludes = ["obj", "exe.unstripped", "so.unstripped"] if IS_WINDOWS: - excludes.extend([".*\.ilk", ".*\.pdb"]) + excludes.extend([r".*\.ilk", r".*\.pdb"]) zipFileDir(fileIn, fileName, prefixInZip, excludes=excludes, useZip2=useZip2) diff --git a/shell/platform/ohos/BUILD.gn b/shell/platform/ohos/BUILD.gn index 84548cee193d2a885072d0b358a0806dd746d674..62c781f18dd9cde37095e856a07f8103b34b060d 100644 --- a/shell/platform/ohos/BUILD.gn +++ b/shell/platform/ohos/BUILD.gn @@ -90,7 +90,9 @@ source_set("flutter_ohos_sources") { "./accessibility/ohos_accessibility_manager.h", "./accessibility/native_accessibility_channel.h", "./accessibility/ohos_accessibility_ddl.h", - "./utils/ddl_utils.h" + "./utils/ddl_utils.h", + "./utils/ohos_utils.h", + "./utils/arkui_accessibility_constant.h" ] #configs += [ "//flutter/shell/platform/ohos/config:gtk" ] @@ -126,7 +128,8 @@ source_set("flutter_ohos_sources") { "./accessibility/ohos_accessibility_features.cpp", "./accessibility/ohos_accessibility_manager.cpp", "./accessibility/native_accessibility_channel.cpp", - "./accessibility/ohos_accessibility_ddl.cpp" + "./accessibility/ohos_accessibility_ddl.cpp", + "./utils/ohos_utils.cpp" ] # Set flag to stop headers being directly included (library users should not do this) @@ -247,6 +250,7 @@ executable("flutter_ohos_unittests") { ldflags += ["-lnative_window"] ldflags += ["-lnative_vsync"] ldflags += ["-limage_ndk.z"] + ldflags += ["-ldeviceinfo_ndk.z"] ldflags += ["-lrawfile.z"] ldflags += ["-lnative_image"] ldflags += ["-lpixelmap_ndk.z"] diff --git a/shell/platform/ohos/accessibility/native_accessibility_channel.cpp b/shell/platform/ohos/accessibility/native_accessibility_channel.cpp index 1d3e8a7a3aa374ae7bbfcaea280754673fbfa46d..7d571f3528bd1d3484c97909e4cbacc28fc304cc 100644 --- a/shell/platform/ohos/accessibility/native_accessibility_channel.cpp +++ b/shell/platform/ohos/accessibility/native_accessibility_channel.cpp @@ -73,7 +73,7 @@ namespace flutter { { auto ohos_shell_holder = reinterpret_cast(shellHolderId); - ohos_shell_holder->GetPlatformView()->PlatformView::DispatchSemanticsAction(id, action, fml::MallocMapping()); + ohos_shell_holder->GetPlatformView()->PlatformView::DispatchSemanticsAction(id, action, std::move(args)); } /** @@ -83,8 +83,7 @@ namespace flutter { flutter::SemanticsNodeUpdates update, flutter::CustomAccessibilityActionUpdates actions) { - auto ohos_a11y_bridge = OhosAccessibilityBridge::GetInstance(); - ohos_a11y_bridge->updateSemantics(update, actions); + OhosAccessibilityBridge::GetInstance()->UpdateSemantics(update, actions); } /** @@ -102,7 +101,33 @@ namespace flutter { void NativeAccessibilityChannel::AccessibilityMessageHandler::Announce( std::unique_ptr& message) { - auto ohos_a11y_bridge = OhosAccessibilityBridge::GetInstance(); - ohos_a11y_bridge->Announce(message); + OhosAccessibilityBridge::GetInstance()->Announce(message); + } + + /** + * 利用通道内部类AccessibilityMessageHandler处理主动点击给定id组件事件 + */ + void NativeAccessibilityChannel::AccessibilityMessageHandler::OnTap( + int32_t nodeId) + { + OhosAccessibilityBridge::GetInstance()->OnTap(nodeId); + } + + /** + * 利用通道内部类AccessibilityMessageHandler处理主动长按给定id组件事件 + */ + void NativeAccessibilityChannel::AccessibilityMessageHandler::OnLongPress( + int32_t nodeId) + { + OhosAccessibilityBridge::GetInstance()->OnLongPress(nodeId); + } + + /** + * 利用通道内部类AccessibilityMessageHandler处理提示文字事件 + */ + void NativeAccessibilityChannel::AccessibilityMessageHandler::OnTooltip( + std::unique_ptr& message) + { + OhosAccessibilityBridge::GetInstance()->OnTooltip(message); } } \ 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 5bda8bfaea0e5a4f3de851e011763c650b5243fb..16f9d4b7b6714fe3c6ae9de2a5a3473194c8fa00 100644 --- a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp +++ b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp @@ -14,61 +14,78 @@ */ #include "ohos_accessibility_bridge.h" #include -#include -#include +#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 OHOS_API_VERSION 13 -#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) \ +#include "flutter/shell/platform/ohos/ohos_xcomponent_adapter.h" namespace flutter { -OhosAccessibilityBridge* OhosAccessibilityBridge::bridgeInstance = nullptr; +const int32_t OhosAccessibilityBridge::OHOS_API_VERSION = OH_GetSdkApiVersion(); -OhosAccessibilityBridge* OhosAccessibilityBridge::GetInstance() -{ - if(!bridgeInstance) { - bridgeInstance = new OhosAccessibilityBridge(); +std::unique_ptr OhosAccessibilityBridge::bridgeInstance_ = nullptr; + +/** + * flutter无障碍相关语义树、句柄指针provider等参数 + * 跟随xcomponentid显示切换,而加载对应xcomponent的语义树和provider指针 + * @NOTE: 当屏幕同时显示多个xcomponent时,无法通过聚焦事件而触发xcomponentid改变 + */ +void OhosAccessibilityBridge::AccessibiltiyChangesWithXComponentId() +{ + auto xcompMap = XComponentAdapter::GetInstance()->xcomponetMap_; + // 获取当前显示的xcomponetid + std::string currXcompId = XComponentAdapter::GetInstance()->currentXComponentId_; + if (xcomponentId_ == currXcompId) { return; } + + auto it = xcompMap.find(currXcompId); + if (!xcompMap.empty() && it != xcompMap.end()) { + // 更新xcompid,shellholderId,provider指针 + xcomponentId_ = currXcompId; + native_shell_holder_id_ = std::stoll(it->second->shellholderId_); + g_flutterSemanticsTree = g_flutterSemanticsTreeXComponents[xcomponentId_]; + g_parentChildIdVec = g_parentChildIdVecXComponents[xcomponentId_]; + FML_DLOG(INFO) << "AccessibiltiyChangesWithXComponentId -> xcomponentid:" << xcomponentId_; + } else { + xcomponentId_ = "oh_flutter_1"; + g_flutterSemanticsTree = g_flutterSemanticsTreeXComponents[xcomponentId_]; + g_parentChildIdVec = g_parentChildIdVecXComponents[xcomponentId_]; + FML_DLOG(INFO) << "AccessibiltiyChangesWithXComponentId -> xcomponentid:" << xcomponentId_; } - return bridgeInstance; } -void OhosAccessibilityBridge::DestroyInstance() { - delete bridgeInstance; - bridgeInstance = nullptr; +/** + * 采用局部静态变量配合call-once特性,实现线程安全的单例模式 + */ +OhosAccessibilityBridge* OhosAccessibilityBridge::GetInstance() +{ + static std::once_flag onceFlag; + std::call_once(onceFlag, []() { + bridgeInstance_.reset(new OhosAccessibilityBridge()); + }); + return bridgeInstance_.get(); } -OhosAccessibilityBridge::OhosAccessibilityBridge() {} +OhosAccessibilityBridge::OhosAccessibilityBridge() + : isFlutterNavigated_(false), + isAccessibilityEnabled_(false) {} /** * 监听当前ohos平台是否开启无障碍屏幕朗读服务 */ void OhosAccessibilityBridge::OnOhosAccessibilityStateChange( - int64_t shellHolderId, - bool ohosAccessibilityEnabled) + bool ohosAccessibilityEnabled, int64_t shellholderId) { - native_shell_holder_id_ = shellHolderId; + native_shell_holder_id_ = shellholderId; + AccessibiltiyChangesWithXComponentId(); nativeAccessibilityChannel_ = std::make_shared(); accessibilityFeatures_ = std::make_shared(); if (ohosAccessibilityEnabled) { + isAccessibilityEnabled_ = ohosAccessibilityEnabled; nativeAccessibilityChannel_->OnOhosAccessibilityEnabled(native_shell_holder_id_); } else { accessibilityFeatures_->SetAccessibleNavigation(false, native_shell_holder_id_); @@ -76,412 +93,334 @@ void OhosAccessibilityBridge::OnOhosAccessibilityStateChange( } } -void OhosAccessibilityBridge::SetNativeShellHolderId(int64_t id) +/** + * build the id mapping betwween parent node and its children nodes + */ +void OhosAccessibilityBridge::BuildParentChildNodeIdRelation( + const SemanticsNodeExtent& node) { - this->native_shell_holder_id_ = id; + if (!IsNodeVisible(node)) { return; } + for (const auto& childId : node.childrenInTraversalOrder) { + auto childNode = GetFlutterSemanticsNode(childId); + if (!IsNodeVisible(childNode)) { continue; } + g_parentChildIdVec.emplace_back(std::make_pair(node.id, childId)); + } } /** - * 从dart侧传递到c++侧的flutter无障碍语义树节点更新过程 + * 从dart侧传递到c++侧的flutter无障碍语义树节点更新过程, + * 路由新页面、滑动页面等操作会自动触发该语义树的更新 */ -void OhosAccessibilityBridge::updateSemantics( +void OhosAccessibilityBridge::UpdateSemantics( flutter::SemanticsNodeUpdates update, flutter::CustomAccessibilityActionUpdates actions) { - FML_DLOG(INFO) << ("OhosAccessibilityBridge::UpdateSemantics()"); + FML_DLOG(INFO) << "OhosAccessibilityBridge::UpdateSemantics()"; + std::vector updatedFlutterNodes; - // 当flutter页面更新时,自动请求id=0节点组件获焦(滑动组件除外) - if (IS_FLUTTER_NAVIGATE) { - RequestFocusWhenPageUpdate(); - IS_FLUTTER_NAVIGATE = false; + // 当flutter页面状态更新(路由新页面)时,自动请求root节点组件获焦(规避滑动组件更新干扰) + if (isFlutterNavigated_) { + RequestFocusWhenPageUpdate(0); + isFlutterNavigated_ = false; } /** 获取并分析每个语义节点的更新属性 */ - for (auto& item : update) { - // 获取当前更新的节点node - const flutter::SemanticsNode& node = item.second; - - // set struct SemanticsNodeExtent - auto nodeEx = SetAndGetSemanticsNodeExtent(node); - - //print semantics node and flags info for debugging - GetSemanticsNodeDebugInfo(node); - GetSemanticsFlagsDebugInfo(node); - - /** - * 构建flutter无障碍语义节点树 - * NOTE: 若使用g_flutterSemanticsTree.insert({node.id, node})方式 - * 来添加新增的语义节点会导致已有key值自动忽略,不会更新原有key对应的value - */ - g_flutterSemanticsTree[node.id] = node; - - if(!IsNodeVisible(node)) { - continue; - } - - // 获取当前flutter节点的全部子节点数量,并构建父子节点id映射关系 - int32_t childNodeCount = node.childrenInTraversalOrder.size(); - for (int32_t i = 0; i < childNodeCount; i++) { - g_parentChildIdVec.emplace_back( - std::make_pair(node.id, node.childrenInTraversalOrder[i])); - FML_DLOG(INFO) << "UpdateSemantics parentChildIdMap -> (" << node.id - << ", " << node.childrenInTraversalOrder[i] << ")"; - } - - // 当滑动节点产生滑动,并执行滑动处理 - if (HasScrolled(node)) { - LOGD("UpdateSemantics -> has scrolled"); - if (OH_GetSdkApiVersion() >= 13) { - ArkUI_AccessibilityElementInfo* (*OH_ArkUI_CreateAccessibilityElementInfo)(void) = - OhosAccessibilityDDL::DLLoadCreateElemInfoFunc("OH_ArkUI_CreateAccessibilityElementInfo"); - if (OH_ArkUI_CreateAccessibilityElementInfo == nullptr) { - LOGE("OH_ArkUI_CreateAccessibilityElementInfo is null, %{public}s", dlerror()); - } - ArkUI_AccessibilityElementInfo* _elementInfo = OH_ArkUI_CreateAccessibilityElementInfo(); - - FlutterNodeToElementInfoById(_elementInfo, static_cast(node.id)); - FlutterScrollExecution(node, _elementInfo); - - void (*OH_ArkUI_DestoryAccessibilityElementInfo)(ArkUI_AccessibilityElementInfo*) = - OhosAccessibilityDDL::DLLoadDestroyElemFunc("OH_ArkUI_DestoryAccessibilityElementInfo"); - if (OH_ArkUI_DestoryAccessibilityElementInfo == nullptr) { - LOGE("OH_ArkUI_DestoryAccessibilityElementInfo is null, %{public}s", dlerror()); - } - OH_ArkUI_DestoryAccessibilityElementInfo(_elementInfo); - _elementInfo = nullptr; - } - } - // 判断是否触发liveRegion活动区,当前节点是否活跃 - if (node.HasFlag(FLAGS_::kIsLiveRegion)) { - FML_DLOG(INFO) << "UpdateSemantics -> LiveRegion, node.id=" << node.id; - FlutterPageUpdate(ArkUI_AccessibilityEventType:: - ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_PAGE_CONTENT_UPDATE); - } - } - - // 遍历更新的actions,并将所有的actions的id添加进actionMap - for (const auto& item : actions) { - const flutter::CustomAccessibilityAction action = item.second; - GetCustomActionDebugInfo(action); - g_actions_mp[action.id] = action; - } - // 打印flutter语义树的不同节点的属性信息 - for (const auto& item : g_flutterSemanticsTree) { - FML_DLOG(INFO) << "g_flutterSemanticsTree -> {" << item.first << ", " - << item.second.id << "}"; - } - for (const auto& item : g_parentChildIdVec) { - FML_DLOG(INFO) << "g_parentChildIdVec -> (" << item.first << ", " - << item.second << ")"; - } - //打印按层次遍历排序的flutter语义树节点id数组 - std::vector levelOrderTraversalTree = GetLevelOrderTraversalTree(0); - for (const auto& item: levelOrderTraversalTree) { - FML_DLOG(INFO) << "LevelOrderTraversalTree: { " << item << " }"; - } - - FML_DLOG(INFO) << "=== UpdateSemantics is end ==="; + for (const auto& item : update) { + // 获取当前更新的节点node + const auto& node = item.second; + FML_DLOG(INFO) << "*#*#* node.id=" << node.id; + // 更新扩展的SemanticsNode信息 + auto nodeEx = UpdatetSemanticsNodeExtent(node); + + // 构建flutter无障碍语义节点树 + g_flutterSemanticsTree[nodeEx.id] = nodeEx; + // 构建flutter节点的父子id映射关系 + BuildParentChildNodeIdRelation(nodeEx); + + //print semantics node and flags info for debugging + GetSemanticsNodeDebugInfo(nodeEx); + GetSemanticsFlagsDebugInfo(nodeEx); + + if (!IsNodeVisible(nodeEx)) { continue; } + + // 若当前节点为获焦 + if (IsNodeFocused(nodeEx)) { + inputFocusedNode = nodeEx; + } + // 若当前节点和更新前节点信息不同,则加入更新节点数组 + if (nodeEx.hadPreviousConfig) { + updatedFlutterNodes.emplace_back(nodeEx); + FML_DLOG(INFO) << "updatedFlutterNodes -> node.id=" << nodeEx.id; + } + } + + // 将更新后的flutter语义树和父子节点id映射缓存,保存到相应的xcomponent里面 + g_flutterSemanticsTreeXComponents[xcomponentId_] = g_flutterSemanticsTree; + g_parentChildIdVecXComponents[xcomponentId_] = g_parentChildIdVec; + + // 页面内容更新事件 + Flutter_SendAccessibilityAsyncEvent(0, + ArkUI_AccessibilityEventType:: + ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_PAGE_CONTENT_UPDATE); + LOGD("Flutter_SendAccessibilityAsyncEvent -> PAGE_CONTENT_UPDATE"); + + /* 针对更新后的节点进行事件处理 */ + for (auto& nodeEx: updatedFlutterNodes) { + FML_DLOG(INFO) << "*#*#* updated node.id=" << nodeEx.id; + + // 当滑动节点产生滑动,并执行滑动处理 + if (HasScrolled(nodeEx)) { + LOGD("UpdateSemantics -> nodeId = %{public}d has scrolled", nodeEx.id); + auto OH_ArkUI_CreateAccessibilityElementInfo = + OhosAccessibilityDDL::DLLoadCreateElemInfoFunc(ArkUIAccessibilityConstant::ARKUI_CREATE_NODE); + CHECK_DLL_NULL_PTR(OH_ArkUI_CreateAccessibilityElementInfo); + auto* _elementInfo = OH_ArkUI_CreateAccessibilityElementInfo(); + + FlutterSetElementInfoProperties(_elementInfo, static_cast(nodeEx.id)); + // flutter滑动组件滑动处理逻辑 + FlutterScrollExecution(nodeEx, _elementInfo); + + // 屏幕朗读状态下双指滑动,获焦节点绿框实时跟随节点滑动 + Flutter_SendAccessibilityAsyncEvent( + static_cast(accessibilityFocusedNode.id), + ArkUI_AccessibilityEventType::ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_FOCUS_NODE_UPDATE); + + auto OH_ArkUI_DestoryAccessibilityElementInfo = + OhosAccessibilityDDL::DLLoadDestroyElemFunc(ArkUIAccessibilityConstant::ARKUI_DESTORY_NODE); + CHECK_DLL_NULL_PTR(OH_ArkUI_DestoryAccessibilityElementInfo); + OH_ArkUI_DestoryAccessibilityElementInfo(_elementInfo); + _elementInfo = nullptr; + } + + // 判断是否触发liveRegion活动区,当前节点是否活跃 nodeEx.HasFlag(FLAGS_::kIsLiveRegion) + if (nodeEx.HasFlag(FLAGS_::kIsLiveRegion) && HasChangedLabel(nodeEx)) { + FML_DLOG(INFO) << "liveRegion -> page content update, nodeEx.id=" << nodeEx.id; + Flutter_SendAccessibilityAsyncEvent(static_cast(nodeEx.id), + ArkUI_AccessibilityEventType:: + ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_PAGE_CONTENT_UPDATE); + } + } + // calculate the global tranfomr matrix for each node + ComputeGlobalTransform(); + // 输出flutter语义树相关重要语义信息debug日志 + GetSemanticsDebugInfo(); + FML_DLOG(INFO) << "=== UpdateSemantics() is finished ==="; } /** * flutter可滑动组件的滑动逻辑处理实现 */ void OhosAccessibilityBridge::FlutterScrollExecution( - flutter::SemanticsNode node, + SemanticsNodeExtent node, ArkUI_AccessibilityElementInfo* elementInfoFromList) { - if (OH_GetSdkApiVersion() >= 13) { - double nodePosition = node.scrollPosition; - double nodeScrollExtentMax = node.scrollExtentMax; - double nodeScrollExtentMin = node.scrollExtentMin; - double infinity = std::numeric_limits::infinity(); - - // 设置flutter可滑动的最大范围值 - if (nodeScrollExtentMax == infinity) { - nodeScrollExtentMax = SCROLL_EXTENT_FOR_INFINITY; - if (nodePosition > SCROLL_POSITION_CAP_FOR_INFINITY) { - nodePosition = SCROLL_POSITION_CAP_FOR_INFINITY; - } - } - if (nodeScrollExtentMin == infinity) { - nodeScrollExtentMax += SCROLL_EXTENT_FOR_INFINITY; - if (nodePosition < -SCROLL_POSITION_CAP_FOR_INFINITY) { - nodePosition = -SCROLL_POSITION_CAP_FOR_INFINITY; - } - nodePosition += SCROLL_EXTENT_FOR_INFINITY; - } else { - nodeScrollExtentMax -= node.scrollExtentMin; - nodePosition -= node.scrollExtentMin; - } + if (OHOS_API_VERSION < 13) { return; } + double nodePosition = node.scrollPosition; + double nodeScrollExtentMax = node.scrollExtentMax; + double nodeScrollExtentMin = node.scrollExtentMin; + double infinity = std::numeric_limits::infinity(); - if (node.HasAction(ACTIONS_::kScrollUp) || - node.HasAction(ACTIONS_::kScrollDown)) { - } else if (node.HasAction(ACTIONS_::kScrollLeft) || - node.HasAction(ACTIONS_::kScrollRight)) { + // 设置flutter可滑动的最大范围值 + if (nodeScrollExtentMax == infinity) { + nodeScrollExtentMax = SCROLL_EXTENT_FOR_INFINITY; + if (nodePosition > SCROLL_POSITION_CAP_FOR_INFINITY) { + nodePosition = SCROLL_POSITION_CAP_FOR_INFINITY; } - - // 当可滑动组件存在滑动子节点 - if (node.scrollChildren > 0) { - // 配置当前滑动组件的子节点总数 - int32_t itemCount = node.scrollChildren; - int32_t (*OH_ArkUI_AccessibilityElementInfoSetItemCount)(ArkUI_AccessibilityElementInfo*, int32_t) = - OhosAccessibilityDDL::DLLoadSetElemIntFunc("OH_ArkUI_AccessibilityElementInfoSetItemCount"); - if (OH_ArkUI_AccessibilityElementInfoSetItemCount == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetItemCount is null, %{public}s", dlerror()); - } - ARKUI_ACCESSIBILITY_CALL_CHECK(OH_ArkUI_AccessibilityElementInfoSetItemCount(elementInfoFromList, itemCount)); - - // 设置当前页面可见的起始滑动index - int32_t startItemIndex = node.scrollIndex; - int32_t (*OH_ArkUI_AccessibilityElementInfoSetStartItemIndex)(ArkUI_AccessibilityElementInfo*, int32_t) = - OhosAccessibilityDDL::DLLoadSetElemIntFunc("OH_ArkUI_AccessibilityElementInfoSetStartItemIndex"); - if (OH_ArkUI_AccessibilityElementInfoSetStartItemIndex == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetStartItemIndex is null, %{public}s", dlerror()); - } - ARKUI_ACCESSIBILITY_CALL_CHECK(OH_ArkUI_AccessibilityElementInfoSetStartItemIndex(elementInfoFromList, startItemIndex)); - - // 计算当前滑动位置页面的可见子滑动节点数量 - int visibleChildren = 0; - // handle hidden children at the beginning and end of the list. - for (const auto& childId : node.childrenInHitTestOrder) { - auto childNode = GetFlutterSemanticsNode(childId); - if (!childNode.HasFlag(FLAGS_::kIsHidden)) { - visibleChildren += 1; - } - } - // 当可见滑动子节点数量超过滑动组件总子节点数量 - if (node.scrollIndex + visibleChildren > node.scrollChildren) { - FML_DLOG(WARNING) - << "FlutterScrollExecution -> Scroll index is out of bounds"; - } - // 当滑动击中子节点数量为0 - if (!node.childrenInHitTestOrder.size()) { - FML_DLOG(WARNING) << "FlutterScrollExecution -> Had scrollChildren but no " - "childrenInHitTestOrder"; - } - // 设置当前页面可见的末尾滑动index - int32_t endItemIndex = node.scrollIndex + visibleChildren - 1; - int32_t (*OH_ArkUI_AccessibilityElementInfoSetEndItemIndex)(ArkUI_AccessibilityElementInfo*, int32_t) = - OhosAccessibilityDDL::DLLoadSetElemIntFunc("OH_ArkUI_AccessibilityElementInfoSetEndItemIndex"); - if (OH_ArkUI_AccessibilityElementInfoSetEndItemIndex == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetEndItemIndex is null, %{public}s", dlerror()); - } - ARKUI_ACCESSIBILITY_CALL_CHECK( - OH_ArkUI_AccessibilityElementInfoSetEndItemIndex(elementInfoFromList, endItemIndex) - ); + } + if (nodeScrollExtentMin == infinity) { + nodeScrollExtentMax += SCROLL_EXTENT_FOR_INFINITY; + if (nodePosition < -SCROLL_POSITION_CAP_FOR_INFINITY) { + nodePosition = -SCROLL_POSITION_CAP_FOR_INFINITY; } + nodePosition += SCROLL_EXTENT_FOR_INFINITY; + } else { + nodeScrollExtentMax -= node.scrollExtentMin; + nodePosition -= node.scrollExtentMin; } -} -/** - * 当页面内容/状态更新事件,在页面转换、切换、调整大小时发送页面状态更新事件 - */ -void OhosAccessibilityBridge::FlutterPageUpdate( - ArkUI_AccessibilityEventType eventType) -{ - if (provider_ == nullptr) { - FML_DLOG(ERROR) << "PageStateUpdate ->" - "AccessibilityProvider = nullptr"; - return; + if (node.HasAction(ACTIONS_::kScrollUp) || + node.HasAction(ACTIONS_::kScrollDown)) { + } else if (node.HasAction(ACTIONS_::kScrollLeft) || + node.HasAction(ACTIONS_::kScrollRight)) { + LOGD("current flutterNode has scroll up/down/left/right"); } - if (OH_GetSdkApiVersion() >= 13) { - ArkUI_AccessibilityEventInfo* (*OH_ArkUI_CreateAccessibilityEventInfo)(void) = - OhosAccessibilityDDL::DLLoadCreateEventInfoFunc("OH_ArkUI_CreateAccessibilityEventInfo"); - if (OH_ArkUI_CreateAccessibilityEventInfo == nullptr) { - LOGE("OH_ArkUI_CreateAccessibilityEventInfo is null, %{public}s", dlerror()); - } - ArkUI_AccessibilityEventInfo* pageUpdateEventInfo = OH_ArkUI_CreateAccessibilityEventInfo(); - int32_t (*OH_ArkUI_AccessibilityEventSetEventType)(ArkUI_AccessibilityEventInfo*, ArkUI_AccessibilityEventType) = - OhosAccessibilityDDL::DLLoadSetEventFunc("OH_ArkUI_AccessibilityEventSetEventType"); - if (OH_ArkUI_AccessibilityEventSetEventType == nullptr) { - LOGE("OH_ArkUI_AccessibilityEventSetEventType is null, %{public}s", dlerror()); - } + // 当可滑动组件存在滑动子节点 + if (node.scrollChildren > 0) { + // 配置当前滑动组件的子节点总数 + int32_t itemCount = node.scrollChildren; + auto OH_ArkUI_AccessibilityElementInfoSetItemCount = + OhosAccessibilityDDL::DLLoadSetElemIntFunc(ArkUIAccessibilityConstant::ARKUI_SET_ITEM_COUNT); + CHECK_DLL_NULL_PTR(OH_ArkUI_AccessibilityElementInfoSetItemCount); ARKUI_ACCESSIBILITY_CALL_CHECK( - OH_ArkUI_AccessibilityEventSetEventType(pageUpdateEventInfo, eventType) - ); - - auto callback = [](int32_t errorCode) { - FML_DLOG(WARNING) << "PageStateUpdate callback-> errorCode =" << errorCode; - }; + OH_ArkUI_AccessibilityElementInfoSetItemCount(elementInfoFromList, itemCount)); - void (*OH_ArkUI_SendAccessibilityAsyncEvent)(ArkUI_AccessibilityProvider*, ArkUI_AccessibilityEventInfo*, void (*callback)(int32_t)) = - OhosAccessibilityDDL::DLLoadSendAsyncEventFunc("OH_ArkUI_SendAccessibilityAsyncEvent"); - if (OH_ArkUI_SendAccessibilityAsyncEvent == nullptr) { - LOGE("OH_ArkUI_SendAccessibilityAsyncEvent is null, %{public}s", dlerror()); - } - OH_ArkUI_SendAccessibilityAsyncEvent(provider_, pageUpdateEventInfo, callback); + // 设置当前页面可见的起始滑动index + int32_t startItemIndex = node.scrollIndex; + auto OH_ArkUI_AccessibilityElementInfoSetStartItemIndex = + OhosAccessibilityDDL::DLLoadSetElemIntFunc(ArkUIAccessibilityConstant::ARKUI_SET_START_ITEM_IDX); + CHECK_DLL_NULL_PTR(OH_ArkUI_AccessibilityElementInfoSetStartItemIndex); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetStartItemIndex(elementInfoFromList, startItemIndex)); - void (*OH_ArkUI_DestoryAccessibilityEventInfo)(ArkUI_AccessibilityEventInfo*) = - OhosAccessibilityDDL::DLLoadDestroyEventFunc("OH_ArkUI_DestoryAccessibilityEventInfo"); - if (OH_ArkUI_DestoryAccessibilityEventInfo == nullptr) { - LOGE("OH_ArkUI_DestoryAccessibilityEventInfo is null, %{public}s", dlerror()); + // 设置当前获焦节点的当前index + int32_t currItemIndex = accessibilityFocusedNode.id; + auto OH_ArkUI_AccessibilityElementInfoSetCurrentItemIndex = + OhosAccessibilityDDL::DLLoadSetElemIntFunc(ArkUIAccessibilityConstant::ARKUI_SET_CURR_ITEM_IDX); + CHECK_DLL_NULL_PTR(OH_ArkUI_AccessibilityElementInfoSetCurrentItemIndex); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetCurrentItemIndex(elementInfoFromList, currItemIndex)); + + // 计算当前滑动位置页面的可见子滑动节点数量 + int visibleChildren = 0; + // handle hidden children at the beginning and end of the list. + for (const auto& childId : node.childrenInHitTestOrder) { + auto childNode = GetFlutterSemanticsNode(childId); + if (!childNode.HasFlag(FLAGS_::kIsHidden)) { + visibleChildren += 1; + } } - OH_ArkUI_DestoryAccessibilityEventInfo(pageUpdateEventInfo); - pageUpdateEventInfo = nullptr; + // 当可见滑动子节点数量超过滑动组件总子节点数量 + if (node.scrollIndex + visibleChildren > node.scrollChildren) { + FML_DLOG(WARNING) + << "FlutterScrollExecution -> Scroll index is out of bounds"; + } + // 当滑动击中子节点数量为0 + if (!node.childrenInHitTestOrder.size()) { + FML_DLOG(WARNING) << "FlutterScrollExecution -> Had scrollChildren but no " + "childrenInHitTestOrder"; + } + // 设置当前页面可见的末尾滑动index + int32_t endItemIndex = node.scrollIndex + visibleChildren - 1; + auto OH_ArkUI_AccessibilityElementInfoSetEndItemIndex = + OhosAccessibilityDDL::DLLoadSetElemIntFunc(ArkUIAccessibilityConstant::ARKUI_SET_END_ITEM_IDX); + CHECK_DLL_NULL_PTR(OH_ArkUI_AccessibilityElementInfoSetEndItemIndex); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetEndItemIndex(elementInfoFromList, endItemIndex)); } } /** * 特定节点的焦点请求 (当页面更新时自动请求id=0节点获焦) */ -void OhosAccessibilityBridge::RequestFocusWhenPageUpdate() -{ - if (provider_ == nullptr) { - FML_DLOG(ERROR) << "RequestFocusWhenPageUpdate ->" - "AccessibilityProvider = nullptr"; - return; - } - if (OH_GetSdkApiVersion() >= 13) { - ArkUI_AccessibilityEventInfo* (*OH_ArkUI_CreateAccessibilityEventInfo)(void) = - OhosAccessibilityDDL::DLLoadCreateEventInfoFunc("OH_ArkUI_CreateAccessibilityEventInfo"); - if (OH_ArkUI_CreateAccessibilityEventInfo == nullptr) { - LOGE("OH_ArkUI_CreateAccessibilityEventInfo is null, %{public}s", dlerror()); - } - ArkUI_AccessibilityEventInfo* reqFocusEventInfo = OH_ArkUI_CreateAccessibilityEventInfo(); - - ArkUI_AccessibilityElementInfo* (*OH_ArkUI_CreateAccessibilityElementInfo)(void) = - OhosAccessibilityDDL::DLLoadCreateElemInfoFunc("OH_ArkUI_CreateAccessibilityElementInfo"); - if (OH_ArkUI_CreateAccessibilityElementInfo == nullptr) { - LOGE("OH_ArkUI_CreateAccessibilityElementInfo is null, %{public}s", dlerror()); - } - ArkUI_AccessibilityElementInfo* elementInfo = OH_ArkUI_CreateAccessibilityElementInfo(); - - int32_t (*OH_ArkUI_AccessibilityEventSetEventType)(ArkUI_AccessibilityEventInfo*, ArkUI_AccessibilityEventType) = - OhosAccessibilityDDL::DLLoadSetEventFunc("OH_ArkUI_AccessibilityEventSetEventType"); - if (OH_ArkUI_AccessibilityEventSetEventType == nullptr) { - LOGE("OH_ArkUI_AccessibilityEventSetEventType is null, %{public}s", dlerror()); - } - ARKUI_ACCESSIBILITY_CALL_CHECK( - OH_ArkUI_AccessibilityEventSetEventType( - reqFocusEventInfo, - ArkUI_AccessibilityEventType:: - ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_REQUEST_ACCESSIBILITY_FOCUS) - ); - - int32_t requestFocusId = 0; - int32_t (*OH_ArkUI_AccessibilityEventSetRequestFocusId)(ArkUI_AccessibilityEventInfo*, int32_t) = - OhosAccessibilityDDL::DLLoadSetReqFocusFunc("OH_ArkUI_AccessibilityEventSetRequestFocusId"); - if (OH_ArkUI_AccessibilityEventSetRequestFocusId == nullptr) { - LOGE("OH_ArkUI_AccessibilityEventSetRequestFocusId is null, %{public}s", dlerror()); - } - ARKUI_ACCESSIBILITY_CALL_CHECK( - OH_ArkUI_AccessibilityEventSetRequestFocusId(reqFocusEventInfo, - requestFocusId) - ); - - int32_t (*OH_ArkUI_AccessibilityEventSetElementInfo)(ArkUI_AccessibilityEventInfo*, ArkUI_AccessibilityElementInfo*) = - OhosAccessibilityDDL::DLLoadSetEventElemFunc("OH_ArkUI_AccessibilityEventSetElementInfo"); - if (OH_ArkUI_AccessibilityEventSetElementInfo == nullptr) { - LOGE("OH_ArkUI_AccessibilityEventSetElementInfo is null, %{public}s", dlerror()); - } - ARKUI_ACCESSIBILITY_CALL_CHECK( - OH_ArkUI_AccessibilityEventSetElementInfo(reqFocusEventInfo, elementInfo) - ); - - auto callback = [](int32_t errorCode) { - FML_DLOG(WARNING) << "PageStateUpdate callback-> errorCode =" << errorCode; - }; - - void (*OH_ArkUI_SendAccessibilityAsyncEvent)(ArkUI_AccessibilityProvider*, ArkUI_AccessibilityEventInfo*, void (*callback)(int32_t)) = - OhosAccessibilityDDL::DLLoadSendAsyncEventFunc("OH_ArkUI_SendAccessibilityAsyncEvent"); - if (OH_ArkUI_SendAccessibilityAsyncEvent == nullptr) { - LOGE("OH_ArkUI_SendAccessibilityAsyncEvent is null, %{public}s", dlerror()); - } - OH_ArkUI_SendAccessibilityAsyncEvent(provider_, reqFocusEventInfo, callback); - - void (*OH_ArkUI_DestoryAccessibilityEventInfo)(ArkUI_AccessibilityEventInfo*) = - OhosAccessibilityDDL::DLLoadDestroyEventFunc("OH_ArkUI_DestoryAccessibilityEventInfo"); - if (OH_ArkUI_DestoryAccessibilityEventInfo == nullptr) { - LOGE("OH_ArkUI_DestoryAccessibilityEventInfo is null, %{public}s", dlerror()); - } - OH_ArkUI_DestoryAccessibilityEventInfo(reqFocusEventInfo); - reqFocusEventInfo = nullptr; - - void (*OH_ArkUI_DestoryAccessibilityElementInfo)(ArkUI_AccessibilityElementInfo*) = - OhosAccessibilityDDL::DLLoadDestroyElemFunc("OH_ArkUI_DestoryAccessibilityElementInfo"); - if (OH_ArkUI_DestoryAccessibilityElementInfo == nullptr) { - LOGE("OH_ArkUI_DestoryAccessibilityElementInfo is null, %{public}s", dlerror()); - } - OH_ArkUI_DestoryAccessibilityElementInfo(elementInfo); - elementInfo = nullptr; - } +void OhosAccessibilityBridge::RequestFocusWhenPageUpdate(int32_t requestFocusId) +{ + if (OHOS_API_VERSION < 13) { return; } + std::lock_guard lock(XComponentAdapter::GetInstance()->mutex_); + auto provider_ = XComponentAdapter::GetInstance()->GetAccessibilityProvider(xcomponentId_); + CHECK_NULL_PTR_RET_VOID(provider_, RequestFocusWhenPageUpdate); + + auto OH_ArkUI_CreateAccessibilityEventInfo = + OhosAccessibilityDDL::DLLoadCreateEventInfoFunc(ArkUIAccessibilityConstant::ARKUI_CREATE_EVENT); + CHECK_DLL_NULL_PTR(OH_ArkUI_CreateAccessibilityEventInfo); + auto* reqFocusEventInfo = OH_ArkUI_CreateAccessibilityEventInfo(); + + auto OH_ArkUI_CreateAccessibilityElementInfo = + OhosAccessibilityDDL::DLLoadCreateElemInfoFunc(ArkUIAccessibilityConstant::ARKUI_CREATE_NODE); + CHECK_DLL_NULL_PTR(OH_ArkUI_CreateAccessibilityElementInfo); + auto* elementInfo = OH_ArkUI_CreateAccessibilityElementInfo(); + + auto OH_ArkUI_AccessibilityEventSetEventType = + OhosAccessibilityDDL::DLLoadSetEventFunc(ArkUIAccessibilityConstant::ARKUI_SET_EVENT_TYPE); + CHECK_DLL_NULL_PTR(OH_ArkUI_AccessibilityEventSetEventType); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityEventSetEventType( + reqFocusEventInfo, + ArkUI_AccessibilityEventType:: + ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_REQUEST_ACCESSIBILITY_FOCUS) + ); + + auto OH_ArkUI_AccessibilityEventSetRequestFocusId = + OhosAccessibilityDDL::DLLoadSetReqFocusFunc(ArkUIAccessibilityConstant::ARKUI_SET_REQ_FOCUSED_ID); + CHECK_DLL_NULL_PTR(OH_ArkUI_AccessibilityEventSetRequestFocusId); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityEventSetRequestFocusId(reqFocusEventInfo, requestFocusId) + ); + + auto OH_ArkUI_AccessibilityEventSetElementInfo = + OhosAccessibilityDDL::DLLoadSetEventElemFunc(ArkUIAccessibilityConstant::ARKUI_EVENT_SET_NODE); + CHECK_DLL_NULL_PTR(OH_ArkUI_AccessibilityEventSetElementInfo); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityEventSetElementInfo(reqFocusEventInfo, elementInfo) + ); + + auto callback = [](int32_t errorCode) { + FML_DLOG(WARNING) << "PageStateUpdate callback-> errorCode =" << errorCode; + }; + + auto OH_ArkUI_SendAccessibilityAsyncEvent = + OhosAccessibilityDDL::DLLoadSendAsyncEventFunc(ArkUIAccessibilityConstant::ARKUI_SEND_A11Y_EVENT); + CHECK_DLL_NULL_PTR(OH_ArkUI_SendAccessibilityAsyncEvent); + OH_ArkUI_SendAccessibilityAsyncEvent(provider_, reqFocusEventInfo, callback); + + auto OH_ArkUI_DestoryAccessibilityEventInfo = + OhosAccessibilityDDL::DLLoadDestroyEventFunc(ArkUIAccessibilityConstant::ARKUI_DESTORY_EVENT); + CHECK_DLL_NULL_PTR(OH_ArkUI_DestoryAccessibilityEventInfo); + OH_ArkUI_DestoryAccessibilityEventInfo(reqFocusEventInfo); + reqFocusEventInfo = nullptr; + + auto OH_ArkUI_DestoryAccessibilityElementInfo = + OhosAccessibilityDDL::DLLoadDestroyElemFunc(ArkUIAccessibilityConstant::ARKUI_DESTORY_NODE); + CHECK_DLL_NULL_PTR(OH_ArkUI_DestoryAccessibilityElementInfo); + OH_ArkUI_DestoryAccessibilityElementInfo(elementInfo); + elementInfo = nullptr; } /** - * 主动播报特定文本 + * 业务侧通过无障碍通道主动播报自定义文本内容 */ void OhosAccessibilityBridge::Announce(std::unique_ptr& message) { - if (provider_ == nullptr) { - FML_DLOG(ERROR) << "announce ->" - "AccessibilityProvider = nullptr"; - return; - } - if (OH_GetSdkApiVersion() >= 13) { - // 创建并设置屏幕朗读事件 - ArkUI_AccessibilityEventInfo* (*OH_ArkUI_CreateAccessibilityEventInfo)(void) = - OhosAccessibilityDDL::DLLoadCreateEventInfoFunc("OH_ArkUI_CreateAccessibilityEventInfo"); - if (OH_ArkUI_CreateAccessibilityEventInfo == nullptr) { - LOGE("OH_ArkUI_CreateAccessibilityEventInfo is null, %{public}s", dlerror()); - } - ArkUI_AccessibilityEventInfo* announceEventInfo = OH_ArkUI_CreateAccessibilityEventInfo(); - - - int32_t (*OH_ArkUI_AccessibilityEventSetEventType)(ArkUI_AccessibilityEventInfo*, ArkUI_AccessibilityEventType) = - OhosAccessibilityDDL::DLLoadSetEventFunc("OH_ArkUI_AccessibilityEventSetEventType"); - if (OH_ArkUI_AccessibilityEventSetEventType == nullptr) { - LOGE("OH_ArkUI_AccessibilityEventSetEventType is null, %{public}s", dlerror()); - } - ARKUI_ACCESSIBILITY_CALL_CHECK( - OH_ArkUI_AccessibilityEventSetEventType( - announceEventInfo, - ArkUI_AccessibilityEventType::ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_ANNOUNCE_FOR_ACCESSIBILITY) - ); - - int32_t (*OH_ArkUI_AccessibilityEventSetTextAnnouncedForAccessibility)(ArkUI_AccessibilityEventInfo*, const char*) = - OhosAccessibilityDDL::DLLoadSetEventStringFunc("OH_ArkUI_AccessibilityEventSetTextAnnouncedForAccessibility"); - if (OH_ArkUI_AccessibilityEventSetTextAnnouncedForAccessibility == nullptr) { - LOGE("OH_ArkUI_AccessibilityEventSetTextAnnouncedForAccessibility is null, %{public}s", dlerror()); - } - ARKUI_ACCESSIBILITY_CALL_CHECK( - OH_ArkUI_AccessibilityEventSetTextAnnouncedForAccessibility( - announceEventInfo, message.get()) - ); - FML_DLOG(INFO) << ("announce -> message: ") << (message.get()); + if (!isAccessibilityEnabled_) { return; } + Flutter_SendAccessibilityAnnounceEvent( + message, ArkUI_AccessibilityEventType::ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_ANNOUNCE_FOR_ACCESSIBILITY); + LOGD("Announce -> message: %{public}s", message.get()); +} - auto callback = [](int32_t errorCode) { - FML_DLOG(WARNING) << "announce callback-> errorCode =" << errorCode; - }; +/** + * 业务侧通过无障碍通道主动点击给定id的组件节点 + */ +void OhosAccessibilityBridge::OnTap(int32_t nodeId) +{ + if (!isAccessibilityEnabled_) { return; } + Flutter_SendAccessibilityAsyncEvent(static_cast(nodeId), + ArkUI_AccessibilityEventType::ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_CLICKED); + LOGD("OnTap -> nodeId: %{public}d", nodeId); +} - void (*OH_ArkUI_SendAccessibilityAsyncEvent)(ArkUI_AccessibilityProvider*, ArkUI_AccessibilityEventInfo*, void (*callback)(int32_t)) = - OhosAccessibilityDDL::DLLoadSendAsyncEventFunc("OH_ArkUI_SendAccessibilityAsyncEvent"); - if (OH_ArkUI_SendAccessibilityAsyncEvent == nullptr) { - LOGE("OH_ArkUI_SendAccessibilityAsyncEvent is null, %{public}s", dlerror()); - } - OH_ArkUI_SendAccessibilityAsyncEvent(provider_, announceEventInfo, callback); +/** + * 业务侧通过无障碍通道主动长按给定id的组件节点 + */ +void OhosAccessibilityBridge::OnLongPress(int32_t nodeId) +{ + if (!isAccessibilityEnabled_) { return; } + Flutter_SendAccessibilityAsyncEvent(static_cast(nodeId), + ArkUI_AccessibilityEventType::ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_LONG_CLICKED); + LOGD("OnLongPress -> nodeId: %{public}d", nodeId); +} - void (*OH_ArkUI_DestoryAccessibilityEventInfo)(ArkUI_AccessibilityEventInfo*) = - OhosAccessibilityDDL::DLLoadDestroyEventFunc("OH_ArkUI_DestoryAccessibilityEventInfo"); - if (OH_ArkUI_DestoryAccessibilityEventInfo == nullptr) { - LOGE("OH_ArkUI_DestoryAccessibilityEventInfo is null, %{public}s", dlerror()); - } - OH_ArkUI_DestoryAccessibilityEventInfo(announceEventInfo); - announceEventInfo = nullptr; - } +/** + * 业务侧通过无障碍通道主动长按给定id的组件节点 + */ +void OhosAccessibilityBridge::OnTooltip(std::unique_ptr& message) +{ + if (!isAccessibilityEnabled_) { return; } + Flutter_SendAccessibilityAsyncEvent(static_cast(ROOT_NODE_ID), + ArkUI_AccessibilityEventType::ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_PAGE_STATE_UPDATE); + Flutter_SendAccessibilityAnnounceEvent( + message, ArkUI_AccessibilityEventType::ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_ANNOUNCE_FOR_ACCESSIBILITY); + LOGD("OnTooltip -> message: %{public}s", message.get()); } //获取根节点 -flutter::SemanticsNode OhosAccessibilityBridge::GetFlutterRootSemanticsNode() +SemanticsNodeExtent OhosAccessibilityBridge::GetFlutterRootSemanticsNode() { if (!g_flutterSemanticsTree.size()) { - FML_DLOG(ERROR) - << "GetFlutterRootSemanticsNode -> g_flutterSemanticsTree.size()=0"; + LOGE("GetFlutterRootSemanticsNode: g_flutterSemanticsTree.size()=0"); return {}; } if (g_flutterSemanticsTree.find(0) == g_flutterSemanticsTree.end()) { - FML_DLOG(ERROR) << "GetFlutterRootSemanticsNode -> g_flutterSemanticsTree " - "has no keys = 0"; + LOGE("GetFlutterRootSemanticsNod: g_flutterSemanticsTree has no root id"); return {}; } return g_flutterSemanticsTree.at(0); @@ -490,206 +429,27 @@ flutter::SemanticsNode OhosAccessibilityBridge::GetFlutterRootSemanticsNode() /** * 根据nodeid获取或创建flutter语义节点 */ -flutter::SemanticsNode OhosAccessibilityBridge::GetFlutterSemanticsNode( +SemanticsNodeExtent OhosAccessibilityBridge::GetFlutterSemanticsNode( int32_t id) { - flutter::SemanticsNode node; if (g_flutterSemanticsTree.count(id) > 0) { return g_flutterSemanticsTree.at(id); - FML_DLOG(INFO) << "GetFlutterSemanticsNode get node.id=" << id; } else { - FML_DLOG(ERROR) << "GetFlutterSemanticsNode g_flutterSemanticsTree = null" << id; + LOGE("GetFlutterSemanticsNode g_flutterSemanticsTree = null"); return {}; } } -/** - * flutter的语义节点初始化配置给arkui创建的elementInfos - */ -void OhosAccessibilityBridge::FlutterTreeToArkuiTree( - ArkUI_AccessibilityElementInfoList* elementInfoList) -{ - if (g_flutterSemanticsTree.size() == 0) { - FML_DLOG(ERROR) << "OhosAccessibilityBridge::FlutterTreeToArkuiTree " - "g_flutterSemanticsTree.size() = 0"; - return; - } - if (OH_GetSdkApiVersion() >= 13) { - // 将flutter语义节点树传递给arkui的无障碍elementinfo - for (const auto& item : g_flutterSemanticsTree) { - flutter::SemanticsNode flutterNode = item.second; - - // 创建elementinfo,系统自动加入到elementinfolist - ArkUI_AccessibilityElementInfo* (*OH_ArkUI_AddAndGetAccessibilityElementInfo)(ArkUI_AccessibilityElementInfoList*) = - OhosAccessibilityDDL::DLLoadGetElemFunc("OH_ArkUI_AddAndGetAccessibilityElementInfo"); - if (OH_ArkUI_AddAndGetAccessibilityElementInfo == nullptr) { - LOGE("OH_ArkUI_AddAndGetAccessibilityElementInfo is null, %{public}s", dlerror()); - } - ArkUI_AccessibilityElementInfo* elementInfo = - OH_ArkUI_AddAndGetAccessibilityElementInfo(elementInfoList); - if (elementInfo == nullptr) { - FML_DLOG(INFO) << "OhosAccessibilityBridge::FlutterTreeToArkuiTree " - "elementInfo is null"; - return; - } - // 设置elementinfo的屏幕坐标范围 - int32_t left = static_cast(flutterNode.rect.fLeft); - int32_t top = static_cast(flutterNode.rect.fTop); - int32_t right = static_cast(flutterNode.rect.fRight); - int32_t bottom = static_cast(flutterNode.rect.fBottom); - ArkUI_AccessibleRect rect = {left, top, right, bottom}; - - int32_t (*OH_ArkUI_AccessibilityElementInfoSetScreenRect)(ArkUI_AccessibilityElementInfo*, ArkUI_AccessibleRect*) = - OhosAccessibilityDDL::DLLoadSetElemSreenRectFunc("OH_ArkUI_AccessibilityElementInfoSetScreenRect"); - if (OH_ArkUI_AccessibilityElementInfoSetScreenRect == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetScreenRect is null, %{public}s", dlerror()); - } - ARKUI_ACCESSIBILITY_CALL_CHECK( - OH_ArkUI_AccessibilityElementInfoSetScreenRect(elementInfo, &rect) - ); - - // 设置elementinfo的action类型 - std::string widget_type = GetNodeComponentType(flutterNode); - FlutterSetElementInfoOperationActions(elementInfo, widget_type); - - // 设置elementid - int32_t (*OH_ArkUI_AccessibilityElementInfoSetElementId)(ArkUI_AccessibilityElementInfo*, int32_t) = - OhosAccessibilityDDL::DLLoadSetElemIntFunc("OH_ArkUI_AccessibilityElementInfoSetElementId"); - if (OH_ArkUI_AccessibilityElementInfoSetElementId == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetElementId is null, %{public}s", dlerror()); - } - ARKUI_ACCESSIBILITY_CALL_CHECK( - OH_ArkUI_AccessibilityElementInfoSetElementId(elementInfo, flutterNode.id) - ); - - // 设置父节点id - int32_t parentId = GetParentId(flutterNode.id); - int32_t (*OH_ArkUI_AccessibilityElementInfoSetParentId)(ArkUI_AccessibilityElementInfo*, int32_t) = - OhosAccessibilityDDL::DLLoadSetElemIntFunc("OH_ArkUI_AccessibilityElementInfoSetParentId"); - if (OH_ArkUI_AccessibilityElementInfoSetParentId == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetParentId is null, %{public}s", dlerror()); - } - if (flutterNode.id == 0) { - ARKUI_ACCESSIBILITY_CALL_CHECK( - OH_ArkUI_AccessibilityElementInfoSetParentId(elementInfo, ARKUI_ACCESSIBILITY_ROOT_PARENT_ID) - ); - } else { - ARKUI_ACCESSIBILITY_CALL_CHECK(OH_ArkUI_AccessibilityElementInfoSetParentId(elementInfo, parentId)); - } - - // 设置孩子节点 - 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(childrenIdsVec[i]); - FML_DLOG(INFO) << "FlutterTreeToArkuiTree flutterNode.id= " - << flutterNode.id << " childCount= " << childCount - << " childNodeId=" << childNodeIds[i]; - } - int32_t (*OH_ArkUI_AccessibilityElementInfoSetChildNodeIds)(ArkUI_AccessibilityElementInfo*, int32_t, int64_t*) = - OhosAccessibilityDDL::DLLoadSetElemChildFunc("OH_ArkUI_AccessibilityElementInfoSetChildNodeIds"); - if (OH_ArkUI_AccessibilityElementInfoSetChildNodeIds == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetChildNodeIds is null, %{public}s", dlerror()); - } - ARKUI_ACCESSIBILITY_CALL_CHECK( - OH_ArkUI_AccessibilityElementInfoSetChildNodeIds(elementInfo, childCount, childNodeIds) - ); - - // 配置常用属性 - int32_t (*OH_ArkUI_AccessibilityElementInfoSetEnabled)(ArkUI_AccessibilityElementInfo*, bool) = - OhosAccessibilityDDL::DLLoadSetElemBoolFunc("OH_ArkUI_AccessibilityElementInfoSetEnabled"); - if (OH_ArkUI_AccessibilityElementInfoSetEnabled == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetEnabled is null, %{public}s", dlerror()); - } - ARKUI_ACCESSIBILITY_CALL_CHECK(OH_ArkUI_AccessibilityElementInfoSetEnabled(elementInfo, true)); - - int32_t (*OH_ArkUI_AccessibilityElementInfoSetClickable)(ArkUI_AccessibilityElementInfo*, bool) = - OhosAccessibilityDDL::DLLoadSetElemBoolFunc("OH_ArkUI_AccessibilityElementInfoSetClickable"); - if (OH_ArkUI_AccessibilityElementInfoSetClickable == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetClickable is null, %{public}s", dlerror()); - } - ARKUI_ACCESSIBILITY_CALL_CHECK(OH_ArkUI_AccessibilityElementInfoSetClickable(elementInfo, true)); - int32_t (*OH_ArkUI_AccessibilityElementInfoSetCheckable)(ArkUI_AccessibilityElementInfo*, bool) = - OhosAccessibilityDDL::DLLoadSetElemBoolFunc("OH_ArkUI_AccessibilityElementInfoSetCheckable"); - if (OH_ArkUI_AccessibilityElementInfoSetCheckable == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetCheckable is null, %{public}s", dlerror()); - } - ARKUI_ACCESSIBILITY_CALL_CHECK(OH_ArkUI_AccessibilityElementInfoSetCheckable(elementInfo, true)); - - int32_t (*OH_ArkUI_AccessibilityElementInfoSetFocusable)(ArkUI_AccessibilityElementInfo*, bool) = - OhosAccessibilityDDL::DLLoadSetElemBoolFunc("OH_ArkUI_AccessibilityElementInfoSetFocusable"); - if (OH_ArkUI_AccessibilityElementInfoSetFocusable == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetFocusable is null, %{public}s", dlerror()); - } - ARKUI_ACCESSIBILITY_CALL_CHECK(OH_ArkUI_AccessibilityElementInfoSetFocusable(elementInfo, true)); - - int32_t (*OH_ArkUI_AccessibilityElementInfoSetVisible)(ArkUI_AccessibilityElementInfo*, bool) = - OhosAccessibilityDDL::DLLoadSetElemBoolFunc("OH_ArkUI_AccessibilityElementInfoSetVisible"); - if (OH_ArkUI_AccessibilityElementInfoSetVisible == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetVisible is null, %{public}s", dlerror()); - } - ARKUI_ACCESSIBILITY_CALL_CHECK(OH_ArkUI_AccessibilityElementInfoSetVisible(elementInfo, true)); - - // 设置组件类型 - std::string componentTypeName = GetNodeComponentType(flutterNode); - int32_t (*OH_ArkUI_AccessibilityElementInfoSetComponentType)(ArkUI_AccessibilityElementInfo*, const char*) = - OhosAccessibilityDDL::DLLoadSetElemStringFunc("OH_ArkUI_AccessibilityElementInfoSetComponentType"); - if (OH_ArkUI_AccessibilityElementInfoSetComponentType == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetComponentType is null, %{public}s", dlerror()); - } - ARKUI_ACCESSIBILITY_CALL_CHECK( - OH_ArkUI_AccessibilityElementInfoSetComponentType(elementInfo, componentTypeName.c_str()) - ); - - std::string contents = componentTypeName + "_content"; - int32_t (*OH_ArkUI_AccessibilityElementInfoSetContents)(ArkUI_AccessibilityElementInfo*, const char*) = - OhosAccessibilityDDL::DLLoadSetElemStringFunc("OH_ArkUI_AccessibilityElementInfoSetContents"); - if (OH_ArkUI_AccessibilityElementInfoSetContents == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetContents is null, %{public}s", dlerror()); - } - ARKUI_ACCESSIBILITY_CALL_CHECK( - OH_ArkUI_AccessibilityElementInfoSetContents(elementInfo, contents.c_str()) - ); - - // 设置无障碍相关属性 - int32_t (*OH_ArkUI_AccessibilityElementInfoSetAccessibilityText)(ArkUI_AccessibilityElementInfo*, const char*) = - OhosAccessibilityDDL::DLLoadSetElemStringFunc("OH_ArkUI_AccessibilityElementInfoSetAccessibilityText"); - if (OH_ArkUI_AccessibilityElementInfoSetAccessibilityText == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetAccessibilityText is null, %{public}s", dlerror()); - } - ARKUI_ACCESSIBILITY_CALL_CHECK( - OH_ArkUI_AccessibilityElementInfoSetAccessibilityText(elementInfo, flutterNode.label.c_str()) - ); - - int32_t (*OH_ArkUI_AccessibilityElementInfoSetAccessibilityLevel)(ArkUI_AccessibilityElementInfo*, const char*) = - OhosAccessibilityDDL::DLLoadSetElemStringFunc("OH_ArkUI_AccessibilityElementInfoSetAccessibilityLevel"); - if (OH_ArkUI_AccessibilityElementInfoSetAccessibilityLevel == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetAccessibilityLevel is null, %{public}s", dlerror()); - } - ARKUI_ACCESSIBILITY_CALL_CHECK(OH_ArkUI_AccessibilityElementInfoSetAccessibilityLevel(elementInfo, "yes")); - - int32_t (*OH_ArkUI_AccessibilityElementInfoSetAccessibilityGroup)(ArkUI_AccessibilityElementInfo*, bool) = - OhosAccessibilityDDL::DLLoadSetElemBoolFunc("OH_ArkUI_AccessibilityElementInfoSetAccessibilityGroup"); - if (OH_ArkUI_AccessibilityElementInfoSetAccessibilityGroup == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetAccessibilityGroup is null, %{public}s", dlerror()); - } - ARKUI_ACCESSIBILITY_CALL_CHECK(OH_ArkUI_AccessibilityElementInfoSetAccessibilityGroup(elementInfo, false)); - } - } -} - /** * 获取当前elementid的父节点id */ int32_t OhosAccessibilityBridge::GetParentId(int64_t elementId) { if (!g_parentChildIdVec.size()) { - FML_DLOG(INFO) << "OhosAccessibilityBridge::GetParentId parentChildIdMap.size()=0"; + FML_DLOG(WARNING) << "OhosAccessibilityBridge::GetParentId parentChildIdMap.size()=0"; return ARKUI_ACCESSIBILITY_ROOT_PARENT_ID; } - if (elementId == -1) { + if (elementId == -1 || elementId == 0) { return ARKUI_ACCESSIBILITY_ROOT_PARENT_ID; } int32_t childElementId = static_cast(elementId); @@ -704,292 +464,101 @@ int32_t OhosAccessibilityBridge::GetParentId(int64_t elementId) /** * 设置并获取xcomponet上渲染的组件的屏幕绝对坐标rect */ -void OhosAccessibilityBridge::SetAbsoluteScreenRect(int32_t flutterNodeId, +void OhosAccessibilityBridge::SetAbsoluteScreenRect(SemanticsNodeExtent& flutterNode, float left, float top, float right, float bottom) { - g_screenRectMap[flutterNodeId] = - std::make_pair(std::make_pair(left, top), std::make_pair(right, bottom)); - FML_DLOG(INFO) << "SetAbsoluteScreenRect -> insert { " << flutterNodeId - << ", <" << left << ", " << top << ", " << right << ", " - << bottom << "> } is succeed"; + g_screenRectMap[flutterNode.id] = AbsoluteRect{left, top, right, bottom}; + FML_DLOG(INFO) << "SetAbsoluteScreenRect -> id=" << flutterNode.id + << ", {" << left << ", " << top << ", " << right << ", "<< bottom << "> }"; } -std::pair, std::pair> -OhosAccessibilityBridge::GetAbsoluteScreenRect(int32_t flutterNodeId) +AbsoluteRect OhosAccessibilityBridge::GetAbsoluteScreenRect(SemanticsNodeExtent& flutterNode) { - if (!g_screenRectMap.empty() && g_screenRectMap.count(flutterNodeId) > 0) { - return g_screenRectMap.at(flutterNodeId); + if (!g_screenRectMap.empty() && g_screenRectMap.count(flutterNode.id) > 0) { + return g_screenRectMap.at(flutterNode.id); } else { FML_DLOG(ERROR) << "GetAbsoluteScreenRect -> flutterNodeId=" - << flutterNodeId << " is not found !"; + << flutterNode.id << " is not found !"; return {}; } } /** - * flutter无障碍语义树的子节点相对坐标系转化为屏幕绝对坐标的映射算法 - * 目前暂未考虑旋转、透视场景,不影响屏幕朗读功能 + * 获取flutter相对-绝对坐标映射的真实缩放系数 */ -void OhosAccessibilityBridge::ConvertChildRelativeRectToScreenRect( - flutter::SemanticsNode currNode) -{ - // 获取当前flutter节点的相对rect - auto currLeft = static_cast(currNode.rect.fLeft); - auto currTop = static_cast(currNode.rect.fTop); - auto currRight = static_cast(currNode.rect.fRight); - auto currBottom = static_cast(currNode.rect.fBottom); - - // 获取当前flutter节点的缩放、平移、透视等矩阵坐标转换 - SkMatrix transform = currNode.transform.asM33(); - auto _kMScaleX = transform.get(SkMatrix::kMScaleX); - auto _kMTransX = transform.get(SkMatrix::kMTransX); - auto _kMScaleY = transform.get(SkMatrix::kMScaleY); - auto _kMTransY = transform.get(SkMatrix::kMTransY); - /** 以下矩阵坐标变换参数(如:旋转/错切、透视)场景目前暂不考虑 - * NOTE: SkMatrix::kMSkewX, SkMatrix::kMSkewY, - * SkMatrix::kMPersp0, SkMatrix::kMPersp1, SkMatrix::kMPersp2 - */ - - // 获取当前flutter节点的父节点的相对rect - int32_t parentId = GetParentId(currNode.id); - auto parentNode = GetFlutterSemanticsNode(parentId); - auto parentRight = parentNode.rect.fRight; - auto parentBottom = parentNode.rect.fBottom; - - // 获取当前flutter节点的父节点的绝对坐标 - auto _rectPairs = GetAbsoluteScreenRect(parentNode.id); - auto realParentLeft = _rectPairs.first.first; - auto realParentTop = _rectPairs.first.second; - auto realParentRight = _rectPairs.second.first; - auto realParentBottom = _rectPairs.second.second; - - // 获取root节点的绝对坐标, 即xcomponent屏幕长宽 - auto _rootRect = GetAbsoluteScreenRect(0); - auto rootHeight = _rootRect.second.second; - - // 真实缩放系数 - float realScaleFactor = realParentRight / parentRight * 1.0; - float newLeft; - float newTop; - float newRight; - float newBottom; - - if (_kMScaleX > 1 && _kMScaleY > 1) { - // 子节点相对父节点进行变化(缩放、 平移) - newLeft = currLeft + _kMTransX * _kMScaleX; - newTop = currTop + _kMTransY * _kMScaleY; - newRight = currRight * _kMScaleX; - newBottom = currBottom * _kMScaleY; - // 更新当前flutter节点currNode的相对坐标 -> 屏幕绝对坐标 - SetAbsoluteScreenRect(currNode.id, newLeft, newTop, newRight, newBottom); - } else { - // 若当前节点的相对坐标与父亲节点的相对坐标值相同,则直接继承坐标值 - if (currRight == parentRight && currBottom == parentBottom) { - newLeft = realParentLeft; - newTop = realParentTop; - newRight = realParentRight; - newBottom = realParentBottom; - } else { - // 子节点的屏幕绝对坐标转换,包括offset偏移值计算、缩放系数变换 - newLeft = (currLeft + _kMTransX) * realScaleFactor + realParentLeft; - newTop = (currTop + _kMTransY) * realScaleFactor + realParentTop; - newRight = (currLeft + _kMTransX + currRight) * realScaleFactor + realParentLeft; - newBottom = (currTop + _kMTransY + currBottom) * realScaleFactor + realParentTop; - } - // 若子节点rect超过父节点则跳过显示(单个屏幕显示不下,滑动再重新显示) - 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 - << ", " << newRight << ", " << newBottom << ")}"; - // 防止滑动场景下绿框坐标超出屏幕范围,进行正则化处理 - newTop -= rootHeight; - newBottom -= rootHeight; - SetAbsoluteScreenRect(currNode.id, newLeft, newTop, newRight, newBottom); - } else { - SetAbsoluteScreenRect(currNode.id, newLeft, newTop, newRight, newBottom); - } - } - FML_DLOG(INFO) << "ConvertChildRelativeRectToScreenRect -> { nodeId: " - << currNode.id << ", (" << newLeft << ", " << newTop << ", " - << newRight << ", " << newBottom << ")}"; +std::pair OhosAccessibilityBridge::GetRealScaleFactor() +{ + auto secondNode = GetFlutterSemanticsNode(1); + SkMatrix transform = secondNode.transform.asM33(); + auto scaleX = transform.get(SkMatrix::kMScaleX); + auto scaleY = transform.get(SkMatrix::kMScaleY); + return std::make_pair(scaleX, scaleY); } /** - * 实现对特定id的flutter节点到arkui的elementinfo节点转化 + * calculate the global transform matrix for each node */ -void OhosAccessibilityBridge::FlutterNodeToElementInfoById( - ArkUI_AccessibilityElementInfo* elementInfoFromList, - int64_t elementId) +void OhosAccessibilityBridge::ComputeGlobalTransform() { - if (elementInfoFromList == nullptr) { - FML_DLOG(INFO) << "OhosAccessibilityBridge::FlutterNodeToElementInfoById " - "elementInfoFromList is null"; - return; - } - FML_DLOG(INFO) << "FlutterNodeToElementInfoById elementId = " << elementId; - - if (OH_GetSdkApiVersion() >= 13) { - // 当elementId = -1或0时,创建root节点 - if (elementId == 0 || elementId == -1) { - // 获取flutter的root节点 - flutter::SemanticsNode flutterNode = GetFlutterSemanticsNode(static_cast(0)); - - // 设置elementinfo的屏幕坐标范围 - int32_t left = static_cast(flutterNode.rect.fLeft); - int32_t top = static_cast(flutterNode.rect.fTop); - int32_t right = static_cast(flutterNode.rect.fRight); - int32_t bottom = static_cast(flutterNode.rect.fBottom); - ArkUI_AccessibleRect rect = {left, top, right, bottom}; - int32_t (*OH_ArkUI_AccessibilityElementInfoSetScreenRect)(ArkUI_AccessibilityElementInfo*, ArkUI_AccessibleRect*) = - OhosAccessibilityDDL::DLLoadSetElemSreenRectFunc("OH_ArkUI_AccessibilityElementInfoSetScreenRect"); - if (OH_ArkUI_AccessibilityElementInfoSetScreenRect == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetScreenRect is null, %{public}s", dlerror()); - } - ARKUI_ACCESSIBILITY_CALL_CHECK( - OH_ArkUI_AccessibilityElementInfoSetScreenRect(elementInfoFromList, &rect) - ); - - // 设置root节点的屏幕绝对坐标rect - SetAbsoluteScreenRect(0, left, top, right, bottom); - - // 设置elementinfo的action类型 - std::string widget_type = "root"; - FlutterSetElementInfoOperationActions(elementInfoFromList, widget_type); - - // 根据flutternode信息配置对应的elementinfo - int32_t (*OH_ArkUI_AccessibilityElementInfoSetElementId)(ArkUI_AccessibilityElementInfo*, int32_t) = - OhosAccessibilityDDL::DLLoadSetElemIntFunc("OH_ArkUI_AccessibilityElementInfoSetElementId"); - if (OH_ArkUI_AccessibilityElementInfoSetElementId == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetElementId is null, %{public}s", dlerror()); - } - ARKUI_ACCESSIBILITY_CALL_CHECK(OH_ArkUI_AccessibilityElementInfoSetElementId(elementInfoFromList, 0)); - - // NOTE: arkui无障碍子系统强制设置root的父节点id = -2100000 (严禁更改) - int32_t (*OH_ArkUI_AccessibilityElementInfoSetParentId)(ArkUI_AccessibilityElementInfo*, int32_t) = - OhosAccessibilityDDL::DLLoadSetElemIntFunc("OH_ArkUI_AccessibilityElementInfoSetParentId"); - if (OH_ArkUI_AccessibilityElementInfoSetParentId == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetParentId is null, %{public}s", dlerror()); - } - ARKUI_ACCESSIBILITY_CALL_CHECK( - OH_ArkUI_AccessibilityElementInfoSetParentId(elementInfoFromList, ARKUI_ACCESSIBILITY_ROOT_PARENT_ID) - ); - - // 设置无障碍播报文本 - int32_t (*OH_ArkUI_AccessibilityElementInfoSetAccessibilityText)(ArkUI_AccessibilityElementInfo*, const char*) = - OhosAccessibilityDDL::DLLoadSetElemStringFunc("OH_ArkUI_AccessibilityElementInfoSetAccessibilityText"); - if (OH_ArkUI_AccessibilityElementInfoSetAccessibilityText == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetAccessibilityText is null, %{public}s", dlerror()); - } - ARKUI_ACCESSIBILITY_CALL_CHECK( - OH_ArkUI_AccessibilityElementInfoSetAccessibilityText( - elementInfoFromList, flutterNode.label.empty() ? flutterNode.hint.c_str() : flutterNode.label.c_str()) - ); - - int32_t (*OH_ArkUI_AccessibilityElementInfoSetAccessibilityLevel)(ArkUI_AccessibilityElementInfo*, const char*) = - OhosAccessibilityDDL::DLLoadSetElemStringFunc("OH_ArkUI_AccessibilityElementInfoSetAccessibilityLevel"); - if (OH_ArkUI_AccessibilityElementInfoSetAccessibilityLevel == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetAccessibilityLevel is null, %{public}s", dlerror()); - } - ARKUI_ACCESSIBILITY_CALL_CHECK( - OH_ArkUI_AccessibilityElementInfoSetAccessibilityLevel(elementInfoFromList, "yes") - ); - - int32_t (*OH_ArkUI_AccessibilityElementInfoSetAccessibilityGroup)(ArkUI_AccessibilityElementInfo*, bool) = - OhosAccessibilityDDL::DLLoadSetElemBoolFunc("OH_ArkUI_AccessibilityElementInfoSetAccessibilityGroup"); - if (OH_ArkUI_AccessibilityElementInfoSetAccessibilityGroup == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetAccessibilityGroup is null, %{public}s", dlerror()); - } - ARKUI_ACCESSIBILITY_CALL_CHECK( - OH_ArkUI_AccessibilityElementInfoSetAccessibilityGroup(elementInfoFromList, false) - ); - - // 配置child节点信息 - 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(childrenIdsVec[i]); - FML_DLOG(INFO) - << "FlutterNodeToElementInfoById -> elementid=0 childCount=" - << childCount << " childNodeIds=" << childNodeIds[i]; - } - int32_t (*OH_ArkUI_AccessibilityElementInfoSetChildNodeIds)(ArkUI_AccessibilityElementInfo*, int32_t, int64_t*) = - OhosAccessibilityDDL::DLLoadSetElemChildFunc("OH_ArkUI_AccessibilityElementInfoSetChildNodeIds"); - if (OH_ArkUI_AccessibilityElementInfoSetChildNodeIds == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetChildNodeIds is null, %{public}s", dlerror()); - } - ARKUI_ACCESSIBILITY_CALL_CHECK( - OH_ArkUI_AccessibilityElementInfoSetChildNodeIds(elementInfoFromList, childCount, childNodeIds) - ); - - // 配置root节点常用属性 - int32_t (*OH_ArkUI_AccessibilityElementInfoSetEnabled)(ArkUI_AccessibilityElementInfo*, bool) = - OhosAccessibilityDDL::DLLoadSetElemBoolFunc("OH_ArkUI_AccessibilityElementInfoSetEnabled"); - if (OH_ArkUI_AccessibilityElementInfoSetEnabled == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetEnabled is null, %{public}s", dlerror()); - } - ARKUI_ACCESSIBILITY_CALL_CHECK(OH_ArkUI_AccessibilityElementInfoSetEnabled(elementInfoFromList, true)); + std::queue semanticsQue; - int32_t (*OH_ArkUI_AccessibilityElementInfoSetClickable)(ArkUI_AccessibilityElementInfo*, bool) = - OhosAccessibilityDDL::DLLoadSetElemBoolFunc("OH_ArkUI_AccessibilityElementInfoSetClickable"); - if (OH_ArkUI_AccessibilityElementInfoSetClickable == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetClickable is null, %{public}s", dlerror()); - } - ARKUI_ACCESSIBILITY_CALL_CHECK(OH_ArkUI_AccessibilityElementInfoSetClickable(elementInfoFromList, true)); - - int32_t (*OH_ArkUI_AccessibilityElementInfoSetFocusable)(ArkUI_AccessibilityElementInfo*, bool) = - OhosAccessibilityDDL::DLLoadSetElemBoolFunc("OH_ArkUI_AccessibilityElementInfoSetFocusable"); - if (OH_ArkUI_AccessibilityElementInfoSetFocusable == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetFocusable is null, %{public}s", dlerror()); - } - ARKUI_ACCESSIBILITY_CALL_CHECK(OH_ArkUI_AccessibilityElementInfoSetFocusable(elementInfoFromList, true)); - - int32_t (*OH_ArkUI_AccessibilityElementInfoSetVisible)(ArkUI_AccessibilityElementInfo*, bool) = - OhosAccessibilityDDL::DLLoadSetElemBoolFunc("OH_ArkUI_AccessibilityElementInfoSetVisible"); - if (OH_ArkUI_AccessibilityElementInfoSetVisible == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetVisible is null, %{public}s", dlerror()); - } - ARKUI_ACCESSIBILITY_CALL_CHECK(OH_ArkUI_AccessibilityElementInfoSetVisible(elementInfoFromList, true)); + auto root = GetFlutterSemanticsNode(0); + semanticsQue.push(root); + g_globalTransformMap[root.id] = root.transform; - int32_t (*OH_ArkUI_AccessibilityElementInfoSetComponentType)(ArkUI_AccessibilityElementInfo*, const char*) = - OhosAccessibilityDDL::DLLoadSetElemStringFunc("OH_ArkUI_AccessibilityElementInfoSetComponentType"); - if (OH_ArkUI_AccessibilityElementInfoSetComponentType == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetComponentType is null, %{public}s", dlerror()); - } - ARKUI_ACCESSIBILITY_CALL_CHECK(OH_ArkUI_AccessibilityElementInfoSetComponentType(elementInfoFromList, "root")); + while (!semanticsQue.empty()) { + uint32_t queSize = semanticsQue.size(); + for (uint32_t i=0; i= 1时,根据flutter节点信息配置elementinfo无障碍属性 - FlutterSetElementInfoProperties(elementInfoFromList, elementId); - } + for (const auto& childId: currNode.childrenInTraversalOrder) { + auto childNode = GetFlutterSemanticsNode(childId); + semanticsQue.push(childNode); + g_globalTransformMap[childId] = g_globalTransformMap[currNode.id] * childNode.transform; + } } - FML_DLOG(INFO) << "=== OhosAccessibilityBridge::FlutterNodeToElementInfoById is end ==="; + } +} + +SkPoint OhosAccessibilityBridge::ApplyTransform( + SkPoint& point, const SkM44& transform) { + SkV4 vector = transform.map(point.x(), point.y(), 0, 1); + return SkPoint::Make(vector.x / vector.w, vector.y / vector.w); } /** - * 判断源字符串是否包含目标字符串 + * convert local(relative) rect to global(absolut) rect + * @param node flutter semantics node */ -bool OhosAccessibilityBridge::Contains(const std::string source, - const std::string target) +void OhosAccessibilityBridge::RelativeRectToScreenRect(SemanticsNodeExtent& node) { - return source.find(target) != std::string::npos; + auto [left, top, right, bottom] = node.rect; + SkM44 globalTransform = g_globalTransformMap[node.id]; + + SkPoint points[4] = { + SkPoint::Make(left, top), // top-left point + SkPoint::Make(right, top), // top-right point + SkPoint::Make(right, bottom), // bottom-right point + SkPoint::Make(left, bottom) // bottom-left point + }; + + for (auto& point : points) { + point = ApplyTransform(point, globalTransform); + } + + SkRect globalRect; + bool checkResult = globalRect.setBoundsCheck(points, 4); + if (!checkResult) { + FML_DLOG(WARNING) << "RelativeRectToScreenRect -> Transformed points can't make a rect "; + } + globalRect.setBounds(points, 4); + + SetAbsoluteScreenRect(node, globalRect.left(), globalRect.top(), + globalRect.right(), globalRect.bottom()); } /** @@ -999,432 +568,372 @@ void OhosAccessibilityBridge::FlutterSetElementInfoOperationActions( ArkUI_AccessibilityElementInfo* elementInfoFromList, std::string widget_type) { - if (OH_GetSdkApiVersion() >= 13) { - int32_t (*OH_ArkUI_AccessibilityElementInfoSetOperationActions)(ArkUI_AccessibilityElementInfo*, int32_t, ArkUI_AccessibleAction*) = - OhosAccessibilityDDL::DLLoadSetElemOperActionsFunc("OH_ArkUI_AccessibilityElementInfoSetOperationActions"); - if (OH_ArkUI_AccessibilityElementInfoSetOperationActions == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetOperationActions is null, %{public}s", dlerror()); - } - if (widget_type == "textfield") { - // set elementinfo action types - int32_t actionTypeNum = 10; - ArkUI_AccessibleAction actions[actionTypeNum]; - - actions[0].actionType = ArkUI_Accessibility_ActionType:: - ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_GAIN_ACCESSIBILITY_FOCUS; - actions[0].description = "获取焦点"; - - actions[1].actionType = ArkUI_Accessibility_ActionType:: - ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_CLEAR_ACCESSIBILITY_FOCUS; - actions[1].description = "清除焦点"; - - actions[2].actionType = ArkUI_Accessibility_ActionType:: - ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_CLICK; - actions[2].description = "点击操作"; - - actions[3].actionType = ArkUI_Accessibility_ActionType:: - ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_LONG_CLICK; - actions[3].description = "长按操作"; - - actions[4].actionType = ArkUI_Accessibility_ActionType:: - ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_COPY; - actions[4].description = "文本复制"; - - actions[5].actionType = ArkUI_Accessibility_ActionType:: - ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_PASTE; - actions[5].description = "文本粘贴"; - - actions[6].actionType = ArkUI_Accessibility_ActionType:: - ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_CUT; - actions[6].description = "文本剪切"; - - actions[7].actionType = ArkUI_Accessibility_ActionType:: - ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SELECT_TEXT; - actions[7].description = "文本选择"; - - actions[8].actionType = ArkUI_Accessibility_ActionType:: - ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SET_TEXT; - actions[8].description = "文本内容设置"; - - actions[9].actionType = ArkUI_Accessibility_ActionType:: - ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SET_CURSOR_POSITION; - actions[9].description = "光标位置设置"; - - 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; - ArkUI_AccessibleAction actions[actionTypeNum]; - - actions[0].actionType = ArkUI_Accessibility_ActionType:: - ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_GAIN_ACCESSIBILITY_FOCUS; - actions[0].description = "获取焦点"; - - actions[1].actionType = ArkUI_Accessibility_ActionType:: - ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_CLEAR_ACCESSIBILITY_FOCUS; - actions[1].description = "清除焦点"; - - actions[2].actionType = ArkUI_Accessibility_ActionType:: - ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_CLICK; - actions[2].description = "点击动作"; - - actions[3].actionType = ArkUI_Accessibility_ActionType:: - ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SCROLL_FORWARD; - actions[3].description = "向上滑动"; - - actions[4].actionType = ArkUI_Accessibility_ActionType:: - ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SCROLL_BACKWARD; - actions[4].description = "向下滑动"; - - ARKUI_ACCESSIBILITY_CALL_CHECK( - OH_ArkUI_AccessibilityElementInfoSetOperationActions(elementInfoFromList, actionTypeNum, actions) - ); - } else { - // set common component action types - int32_t actionTypeNum = 3; - ArkUI_AccessibleAction actions[actionTypeNum]; - - actions[0].actionType = ArkUI_Accessibility_ActionType:: - ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_GAIN_ACCESSIBILITY_FOCUS; - actions[0].description = "获取焦点"; + if (OHOS_API_VERSION < 13) { return; } + auto OH_ArkUI_AccessibilityElementInfoSetOperationActions = + OhosAccessibilityDDL::DLLoadSetElemOperActionsFunc(ArkUIAccessibilityConstant::ARKUI_SET_ACTIONS); + CHECK_DLL_NULL_PTR(OH_ArkUI_AccessibilityElementInfoSetOperationActions); + if (OHOSUtils::Contains(widget_type, EDIT_TEXT_WIDGET_NAME) || + OHOSUtils::Contains(widget_type, EDIT_MULTILINE_TEXT_WIDGET_NAME)) { + // set elementinfo action types + int32_t actionTypeNum = 10; + ArkUI_AccessibleAction actions[actionTypeNum]; + int32_t idx = 0; + actions[idx].actionType = ArkUI_Accessibility_ActionType:: + ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_GAIN_ACCESSIBILITY_FOCUS; + actions[idx++].description = "获取焦点"; + actions[idx].actionType = ArkUI_Accessibility_ActionType:: + ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_CLEAR_ACCESSIBILITY_FOCUS; + actions[idx++].description = "清除焦点"; + actions[idx].actionType = ArkUI_Accessibility_ActionType:: + ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_CLICK; + actions[idx++].description = "点击操作"; + actions[idx].actionType = ArkUI_Accessibility_ActionType:: + ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_LONG_CLICK; + actions[idx++].description = "长按操作"; + actions[idx].actionType = ArkUI_Accessibility_ActionType:: + ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_COPY; + actions[idx++].description = "文本复制"; + actions[idx].actionType = ArkUI_Accessibility_ActionType:: + ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_PASTE; + actions[idx++].description = "文本粘贴"; + actions[idx].actionType = ArkUI_Accessibility_ActionType:: + ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_CUT; + actions[idx++].description = "文本剪切"; + actions[idx].actionType = ArkUI_Accessibility_ActionType:: + ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SELECT_TEXT; + actions[idx++].description = "文本选择"; + actions[idx].actionType = ArkUI_Accessibility_ActionType:: + ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SET_TEXT; + actions[idx++].description = "文本内容设置"; + actions[idx].actionType = ArkUI_Accessibility_ActionType:: + ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SET_CURSOR_POSITION; + actions[idx].description = "光标位置设置"; - actions[1].actionType = ArkUI_Accessibility_ActionType:: - ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_CLEAR_ACCESSIBILITY_FOCUS; - actions[1].description = "清除焦点"; + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetOperationActions(elementInfoFromList, actionTypeNum, actions) + ); + } else if (OHOSUtils::Contains(widget_type, SCROLL_WIDGET_NAME)) { + // if node is a scrollable component + int32_t actionTypeNum = 5; + ArkUI_AccessibleAction actions[actionTypeNum]; + int32_t idx = 0; + actions[idx].actionType = ArkUI_Accessibility_ActionType:: + ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_GAIN_ACCESSIBILITY_FOCUS; + actions[idx++].description = "获取焦点"; + actions[idx].actionType = ArkUI_Accessibility_ActionType:: + ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_CLEAR_ACCESSIBILITY_FOCUS; + actions[idx++].description = "清除焦点"; + actions[idx].actionType = ArkUI_Accessibility_ActionType:: + ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_CLICK; + actions[idx++].description = "点击动作"; + actions[idx].actionType = ArkUI_Accessibility_ActionType:: + ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SCROLL_FORWARD; + actions[idx++].description = "向上滑动"; + actions[idx].actionType = ArkUI_Accessibility_ActionType:: + ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SCROLL_BACKWARD; + actions[idx].description = "向下滑动"; - actions[2].actionType = ArkUI_Accessibility_ActionType:: - ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_CLICK; - actions[2].description = "点击动作"; + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetOperationActions(elementInfoFromList, actionTypeNum, actions) + ); + } else { + // set common component action types + int32_t actionTypeNum = 3; + ArkUI_AccessibleAction actions[actionTypeNum]; + int32_t idx = 0; + actions[idx].actionType = ArkUI_Accessibility_ActionType:: + ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_GAIN_ACCESSIBILITY_FOCUS; + actions[idx++].description = "获取焦点"; + actions[idx].actionType = ArkUI_Accessibility_ActionType:: + ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_CLEAR_ACCESSIBILITY_FOCUS; + actions[idx++].description = "清除焦点"; + actions[idx].actionType = ArkUI_Accessibility_ActionType:: + ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_CLICK; + actions[idx].description = "点击动作"; - ARKUI_ACCESSIBILITY_CALL_CHECK( - OH_ArkUI_AccessibilityElementInfoSetOperationActions(elementInfoFromList, actionTypeNum, actions) - ); - } + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetOperationActions(elementInfoFromList, actionTypeNum, actions) + ); } } /** + * 实现对特定id的flutter节点到arkui的elementinfo节点转化, * 根据flutter节点信息配置elementinfo无障碍属性 */ void OhosAccessibilityBridge::FlutterSetElementInfoProperties( ArkUI_AccessibilityElementInfo* elementInfoFromList, int64_t elementId) { - if (OH_GetSdkApiVersion() >= 13) { - flutter::SemanticsNode flutterNode = GetFlutterSemanticsNode(static_cast(elementId)); - - // set elementinfo id - int32_t (*OH_ArkUI_AccessibilityElementInfoSetElementId)(ArkUI_AccessibilityElementInfo*, int32_t) = - OhosAccessibilityDDL::DLLoadSetElemIntFunc("OH_ArkUI_AccessibilityElementInfoSetElementId"); - if (OH_ArkUI_AccessibilityElementInfoSetElementId == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetElementId is null, %{public}s", dlerror()); + if (OHOS_API_VERSION < 13) { return; } + auto flutterNode = GetFlutterSemanticsNode(static_cast(elementId > 0 ? elementId : 0)); + if (!g_flutterSemanticsTree.count(flutterNode.id)) { + LOGE("FlutterSetElementInfoProperties: GetFlutterSemanticsNode id=%{public}ld null", elementId); + } + + // 设置当前节点id + auto OH_ArkUI_AccessibilityElementInfoSetElementId = + OhosAccessibilityDDL::DLLoadSetElemIntFunc(ArkUIAccessibilityConstant::ARKUI_SET_NODE_ID); + CHECK_DLL_NULL_PTR(OH_ArkUI_AccessibilityElementInfoSetElementId); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetElementId(elementInfoFromList, flutterNode.id) + ); + + // 相对-绝对坐标映射 + ArkUI_AccessibleRect rect; + if (elementId < 1) { // 若当前节点为root + int32_t left = flutterNode.rect.fLeft; + int32_t top = flutterNode.rect.fTop; + int32_t right = flutterNode.rect.fRight; + int32_t bottom = flutterNode.rect.fBottom; + SetAbsoluteScreenRect(flutterNode, left, top, right, bottom); + rect = {static_cast(left), static_cast(top), + static_cast(right), static_cast(bottom)}; + } else { // 若当前节点为id >= 1的节点 + RelativeRectToScreenRect(flutterNode); + auto [left, top, right, bottom] = GetAbsoluteScreenRect(flutterNode); + rect = {static_cast(left), static_cast(top), + static_cast(right), static_cast(bottom)}; + } + auto OH_ArkUI_AccessibilityElementInfoSetScreenRect = + OhosAccessibilityDDL::DLLoadSetElemSreenRectFunc(ArkUIAccessibilityConstant::ARKUI_SET_SCREEN_RECT); + CHECK_DLL_NULL_PTR(OH_ArkUI_AccessibilityElementInfoSetScreenRect); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetScreenRect(elementInfoFromList, &rect) + ); + + // 配置arkui的elementinfo可操作动作属性 + // 设置root节点的action类型 + std::string widgeType = GetNodeComponentType(flutterNode); + if (elementId < 1) { + FlutterSetElementInfoOperationActions(elementInfoFromList, OTHER_WIDGET_NAME); + } else { + FlutterSetElementInfoOperationActions(elementInfoFromList, widgeType); + } + + // 设置当前节点的父节点id + int32_t parentId = GetParentId(elementId); + auto OH_ArkUI_AccessibilityElementInfoSetParentId = + OhosAccessibilityDDL::DLLoadSetElemIntFunc(ArkUIAccessibilityConstant::ARKUI_SET_PARENT_ID); + CHECK_DLL_NULL_PTR(OH_ArkUI_AccessibilityElementInfoSetParentId); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetParentId(elementInfoFromList, parentId) + ); + FML_DLOG(INFO) << "FlutterSetElementInfoProperties GetParentId = " << parentId; + + // 设置可朗读文本 + std::string text = flutterNode.label + flutterNode.value; + auto OH_ArkUI_AccessibilityElementInfoSetAccessibilityText = + OhosAccessibilityDDL::DLLoadSetElemStringFunc(ArkUIAccessibilityConstant::ARKUI_SET_A11Y_TEXT); + CHECK_DLL_NULL_PTR(OH_ArkUI_AccessibilityElementInfoSetAccessibilityText); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetAccessibilityText(elementInfoFromList, text.c_str()) + ); + FML_DLOG(INFO) << "FlutterSetElementInfoProperties SetAccessibilityText = " << text; + + // 设置无障碍content文本 + auto OH_ArkUI_AccessibilityElementInfoSetContents = + OhosAccessibilityDDL::DLLoadSetElemStringFunc(ArkUIAccessibilityConstant::ARKUI_SET_CONTENTS); + CHECK_DLL_NULL_PTR(OH_ArkUI_AccessibilityElementInfoSetContents); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetContents(elementInfoFromList, text.c_str()) + ); + // 设置hint提示文本 + std::string hint = flutterNode.hint; + auto OH_ArkUI_AccessibilityElementInfoSetHintText = + OhosAccessibilityDDL::DLLoadSetElemStringFunc(ArkUIAccessibilityConstant::ARKUI_SET_HINT); + CHECK_DLL_NULL_PTR(OH_ArkUI_AccessibilityElementInfoSetHintText); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetHintText(elementInfoFromList, hint.c_str()) + ); + + // 设置当前节点的全部孩子节点 + int32_t childCount = flutterNode.childrenInTraversalOrder.size(); + if (childCount > 0) { + auto childrenIdsVec = flutterNode.childrenInTraversalOrder; + std::sort(childrenIdsVec.begin(), childrenIdsVec.end()); + int64_t childNodeIds[childCount]; + for (int32_t i = 0; i < childCount; i++) { + childNodeIds[i] = static_cast(childrenIdsVec[i]); + FML_DLOG(INFO) << "FlutterSetElementInfoProperties -> elementid=" << elementId + << " childCount=" << childCount + << " childNodeIds=" << childNodeIds[i]; } + auto OH_ArkUI_AccessibilityElementInfoSetChildNodeIds = + OhosAccessibilityDDL::DLLoadSetElemChildFunc(ArkUIAccessibilityConstant::ARKUI_SET_CHILD_IDS); + CHECK_DLL_NULL_PTR(OH_ArkUI_AccessibilityElementInfoSetChildNodeIds); ARKUI_ACCESSIBILITY_CALL_CHECK( - OH_ArkUI_AccessibilityElementInfoSetElementId(elementInfoFromList, flutterNode.id) + OH_ArkUI_AccessibilityElementInfoSetChildNodeIds(elementInfoFromList, childCount, childNodeIds) ); + } - // convert relative rect to absolute rect - ConvertChildRelativeRectToScreenRect(flutterNode); - auto rectPairs = GetAbsoluteScreenRect(flutterNode.id); - // set screen rect in xcomponent - int32_t left = rectPairs.first.first; - int32_t top = rectPairs.first.second; - int32_t right = rectPairs.second.first; - int32_t bottom = rectPairs.second.second; - ArkUI_AccessibleRect rect = {left, top, right, bottom}; - int32_t (*OH_ArkUI_AccessibilityElementInfoSetScreenRect)(ArkUI_AccessibilityElementInfo*, ArkUI_AccessibleRect*) = - OhosAccessibilityDDL::DLLoadSetElemSreenRectFunc("OH_ArkUI_AccessibilityElementInfoSetScreenRect"); - if (OH_ArkUI_AccessibilityElementInfoSetScreenRect == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetScreenRect is null, %{public}s", dlerror()); - } + // 判断当前节点组件是否enabled + if (IsNodeEnabled(flutterNode)) { + auto OH_ArkUI_AccessibilityElementInfoSetEnabled = + OhosAccessibilityDDL::DLLoadSetElemBoolFunc(ArkUIAccessibilityConstant::ARKUI_SET_ENABLED); + CHECK_DLL_NULL_PTR(OH_ArkUI_AccessibilityElementInfoSetEnabled); ARKUI_ACCESSIBILITY_CALL_CHECK( - OH_ArkUI_AccessibilityElementInfoSetScreenRect(elementInfoFromList, &rect) + OH_ArkUI_AccessibilityElementInfoSetEnabled(elementInfoFromList, true) ); - FML_DLOG(INFO) << "FlutterNodeToElementInfoById -> node.id= " - << flutterNode.id << " SceenRect = (" << left << ", " << top - << ", " << right << ", " << bottom << ")"; - - // 配置arkui的elementinfo可操作动作属性 - if (IsTextField(flutterNode)) { - // 若当前flutter节点为文本输入框组件 - std::string widget_type = "textfield"; - FlutterSetElementInfoOperationActions(elementInfoFromList, widget_type); - } else if (IsScrollableWidget(flutterNode) || IsNodeScrollable(flutterNode)) { - // 若当前flutter节点为可滑动组件类型 - std::string widget_type = "scrollable"; - FlutterSetElementInfoOperationActions(elementInfoFromList, widget_type); - } else { - // 若当前flutter节点为通用组件 - std::string widget_type = "common"; - FlutterSetElementInfoOperationActions(elementInfoFromList, widget_type); - } - - // set current elementinfo parent id - int32_t parentId = GetParentId(elementId); - int32_t (*OH_ArkUI_AccessibilityElementInfoSetParentId)(ArkUI_AccessibilityElementInfo*, int32_t) = - OhosAccessibilityDDL::DLLoadSetElemIntFunc("OH_ArkUI_AccessibilityElementInfoSetParentId"); - if (OH_ArkUI_AccessibilityElementInfoSetParentId == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetParentId is null, %{public}s", dlerror()); - } + FML_DLOG(INFO) << "flutterNode.id=" << flutterNode.id + << " OH_ArkUI_AccessibilityElementInfoSetEnabled -> true"; + } + // 判断当前节点是否可点击 + if (IsNodeClickable(flutterNode)) { + auto OH_ArkUI_AccessibilityElementInfoSetClickable = + OhosAccessibilityDDL::DLLoadSetElemBoolFunc(ArkUIAccessibilityConstant::ARKUI_SET_CLICKABLE); + CHECK_DLL_NULL_PTR(OH_ArkUI_AccessibilityElementInfoSetClickable); ARKUI_ACCESSIBILITY_CALL_CHECK( - OH_ArkUI_AccessibilityElementInfoSetParentId(elementInfoFromList, parentId) + OH_ArkUI_AccessibilityElementInfoSetClickable(elementInfoFromList, true) ); - FML_DLOG(INFO) << "FlutterNodeToElementInfoById GetParentId = " << parentId; - - // set accessibility text for announcing - std::string text = flutterNode.label; - int32_t (*OH_ArkUI_AccessibilityElementInfoSetAccessibilityText)(ArkUI_AccessibilityElementInfo*, const char*) = - OhosAccessibilityDDL::DLLoadSetElemStringFunc("OH_ArkUI_AccessibilityElementInfoSetAccessibilityText"); - if (OH_ArkUI_AccessibilityElementInfoSetAccessibilityText == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetAccessibilityText is null, %{public}s", dlerror()); - } + FML_DLOG(INFO) << "flutterNode.id=" << flutterNode.id + << " OH_ArkUI_AccessibilityElementInfoSetClickable -> true"; + } + // 判断当前节点是否可获焦点 + if (IsNodeFocusable(flutterNode)) { + auto OH_ArkUI_AccessibilityElementInfoSetFocusable = + OhosAccessibilityDDL::DLLoadSetElemBoolFunc(ArkUIAccessibilityConstant::ARKUI_SET_FOCUSABLE); + CHECK_DLL_NULL_PTR(OH_ArkUI_AccessibilityElementInfoSetFocusable); ARKUI_ACCESSIBILITY_CALL_CHECK( - OH_ArkUI_AccessibilityElementInfoSetAccessibilityText(elementInfoFromList, text.c_str()) + OH_ArkUI_AccessibilityElementInfoSetFocusable(elementInfoFromList, true) ); - FML_DLOG(INFO) << "FlutterNodeToElementInfoById SetAccessibilityText = " - << text; - - //set contents (same as AccessibilityText) - int32_t (*OH_ArkUI_AccessibilityElementInfoSetContents)(ArkUI_AccessibilityElementInfo*, const char*) = - OhosAccessibilityDDL::DLLoadSetElemStringFunc("OH_ArkUI_AccessibilityElementInfoSetContents"); - if (OH_ArkUI_AccessibilityElementInfoSetContents == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetContents is null, %{public}s", dlerror()); - } + FML_DLOG(INFO) << "flutterNode.id=" << flutterNode.id + << " OH_ArkUI_AccessibilityElementInfoSetFocusable -> true"; + } + if (IsNodeFocused(flutterNode)) { + auto OH_ArkUI_AccessibilityElementInfoSetAccessibilityFocused = + OhosAccessibilityDDL::DLLoadSetElemBoolFunc(ArkUIAccessibilityConstant::ARKUI_SET_A11Y_FOCUSED); + CHECK_DLL_NULL_PTR(OH_ArkUI_AccessibilityElementInfoSetAccessibilityFocused); ARKUI_ACCESSIBILITY_CALL_CHECK( - OH_ArkUI_AccessibilityElementInfoSetContents(elementInfoFromList, text.c_str()) + OH_ArkUI_AccessibilityElementInfoSetAccessibilityFocused(elementInfoFromList, true) ); - - std::string hint = flutterNode.hint; - int32_t (*OH_ArkUI_AccessibilityElementInfoSetHintText)(ArkUI_AccessibilityElementInfo*, const char*) = - OhosAccessibilityDDL::DLLoadSetElemStringFunc("OH_ArkUI_AccessibilityElementInfoSetHintText"); - if (OH_ArkUI_AccessibilityElementInfoSetHintText == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetHintText is null, %{public}s", dlerror()); - } + FML_DLOG(INFO) << "flutterNode.id=" << flutterNode.id + << " OH_ArkUI_AccessibilityElementInfoSetAccessibilityFocused -> true"; + } + // 判断当前节点是否为密码输入框 + if (IsNodePassword(flutterNode)) { + auto OH_ArkUI_AccessibilityElementInfoSetIsPassword = + OhosAccessibilityDDL::DLLoadSetElemBoolFunc(ArkUIAccessibilityConstant::ARKUI_SET_IS_PASSWORD); + CHECK_DLL_NULL_PTR(OH_ArkUI_AccessibilityElementInfoSetIsPassword); ARKUI_ACCESSIBILITY_CALL_CHECK( - OH_ArkUI_AccessibilityElementInfoSetHintText(elementInfoFromList, hint.c_str()) + OH_ArkUI_AccessibilityElementInfoSetIsPassword(elementInfoFromList, true) ); - - // set chidren elementinfo ids - 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(childrenIdsVec[i]); - FML_DLOG(INFO) << "FlutterNodeToElementInfoById -> elementid=" << elementId - << " childCount=" << childCount - << " childNodeIds=" << childNodeIds[i]; - } - int32_t (*OH_ArkUI_AccessibilityElementInfoSetChildNodeIds)(ArkUI_AccessibilityElementInfo*, int32_t, int64_t*) = - OhosAccessibilityDDL::DLLoadSetElemChildFunc("OH_ArkUI_AccessibilityElementInfoSetChildNodeIds"); - if (OH_ArkUI_AccessibilityElementInfoSetChildNodeIds == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetChildNodeIds is null, %{public}s", dlerror()); - } + FML_DLOG(INFO) << "flutterNode.id=" << flutterNode.id + << " OH_ArkUI_AccessibilityElementInfoSetIsPassword -> true"; + } + // 判断当前节点是否具备checkable状态 (如:checkbox, radio button) + if (IsNodeCheckable(flutterNode)) { + auto OH_ArkUI_AccessibilityElementInfoSetCheckable = + OhosAccessibilityDDL::DLLoadSetElemBoolFunc(ArkUIAccessibilityConstant::ARKUI_SET_CHECKABLE); + CHECK_DLL_NULL_PTR(OH_ArkUI_AccessibilityElementInfoSetCheckable); ARKUI_ACCESSIBILITY_CALL_CHECK( - OH_ArkUI_AccessibilityElementInfoSetChildNodeIds(elementInfoFromList, childCount, childNodeIds) + OH_ArkUI_AccessibilityElementInfoSetCheckable(elementInfoFromList, true) ); - - /** - * 根据当前flutter节点的SemanticsFlags特性,配置对应的elmentinfo属性 - */ - // 判断当前节点组件是否enabled - if (IsNodeEnabled(flutterNode)) { - int32_t (*OH_ArkUI_AccessibilityElementInfoSetEnabled)(ArkUI_AccessibilityElementInfo*, bool) = - OhosAccessibilityDDL::DLLoadSetElemBoolFunc("OH_ArkUI_AccessibilityElementInfoSetEnabled"); - if (OH_ArkUI_AccessibilityElementInfoSetEnabled == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetEnabled is null, %{public}s", dlerror()); - } - ARKUI_ACCESSIBILITY_CALL_CHECK( - OH_ArkUI_AccessibilityElementInfoSetEnabled(elementInfoFromList, true) - ); - FML_DLOG(INFO) << "flutterNode.id=" << flutterNode.id - << " OH_ArkUI_AccessibilityElementInfoSetEnabled -> true"; - } - // 判断当前节点是否可点击 - if (IsNodeClickable(flutterNode)) { - int32_t (*OH_ArkUI_AccessibilityElementInfoSetClickable)(ArkUI_AccessibilityElementInfo*, bool) = - OhosAccessibilityDDL::DLLoadSetElemBoolFunc("OH_ArkUI_AccessibilityElementInfoSetClickable"); - if (OH_ArkUI_AccessibilityElementInfoSetClickable == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetClickable is null, %{public}s", dlerror()); - } - ARKUI_ACCESSIBILITY_CALL_CHECK( - OH_ArkUI_AccessibilityElementInfoSetClickable(elementInfoFromList, true) - ); - FML_DLOG(INFO) << "flutterNode.id=" << flutterNode.id - << " OH_ArkUI_AccessibilityElementInfoSetClickable -> true"; - } - // 判断当前节点是否可获焦点 - if (IsNodeFocusable(flutterNode)) { - int32_t (*OH_ArkUI_AccessibilityElementInfoSetFocusable)(ArkUI_AccessibilityElementInfo*, bool) = - OhosAccessibilityDDL::DLLoadSetElemBoolFunc("OH_ArkUI_AccessibilityElementInfoSetFocusable"); - if (OH_ArkUI_AccessibilityElementInfoSetFocusable == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetFocusable is null, %{public}s", dlerror()); - } - ARKUI_ACCESSIBILITY_CALL_CHECK( - OH_ArkUI_AccessibilityElementInfoSetFocusable(elementInfoFromList, true) - ); - FML_DLOG(INFO) << "flutterNode.id=" << flutterNode.id - << " OH_ArkUI_AccessibilityElementInfoSetFocusable -> true"; - } - // 判断当前节点是否为密码输入框 - if (IsNodePassword(flutterNode)) { - int32_t (*OH_ArkUI_AccessibilityElementInfoSetIsPassword)(ArkUI_AccessibilityElementInfo*, bool) = - OhosAccessibilityDDL::DLLoadSetElemBoolFunc("OH_ArkUI_AccessibilityElementInfoSetIsPassword"); - if (OH_ArkUI_AccessibilityElementInfoSetIsPassword == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetIsPassword is null, %{public}s", dlerror()); - } - 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)) { - int32_t (*OH_ArkUI_AccessibilityElementInfoSetCheckable)(ArkUI_AccessibilityElementInfo*, bool) = - OhosAccessibilityDDL::DLLoadSetElemBoolFunc("OH_ArkUI_AccessibilityElementInfoSetCheckable"); - if (OH_ArkUI_AccessibilityElementInfoSetCheckable == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetCheckable is null, %{public}s", dlerror()); - } - 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)) { - int32_t (*OH_ArkUI_AccessibilityElementInfoSetChecked)(ArkUI_AccessibilityElementInfo*, bool) = - OhosAccessibilityDDL::DLLoadSetElemBoolFunc("OH_ArkUI_AccessibilityElementInfoSetChecked"); - if (OH_ArkUI_AccessibilityElementInfoSetChecked == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetChecked is null, %{public}s", dlerror()); - } - ARKUI_ACCESSIBILITY_CALL_CHECK( - OH_ArkUI_AccessibilityElementInfoSetChecked(elementInfoFromList, true) - ); - FML_DLOG(INFO) << "flutterNode.id=" << flutterNode.id - << " OH_ArkUI_AccessibilityElementInfoSetChecked -> true"; - } - // 判断当前节点组件是否可显示 - if (IsNodeVisible(flutterNode)) { - int32_t (*OH_ArkUI_AccessibilityElementInfoSetVisible)(ArkUI_AccessibilityElementInfo*, bool) = - OhosAccessibilityDDL::DLLoadSetElemBoolFunc("OH_ArkUI_AccessibilityElementInfoSetVisible"); - if (OH_ArkUI_AccessibilityElementInfoSetVisible == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetVisible is null, %{public}s", dlerror()); - } - ARKUI_ACCESSIBILITY_CALL_CHECK( - OH_ArkUI_AccessibilityElementInfoSetVisible(elementInfoFromList, true) - ); - FML_DLOG(INFO) << "flutterNode.id=" << flutterNode.id - << " OH_ArkUI_AccessibilityElementInfoSetVisible -> true"; - } - // 判断当前节点组件是否选中 - if (IsNodeSelected(flutterNode)) { - int32_t (*OH_ArkUI_AccessibilityElementInfoSetSelected)(ArkUI_AccessibilityElementInfo*, bool) = - OhosAccessibilityDDL::DLLoadSetElemBoolFunc("OH_ArkUI_AccessibilityElementInfoSetSelected"); - if (OH_ArkUI_AccessibilityElementInfoSetSelected == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetSelected is null, %{public}s", dlerror()); - } - OH_ArkUI_AccessibilityElementInfoSetSelected(elementInfoFromList, true); - FML_DLOG(INFO) << "flutterNode.id=" << flutterNode.id - << " OH_ArkUI_AccessibilityElementInfoSetSelected -> true"; - } - // 判断当前节点组件是否可滑动 - if (IsNodeScrollable(flutterNode)) { - int32_t (*OH_ArkUI_AccessibilityElementInfoSetScrollable)(ArkUI_AccessibilityElementInfo*, bool) = - OhosAccessibilityDDL::DLLoadSetElemBoolFunc("OH_ArkUI_AccessibilityElementInfoSetScrollable"); - if (OH_ArkUI_AccessibilityElementInfoSetScrollable == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetScrollable is null, %{public}s", dlerror()); - } - ARKUI_ACCESSIBILITY_CALL_CHECK( - OH_ArkUI_AccessibilityElementInfoSetScrollable(elementInfoFromList, true) - ); - FML_DLOG(INFO) << "flutterNode.id=" << flutterNode.id - << " OH_ArkUI_AccessibilityElementInfoSetScrollable -> true"; - } - // 判断当前节点组件是否可编辑(文本输入框) - if (IsTextField(flutterNode)) { - int32_t (*OH_ArkUI_AccessibilityElementInfoSetEditable)(ArkUI_AccessibilityElementInfo*, bool) = - OhosAccessibilityDDL::DLLoadSetElemBoolFunc("OH_ArkUI_AccessibilityElementInfoSetEditable"); - if (OH_ArkUI_AccessibilityElementInfoSetEditable == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetEditable is null, %{public}s", dlerror()); - } - ARKUI_ACCESSIBILITY_CALL_CHECK( - OH_ArkUI_AccessibilityElementInfoSetEditable(elementInfoFromList, true) - ); - FML_DLOG(INFO) << "flutterNode.id=" << flutterNode.id - << " OH_ArkUI_AccessibilityElementInfoSetEditable -> true"; - } - // 判断当前节点组件是否为滑动条 - if (IsSlider(flutterNode)) { - FML_DLOG(INFO) << "flutterNode.id=" << flutterNode.id - << " OH_ArkUI_AccessibilityElementInfoSetRangeInfo -> true"; - } - // 判断当前节点组件是否支持长按 - if (IsNodeHasLongPress(flutterNode)) { - int32_t (*OH_ArkUI_AccessibilityElementInfoSetLongClickable)(ArkUI_AccessibilityElementInfo*, bool) = - OhosAccessibilityDDL::DLLoadSetElemBoolFunc("OH_ArkUI_AccessibilityElementInfoSetLongClickable"); - if (OH_ArkUI_AccessibilityElementInfoSetLongClickable == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetLongClickable is null, %{public}s", dlerror()); - } - ARKUI_ACCESSIBILITY_CALL_CHECK( - OH_ArkUI_AccessibilityElementInfoSetLongClickable(elementInfoFromList, true) - ); - FML_DLOG(INFO) - << "flutterNode.id=" << flutterNode.id - << " OH_ArkUI_AccessibilityElementInfoSetLongClickable -> true"; - } - - // 获取当前节点的组件类型 - std::string componentTypeName = GetNodeComponentType(flutterNode); - FML_DLOG(INFO) << "FlutterNodeToElementInfoById componentTypeName = " - << componentTypeName; - // flutter节点对应elementinfo所属的组件类型(如:root, button,text等) - int32_t (*OH_ArkUI_AccessibilityElementInfoSetComponentType)(ArkUI_AccessibilityElementInfo*, const char*) = - OhosAccessibilityDDL::DLLoadSetElemStringFunc("OH_ArkUI_AccessibilityElementInfoSetComponentType"); - if (OH_ArkUI_AccessibilityElementInfoSetComponentType == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetComponentType is null, %{public}s", dlerror()); - } - if (elementId == 0) { - ARKUI_ACCESSIBILITY_CALL_CHECK( - OH_ArkUI_AccessibilityElementInfoSetComponentType(elementInfoFromList, "root") - ); - } else { - ARKUI_ACCESSIBILITY_CALL_CHECK( - OH_ArkUI_AccessibilityElementInfoSetComponentType(elementInfoFromList, - componentTypeName.c_str()) - ); - } - FML_DLOG(INFO) << "FlutterNodeToElementInfoById SetComponentType: " - << componentTypeName; - - /** - * 无障碍重要性,用于控制某个组件是否可被无障碍辅助服务所识别。支持的值为(默认值:“auto”): - * “auto”:根据组件不同会转换为“yes”或者“no” - * “yes”:当前组件可被无障碍辅助服务所识别 - * “no”:当前组件不可被无障碍辅助服务所识别 - * “no-hide-descendants”:当前组件及其所有子组件不可被无障碍辅助服务所识别 - */ - int32_t (*OH_ArkUI_AccessibilityElementInfoSetAccessibilityLevel)(ArkUI_AccessibilityElementInfo*, const char*) = - OhosAccessibilityDDL::DLLoadSetElemStringFunc("OH_ArkUI_AccessibilityElementInfoSetAccessibilityLevel"); - if (OH_ArkUI_AccessibilityElementInfoSetAccessibilityLevel == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetAccessibilityLevel is null, %{public}s", dlerror()); - } + FML_DLOG(INFO) << "flutterNode.id=" << flutterNode.id + << " OH_ArkUI_AccessibilityElementInfoSetCheckable -> true"; + } + // 判断当前节点(check box/radio button)是否checked/unchecked + if (IsNodeChecked(flutterNode)) { + auto OH_ArkUI_AccessibilityElementInfoSetChecked = + OhosAccessibilityDDL::DLLoadSetElemBoolFunc(ArkUIAccessibilityConstant::ARKUI_SET_CHECKED); + CHECK_DLL_NULL_PTR(OH_ArkUI_AccessibilityElementInfoSetChecked); ARKUI_ACCESSIBILITY_CALL_CHECK( - OH_ArkUI_AccessibilityElementInfoSetAccessibilityLevel(elementInfoFromList, "yes"); + OH_ArkUI_AccessibilityElementInfoSetChecked(elementInfoFromList, true) ); - // 无障碍组,设置为true时表示该组件及其所有子组件为一整个可以选中的组件,无障碍服务将不再关注其子组件内容。默认值:false - int32_t (*OH_ArkUI_AccessibilityElementInfoSetAccessibilityGroup)(ArkUI_AccessibilityElementInfo*, bool) = - OhosAccessibilityDDL::DLLoadSetElemBoolFunc("OH_ArkUI_AccessibilityElementInfoSetAccessibilityGroup"); - if (OH_ArkUI_AccessibilityElementInfoSetAccessibilityGroup == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetAccessibilityGroup is null, %{public}s", dlerror()); - } + FML_DLOG(INFO) << "flutterNode.id=" << flutterNode.id + << " OH_ArkUI_AccessibilityElementInfoSetChecked -> true"; + } + // 判断当前节点组件是否可显示 + if (IsNodeVisible(flutterNode)) { + auto OH_ArkUI_AccessibilityElementInfoSetVisible = + OhosAccessibilityDDL::DLLoadSetElemBoolFunc(ArkUIAccessibilityConstant::ARKUI_SET_VISIBLE); + CHECK_DLL_NULL_PTR(OH_ArkUI_AccessibilityElementInfoSetVisible); ARKUI_ACCESSIBILITY_CALL_CHECK( - OH_ArkUI_AccessibilityElementInfoSetAccessibilityGroup(elementInfoFromList, false); + OH_ArkUI_AccessibilityElementInfoSetVisible(elementInfoFromList, true) ); - } + FML_DLOG(INFO) << "flutterNode.id=" << flutterNode.id + << " OH_ArkUI_AccessibilityElementInfoSetVisible -> true"; + } + // 判断当前节点组件是否选中 + if (IsNodeSelected(flutterNode)) { + auto OH_ArkUI_AccessibilityElementInfoSetSelected = + OhosAccessibilityDDL::DLLoadSetElemBoolFunc(ArkUIAccessibilityConstant::ARKUI_SET_SELECTED); + CHECK_DLL_NULL_PTR(OH_ArkUI_AccessibilityElementInfoSetSelected); + OH_ArkUI_AccessibilityElementInfoSetSelected(elementInfoFromList, true); + FML_DLOG(INFO) << "flutterNode.id=" << flutterNode.id + << " OH_ArkUI_AccessibilityElementInfoSetSelected -> true"; + } + // 判断当前节点组件是否可滑动 + if (IsNodeScrollable(flutterNode)) { + auto OH_ArkUI_AccessibilityElementInfoSetScrollable = + OhosAccessibilityDDL::DLLoadSetElemBoolFunc(ArkUIAccessibilityConstant::ARKUI_SET_SCROLLABLE); + CHECK_DLL_NULL_PTR(OH_ArkUI_AccessibilityElementInfoSetScrollable); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetScrollable(elementInfoFromList, true) + ); + FML_DLOG(INFO) << "flutterNode.id=" << flutterNode.id + << " OH_ArkUI_AccessibilityElementInfoSetScrollable -> true"; + } + // 判断当前节点组件是否可编辑(文本输入框) + if (IsTextField(flutterNode)) { + auto OH_ArkUI_AccessibilityElementInfoSetEditable = + OhosAccessibilityDDL::DLLoadSetElemBoolFunc(ArkUIAccessibilityConstant::ARKUI_SET_EDITABLE); + CHECK_DLL_NULL_PTR(OH_ArkUI_AccessibilityElementInfoSetEditable); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetEditable(elementInfoFromList, true) + ); + FML_DLOG(INFO) << "flutterNode.id=" << flutterNode.id + << " OH_ArkUI_AccessibilityElementInfoSetEditable -> true"; + } + // 判断当前节点组件是否支持长按 + if (IsNodeHasLongPress(flutterNode)) { + auto OH_ArkUI_AccessibilityElementInfoSetLongClickable = + OhosAccessibilityDDL::DLLoadSetElemBoolFunc(ArkUIAccessibilityConstant::ARKUI_SET_LONG_PRESS); + CHECK_DLL_NULL_PTR(OH_ArkUI_AccessibilityElementInfoSetLongClickable); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetLongClickable(elementInfoFromList, true) + ); + FML_DLOG(INFO) + << "flutterNode.id=" << flutterNode.id + << " OH_ArkUI_AccessibilityElementInfoSetLongClickable -> true"; + } + + // 获取当前节点的组件类型 + std::string componentTypeName = GetNodeComponentType(flutterNode); + FML_DLOG(INFO) << "FlutterSetElementInfoProperties componentTypeName = " + << componentTypeName; + // flutter节点对应elementinfo所属的组件类型(如:root, button,text等) + auto OH_ArkUI_AccessibilityElementInfoSetComponentType = + OhosAccessibilityDDL::DLLoadSetElemStringFunc(ArkUIAccessibilityConstant::ARKUI_SET_COMPONENT_TYPE); + CHECK_DLL_NULL_PTR(OH_ArkUI_AccessibilityElementInfoSetComponentType); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetComponentType( + elementInfoFromList, elementId < 1 ? "root" : componentTypeName.c_str()) + ); + FML_DLOG(INFO) << "FlutterSetElementInfoProperties SetComponentType: " + << componentTypeName; + + /** + * 无障碍重要性,用于控制某个组件是否可被无障碍辅助服务所识别。支持的值为(默认值:“auto”): + * “auto”:根据组件不同会转换为“yes”或者“no” + * “yes”:当前组件可被无障碍辅助服务所识别 + * “no”:当前组件不可被无障碍辅助服务所识别 + * “no-hide-descendants”:当前组件及其所有子组件不可被无障碍辅助服务所识别 + */ + auto OH_ArkUI_AccessibilityElementInfoSetAccessibilityLevel = + OhosAccessibilityDDL::DLLoadSetElemStringFunc(ArkUIAccessibilityConstant::ARKUI_SET_A11Y_LEVEL); + CHECK_DLL_NULL_PTR(OH_ArkUI_AccessibilityElementInfoSetAccessibilityLevel); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetAccessibilityLevel( + elementInfoFromList, componentTypeName != OTHER_WIDGET_NAME ? "yes" : "no"); + ); + // 无障碍组,设置为true时表示该组件及其所有子组件为一整个可以选中的组件,无障碍服务将不再关注其子组件内容。默认值:false + auto OH_ArkUI_AccessibilityElementInfoSetAccessibilityGroup = + OhosAccessibilityDDL::DLLoadSetElemBoolFunc(ArkUIAccessibilityConstant::ARKUI_SET_A11Y_GROUP); + CHECK_DLL_NULL_PTR(OH_ArkUI_AccessibilityElementInfoSetAccessibilityGroup); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetAccessibilityGroup(elementInfoFromList, false); + ); } /** @@ -1435,7 +944,7 @@ void OhosAccessibilityBridge::FlutterSetElementInfoProperties( std::vector OhosAccessibilityBridge::GetLevelOrderTraversalTree(int32_t rootId) { std::vector levelOrderTraversalTree; - std::queue semanticsQue; + std::queue semanticsQue; auto root = GetFlutterSemanticsNode(rootId); semanticsQue.push(root); @@ -1444,6 +953,7 @@ std::vector OhosAccessibilityBridge::GetLevelOrderTraversalTree(int32_t uint32_t queSize = semanticsQue.size(); for (uint32_t i=0; i(currNode.id)); @@ -1451,6 +961,7 @@ std::vector OhosAccessibilityBridge::GetLevelOrderTraversalTree(int32_t currNode.childrenInTraversalOrder.end()); for (const auto& childId: currNode.childrenInTraversalOrder) { auto childNode = GetFlutterSemanticsNode(childId); + semanticsQue.push(childNode); } } @@ -1459,126 +970,431 @@ std::vector OhosAccessibilityBridge::GetLevelOrderTraversalTree(int32_t } /** - * 创建并配置完整arkui无障碍语义树 + * 创建并配置完整arkui无障碍语义树 + */ +void OhosAccessibilityBridge::BuildArkUISemanticsTree( + int64_t elementId, + ArkUI_AccessibilityElementInfo* elementInfoFromList, + ArkUI_AccessibilityElementInfoList* elementList) +{ + if (OHOS_API_VERSION < 13) { return; } + //配置root节点信息 + FlutterSetElementInfoProperties(elementInfoFromList, elementId); + //获取flutter无障碍语义树的节点总数 + auto levelOrderTreeVec = GetLevelOrderTraversalTree(0); + int64_t elementInfoCount = levelOrderTreeVec.size(); + //创建并配置节点id >= 1的全部节点 + for (int64_t i = 1; i < elementInfoCount; i++) { + int64_t levelOrderId = levelOrderTreeVec[i]; + auto newNode = GetFlutterSemanticsNode(levelOrderId); + if (g_flutterSemanticsTree.count(newNode.id)) { + LOGE("BuildArkUISemanticsTree: GetFlutterSemanticsNode id=%{public}ld null", levelOrderId); + } + //当节点为隐藏状态时,自动规避 + auto OH_ArkUI_AddAndGetAccessibilityElementInfo = + OhosAccessibilityDDL::DLLoadGetElemFunc(ArkUIAccessibilityConstant::ARKUI_GET_A11Y_NODE); + CHECK_DLL_NULL_PTR(OH_ArkUI_AddAndGetAccessibilityElementInfo); + auto* newElementInfo = OH_ArkUI_AddAndGetAccessibilityElementInfo(elementList); + //配置当前子节点信息 + FlutterSetElementInfoProperties(newElementInfo, levelOrderId); + } +} + +/** + * 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) +{ + if (OHOS_API_VERSION < 13) { return ARKUI_FAILED_CODE; } + FML_DLOG(INFO) + << "#### FindAccessibilityNodeInfosById input-params ####: elementId = " + << elementId << " mode=" << mode; + CHECK_NULL_PTR_WITH_RET(elementList, FindAccessibilityNodeInfosById); + + AccessibiltiyChangesWithXComponentId(); + + if (g_flutterSemanticsTree.size() == 0) { + FML_DLOG(INFO) + << "FindAccessibilityNodeInfosById g_flutterSemanticsTree is null"; + return ARKUI_ACCESSIBILITY_NATIVE_RESULT_FAILED; + } + + // 获取当前对应id的flutter节点,若为空则返回错误编码 + auto flutterNode = GetFlutterSemanticsNode(static_cast(elementId)); + if (!g_flutterSemanticsTree.count(flutterNode.id)) { + LOGE("FindAccessibilityNodeInfosById: GetFlutterSemanticsNode id=%{public}ld is null", elementId); + } + + // 开启无障碍导航功能 + if(elementId == -1 || elementId == 0) { + accessibilityFeatures_->SetAccessibleNavigation(true, native_shell_holder_id_); + } + + // 从elementinfolist中获取elementinfo + auto OH_ArkUI_AddAndGetAccessibilityElementInfo = + OhosAccessibilityDDL::DLLoadGetElemFunc(ArkUIAccessibilityConstant::ARKUI_GET_A11Y_NODE); + CHECK_DLL_NULL_PTR(OH_ArkUI_AddAndGetAccessibilityElementInfo); + auto* elementInfoFromList = OH_ArkUI_AddAndGetAccessibilityElementInfo(elementList); + CHECK_NULL_PTR_WITH_RET(elementInfoFromList, OH_ArkUI_AddAndGetAccessibilityElementInfo); + + if (mode == ArkUI_AccessibilitySearchMode::ARKUI_ACCESSIBILITY_NATIVE_SEARCH_MODE_PREFETCH_CURRENT) { + /** Search for current nodes. (mode = 0) */ + BuildArkUISemanticsTree(elementId, elementInfoFromList, elementList); + } else if (mode ==ArkUI_AccessibilitySearchMode::ARKUI_ACCESSIBILITY_NATIVE_SEARCH_MODE_PREFETCH_PREDECESSORS) { + /** Search for parent nodes. (mode = 1) */ + if (IsNodeVisible(flutterNode)) { + FlutterSetElementInfoProperties(elementInfoFromList, elementId); + } + } else if (mode ==ArkUI_AccessibilitySearchMode::ARKUI_ACCESSIBILITY_NATIVE_SEARCH_MODE_PREFETCH_SIBLINGS) { + /** Search for sibling nodes. (mode = 2) */ + if (IsNodeVisible(flutterNode)) { + FlutterSetElementInfoProperties(elementInfoFromList, elementId); + } + } else if (mode ==ArkUI_AccessibilitySearchMode::ARKUI_ACCESSIBILITY_NATIVE_SEARCH_MODE_PREFETCH_CHILDREN) { + /** Search for child nodes at the next level. (mode = 4) */ + if (IsNodeVisible(flutterNode)) { + FlutterSetElementInfoProperties(elementInfoFromList, elementId); + } + } else if (mode ==ArkUI_AccessibilitySearchMode::ARKUI_ACCESSIBILITY_NATIVE_SEARCH_MODE_PREFETCH_RECURSIVE_CHILDREN) { + /** Search for all child nodes. (mode = 8) */ + BuildArkUISemanticsTree(elementId, elementInfoFromList, elementList); + } else { + FlutterSetElementInfoProperties(elementInfoFromList, elementId); + } + FML_DLOG(INFO) << "--- FindAccessibilityNodeInfosById is end ---"; + + return ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL; +} + +/** + * 解析flutter语义动作,并通过NativAccessibilityChannel分发 + */ +void OhosAccessibilityBridge::DispatchSemanticsAction( + int32_t id, + flutter::SemanticsAction action, + fml::MallocMapping args) +{ + nativeAccessibilityChannel_->DispatchSemanticsAction(native_shell_holder_id_, + id, + action, + std::move(args)); +} + +/** + * flutter按钮节点双击跳转新页面时,发送页面更新事件 + */ +void OhosAccessibilityBridge::DoubleClickRouteToNewPage(SemanticsNodeExtent node) +{ + if (node.HasFlag(FLAGS_::kIsButton)) { + RequestFocusWhenPageUpdate(0); + } +} + +/** + * perform click action in accessibility status + */ +void OhosAccessibilityBridge::PerformClickAction( + int64_t elementId, + ArkUI_Accessibility_ActionType action, + SemanticsNodeExtent flutterNode) +{ + /** Click event, sent after the UI component responds. 1 */ + auto clickEventType = ArkUI_AccessibilityEventType::ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_CLICKED; + Flutter_SendAccessibilityAsyncEvent(elementId, clickEventType); + FML_DLOG(INFO) << "ExecuteAccessibilityAction -> action: click(" << action + << ")" << " event: click(" << clickEventType << ")"; + auto flutterTapAction = ArkuiActionsToFlutterActions(action); + DispatchSemanticsAction(static_cast(elementId), flutterTapAction, {}); + // double click at button-like node for pushing page update + DoubleClickRouteToNewPage(flutterNode); +} + +/** + * perform long-press action in accessibility status + */ +void OhosAccessibilityBridge::PerformLongClickAction( + int64_t elementId, + ArkUI_Accessibility_ActionType action, + SemanticsNodeExtent flutterNode) +{ + /** Long click event, sent after the UI component responds. 2 */ + auto longClickEventType = ArkUI_AccessibilityEventType::ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_LONG_CLICKED; + Flutter_SendAccessibilityAsyncEvent(elementId, longClickEventType); + FML_DLOG(INFO) << "ExecuteAccessibilityAction -> action: longclick(" + << action << ")" << " event: longclick(" + << longClickEventType << ")"; + auto flutterLongPressAction = ArkuiActionsToFlutterActions(action); + DispatchSemanticsAction(static_cast(elementId), flutterLongPressAction, {}); +} + +/** + * perform focus acquisition in accessibility status */ -void OhosAccessibilityBridge::BuildArkUISemanticsTree( +void OhosAccessibilityBridge::PerformGainFocusnAction( int64_t elementId, - ArkUI_AccessibilityElementInfo* elementInfoFromList, - ArkUI_AccessibilityElementInfoList* elementList) + ArkUI_Accessibility_ActionType action, + SemanticsNodeExtent flutterNode) { - if (OH_GetSdkApiVersion() >= 13) { - //配置root节点信息 - FlutterNodeToElementInfoById(elementInfoFromList, elementId); - //获取flutter无障碍语义树的节点总数 - auto levelOrderTreeVec = GetLevelOrderTraversalTree(0); - int64_t elementInfoCount = levelOrderTreeVec.size(); - //创建并配置节点id >= 1的全部节点 - for (int64_t i = 1; i < elementInfoCount; i++) { - int64_t levelOrderId = levelOrderTreeVec[i]; - auto newNode = GetFlutterSemanticsNode(levelOrderId); - //当节点为隐藏状态时,自动规避 - if (IsNodeVisible(newNode)) { - ArkUI_AccessibilityElementInfo* (*OH_ArkUI_AddAndGetAccessibilityElementInfo)(ArkUI_AccessibilityElementInfoList*) = - OhosAccessibilityDDL::DLLoadGetElemFunc("OH_ArkUI_AddAndGetAccessibilityElementInfo"); - if (OH_ArkUI_AddAndGetAccessibilityElementInfo == nullptr) { - LOGE("OH_ArkUI_AddAndGetAccessibilityElementInfo is null, %{public}s", dlerror()); - } - ArkUI_AccessibilityElementInfo* newElementInfo = - OH_ArkUI_AddAndGetAccessibilityElementInfo(elementList); - //配置当前子节点信息 - FlutterNodeToElementInfoById(newElementInfo, levelOrderId); - } - } + // 感知获焦flutter节点 + accessibilityFocusedNode = flutterNode; + // 解析arkui的获焦 -> flutter对应节点的获焦 + auto flutterGainFocusAction = ArkuiActionsToFlutterActions(action); + DispatchSemanticsAction(static_cast(elementId), + flutterGainFocusAction, {}); + // 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); + 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); } } /** - * Called to obtain element information based on a specified node. - * NOTE:该arkui接口需要在系统无障碍服务开启时,才能触发调用 + * perform focus clearance in accessibility status */ -int32_t OhosAccessibilityBridge::FindAccessibilityNodeInfosById( +void OhosAccessibilityBridge::PerformClearFocusAction( int64_t elementId, - ArkUI_AccessibilitySearchMode mode, - int32_t requestId, - ArkUI_AccessibilityElementInfoList* elementList) + ArkUI_Accessibility_ActionType action, + SemanticsNodeExtent flutterNode) { - FML_DLOG(INFO) - << "#### FindAccessibilityNodeInfosById input-params ####: elementId = " - << elementId << " mode=" << mode << " requestId=" << requestId - << " elementList= " << elementList; + // 解析arkui的失焦 -> flutter对应节点的失焦 + auto flutterLoseFocusAction = ArkuiActionsToFlutterActions(action); + DispatchSemanticsAction(static_cast(elementId), flutterLoseFocusAction, {}); + /** Accessibility focus cleared event, sent after the UI component + * responds. 65536 */ + auto clearFocusEventType = ArkUI_AccessibilityEventType:: + ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_ACCESSIBILITY_FOCUS_CLEARED; + Flutter_SendAccessibilityAsyncEvent(elementId, clearFocusEventType); + FML_DLOG(INFO) << "ExecuteAccessibilityAction -> action: clearfocus(" + << action << ")" << " event: clearfocus(" + << clearFocusEventType << ")"; +} - if (g_flutterSemanticsTree.size() == 0) { +/** + * perform scroll forward in accessibility status + */ +void OhosAccessibilityBridge::PerformScrollUpAction( + int64_t elementId, + ArkUI_Accessibility_ActionType action, + SemanticsNodeExtent flutterNode) +{ + // flutter scroll forward with different situations + if (flutterNode.HasAction(ACTIONS_::kScrollUp)) { + 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, {}); + } + std::string currComponetType = GetNodeComponentType(flutterNode); + if (OHOSUtils::Contains(currComponetType, SCROLL_WIDGET_NAME)) { + /** Scrolled event, sent when a scrollable component experiences a scroll event. 4096 */ + ArkUI_AccessibilityEventType scrollEventType1 = + ArkUI_AccessibilityEventType::ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_SCROLLED; + Flutter_SendAccessibilityAsyncEvent(elementId, scrollEventType1); FML_DLOG(INFO) - << "FindAccessibilityNodeInfosById g_flutterSemanticsTree is null"; - return ARKUI_ACCESSIBILITY_NATIVE_RESULT_FAILED; + << "ExecuteAccessibilityAction -> action: scroll forward(" << action + << ")" << " event: scroll forward(" << scrollEventType1 << ")"; } - if (elementList == nullptr) { - FML_DLOG(INFO) << "FindAccessibilityNodeInfosById elementList is null"; - return ARKUI_ACCESSIBILITY_NATIVE_RESULT_FAILED; +} + +/** + * perform scroll backward in accessibility status + */ +void OhosAccessibilityBridge::PerformScrollDownAction( + int64_t elementId, + ArkUI_Accessibility_ActionType action, + SemanticsNodeExtent flutterNode) +{ + // flutter scroll down with different situations + if (flutterNode.HasAction(ACTIONS_::kScrollDown)) { + 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; + + Flutter_SendAccessibilityAsyncEvent( + elementId, ArkUI_AccessibilityEventType::ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_SELECTED); + DispatchSemanticsAction(static_cast(elementId), ACTIONS_::kDecrease, {}); + } + std::string currComponetType = GetNodeComponentType(flutterNode); + if (OHOSUtils::Contains(currComponetType, SCROLL_WIDGET_NAME)) { + /** Scrolled event, sent when a scrollable component experiences a + * scroll event. 4096 */ + ArkUI_AccessibilityEventType scrollEventType1 = + ArkUI_AccessibilityEventType::ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_SCROLLED; + Flutter_SendAccessibilityAsyncEvent(elementId, scrollEventType1); + FML_DLOG(INFO) + << "ExecuteAccessibilityAction -> action: scroll forward(" << action + << ")" << " event: scroll forward(" << scrollEventType1 << ")"; } - // 开启无障碍导航功能 - if(elementId == -1 || elementId == 0) { - accessibilityFeatures_->SetAccessibleNavigation(true, native_shell_holder_id_); +} +/** + * perform invalid action in accessibility status + */ +void OhosAccessibilityBridge::PerformClipboardAction( + int64_t elementId, + ArkUI_Accessibility_ActionType action) +{ + if (action == ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_COPY) { + FML_DLOG(INFO) << "ExecuteAccessibilityAction -> action: copy(" << action << ")"; + DispatchSemanticsAction(static_cast(elementId), ACTIONS_::kCopy, {}); + } else if (action == ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_PASTE) { + FML_DLOG(INFO) << "ExecuteAccessibilityAction -> action: paste(" << action << ")"; + DispatchSemanticsAction(static_cast(elementId), ACTIONS_::kPaste, {}); + } else { + FML_DLOG(INFO) << "ExecuteAccessibilityAction -> action: cut(" << action << ")"; + DispatchSemanticsAction(static_cast(elementId), ACTIONS_::kCut, {}); } +} +/** + * perform invalid action in accessibility status + */ +void OhosAccessibilityBridge::PerformInvalidAction( + int64_t elementId, + ArkUI_Accessibility_ActionType action, + SemanticsNodeExtent flutterNode) +{ + /** Invalid event. 0 */ + ArkUI_AccessibilityEventType invalidEventType = + ArkUI_AccessibilityEventType::ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_INVALID; + Flutter_SendAccessibilityAsyncEvent(elementId, invalidEventType); + FML_DLOG(ERROR) << "ExecuteAccessibilityAction -> action: invalid(" + << action << ")" << " event: innvalid(" + << invalidEventType << ")"; +} +/** + * 设置输入框文本 + */ +void OhosAccessibilityBridge::PerformSetText( + SemanticsNodeExtent flutterNode, + ArkUI_Accessibility_ActionType action, + ArkUI_AccessibilityActionArguments* actionArguments) +{ + if (OHOS_API_VERSION < 13) { return; } + auto OH_ArkUI_FindAccessibilityActionArgumentByKey = + OhosAccessibilityDDL::DLLoadGetFindActionArgs(ArkUIAccessibilityConstant::ARKUI_FIND_ACTION_ARG_BY_KEY); + CHECK_DLL_NULL_PTR(OH_ArkUI_FindAccessibilityActionArgumentByKey); + + char* newText; + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_FindAccessibilityActionArgumentByKey(actionArguments, ARKUI_ACTION_ARG_SET_TEXT, &newText)); + CHECK_NULL_PTR(newText, PerformSetText); + + auto flutterSetTextAction = ArkuiActionsToFlutterActions(action); + DispatchSemanticsAction(flutterNode.id, + flutterSetTextAction, + fml::MallocMapping::Copy(newText, strlen(newText))); + flutterNode.value = newText; + flutterNode.valueAttributes = {}; + LOGI("ExecuteAccessibilityAction -> action: set text(%{public}d), newText=%{public}s", action, newText); +} - if (OH_GetSdkApiVersion() >= 13) { - // 从elementinfolist中获取elementinfo - ArkUI_AccessibilityElementInfo* (*OH_ArkUI_AddAndGetAccessibilityElementInfo)(ArkUI_AccessibilityElementInfoList*) = - OhosAccessibilityDDL::DLLoadGetElemFunc("OH_ArkUI_AddAndGetAccessibilityElementInfo"); - if (OH_ArkUI_AddAndGetAccessibilityElementInfo == nullptr) { - LOGE("OH_ArkUI_AddAndGetAccessibilityElementInfo is null, %{public}s", dlerror()); - } - ArkUI_AccessibilityElementInfo* elementInfoFromList = - OH_ArkUI_AddAndGetAccessibilityElementInfo(elementList); - if (elementInfoFromList == nullptr) { - FML_DLOG(INFO) << "FindAccessibilityNodeInfosById elementInfoFromList is null"; - return ARKUI_ACCESSIBILITY_NATIVE_RESULT_FAILED; - } +/** + * perform select text (from base to extent) in accessibility status + */ +void OhosAccessibilityBridge::PerformSelectText( + SemanticsNodeExtent flutterNode, + ArkUI_Accessibility_ActionType action, + ArkUI_AccessibilityActionArguments* actionArguments) +{ + FML_DLOG(INFO) << "ExecuteAccessibilityAction -> action: select text(" << action << ")"; + auto OH_ArkUI_FindAccessibilityActionArgumentByKey = + OhosAccessibilityDDL::DLLoadGetFindActionArgs(ArkUIAccessibilityConstant::ARKUI_FIND_ACTION_ARG_BY_KEY); + CHECK_DLL_NULL_PTR(OH_ArkUI_FindAccessibilityActionArgumentByKey); + + auto flutterSelectTextAction = ArkuiActionsToFlutterActions(action); + + char* textSelectBase; + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_FindAccessibilityActionArgumentByKey( + actionArguments, ARKUI_ACTION_ARG_SELECT_TEXT_START, &textSelectBase) + ); + CHECK_NULL_PTR(textSelectBase, PerformSelectText); + + char* textSelectExtent; + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_FindAccessibilityActionArgumentByKey( + actionArguments, ARKUI_ACTION_ARG_SELECT_TEXT_END, &textSelectExtent) + ); + CHECK_NULL_PTR(textSelectExtent, PerformSelectText); + + std::map selectionMap; + bool hasSelected = actionArguments != nullptr && + textSelectBase != nullptr && + textSelectExtent != nullptr; + if (hasSelected) { + int32_t base; + int32_t extent; + OHOSUtils::CharArrayToInt32(textSelectBase, base); + OHOSUtils::CharArrayToInt32(textSelectBase, extent); + selectionMap.insert({ARKUI_ACTION_ARG_SELECT_TEXT_START, base}); + selectionMap.insert({ARKUI_ACTION_ARG_SELECT_TEXT_END, extent}); + } else { + selectionMap.insert({ARKUI_ACTION_ARG_SELECT_TEXT_START, flutterNode.textSelectionBase}); + selectionMap.insert({ARKUI_ACTION_ARG_SELECT_TEXT_END, flutterNode.textSelectionExtent}); + } + // serialize map to byte vector + std::vector encodedData = OHOSUtils::SerializeStringIntMap(selectionMap); + DispatchSemanticsAction(flutterNode.id, + flutterSelectTextAction, + fml::MallocMapping::Copy(encodedData.data(), encodedData.size() * sizeof(uint8_t))); +} - // 过滤非当前屏幕显示的语义节点创建、配置,防止溢出屏幕坐标绘制bug以及优化性能开销 - auto flutterNode = GetFlutterSemanticsNode(static_cast(elementId)); +/** + * perform cursor position setting in accessibility status + */ +void OhosAccessibilityBridge::PerformSetCursorPosition( + SemanticsNodeExtent flutterNode, + ArkUI_Accessibility_ActionType action, + ArkUI_AccessibilityActionArguments* actionArguments) +{ + FML_DLOG(INFO) << "ExecuteAccessibilityAction -> action: set cursor position (" << action << ")"; + return; +} - if (mode == ArkUI_AccessibilitySearchMode::ARKUI_ACCESSIBILITY_NATIVE_SEARCH_MODE_PREFETCH_CURRENT) { - /** Search for current nodes. (mode = 0) */ - BuildArkUISemanticsTree(elementId, elementInfoFromList, elementList); - } else if (mode ==ArkUI_AccessibilitySearchMode::ARKUI_ACCESSIBILITY_NATIVE_SEARCH_MODE_PREFETCH_PREDECESSORS) { - /** Search for parent nodes. (mode = 1) */ - if (IsNodeVisible(flutterNode)) { - FlutterNodeToElementInfoById(elementInfoFromList, elementId); - } - } else if (mode ==ArkUI_AccessibilitySearchMode::ARKUI_ACCESSIBILITY_NATIVE_SEARCH_MODE_PREFETCH_SIBLINGS) { - /** Search for sibling nodes. (mode = 2) */ - 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) */ - if (IsNodeVisible(flutterNode)) { - FlutterNodeToElementInfoById(elementInfoFromList, elementId); - } - } else if (mode ==ArkUI_AccessibilitySearchMode::ARKUI_ACCESSIBILITY_NATIVE_SEARCH_MODE_PREFETCH_RECURSIVE_CHILDREN) { - /** Search for all child nodes. (mode = 8) */ - BuildArkUISemanticsTree(elementId, elementInfoFromList, elementList); - } else { - FlutterNodeToElementInfoById(elementInfoFromList, elementId); - } - } - FML_DLOG(INFO) << "--- FindAccessibilityNodeInfosById is end ---"; - return ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL; +/** + * perform custom action in accessibility status + */ +void OhosAccessibilityBridge::PerformCustomAction( + SemanticsNodeExtent flutterNode, + ArkUI_Accessibility_ActionType action, + ArkUI_AccessibilityActionArguments* actionArguments) +{ + FML_DLOG(INFO) << "ExecuteAccessibilityAction -> action: custom action (" << action << ")"; + DispatchSemanticsAction(flutterNode.id, ACTIONS_::kCustomAction, {}); + return; } /** - * 解析flutter语义动作,并通过NativAccessibilityChannel分发 + * perform show on screen action in accessibility status */ -void OhosAccessibilityBridge::DispatchSemanticsAction( - int32_t id, - flutter::SemanticsAction action, - fml::MallocMapping args) +void OhosAccessibilityBridge::PerformShowOnScreenAction(SemanticsNodeExtent flutterNode) { - nativeAccessibilityChannel_->DispatchSemanticsAction(native_shell_holder_id_, - id, - action, - fml::MallocMapping()); + if (!IsNodeShowOnScreen(flutterNode)) { + DispatchSemanticsAction(flutterNode.id, ACTIONS_::kShowOnScreen, {}); + } } /** @@ -1591,217 +1407,95 @@ int32_t OhosAccessibilityBridge::ExecuteAccessibilityAction( int32_t requestId) { FML_DLOG(INFO) << "ExecuteAccessibilityAction input-params-> elementId=" - << elementId << " action=" << action - << " requestId=" << requestId - << " *actionArguments=" << actionArguments; + << elementId << " action=" << action; + CHECK_NULL_PTR_WITH_RET(actionArguments, ExecuteAccessibilityAction); - if (actionArguments == nullptr) { - FML_DLOG(ERROR) << "OhosAccessibilityBridge::ExecuteAccessibilityAction " - "actionArguments = null"; - return ARKUI_ACCESSIBILITY_NATIVE_RESULT_FAILED; - } + AccessibiltiyChangesWithXComponentId(); // 获取当前elementid对应的flutter语义节点 auto flutterNode = GetFlutterSemanticsNode(static_cast(elementId)); + if (!g_flutterSemanticsTree.count(flutterNode.id)) { + LOGE("ExecuteAccessibilityAction: GetFlutterSemanticsNode id=%{public}ld is null", elementId); + } + + /** + * 将被遮挡的flutter节点显示在屏幕上 + * @NOTE: arkui无障碍缺少showOnScreen动作 + */ + PerformShowOnScreenAction(flutterNode); // 根据当前elementid和无障碍动作类型,发送无障碍事件 switch (action) { /** Response to a click. 16 */ - case ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_CLICK: { - /** Click event, sent after the UI component responds. 1 */ - auto clickEventType = ArkUI_AccessibilityEventType:: - ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_CLICKED; - 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, - {}); + case ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_CLICK: + PerformClickAction(elementId, action, flutterNode); break; - } + /** Response to a long click. 32 */ - case ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_LONG_CLICK: { - /** Long click event, sent after the UI component responds. 2 */ - auto longClickEventType = ArkUI_AccessibilityEventType:: - ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_LONG_CLICKED; - Flutter_SendAccessibilityAsyncEvent(elementId, longClickEventType); - FML_DLOG(INFO) << "ExecuteAccessibilityAction -> action: longclick(" - << action << ")" << " event: longclick(" - << longClickEventType << ")"; - // 解析arkui的屏幕动作 -> flutter对应节点的屏幕动作 - auto flutterLongPressAction = ArkuiActionsToFlutterActions(action); - DispatchSemanticsAction(static_cast(elementId), - flutterLongPressAction, {}); + case ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_LONG_CLICK: + PerformLongClickAction(elementId, action, flutterNode); break; - } + /** Accessibility focus acquisition. 64 */ - case ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_GAIN_ACCESSIBILITY_FOCUS: { - // 解析arkui的获焦 -> flutter对应节点的获焦 - auto flutterGainFocusAction = ArkuiActionsToFlutterActions(action); - DispatchSemanticsAction(static_cast(elementId), - flutterGainFocusAction, {}); - // 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); - 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); - } + case ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_GAIN_ACCESSIBILITY_FOCUS: + PerformGainFocusnAction(elementId, action, flutterNode); break; - } + /** Accessibility focus clearance. 128 */ - case ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_CLEAR_ACCESSIBILITY_FOCUS: { - // 解析arkui的失焦 -> flutter对应节点的失焦 - auto flutterLoseFocusAction = ArkuiActionsToFlutterActions(action); - DispatchSemanticsAction(static_cast(elementId), - flutterLoseFocusAction, {}); - /** Accessibility focus cleared event, sent after the UI component - * responds. 65536 */ - auto clearFocusEventType = ArkUI_AccessibilityEventType:: - ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_ACCESSIBILITY_FOCUS_CLEARED; - Flutter_SendAccessibilityAsyncEvent(elementId, clearFocusEventType); - FML_DLOG(INFO) << "ExecuteAccessibilityAction -> action: clearfocus(" - << action << ")" << " event: clearfocus(" - << clearFocusEventType << ")"; + case ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_CLEAR_ACCESSIBILITY_FOCUS: + PerformClearFocusAction(elementId, action, flutterNode); break; - } + /** Forward scroll action. 256 */ - case ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SCROLL_FORWARD: { - // flutter scroll forward with different situations - if (flutterNode.HasAction(ACTIONS_::kScrollUp)) { - 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); - if (currComponetType == "ListView") { - /** Scrolled event, sent when a scrollable component experiences a - * scroll event. 4096 */ - ArkUI_AccessibilityEventType scrollEventType1 = - ArkUI_AccessibilityEventType:: - ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_SCROLLED; - Flutter_SendAccessibilityAsyncEvent(elementId, scrollEventType1); - FML_DLOG(INFO) - << "ExecuteAccessibilityAction -> action: scroll forward(" << action - << ")" << " event: scroll forward(" << scrollEventType1 << ")"; - } + case ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SCROLL_FORWARD: + PerformScrollUpAction(elementId, action, flutterNode); break; - } + /** Backward scroll action. 512 */ - case ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SCROLL_BACKWARD: { - // flutter scroll down with different situations - if (flutterNode.HasAction(ACTIONS_::kScrollDown)) { - 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; - - Flutter_SendAccessibilityAsyncEvent( - elementId, ArkUI_AccessibilityEventType:: - ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_SELECTED); - DispatchSemanticsAction(static_cast(elementId), - ACTIONS_::kDecrease, {}); - } else { - } - std::string currComponetType = GetNodeComponentType(flutterNode); - if (currComponetType == "ListView") { - /** Scrolled event, sent when a scrollable component experiences a - * scroll event. 4096 */ - ArkUI_AccessibilityEventType scrollBackwardEventType = - ArkUI_AccessibilityEventType:: - ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_SCROLLED; - Flutter_SendAccessibilityAsyncEvent(elementId, scrollBackwardEventType); - FML_DLOG(INFO) - << "ExecuteAccessibilityAction -> action: scroll backward(" - << action << ")" << " event: scroll backward(" - << scrollBackwardEventType << ")"; - } + case ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SCROLL_BACKWARD: + PerformScrollDownAction(elementId, action, flutterNode); break; - } + /** Copy action for text content. 1024 */ - case ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_COPY: { - FML_DLOG(INFO) << "ExecuteAccessibilityAction -> action: copy(" << action - << ")"; - DispatchSemanticsAction(static_cast(elementId), ACTIONS_::kCopy, {}); + case ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_COPY: + PerformClipboardAction(elementId, action); break; - } + /** Paste action for text content. 2048 */ - case ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_PASTE: { - FML_DLOG(INFO) << "ExecuteAccessibilityAction -> action: paste(" << action - << ")"; - DispatchSemanticsAction(static_cast(elementId), ACTIONS_::kPaste, {}); + case ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_PASTE: + PerformClipboardAction(elementId, action); break; - } + /** Cut action for text content. 4096 */ - case ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_CUT: { - FML_DLOG(INFO) << "ExecuteAccessibilityAction -> action: cut(" << action << ")"; - DispatchSemanticsAction(static_cast(elementId), ACTIONS_::kCut, {}); + case ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_CUT: + PerformClipboardAction(elementId, action); break; - } + /** Text selection action, requiring the setting of selectTextBegin, * TextEnd, and TextInForward parameters to select a text * segment in the text box. 8192 */ - case ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SELECT_TEXT: { - FML_DLOG(INFO) << "ExecuteAccessibilityAction -> action: select text(" - << action << ")"; - // 输入框文本选择操作 + case ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SELECT_TEXT: PerformSelectText(flutterNode, action, actionArguments); break; - } + /** Text content setting action. 16384 */ - case ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SET_TEXT: { - FML_DLOG(INFO) << "ExecuteAccessibilityAction -> action: set text(" - << action << ")"; - // 输入框设置文本 + case ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SET_TEXT: PerformSetText(flutterNode, action, actionArguments); break; - } + /** Cursor position setting action. 1048576 */ - case ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SET_CURSOR_POSITION: { - FML_DLOG(INFO) - << "ExecuteAccessibilityAction -> action: set cursor position(" - << action << ")"; + case ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SET_CURSOR_POSITION: + PerformSetCursorPosition(flutterNode, action, actionArguments); break; - } + /** Invalid action. 0 */ - case ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_INVALID: { - /** Invalid event. 0 */ - ArkUI_AccessibilityEventType invalidEventType = - ArkUI_AccessibilityEventType:: - ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_INVALID; - Flutter_SendAccessibilityAsyncEvent(elementId, invalidEventType); - FML_DLOG(ERROR) << "ExecuteAccessibilityAction -> action: invalid(" - << action << ")" << " event: innvalid(" - << invalidEventType << ")"; + case ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_INVALID: + PerformInvalidAction(elementId, action, flutterNode); break; - } - default: { + + default: /** custom semantics action */ - } + PerformCustomAction(flutterNode, action, actionArguments); } FML_DLOG(INFO) << "--- ExecuteAccessibilityAction is end ---"; return ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL; @@ -1891,9 +1585,6 @@ flutter::SemanticsAction OhosAccessibilityBridge::ArkuiActionsToFlutterActions( 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; @@ -1903,218 +1594,199 @@ flutter::SemanticsAction OhosAccessibilityBridge::ArkuiActionsToFlutterActions( return ACTIONS_::kSetText; default: - // might not match to the valid action in arkui + // might not match to the valid action in arkui return ACTIONS_::kCustomAction; } } /** - * 自定义无障碍异步事件发送 + * flutter发送无障碍自定义主动播报事件 */ -void OhosAccessibilityBridge::Flutter_SendAccessibilityAsyncEvent( - int64_t elementId, +void OhosAccessibilityBridge::Flutter_SendAccessibilityAnnounceEvent( + std::unique_ptr& message, ArkUI_AccessibilityEventType eventType) { - if (provider_ == nullptr) { - FML_DLOG(ERROR) << "Flutter_SendAccessibilityAsyncEvent " - "AccessibilityProvider = nullptr"; - return; - } - if (OH_GetSdkApiVersion() >= 13) { - // 1.创建eventInfo对象 - ArkUI_AccessibilityEventInfo* (*OH_ArkUI_CreateAccessibilityEventInfo)(void) = - OhosAccessibilityDDL::DLLoadCreateEventInfoFunc("OH_ArkUI_CreateAccessibilityEventInfo"); - if (OH_ArkUI_CreateAccessibilityEventInfo == nullptr) { - LOGE("OH_ArkUI_CreateAccessibilityEventInfo is null, %{public}s", dlerror()); - } - ArkUI_AccessibilityEventInfo* eventInfo = OH_ArkUI_CreateAccessibilityEventInfo(); - if (eventInfo == nullptr) { - FML_DLOG(ERROR) << "Flutter_SendAccessibilityAsyncEvent " - "OH_ArkUI_CreateAccessibilityEventInfo eventInfo = null"; - return; - } - - // 2.创建的elementinfo并根据对应id的flutternode进行属性初始化 - ArkUI_AccessibilityElementInfo* (*OH_ArkUI_CreateAccessibilityElementInfo)(void) = - OhosAccessibilityDDL::DLLoadCreateElemInfoFunc("OH_ArkUI_CreateAccessibilityElementInfo"); - if (OH_ArkUI_CreateAccessibilityElementInfo == nullptr) { - LOGE("OH_ArkUI_CreateAccessibilityElementInfo is null, %{public}s", dlerror()); - } - ArkUI_AccessibilityElementInfo* _elementInfo = OH_ArkUI_CreateAccessibilityElementInfo(); - FlutterNodeToElementInfoById(_elementInfo, elementId); - // 若为获焦事件,则设置当前elementinfo获焦 - int32_t (*OH_ArkUI_AccessibilityElementInfoSetAccessibilityFocused)(ArkUI_AccessibilityElementInfo*, bool) = - OhosAccessibilityDDL::DLLoadSetElemBoolFunc("OH_ArkUI_AccessibilityElementInfoSetAccessibilityFocused"); - if (OH_ArkUI_AccessibilityElementInfoSetAccessibilityFocused == nullptr) { - LOGE("OH_ArkUI_AccessibilityElementInfoSetAccessibilityFocused is null, %{public}s", dlerror()); - } - if (eventType == ArkUI_AccessibilityEventType::ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_ACCESSIBILITY_FOCUSED) { - ARKUI_ACCESSIBILITY_CALL_CHECK( - OH_ArkUI_AccessibilityElementInfoSetAccessibilityFocused(_elementInfo, true) - ); - } - - // 3.设置发送事件,如配置获焦、失焦、点击、滑动事件 - int32_t (*OH_ArkUI_AccessibilityEventSetEventType)(ArkUI_AccessibilityEventInfo*, ArkUI_AccessibilityEventType) = - OhosAccessibilityDDL::DLLoadSetEventFunc("OH_ArkUI_AccessibilityEventSetEventType"); - if (OH_ArkUI_AccessibilityEventSetEventType == nullptr) { - LOGE("OH_ArkUI_AccessibilityEventSetEventType is null, %{public}s", dlerror()); - } - ARKUI_ACCESSIBILITY_CALL_CHECK(OH_ArkUI_AccessibilityEventSetEventType(eventInfo, eventType)); - - // 4.将eventinfo事件和当前elementinfo进行绑定 - int32_t (*OH_ArkUI_AccessibilityEventSetElementInfo)(ArkUI_AccessibilityEventInfo*, ArkUI_AccessibilityElementInfo*) = - OhosAccessibilityDDL::DLLoadSetEventElemFunc("OH_ArkUI_AccessibilityEventSetElementInfo"); - if (OH_ArkUI_AccessibilityEventSetElementInfo == nullptr) { - LOGE("OH_ArkUI_AccessibilityEventSetElementInfo is null, %{public}s", dlerror()); - } - ARKUI_ACCESSIBILITY_CALL_CHECK(OH_ArkUI_AccessibilityEventSetElementInfo(eventInfo, _elementInfo)); - - // 5.调用接口发送到ohos侧 - auto callback = [](int32_t errorCode) { - FML_DLOG(INFO) - << "Flutter_SendAccessibilityAsyncEvent callback-> errorCode =" - << errorCode; - }; - - // 6.发送event到OH侧 - void (*OH_ArkUI_SendAccessibilityAsyncEvent)(ArkUI_AccessibilityProvider*, ArkUI_AccessibilityEventInfo*, void (*callback)(int32_t)) = - OhosAccessibilityDDL::DLLoadSendAsyncEventFunc("OH_ArkUI_SendAccessibilityAsyncEvent"); - if (OH_ArkUI_SendAccessibilityAsyncEvent == nullptr) { - LOGE("OH_ArkUI_SendAccessibilityAsyncEvent is null, %{public}s", dlerror()); - } - OH_ArkUI_SendAccessibilityAsyncEvent(provider_, eventInfo, callback); - - // 7.销毁新创建的elementinfo, eventinfo - void (*OH_ArkUI_DestoryAccessibilityElementInfo)(ArkUI_AccessibilityElementInfo*) = - OhosAccessibilityDDL::DLLoadDestroyElemFunc("OH_ArkUI_DestoryAccessibilityElementInfo"); - if (OH_ArkUI_DestoryAccessibilityElementInfo == nullptr) { - LOGE("OH_ArkUI_DestoryAccessibilityElementInfo is null, %{public}s", dlerror()); - } - OH_ArkUI_DestoryAccessibilityElementInfo(_elementInfo); - _elementInfo = nullptr; - - void (*OH_ArkUI_DestoryAccessibilityEventInfo)(ArkUI_AccessibilityEventInfo*) = - OhosAccessibilityDDL::DLLoadDestroyEventFunc("OH_ArkUI_DestoryAccessibilityEventInfo"); - if (OH_ArkUI_DestoryAccessibilityEventInfo == nullptr) { - LOGE("OH_ArkUI_DestoryAccessibilityEventInfo is null, %{public}s", dlerror()); - } - OH_ArkUI_DestoryAccessibilityEventInfo(eventInfo); - eventInfo = nullptr; - } - - FML_DLOG(INFO) << "OhosAccessibilityBridge::Flutter_SendAccessibilityAsyncEvent is end"; - return; + if (OHOS_API_VERSION < 13) { return; } + AccessibiltiyChangesWithXComponentId(); + std::lock_guard lock(XComponentAdapter::GetInstance()->mutex_); + auto provider_ = XComponentAdapter::GetInstance()->GetAccessibilityProvider(xcomponentId_); + CHECK_NULL_PTR_RET_VOID(provider_, Flutter_SendAccessibilityAnnounceEvent); + + // 创建并设置屏幕朗读事件 + auto OH_ArkUI_CreateAccessibilityEventInfo = + OhosAccessibilityDDL::DLLoadCreateEventInfoFunc(ArkUIAccessibilityConstant::ARKUI_CREATE_EVENT); + CHECK_DLL_NULL_PTR(OH_ArkUI_CreateAccessibilityEventInfo); + auto* announceEventInfo = OH_ArkUI_CreateAccessibilityEventInfo(); + + auto OH_ArkUI_AccessibilityEventSetEventType = + OhosAccessibilityDDL::DLLoadSetEventFunc(ArkUIAccessibilityConstant::ARKUI_SET_EVENT_TYPE); + CHECK_DLL_NULL_PTR(OH_ArkUI_AccessibilityEventSetEventType); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityEventSetEventType( + announceEventInfo, + ArkUI_AccessibilityEventType::ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_ANNOUNCE_FOR_ACCESSIBILITY)); + + auto OH_ArkUI_AccessibilityEventSetTextAnnouncedForAccessibility = + OhosAccessibilityDDL::DLLoadSetEventStringFunc(ArkUIAccessibilityConstant::ARKUI_SET_ANNOUNCED_TEXT); + CHECK_DLL_NULL_PTR(OH_ArkUI_AccessibilityEventSetTextAnnouncedForAccessibility); + 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; + }; + + auto OH_ArkUI_SendAccessibilityAsyncEvent = + OhosAccessibilityDDL::DLLoadSendAsyncEventFunc(ArkUIAccessibilityConstant::ARKUI_SEND_A11Y_EVENT); + CHECK_DLL_NULL_PTR(OH_ArkUI_SendAccessibilityAsyncEvent); + OH_ArkUI_SendAccessibilityAsyncEvent(provider_, announceEventInfo, callback); + + auto OH_ArkUI_DestoryAccessibilityEventInfo = + OhosAccessibilityDDL::DLLoadDestroyEventFunc(ArkUIAccessibilityConstant::ARKUI_DESTORY_EVENT); + CHECK_DLL_NULL_PTR(OH_ArkUI_DestoryAccessibilityEventInfo); + OH_ArkUI_DestoryAccessibilityEventInfo(announceEventInfo); + announceEventInfo = nullptr; } /** - * 判断当前语义节点是否获焦 + * 自定义无障碍异步事件发送 */ -bool OhosAccessibilityBridge::IsNodeFocusable( - const flutter::SemanticsNode& node) +void OhosAccessibilityBridge::Flutter_SendAccessibilityAsyncEvent( + int64_t elementId, + ArkUI_AccessibilityEventType eventType) { - if (node.HasFlag(FLAGS_::kScopesRoute)) { - return false; - } - if (node.HasFlag(FLAGS_::kIsFocusable)) { - return true; - } - // Always consider platform views focusable. - if (node.IsPlatformViewNode()) { - return true; - } - // Always consider actionable nodes focusable. - if (node.actions != 0) { - return true; - } - if ((node.flags & FOCUSABLE_FLAGS) != 0) { - return true; - } - if ((node.actions & ~FOCUSABLE_FLAGS) != 0) { - return true; - } - // Consider text nodes focusable. - return !node.label.empty() || !node.value.empty() || !node.hint.empty(); + if (OHOS_API_VERSION < 13) { return; } + AccessibiltiyChangesWithXComponentId(); + std::lock_guard lock(XComponentAdapter::GetInstance()->mutex_); + auto provider_ = XComponentAdapter::GetInstance()->GetAccessibilityProvider(xcomponentId_); + CHECK_NULL_PTR_RET_VOID(provider_, Flutter_SendAccessibilityAsyncEvent); + + // 创建eventInfo对象 + auto OH_ArkUI_CreateAccessibilityEventInfo = + OhosAccessibilityDDL::DLLoadCreateEventInfoFunc(ArkUIAccessibilityConstant::ARKUI_CREATE_EVENT); + CHECK_DLL_NULL_PTR(OH_ArkUI_CreateAccessibilityEventInfo); + auto* eventInfo = OH_ArkUI_CreateAccessibilityEventInfo(); + CHECK_NULL_PTR(eventInfo, Flutter_SendAccessibilityAsyncEvent); + + // 创建的elementinfo并根据对应id的flutternode进行属性初始化 + auto OH_ArkUI_CreateAccessibilityElementInfo = + OhosAccessibilityDDL::DLLoadCreateElemInfoFunc(ArkUIAccessibilityConstant::ARKUI_CREATE_NODE); + CHECK_DLL_NULL_PTR(OH_ArkUI_CreateAccessibilityElementInfo); + ArkUI_AccessibilityElementInfo* _elementInfo = OH_ArkUI_CreateAccessibilityElementInfo(); + FlutterSetElementInfoProperties(_elementInfo, elementId); + + // 将eventinfo事件和当前elementinfo进行绑定 + auto OH_ArkUI_AccessibilityEventSetElementInfo = + OhosAccessibilityDDL::DLLoadSetEventElemFunc(ArkUIAccessibilityConstant::ARKUI_EVENT_SET_NODE); + CHECK_DLL_NULL_PTR(OH_ArkUI_AccessibilityEventSetElementInfo); + ARKUI_ACCESSIBILITY_CALL_CHECK(OH_ArkUI_AccessibilityEventSetElementInfo(eventInfo, _elementInfo)); + + // 设置发送事件,如配置获焦、失焦、点击、滑动事件 + auto OH_ArkUI_AccessibilityEventSetEventType = + OhosAccessibilityDDL::DLLoadSetEventFunc(ArkUIAccessibilityConstant::ARKUI_SET_EVENT_TYPE); + CHECK_DLL_NULL_PTR(OH_ArkUI_AccessibilityEventSetEventType); + ARKUI_ACCESSIBILITY_CALL_CHECK(OH_ArkUI_AccessibilityEventSetEventType(eventInfo, eventType)); + + // 调用接口发送到ohos侧 + auto callback = [](int32_t errorCode) { + FML_DLOG(INFO) + << "Flutter_SendAccessibilityAsyncEvent callback-> errorCode =" + << errorCode; + }; + + // 发送event到OH侧 + auto OH_ArkUI_SendAccessibilityAsyncEvent = + OhosAccessibilityDDL::DLLoadSendAsyncEventFunc(ArkUIAccessibilityConstant::ARKUI_SEND_A11Y_EVENT); + CHECK_DLL_NULL_PTR(OH_ArkUI_SendAccessibilityAsyncEvent); + OH_ArkUI_SendAccessibilityAsyncEvent(provider_, eventInfo, callback); + + // 销毁新创建的elementinfo, eventinfo + auto OH_ArkUI_DestoryAccessibilityElementInfo = + OhosAccessibilityDDL::DLLoadDestroyElemFunc(ArkUIAccessibilityConstant::ARKUI_DESTORY_NODE); + CHECK_DLL_NULL_PTR(OH_ArkUI_DestoryAccessibilityElementInfo); + OH_ArkUI_DestoryAccessibilityElementInfo(_elementInfo); + _elementInfo = nullptr; + + auto OH_ArkUI_DestoryAccessibilityEventInfo = + OhosAccessibilityDDL::DLLoadDestroyEventFunc(ArkUIAccessibilityConstant::ARKUI_DESTORY_EVENT); + CHECK_DLL_NULL_PTR(OH_ArkUI_DestoryAccessibilityEventInfo); + OH_ArkUI_DestoryAccessibilityEventInfo(eventInfo); + eventInfo = nullptr; + + FML_DLOG(INFO) << "OhosAccessibilityBridge::Flutter_SendAccessibilityAsyncEvent is end"; + return; } -void OhosAccessibilityBridge::PerformSetText( - flutter::SemanticsNode flutterNode, - ArkUI_Accessibility_ActionType action, - ArkUI_AccessibilityActionArguments* actionArguments) {} - -void OhosAccessibilityBridge::PerformSelectText( - flutter::SemanticsNode flutterNode, - ArkUI_Accessibility_ActionType action, - ArkUI_AccessibilityActionArguments* actionArguments) {} - /** * 获取当前flutter节点的组件类型,并映射为arkui组件 */ std::string OhosAccessibilityBridge::GetNodeComponentType( - const flutter::SemanticsNode& node) + const SemanticsNodeExtent& node) { if (node.HasFlag(FLAGS_::kIsButton)) { - return "Button"; + return BUTTON_WIDGET_NAME; } if (node.HasFlag(FLAGS_::kIsTextField)) { - return "TextField"; + return EDIT_TEXT_WIDGET_NAME; } if (node.HasFlag(FLAGS_::kIsMultiline)) { - return "TextArea"; + return EDIT_MULTILINE_TEXT_WIDGET_NAME; } if (node.HasFlag(FLAGS_::kIsLink)) { - return "Link"; + return LINK_WIDGET_NAME; } if (node.HasFlag(FLAGS_::kIsSlider) || node.HasAction(ACTIONS_::kIncrease) || node.HasAction(ACTIONS_::kDecrease)) { - return "Slider"; + return SLIDER_WIDGET_NAME; } if (node.HasFlag(FLAGS_::kIsHeader)) { - return "Header"; + return HEADER_WIDGET_NAME; } if (node.HasFlag(FLAGS_::kIsImage)) { - return "Image"; + return IMAGE_WIDGET_NAME; } if (node.HasFlag(FLAGS_::kHasCheckedState)) { if (node.HasFlag(FLAGS_::kIsInMutuallyExclusiveGroup)) { // arkui没有RadioButton,这里透传为RadioButton - return "RadioButton"; + return RADIO_BUTTON_WIDGET_NAME; } else { - return "Checkbox"; + return CHECK_BOX_WIDGET_NAME; } } if (node.HasFlag(FLAGS_::kHasToggledState)) { - return "Switch"; + return SWITCH_WIDGET_NAME; } if (node.HasAction(ACTIONS_::kIncrease) || node.HasAction(ACTIONS_::kDecrease)) { - return "SeekBar"; + return SEEKBAR_WIDGET_NAME; } if (node.HasFlag(FLAGS_::kHasImplicitScrolling)) { if (node.HasAction(ACTIONS_::kScrollLeft) || node.HasAction(ACTIONS_::kScrollRight)) { - return "HorizontalScrollView"; + return SCROLL_WIDGET_NAME; } else { - return "ScrollView"; + return SCROLL_WIDGET_NAME; } } if ((!node.label.empty() || !node.tooltip.empty() || !node.hint.empty())) { - return "Text"; + return TEXT_WIDGET_NAME; } - return "Widget"; + return OTHER_WIDGET_NAME; } /** * 判断当前节点是否为textfield文本框 */ -bool OhosAccessibilityBridge::IsTextField(flutter::SemanticsNode flutterNode) +bool OhosAccessibilityBridge::IsTextField(SemanticsNodeExtent flutterNode) { return flutterNode.HasFlag(FLAGS_::kIsTextField); } /** * 判断当前节点是否为滑动条slider类型 */ -bool OhosAccessibilityBridge::IsSlider(flutter::SemanticsNode flutterNode) +bool OhosAccessibilityBridge::IsSlider(SemanticsNodeExtent flutterNode) { return flutterNode.HasFlag(FLAGS_::kIsSlider); } @@ -2122,34 +1794,23 @@ bool OhosAccessibilityBridge::IsSlider(flutter::SemanticsNode flutterNode) * 判断当前flutter节点组件是否可点击 */ bool OhosAccessibilityBridge::IsNodeClickable( - flutter::SemanticsNode flutterNode) + SemanticsNodeExtent 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) + SemanticsNodeExtent flutterNode) { - return flutterNode.HasFlag(FLAGS_::kIsHidden) ? false : true; + return !flutterNode.HasFlag(FLAGS_::kIsHidden); } /** * 判断当前flutter节点组件是否具备checkable属性 */ bool OhosAccessibilityBridge::IsNodeCheckable( - flutter::SemanticsNode flutterNode) + SemanticsNodeExtent flutterNode) { return flutterNode.HasFlag(FLAGS_::kHasCheckedState) || flutterNode.HasFlag(FLAGS_::kHasToggledState); @@ -2158,7 +1819,7 @@ bool OhosAccessibilityBridge::IsNodeCheckable( * 判断当前flutter节点组件是否checked/unchecked(checkbox、radio button) */ bool OhosAccessibilityBridge::IsNodeChecked( - flutter::SemanticsNode flutterNode) + SemanticsNodeExtent flutterNode) { return flutterNode.HasFlag(FLAGS_::kIsChecked) || flutterNode.HasFlag(FLAGS_::kIsToggled); @@ -2167,7 +1828,7 @@ bool OhosAccessibilityBridge::IsNodeChecked( * 判断当前flutter节点组件是否选中 */ bool OhosAccessibilityBridge::IsNodeSelected( - flutter::SemanticsNode flutterNode) + SemanticsNodeExtent flutterNode) { return flutterNode.HasFlag(FLAGS_::kIsSelected); } @@ -2175,7 +1836,7 @@ bool OhosAccessibilityBridge::IsNodeSelected( * 判断当前flutter节点组件是否为密码输入框 */ bool OhosAccessibilityBridge::IsNodePassword( - flutter::SemanticsNode flutterNode) + SemanticsNodeExtent flutterNode) { return flutterNode.HasFlag(FLAGS_::kIsTextField) && flutterNode.HasFlag(FLAGS_::kIsObscured); @@ -2184,7 +1845,7 @@ bool OhosAccessibilityBridge::IsNodePassword( * 判断当前flutter节点组件是否支持长按功能 */ bool OhosAccessibilityBridge::IsNodeHasLongPress( - flutter::SemanticsNode flutterNode) + SemanticsNodeExtent flutterNode) { return flutterNode.HasAction(ACTIONS_::kLongPress); } @@ -2192,24 +1853,81 @@ bool OhosAccessibilityBridge::IsNodeHasLongPress( * 判断当前flutter节点是否enabled */ bool OhosAccessibilityBridge::IsNodeEnabled( - flutter::SemanticsNode flutterNode) + SemanticsNodeExtent flutterNode) { return !flutterNode.HasFlag(FLAGS_::kHasEnabledState) || flutterNode.HasFlag(FLAGS_::kIsEnabled); } +/** + * 判断当前flutter节点是否在当前屏幕上显示 + */ +bool OhosAccessibilityBridge::IsNodeShowOnScreen(SemanticsNodeExtent flutterNode) +{ + return flutterNode.HasAction(ACTIONS_::kShowOnScreen); +} /** * 判断当前节点是否已经滑动 */ bool OhosAccessibilityBridge::HasScrolled( - const flutter::SemanticsNode& flutterNode) + const SemanticsNodeExtent& flutterNode) +{ + return flutterNode.scrollPosition != std::nan("") && + flutterNode.previousScrollPosition != std::nan("") && + flutterNode.previousScrollPosition != flutterNode.scrollPosition; +} +/** + * 判断当前节点是否改变标签文本 + */ +bool OhosAccessibilityBridge::HasChangedLabel(const SemanticsNodeExtent& flutterNode) +{ + if (flutterNode.label.empty() && flutterNode.previousLabel.empty()) { + return false; + } + return flutterNode.label.empty() || + flutterNode.previousLabel.empty() || + flutterNode.label != flutterNode.previousLabel; +} +/** + * 判断当前语义节点是否可获焦 + */ +bool OhosAccessibilityBridge::IsNodeFocusable( + const SemanticsNodeExtent& node) +{ + if (node.HasFlag(FLAGS_::kScopesRoute)) { + return false; + } + if (node.HasFlag(FLAGS_::kIsFocusable)) { + return true; + } + // Always consider platform views focusable. + if (node.IsPlatformViewNode()) { + return true; + } + // Always consider actionable nodes focusable. + if (node.actions != 0) { + return true; + } + if ((node.flags & FOCUSABLE_FLAGS) != 0) { + return true; + } + if ((node.actions & ~FOCUSABLE_FLAGS) != 0) { + return true; + } + // Consider text nodes focusable. + return !node.label.empty() || !node.value.empty() || !node.hint.empty(); +} +/** + * 判断当前flutter节点是否获焦 + */ +bool OhosAccessibilityBridge::IsNodeFocused(const SemanticsNodeExtent& flutterNode) { - return flutterNode.scrollPosition != std::nan(""); + return flutterNode.HasFlag(FLAGS_::kIsFocused); } /** * 判断是否可滑动 */ bool OhosAccessibilityBridge::IsNodeScrollable( - flutter::SemanticsNode flutterNode) + SemanticsNodeExtent flutterNode) { return flutterNode.HasAction(ACTIONS_::kScrollLeft) || flutterNode.HasAction(ACTIONS_::kScrollRight) || @@ -2220,14 +1938,14 @@ bool OhosAccessibilityBridge::IsNodeScrollable( * 判断当前节点组件是否是滑动组件,如: listview, gridview等 */ bool OhosAccessibilityBridge::IsScrollableWidget( - flutter::SemanticsNode flutterNode) + SemanticsNodeExtent flutterNode) { return flutterNode.HasFlag(FLAGS_::kHasImplicitScrolling); } void OhosAccessibilityBridge::AddRouteNodes( - std::vector edges, - flutter::SemanticsNode node) + std::vector edges, + SemanticsNodeExtent node) { if (node.HasFlag(FLAGS_::kScopesRoute)) { edges.emplace_back(node); @@ -2238,7 +1956,7 @@ void OhosAccessibilityBridge::AddRouteNodes( } } -std::string OhosAccessibilityBridge::GetRouteName(flutter::SemanticsNode node) +std::string OhosAccessibilityBridge::GetRouteName(SemanticsNodeExtent node) { if (node.HasFlag(FLAGS_::kNamesRoute) && !node.label.empty()) { return node.label; @@ -2253,7 +1971,7 @@ std::string OhosAccessibilityBridge::GetRouteName(flutter::SemanticsNode node) return ""; } -void OhosAccessibilityBridge::onWindowNameChange(flutter::SemanticsNode route) +void OhosAccessibilityBridge::OnWindowNameChange(SemanticsNodeExtent route) { std::string routeName = GetRouteName(route); if (routeName.empty()) { @@ -2261,11 +1979,12 @@ void OhosAccessibilityBridge::onWindowNameChange(flutter::SemanticsNode route) } Flutter_SendAccessibilityAsyncEvent( static_cast(route.id), - ArkUI_AccessibilityEventType::ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_PAGE_CONTENT_UPDATE); + ArkUI_AccessibilityEventType:: + ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_PAGE_CONTENT_UPDATE); } -void OhosAccessibilityBridge::removeSemanticsNode( - flutter::SemanticsNode nodeToBeRemoved) +void OhosAccessibilityBridge::RemoveSemanticsNode( + SemanticsNodeExtent nodeToBeRemoved) { if (!g_flutterSemanticsTree.size()) { FML_DLOG(ERROR) << "OhosAccessibilityBridge::removeSemanticsNode -> " @@ -2280,7 +1999,7 @@ void OhosAccessibilityBridge::removeSemanticsNode( for (auto it = g_parentChildIdVec.begin(); it != g_parentChildIdVec.end(); it++) { if (it->first == nodeToBeRemovedParentId && it->second == nodeToBeRemoved.id) { - g_parentChildIdVec.erase(it); + g_parentChildIdVec.erase(it); } } } @@ -2294,18 +2013,35 @@ void OhosAccessibilityBridge::ClearFlutterSemanticsCaches() g_flutterSemanticsTree.clear(); g_parentChildIdVec.clear(); g_screenRectMap.clear(); - g_actions_mp.clear(); - g_flutterNavigationVec.clear(); + Flutter_SendAccessibilityAsyncEvent( + accessibilityFocusedNode.id, + ArkUI_AccessibilityEventType::ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_ACCESSIBILITY_FOCUS_CLEARED); + accessibilityFocusedNode = {}; } /** - * extent common struct SemanticsNode to - * derived struct SemanticsNodeExtent + * 更新扩展版flutter语义节点 */ -SemanticsNodeExtent OhosAccessibilityBridge::SetAndGetSemanticsNodeExtent( +SemanticsNodeExtent OhosAccessibilityBridge::UpdatetSemanticsNodeExtent( flutter::SemanticsNode node) { SemanticsNodeExtent nodeEx = SemanticsNodeExtent(); + // 获取更新前的flutter节点信息 + if (g_flutterSemanticsTree.size() > 0) { + auto prevNode = GetFlutterSemanticsNode(node.id); + nodeEx.hadPreviousConfig = true; + nodeEx.previousFlags = prevNode.flags; + nodeEx.previousActions = prevNode.actions; + nodeEx.previousTextSelectionBase = prevNode.textSelectionBase; + nodeEx.previousTextSelectionExtent = prevNode.textSelectionExtent; + nodeEx.previousScrollPosition = prevNode.scrollPosition; + nodeEx.previousScrollExtentMax = prevNode.scrollExtentMax; + nodeEx.previousScrollExtentMin = prevNode.scrollExtentMin; + nodeEx.previousValue = prevNode.value; + nodeEx.previousLabel = prevNode.label; + } + // 更新当前flutter节点信息 + nodeEx.isNull = false; nodeEx.id = std::move(node.id); nodeEx.flags = std::move(node.flags); nodeEx.actions = std::move(node.actions); @@ -2333,87 +2069,93 @@ SemanticsNodeExtent OhosAccessibilityBridge::SetAndGetSemanticsNodeExtent( 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); + nodeEx.customAccessibilityActions = std::move(node.customAccessibilityActions); return nodeEx; } void OhosAccessibilityBridge::GetSemanticsNodeDebugInfo( - flutter::SemanticsNode node) + SemanticsNodeExtent node) { FML_DLOG(INFO) << "-------------------SemanticsNode------------------"; SkMatrix _transform = node.transform.asM33(); FML_DLOG(INFO) << "node.id=" << node.id; FML_DLOG(INFO) << "node.label=" << node.label; + FML_DLOG(INFO) << "node.previousLabel=" << node.previousLabel; FML_DLOG(INFO) << "node.tooltip=" << node.tooltip; FML_DLOG(INFO) << "node.hint=" << node.hint; FML_DLOG(INFO) << "node.flags=" << node.flags; + FML_DLOG(INFO) << "node.previousFlags=" << node.previousFlags; FML_DLOG(INFO) << "node.actions=" << node.actions; + FML_DLOG(INFO) << "node.previousActions=" << node.previousActions; + FML_DLOG(INFO) << "node.value=" << node.value; + FML_DLOG(INFO) << "node.previousValue=" << node.previousValue; FML_DLOG(INFO) << "node.rect= {" << node.rect.fLeft << ", " << node.rect.fTop - << ", " << node.rect.fRight << ", " << node.rect.fBottom - << "}"; + << ", " << node.rect.fRight << ", " << node.rect.fBottom + << "}"; FML_DLOG(INFO) << "node.transform -> kMScaleX=" - << _transform.get(SkMatrix::kMScaleX); + << _transform.get(SkMatrix::kMScaleX); FML_DLOG(INFO) << "node.transform -> kMSkewX=" - << _transform.get(SkMatrix::kMSkewX); + << _transform.get(SkMatrix::kMSkewX); FML_DLOG(INFO) << "node.transform -> kMTransX=" - << _transform.get(SkMatrix::kMTransX); + << _transform.get(SkMatrix::kMTransX); FML_DLOG(INFO) << "node.transform -> kMSkewY=" - << _transform.get(SkMatrix::kMSkewY); + << _transform.get(SkMatrix::kMSkewY); FML_DLOG(INFO) << "node.transform -> kMScaleY=" - << _transform.get(SkMatrix::kMScaleY); + << _transform.get(SkMatrix::kMScaleY); FML_DLOG(INFO) << "node.transform -> kMTransY=" - << _transform.get(SkMatrix::kMTransY); + << _transform.get(SkMatrix::kMTransY); FML_DLOG(INFO) << "node.transform -> kMPersp0=" - << _transform.get(SkMatrix::kMPersp0); + << _transform.get(SkMatrix::kMPersp0); FML_DLOG(INFO) << "node.transform -> kMPersp1=" - << _transform.get(SkMatrix::kMPersp1); + << _transform.get(SkMatrix::kMPersp1); FML_DLOG(INFO) << "node.transform -> kMPersp2=" - << _transform.get(SkMatrix::kMPersp2); + << _transform.get(SkMatrix::kMPersp2); FML_DLOG(INFO) << "node.maxValueLength=" << node.maxValueLength; FML_DLOG(INFO) << "node.currentValueLength=" << node.currentValueLength; FML_DLOG(INFO) << "node.textSelectionBase=" << node.textSelectionBase; + FML_DLOG(INFO) << "node.previousTextSelectionBase=" << node.previousTextSelectionBase; FML_DLOG(INFO) << "node.textSelectionExtent=" << node.textSelectionExtent; - FML_DLOG(INFO) << "node.textSelectionBase=" << node.textSelectionBase; + FML_DLOG(INFO) << "node.previousTextSelectionExtent=" << node.previousTextSelectionExtent; FML_DLOG(INFO) << "node.platformViewId=" << node.platformViewId; FML_DLOG(INFO) << "node.scrollChildren=" << node.scrollChildren; FML_DLOG(INFO) << "node.scrollIndex=" << node.scrollIndex; FML_DLOG(INFO) << "node.scrollPosition=" << node.scrollPosition; + FML_DLOG(INFO) << "node.previousScrollPosition=" << node.previousScrollPosition; FML_DLOG(INFO) << "node.scrollIndex=" << node.scrollIndex; - FML_DLOG(INFO) << "node.scrollPosition=" << node.scrollPosition; FML_DLOG(INFO) << "node.scrollExtentMax=" << node.scrollExtentMax; + FML_DLOG(INFO) << "node.previousScrollExtentMax=" << node.previousScrollExtentMax; FML_DLOG(INFO) << "node.scrollExtentMin=" << node.scrollExtentMin; + FML_DLOG(INFO) << "node.previousScrollExtentMin=" << node.previousScrollExtentMin; FML_DLOG(INFO) << "node.elevation=" << node.elevation; FML_DLOG(INFO) << "node.thickness=" << node.thickness; FML_DLOG(INFO) << "node.textDirection=" << node.textDirection; FML_DLOG(INFO) << "node.childrenInTraversalOrder.size()=" - << node.childrenInTraversalOrder.size(); + << node.childrenInTraversalOrder.size(); for (uint32_t i = 0; i < node.childrenInTraversalOrder.size(); i++) { FML_DLOG(INFO) << "node.childrenInTraversalOrder[" << i - << "]=" << node.childrenInTraversalOrder[i]; + << "]=" << node.childrenInTraversalOrder[i]; } FML_DLOG(INFO) << "node.childrenInHitTestOrder.size()=" - << node.childrenInHitTestOrder.size(); + << node.childrenInHitTestOrder.size(); for (uint32_t i = 0; i < node.childrenInHitTestOrder.size(); i++) { FML_DLOG(INFO) << "node.childrenInHitTestOrder[" << i - << "]=" << node.childrenInHitTestOrder[i]; + << "]=" << node.childrenInHitTestOrder[i]; } FML_DLOG(INFO) << "node.customAccessibilityActions.size()=" - << node.customAccessibilityActions.size(); + << node.customAccessibilityActions.size(); for (uint32_t i = 0; i < node.customAccessibilityActions.size(); i++) { FML_DLOG(INFO) << "node.customAccessibilityActions[" << i - << "]=" << node.customAccessibilityActions[i]; + << "]=" << node.customAccessibilityActions[i]; } FML_DLOG(INFO) << "------------------SemanticsNode-----------------"; } void OhosAccessibilityBridge::GetSemanticsFlagsDebugInfo( - flutter::SemanticsNode node) + SemanticsNodeExtent node) { FML_DLOG(INFO) << "----------------SemanticsFlags-------------------------"; FML_DLOG(INFO) << "node.id=" << node.id; @@ -2467,4 +2209,23 @@ void OhosAccessibilityBridge::GetSemanticsFlagsDebugInfo( << customAccessibilityAction.hint; FML_DLOG(INFO) << "------------CustomAccessibilityAction--------------"; } + +void OhosAccessibilityBridge::GetSemanticsDebugInfo() +{ + // 打印flutter语义树的不同节点的属性信息 + for (const auto& item : g_flutterSemanticsTree) { + FML_DLOG(INFO) << "g_flutterSemanticsTree -> {" << item.first << ", " + << item.second.id << "}"; + } + for (const auto& item : g_parentChildIdVec) { + FML_DLOG(INFO) << "g_parentChildIdVec -> (" << item.first << ", " + << item.second << ")"; + } + //打印按层次遍历排序的flutter语义树节点id数组 + std::vector levelOrderTraversalTree = GetLevelOrderTraversalTree(0); + for (const auto& item: levelOrderTraversalTree) { + FML_DLOG(INFO) << "LevelOrderTraversalTree: { " << item << " }"; + } +} + } // namespace flutter diff --git a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h index 5f03fdc839f5ec12e06b19a5cadd4e57f21eeb61..673f762d3770743aa4f7f97d9455651c058778dd 100644 --- a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h +++ b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h @@ -19,6 +19,8 @@ #include #include #include +#include +#include #include #include "flutter/fml/mapping.h" #include "flutter/lib/ui/semantics/custom_accessibility_action.h" @@ -26,316 +28,372 @@ #include "native_accessibility_channel.h" #include "ohos_accessibility_features.h" #include "ohos_accessibility_ddl.h" +#include "flutter/shell/platform/ohos/utils/ohos_utils.h" +#include "flutter/shell/platform/ohos/utils/arkui_accessibility_constant.h" +#include "third_party/skia/include/core/SkMatrix.h" +#include "third_party/skia/include/core/SkScalar.h" +#include "third_party/skia/include/core/SkPoint.h" namespace flutter { typedef flutter::SemanticsFlags FLAGS_; typedef flutter::SemanticsAction ACTIONS_; struct AbsoluteRect { - float left; - float top; - float right; - float bottom; - - static constexpr AbsoluteRect MakeEmpty() { - return AbsoluteRect{0.0, 0.0, 0.0, 0.0}; - } -}; + float left; + float top; + float right; + float bottom; + static constexpr AbsoluteRect MakeEmpty() { + return AbsoluteRect{0.0, 0.0, 0.0, 0.0}; + } + static constexpr AbsoluteRect MakeRect( + float left, float top, float right, float bottom) { + return AbsoluteRect{left, top, right, bottom}; + } +}; struct SemanticsNodeExtent : flutter::SemanticsNode { - int32_t parentId = -1; - AbsoluteRect abRect = AbsoluteRect::MakeEmpty(); - int32_t previousFlags; - int32_t previousActions; - int32_t previousTextSelectionBase; - int32_t previousTextSelectionExtent; - float previousScrollPosition; - float previousScrollExtentMax; - float previousScrollExtentMin; - std::string previousValue; - std::string previousLabel; + bool isNull = false; + SkM44 globalTransform = SkM44{}; + AbsoluteRect absoluteRect = AbsoluteRect::MakeEmpty(); + int32_t parentId = -1; + bool hadPreviousConfig = false; + int32_t previousNodeId = -1; + int32_t previousFlags = 0; + int32_t previousActions = 0; + int32_t previousTextSelectionBase = -1; + int32_t previousTextSelectionExtent = -1; + double previousScrollPosition = std::nan(""); + double previousScrollExtentMax = std::nan(""); + double previousScrollExtentMin = std::nan(""); + std::string previousValue; + std::string previousLabel; + bool HasPrevAction(SemanticsAction action) const + { + return (previousActions & this->actions) != 0; + } + bool HasPrevFlag(SemanticsFlags flag) const + { + return (previousFlags & this->flags) != 0; + } }; /** - * flutter和ohos的无障碍服务桥接 + * 桥接flutter无障碍功能和ohos无障碍系统服务 */ class OhosAccessibilityBridge { - public: - 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_; - ArkUI_AccessibilityProvider* provider_; - - void OnOhosAccessibilityStateChange( - int64_t shellHolderId, - bool ohosAccessibilityEnabled); - - void SetNativeShellHolderId(int64_t id); - - void updateSemantics(flutter::SemanticsNodeUpdates update, - flutter::CustomAccessibilityActionUpdates actions); - - void DispatchSemanticsAction(int32_t id, - flutter::SemanticsAction action, - fml::MallocMapping args); - - void Announce(std::unique_ptr& message); - - flutter::SemanticsNode GetFlutterSemanticsNode(int32_t id); - - int32_t FindAccessibilityNodeInfosById( - int64_t elementId, - ArkUI_AccessibilitySearchMode mode, - int32_t requestId, - ArkUI_AccessibilityElementInfoList* elementList); - int32_t FindAccessibilityNodeInfosByText( - int64_t elementId, - const char* text, - int32_t requestId, - ArkUI_AccessibilityElementInfoList* elementList); - int32_t FindFocusedAccessibilityNode( - int64_t elementId, - ArkUI_AccessibilityFocusType focusType, - int32_t requestId, - ArkUI_AccessibilityElementInfo* elementinfo); - int32_t FindNextFocusAccessibilityNode( - int64_t elementId, - ArkUI_AccessibilityFocusMoveDirection direction, - int32_t requestId, - ArkUI_AccessibilityElementInfo* elementList); - int32_t ExecuteAccessibilityAction( - int64_t elementId, - ArkUI_Accessibility_ActionType action, - ArkUI_AccessibilityActionArguments* actionArguments, - int32_t requestId); - int32_t ClearFocusedFocusAccessibilityNode(); - int32_t GetAccessibilityNodeCursorPosition(int64_t elementId, - int32_t requestId, - int32_t* index); - - void Flutter_SendAccessibilityAsyncEvent( - int64_t elementId, - ArkUI_AccessibilityEventType eventType); - void FlutterNodeToElementInfoById( - ArkUI_AccessibilityElementInfo* elementInfoFromList, - int64_t elementId); - int32_t GetParentId(int64_t elementId); - - void ConvertChildRelativeRectToScreenRect(flutter::SemanticsNode node); - std::pair, std::pair> - GetAbsoluteScreenRect(int32_t flutterNodeId); - void SetAbsoluteScreenRect(int32_t flutterNodeId, - float left, - float top, - float right, - float bottom); - - SemanticsNodeExtent SetAndGetSemanticsNodeExtent(flutter::SemanticsNode node); - - void FlutterScrollExecution( - flutter::SemanticsNode node, - ArkUI_AccessibilityElementInfo* elementInfoFromList); - - void ClearFlutterSemanticsCaches(); - - private: - OhosAccessibilityBridge(); - static OhosAccessibilityBridge* bridgeInstance; - 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; - - flutter::SemanticsNode inputFocusedNode; - flutter::SemanticsNode lastInputFocusedNode; - flutter::SemanticsNode accessibilityFocusedNode; - - std::vector> g_parentChildIdVec; - std::map g_flutterSemanticsTree; - std::unordered_map< - int32_t, - std::pair, std::pair>> - g_screenRectMap; - std::unordered_map g_actions_mp; - std::vector g_flutterNavigationVec; - - const std::map - ArkUI_ACTION_TYPE_MAP_ = { - {"invalid", ArkUI_Accessibility_ActionType:: - ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_INVALID}, - {"click", ArkUI_Accessibility_ActionType:: - ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_CLICK}, - {"long press", ArkUI_Accessibility_ActionType:: - ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_LONG_CLICK}, - {"focus acquisition", - ArkUI_Accessibility_ActionType:: - ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_GAIN_ACCESSIBILITY_FOCUS}, - {"focus clearance", - ArkUI_Accessibility_ActionType:: - ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_CLEAR_ACCESSIBILITY_FOCUS}, - {"forward scroll", - ArkUI_Accessibility_ActionType:: - ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SCROLL_FORWARD}, - {"backward scroll", - ArkUI_Accessibility_ActionType:: - ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SCROLL_BACKWARD}, - {"copy text", ArkUI_Accessibility_ActionType:: - ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_COPY}, - {"paste text", ArkUI_Accessibility_ActionType:: - ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_PASTE}, - {"cut text", ArkUI_Accessibility_ActionType:: - ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_CUT}, - {"text selection", - ArkUI_Accessibility_ActionType:: - ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SELECT_TEXT}, - {"set text", ArkUI_Accessibility_ActionType:: - ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SET_TEXT}, - {"text cursor position setting", - ArkUI_Accessibility_ActionType:: - ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SET_CURSOR_POSITION}, - }; - - static const int32_t FOCUSABLE_FLAGS = - static_cast(FLAGS_::kHasCheckedState) | - static_cast(FLAGS_::kIsChecked) | - static_cast(FLAGS_::kIsSelected) | - static_cast(FLAGS_::kIsTextField) | - static_cast(FLAGS_::kIsFocused) | - static_cast(FLAGS_::kHasEnabledState) | - static_cast(FLAGS_::kIsEnabled) | - static_cast(FLAGS_::kIsInMutuallyExclusiveGroup) | - static_cast(FLAGS_::kHasToggledState) | - static_cast(FLAGS_::kIsToggled) | - static_cast(FLAGS_::kHasToggledState) | - static_cast(FLAGS_::kIsFocusable) | - static_cast(FLAGS_::kIsSlider); - - static const int32_t SCROLLABLE_ACTIONS = - static_cast(ACTIONS_::kScrollUp) | - static_cast(ACTIONS_::kScrollDown) | - static_cast(ACTIONS_::kScrollLeft) | - static_cast(ACTIONS_::kScrollRight); - - void FlutterSetElementInfoProperties( - ArkUI_AccessibilityElementInfo* elementInfoFromList, - int64_t elementId); - void FlutterSetElementInfoOperationActions( - ArkUI_AccessibilityElementInfo* elementInfoFromList, - std::string widget_type); - void FlutterTreeToArkuiTree( - ArkUI_AccessibilityElementInfoList* elementInfoList); - void BuildArkUISemanticsTree( - 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( - ArkUI_Accessibility_ActionType arkui_action); - - bool HasScrolled(const flutter::SemanticsNode& flutterNode); - - bool IsNodeFocusable(const flutter::SemanticsNode& flutterNode); - bool IsNodeCheckable(flutter::SemanticsNode flutterNode); - bool IsNodeChecked(flutter::SemanticsNode flutterNode); - bool IsNodeSelected(flutter::SemanticsNode flutterNode); - bool IsNodeClickable(flutter::SemanticsNode flutterNode); - bool IsNodeScrollable(flutter::SemanticsNode flutterNode); - bool IsNodePassword(flutter::SemanticsNode flutterNode); - bool IsNodeVisible(flutter::SemanticsNode flutterNode); - bool IsNodeEnabled(flutter::SemanticsNode flutterNode); - bool IsNodeHasLongPress(flutter::SemanticsNode flutterNode); - - bool IsTextField(flutter::SemanticsNode flutterNode); - bool IsSlider(flutter::SemanticsNode flutterNode); - bool IsScrollableWidget(flutter::SemanticsNode flutterNode); - void PerformSetText(flutter::SemanticsNode flutterNode, - ArkUI_Accessibility_ActionType action, - ArkUI_AccessibilityActionArguments* actionArguments); - void PerformSelectText(flutter::SemanticsNode flutterNode, - ArkUI_Accessibility_ActionType action, - ArkUI_AccessibilityActionArguments* actionArguments); - - void AddRouteNodes(std::vector edges, - flutter::SemanticsNode node); - std::string GetRouteName(flutter::SemanticsNode node); - void onWindowNameChange(flutter::SemanticsNode route); - void removeSemanticsNode(flutter::SemanticsNode nodeToBeRemoved); - - void GetSemanticsNodeDebugInfo(flutter::SemanticsNode node); - void GetSemanticsFlagsDebugInfo(flutter::SemanticsNode node); - void GetCustomActionDebugInfo( - flutter::CustomAccessibilityAction customAccessibilityAction); - - void FlutterPageUpdate(ArkUI_AccessibilityEventType eventType); - void RequestFocusWhenPageUpdate(); - - bool Contains(const std::string source, const std::string target); +public: + static OhosAccessibilityBridge* GetInstance(); + OhosAccessibilityBridge(const OhosAccessibilityBridge&) = delete; + OhosAccessibilityBridge& operator=(const OhosAccessibilityBridge&) = delete; + + std::string xcomponentId_; + bool isFlutterNavigated_; + int64_t native_shell_holder_id_; + + void OnOhosAccessibilityStateChange(bool ohosAccessibilityEnabled, int64_t shellholderId); + + void UpdateSemantics(flutter::SemanticsNodeUpdates update, + flutter::CustomAccessibilityActionUpdates actions); + + void DispatchSemanticsAction(int32_t id, + flutter::SemanticsAction action, + fml::MallocMapping args); + + void Announce(std::unique_ptr& message); + void OnTap(int32_t nodeId); + void OnLongPress(int32_t nodeId); + void OnTooltip(std::unique_ptr& message); + + SemanticsNodeExtent GetFlutterSemanticsNode(int32_t id); + int32_t GetParentId(int64_t elementId); + + int32_t FindAccessibilityNodeInfosById( + int64_t elementId, + ArkUI_AccessibilitySearchMode mode, + int32_t requestId, + ArkUI_AccessibilityElementInfoList* elementList); + int32_t FindAccessibilityNodeInfosByText( + int64_t elementId, + const char* text, + int32_t requestId, + ArkUI_AccessibilityElementInfoList* elementList); + int32_t FindFocusedAccessibilityNode( + int64_t elementId, + ArkUI_AccessibilityFocusType focusType, + int32_t requestId, + ArkUI_AccessibilityElementInfo* elementinfo); + int32_t FindNextFocusAccessibilityNode( + int64_t elementId, + ArkUI_AccessibilityFocusMoveDirection direction, + int32_t requestId, + ArkUI_AccessibilityElementInfo* elementList); + int32_t ExecuteAccessibilityAction( + int64_t elementId, + ArkUI_Accessibility_ActionType action, + ArkUI_AccessibilityActionArguments* actionArguments, + int32_t requestId); + int32_t ClearFocusedFocusAccessibilityNode(); + int32_t GetAccessibilityNodeCursorPosition(int64_t elementId, + int32_t requestId, + int32_t* index); + + void Flutter_SendAccessibilityAsyncEvent( + int64_t elementId, + ArkUI_AccessibilityEventType eventType); + void Flutter_SendAccessibilityAnnounceEvent( + std::unique_ptr& message, + ArkUI_AccessibilityEventType eventType); + + void RelativeRectToScreenRect(SemanticsNodeExtent& node); + AbsoluteRect GetAbsoluteScreenRect(SemanticsNodeExtent& flutterNode); + void SetAbsoluteScreenRect(SemanticsNodeExtent& flutterNode, + float left, + float top, + float right, + float bottom); + + SemanticsNodeExtent UpdatetSemanticsNodeExtent(flutter::SemanticsNode node); + + void FlutterScrollExecution( + SemanticsNodeExtent node, + ArkUI_AccessibilityElementInfo* elementInfoFromList); + + void ClearFlutterSemanticsCaches(); + +private: + OhosAccessibilityBridge(); + bool isAccessibilityEnabled_; + static std::unique_ptr bridgeInstance_; + std::shared_ptr nativeAccessibilityChannel_; + std::shared_ptr accessibilityFeatures_; + + std::unordered_map> g_flutterSemanticsTreeXComponents; + std::unordered_map>> g_parentChildIdVecXComponents; + std::unordered_map> g_screenRectMapXComponents; + + std::unordered_map g_flutterSemanticsTree; + std::vector> g_parentChildIdVec; + std::unordered_map g_screenRectMap; + std::unordered_map g_globalTransformMap; + + SemanticsNodeExtent inputFocusedNode; + SemanticsNodeExtent lastInputFocusedNode; + SemanticsNodeExtent accessibilityFocusedNode; + + static const int32_t OHOS_API_VERSION; + static const int32_t ARKUI_ACCESSIBILITY_ROOT_PARENT_ID = -2100000; + static const int32_t RET_ERROR_STATE_CODE = -1; + 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; + + const char* ARKUI_ACTION_ARG_SET_TEXT = "setText"; + const char* ARKUI_ACTION_ARG_SELECT_TEXT_START = "selectTextBegin"; + const char* ARKUI_ACTION_ARG_SELECT_TEXT_END = "selectTextEnd"; + + const std::string OTHER_WIDGET_NAME = "View"; + const std::string TEXT_WIDGET_NAME = "Text"; + const std::string EDIT_TEXT_WIDGET_NAME = "TextInput"; + const std::string EDIT_MULTILINE_TEXT_WIDGET_NAME = "TextArea"; + const std::string IMAGE_WIDGET_NAME = "Image"; + const std::string SCROLL_WIDGET_NAME = "Scroll"; + const std::string BUTTON_WIDGET_NAME = "Button"; + const std::string LINK_WIDGET_NAME = "Link"; + const std::string SLIDER_WIDGET_NAME = "Slider"; + const std::string HEADER_WIDGET_NAME = "Header"; + const std::string RADIO_BUTTON_WIDGET_NAME = "Radio"; + const std::string CHECK_BOX_WIDGET_NAME = "Checkbox"; + const std::string SWITCH_WIDGET_NAME = "Toggle"; + const std::string SEEKBAR_WIDGET_NAME = "SeekBar"; + + const std::map + ArkUI_ACTION_TYPE_MAP_ = { + {"invalid", ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_INVALID}, + {"click", ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_CLICK}, + {"long press", ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_LONG_CLICK}, + {"focus acquisition", ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_GAIN_ACCESSIBILITY_FOCUS}, + {"focus clearance", ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_CLEAR_ACCESSIBILITY_FOCUS}, + {"forward scroll", ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SCROLL_FORWARD}, + {"backward scroll", ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SCROLL_BACKWARD}, + {"copy text", ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_COPY}, + {"paste text", ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_PASTE}, + {"cut text", ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_CUT}, + {"text selection", ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SELECT_TEXT}, + {"set text", ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SET_TEXT}, + {"text cursor position setting", ArkUI_Accessibility_ActionType::ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SET_CURSOR_POSITION}, + }; + + static const int32_t FOCUSABLE_FLAGS = + static_cast(FLAGS_::kHasCheckedState) | + static_cast(FLAGS_::kIsChecked) | + static_cast(FLAGS_::kIsSelected) | + static_cast(FLAGS_::kIsTextField) | + static_cast(FLAGS_::kIsFocused) | + static_cast(FLAGS_::kHasEnabledState) | + static_cast(FLAGS_::kIsEnabled) | + static_cast(FLAGS_::kIsInMutuallyExclusiveGroup) | + static_cast(FLAGS_::kHasToggledState) | + static_cast(FLAGS_::kIsToggled) | + static_cast(FLAGS_::kHasToggledState) | + static_cast(FLAGS_::kIsFocusable) | + static_cast(FLAGS_::kIsSlider); + + static const int32_t SCROLLABLE_ACTIONS = + static_cast(ACTIONS_::kScrollUp) | + static_cast(ACTIONS_::kScrollDown) | + static_cast(ACTIONS_::kScrollLeft) | + static_cast(ACTIONS_::kScrollRight); + + void FlutterSetElementInfoProperties( + ArkUI_AccessibilityElementInfo* elementInfoFromList, + int64_t elementId); + void FlutterSetElementInfoOperationActions( + ArkUI_AccessibilityElementInfo* elementInfoFromList, + std::string widget_type); + void BuildArkUISemanticsTree( + int64_t elementId, + ArkUI_AccessibilityElementInfo* elementInfoFromList, + ArkUI_AccessibilityElementInfoList* elementList); + + std::vector GetLevelOrderTraversalTree(int32_t rootId); + SemanticsNodeExtent GetFlutterRootSemanticsNode(); + std::string GetNodeComponentType(const SemanticsNodeExtent& node); + flutter::SemanticsAction ArkuiActionsToFlutterActions( + ArkUI_Accessibility_ActionType arkui_action); + + void BuildParentChildNodeIdRelation(const SemanticsNodeExtent& node); + void ComputeGlobalTransform(); + void ConvertRectToGlobal(SemanticsNodeExtent& node); + SkPoint ApplyTransform(SkPoint& point, const SkM44& transform); + + bool HasScrolled(const SemanticsNodeExtent& flutterNode); + bool HasChangedLabel(const SemanticsNodeExtent& flutterNode); + + bool IsNodeFocusable(const SemanticsNodeExtent& flutterNode); + bool IsNodeFocused(const SemanticsNodeExtent& flutterNode); + bool IsNodeCheckable(SemanticsNodeExtent flutterNode); + bool IsNodeChecked(SemanticsNodeExtent flutterNode); + bool IsNodeSelected(SemanticsNodeExtent flutterNode); + bool IsNodeClickable(SemanticsNodeExtent flutterNode); + bool IsNodeScrollable(SemanticsNodeExtent flutterNode); + bool IsNodePassword(SemanticsNodeExtent flutterNode); + bool IsNodeVisible(SemanticsNodeExtent flutterNode); + bool IsNodeEnabled(SemanticsNodeExtent flutterNode); + bool IsNodeHasLongPress(SemanticsNodeExtent flutterNode); + bool IsNodeShowOnScreen(SemanticsNodeExtent flutterNode); + + bool IsTextField(SemanticsNodeExtent flutterNode); + bool IsSlider(SemanticsNodeExtent flutterNode); + bool IsScrollableWidget(SemanticsNodeExtent flutterNode); + + void PerformClickAction(int64_t elementId, + ArkUI_Accessibility_ActionType action, + SemanticsNodeExtent flutterNode); + void PerformLongClickAction(int64_t elementId, + ArkUI_Accessibility_ActionType action, + SemanticsNodeExtent flutterNode); + void PerformGainFocusnAction(int64_t elementId, + ArkUI_Accessibility_ActionType action, + SemanticsNodeExtent flutterNode); + void PerformClearFocusAction(int64_t elementId, + ArkUI_Accessibility_ActionType action, + SemanticsNodeExtent flutterNode); + void PerformScrollUpAction(int64_t elementId, + ArkUI_Accessibility_ActionType action, + SemanticsNodeExtent flutterNode); + void PerformScrollDownAction(int64_t elementId, + ArkUI_Accessibility_ActionType action, + SemanticsNodeExtent flutterNode); + void PerformClipboardAction(int64_t elementId, + ArkUI_Accessibility_ActionType action); + void PerformInvalidAction(int64_t elementId, + ArkUI_Accessibility_ActionType action, + SemanticsNodeExtent flutterNode); + void PerformSetText(SemanticsNodeExtent flutterNode, + ArkUI_Accessibility_ActionType action, + ArkUI_AccessibilityActionArguments* actionArguments); + void PerformSelectText(SemanticsNodeExtent flutterNode, + ArkUI_Accessibility_ActionType action, + ArkUI_AccessibilityActionArguments* actionArguments); + void PerformSetCursorPosition(SemanticsNodeExtent flutterNode, + ArkUI_Accessibility_ActionType action, + ArkUI_AccessibilityActionArguments* actionArguments); + void PerformCustomAction(SemanticsNodeExtent flutterNode, + ArkUI_Accessibility_ActionType action, + ArkUI_AccessibilityActionArguments* actionArguments); + void PerformShowOnScreenAction(SemanticsNodeExtent flutterNode); + + void AddRouteNodes(std::vector edges, + SemanticsNodeExtent node); + std::string GetRouteName(SemanticsNodeExtent node); + void OnWindowNameChange(SemanticsNodeExtent route); + void RemoveSemanticsNode(SemanticsNodeExtent nodeToBeRemoved); + + void GetSemanticsNodeDebugInfo(SemanticsNodeExtent node); + void GetSemanticsFlagsDebugInfo(SemanticsNodeExtent node); + void GetCustomActionDebugInfo( + flutter::CustomAccessibilityAction customAccessibilityAction); + + void RequestFocusWhenPageUpdate(int32_t requestFocusId); + bool Contains(const std::string source, const std::string target); + std::pair GetRealScaleFactor(); + void DoubleClickRouteToNewPage(SemanticsNodeExtent node); + void GetSemanticsDebugInfo(); + void AccessibiltiyChangesWithXComponentId(); }; 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, + 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, + 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 diff --git a/shell/platform/ohos/accessibility/ohos_accessibility_ddl.cpp b/shell/platform/ohos/accessibility/ohos_accessibility_ddl.cpp index 39ea57e8a991583519592ae3fd4e3d206c2e3786..f4be1cadc677663d61541558cf7f060af3458f16 100644 --- a/shell/platform/ohos/accessibility/ohos_accessibility_ddl.cpp +++ b/shell/platform/ohos/accessibility/ohos_accessibility_ddl.cpp @@ -284,4 +284,19 @@ GetNativeA11yProvider OhosAccessibilityDDL::DLLoadGetNativeA11yProvider(const ch } return symbol; } + +GetFindActionArgs OhosAccessibilityDDL::DLLoadGetFindActionArgs(const char* symbolName) +{ + LIBHANDLE handler = LOAD_LIB(ACCESSIBILITY_LIB_NAME); + if (handler == nullptr) { + return nullptr; + } + + auto symbol = reinterpret_cast(LOAD_SYM(handler, symbolName)); + if (symbol == nullptr) { + CLOSE_LIB(handler); + return nullptr; + } + return symbol; +} } \ No newline at end of file diff --git a/shell/platform/ohos/accessibility/ohos_accessibility_ddl.h b/shell/platform/ohos/accessibility/ohos_accessibility_ddl.h index c5d6c3263147685c653237323624f99b5b7cfa81..92f27eee156bf6c52ff8a18942c7af0032c36066 100644 --- a/shell/platform/ohos/accessibility/ohos_accessibility_ddl.h +++ b/shell/platform/ohos/accessibility/ohos_accessibility_ddl.h @@ -42,6 +42,7 @@ using SetEventElemFunc = int32_t (*)(ArkUI_AccessibilityEventInfo*, ArkUI_Access using SetReqFocusFunc = int32_t (*)(ArkUI_AccessibilityEventInfo*, int32_t); using GetNativeA11yProvider = int32_t (*)(OH_NativeXComponent*, ArkUI_AccessibilityProvider**); +using GetFindActionArgs = int32_t (*)(ArkUI_AccessibilityActionArguments*, const char*, char**); class OhosAccessibilityDDL { public: @@ -72,11 +73,8 @@ public: static SetReqFocusFunc DLLoadSetReqFocusFunc(const char* symbolName); static GetNativeA11yProvider DLLoadGetNativeA11yProvider(const char* symbolName); - - + static GetFindActionArgs DLLoadGetFindActionArgs(const char* symbolName); }; - } // namespace flutter - #endif \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/cpp/types/libflutter/index.d.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/cpp/types/libflutter/index.d.ets index 629988a8937eed70c95f0b912e66693a7f247087..a683639641a3e5b0365847e7e9ace9833b6b5fa1 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 @@ -148,7 +148,13 @@ export const nativeSetAccessibilityFeatures: (accessibilityFeatureFlags: number, export const nativeAccessibilityStateChange: (nativeShellHolderId: number, state: Boolean) => void; -export const nativeAnnounce: (message: string) => void; +export const nativeAccessibilityAnnounce: (message: string) => void; + +export const nativeAccessibilityOnTap: (nodeId: number) => void; + +export const nativeAccessibilityOnLongPress: (nodeId: number) => void; + +export const nativeAccessibilityOnTooltip: (message: string) => void; export const nativeSetSemanticsEnabled: (nativeShellHolderId: number, enabled: boolean) => void; @@ -169,4 +175,6 @@ export const nativeUnicodeIsEmojiModifierBase: (code: number) => number; export const nativeUnicodeIsVariationSelector: (code: number) => number; -export const nativeUnicodeIsRegionalIndicatorSymbol: (code: number) => number; \ No newline at end of file +export const nativeUnicodeIsRegionalIndicatorSymbol: (code: number) => number; + +export const nativeGetXComponentId: (id: string) => number; \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/AccessibilityChannel.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/AccessibilityChannel.ets index bbc5a658ea5c9af1e99f69a45e737b861fabcfd8..1a6eba7bc91ba1ac1803177655c4324249c5ef6c 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/AccessibilityChannel.ets +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/AccessibilityChannel.ets @@ -122,24 +122,32 @@ export interface AccessibilityMessageHandler extends AccessibilityDelegate { announce(message: string): void; onTap(nodeId: number): void; onLongPress(nodeId: number): void; - onTooltip(nodeId: string): void; + onTooltip(message: string): void; } export class DefaultHandler implements AccessibilityMessageHandler { - private static TAG = "AccessibilityMessageHandler"; + private static TAG = "AccessibilityMessageHandler"; + announce(message: string): void { Log.i(DefaultHandler.TAG, "handler announce."); - flutter.nativeAnnounce(message); + flutter.nativeAccessibilityAnnounce(message); } + onTap(nodeId: number): void { Log.i(DefaultHandler.TAG, "handler onTap."); + flutter.nativeAccessibilityOnTap(nodeId); } + onLongPress(nodeId: number): void { Log.i(DefaultHandler.TAG, "handler onLongPress."); + flutter.nativeAccessibilityOnLongPress(nodeId); } - onTooltip(nodeId: string): void { + + onTooltip(message: string): void { Log.i(DefaultHandler.TAG, "handler onTooltip."); + flutter.nativeAccessibilityOnTooltip(message); } + updateSemantics(buffer: ByteBuffer, strings: string[], stringAttributeArgs: ByteBuffer[]): void { Log.i(DefaultHandler.TAG, "handler updateSemantics"); } 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 d13fd9859a57ae1231ceec489a091d3f84ec6a63..00bd70286650d9a45a3f4819682cf05cc02da8ef 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 @@ -36,7 +36,6 @@ import appRecovery from '@ohos.app.ability.appRecovery'; 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"; @@ -107,13 +106,6 @@ export class FlutterAbility extends UIAbility implements Host { if (flutterApplicationInfo.isDebugMode) { this.delegate?.initWindow(); } - - //冷启动对os是否开启无障碍服务进行查询 - let accessibilityState: boolean = accessibility.isOpenAccessibilitySync(); - if(accessibilityState) { - this.delegate?.getFlutterNapi()?.accessibilityStateChange(accessibilityState); - } - Log.i(TAG, `accessibility isOpen state -> ${JSON.stringify(accessibilityState)}`); } onDestroy() { @@ -319,7 +311,7 @@ export class FlutterAbility extends UIAbility implements Host { if (this.launchWant.parameters![FlutterAbilityLaunchConfigs.EXTRA_CACHED_ENGINE_ID] != undefined) { return this.launchWant.parameters![FlutterAbilityLaunchConfigs.EXTRA_CACHED_ENGINE_ID] as boolean; } - if (this.getCachedEngineId() != null) { + if (this.getCachedEngineId() != null && this.getCachedEngineId().length > 0) { // Prevent overwriting the existing state in a cached engine with restoration state. return false; } diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterAbilityAndEntryDelegate.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterAbilityAndEntryDelegate.ets index df567109745d0c2624d6c72283b277c67e13547c..1f3c735b0ef795858c91cc0ecf71c058ff421124 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterAbilityAndEntryDelegate.ets +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterAbilityAndEntryDelegate.ets @@ -35,7 +35,6 @@ import FlutterNapi from '../engine/FlutterNapi'; import { FlutterView } from '../../view/FlutterView'; import FlutterManager from './FlutterManager'; import Any from '../../plugin/common/Any'; -import inputMethod from '@ohos.inputMethod'; const TAG = "FlutterAbilityDelegate"; const PLUGINS_RESTORATION_BUNDLE_KEY = "plugins"; @@ -56,7 +55,6 @@ class FlutterAbilityAndEntryDelegate implements ExclusiveAppComponent private engineGroup?: FlutterEngineGroup; private isHost:boolean = false; private flutterView?: FlutterView; - private inputMethodController: inputMethod.InputMethodController = inputMethod.getController(); constructor(host?: Host) { this.host = host; @@ -99,7 +97,7 @@ class FlutterAbilityAndEntryDelegate implements ExclusiveAppComponent this.flutterEngine?.getNavigationChannel()?.popRoute(); this.flutterEngine?.getPlatformViewsController()?.setBackNodeControllers(); } else { - this.inputMethodController.detach(); + this.flutterEngine?.getTextInputChannel()?.textInputMethodHandler?.hide(); } }); } diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterEntry.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterEntry.ets index 38f0192ea066838fc8578c64bd7212ccd363e3ad..de27aa398fc3dd295515049a4a431f69dd3d41be 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterEntry.ets +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterEntry.ets @@ -152,15 +152,27 @@ export default class FlutterEntry implements Host { } shouldAttachEngineToAbility(): boolean { - return this.parameters![FlutterEntry.ARG_SHOULD_ATTACH_ENGINE_TO_ABILITY] as boolean + let param = this.parameters![FlutterEntry.ARG_SHOULD_ATTACH_ENGINE_TO_ABILITY]; + if (!param) { + return true; + } + return param as boolean } getCachedEngineId(): string { - return this.parameters![FlutterAbilityLaunchConfigs.EXTRA_CACHED_ENGINE_ID] as string + let param = this.parameters![FlutterAbilityLaunchConfigs.EXTRA_CACHED_ENGINE_ID]; + if (!param) { + return ""; + } + return param as string } getCachedEngineGroupId(): string | null { - return this.parameters![FlutterAbilityLaunchConfigs.EXTRA_CACHED_ENGINE_GROUP_ID] as string + let param = this.parameters![FlutterAbilityLaunchConfigs.EXTRA_CACHED_ENGINE_GROUP_ID]; + if (!param) { + return null; + } + return param as string } shouldDestroyEngineWithHost(): boolean { diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterPage.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterPage.ets index f5f641c4ec630bab11a5906ae3928c4ba8b0821e..64497b3d8c38bd13e6fb764d802279e799d8d278 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterPage.ets +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterPage.ets @@ -17,7 +17,7 @@ import Log from '../../util/Log'; import { FlutterView } from '../../view/FlutterView'; import FlutterManager from './FlutterManager'; import { DVModel, DVModelChildren, DynamicView } from '../../view/DynamicView/dynamicView'; - +import flutter from 'libflutter.so'; const TAG = "FlutterPage"; export const OHOS_FLUTTER_PAGE_UPDATE = "ohos_flutter_page_update"; @@ -56,6 +56,19 @@ export struct FlutterPage { .onLoad((context) => { this.flutterView?.onSurfaceCreated() Log.d(TAG, "XComponent onLoad "); + // 当xcomponent窗口部分显示或完全隐藏时触发回调 + this.getUIContext()?.getAttachedFrameNodeById(this.viewId)?.commonEvent.setOnVisibleAreaApproximateChange( + { ratios: [0.0, 1.0], expectedUpdateInterval: 0 }, + (ratioInc: boolean, ratio: number) => { + if (ratioInc) { + Log.i(TAG, "setOnVisibleAreaApproximateChange -> xcomponentId: " + this.viewId + + " ratioInc: " + ratioInc + " ratio: " + ratio); + flutter.nativeGetXComponentId(this.viewId); + // 保证获取xcomponentid之后再使用无障碍 + this.flutterView?.onAccessibilityIsOpen(); + } + } + ) }) .onDestroy(() => { Log.d(TAG, "XComponent onDestroy "); @@ -135,6 +148,19 @@ export struct FlutterPage { .onLoad((context) => { this.flutterView?.onSurfaceCreated() Log.d(TAG, "XComponent onLoad "); + // 当xcomponent窗口部分显示或完全隐藏时触发回调 + this.getUIContext()?.getAttachedFrameNodeById(this.viewId)?.commonEvent.setOnVisibleAreaApproximateChange( + { ratios: [0.0, 1.0], expectedUpdateInterval: 0 }, + (ratioInc: boolean, ratio: number) => { + if (ratioInc) { + Log.i(TAG, "setOnVisibleAreaApproximateChange -> xcomponentId: " + this.viewId + + " ratioInc: " + ratioInc + " ratio: " + ratio); + flutter.nativeGetXComponentId(this.viewId); + // 保证获取xcomponentid之后再使用无障碍 + this.flutterView?.onAccessibilityIsOpen(); + } + } + ) }) .onDestroy(() => { Log.d(TAG, "XComponent onDestroy "); diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/TouchEventProcessor.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/TouchEventProcessor.ets index e6100e08335ae582e9a048471e017163ba749c3a..582d2dca293534c70c87fe75256877b07891ecf8 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/TouchEventProcessor.ets +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/TouchEventProcessor.ets @@ -257,6 +257,10 @@ export default class TouchEventProcessor { //如果flutter端判断当前platformView是可点击的,则将事件分发出去 let touchEvent = TouchEventProcessor.getInstance().constureCustomTouchEvent(strings, top, left); let nodeController = params['nodeController'] as EmbeddingNodeController; + // 保证platformviewcontroller.ets的onTouch的down属性正常结束 + if (touchEvent.type === TouchType.Up) { + params['down'] === false; + } nodeController.postEvent(touchEvent) } else { //如果触摸事件为OH_NATIVEXCOMPONENT_DOWN=0,且只有一个手指,说明是下一次点击了,这时候需要清空上一次的数据 diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/editing/TextInputPlugin.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/editing/TextInputPlugin.ets index 5f3a67c3628f4209dce770b382a28fc442b66431..50be54c4b0ad32053498917760e5b350a72c2bf7 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/editing/TextInputPlugin.ets +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/editing/TextInputPlugin.ets @@ -324,9 +324,6 @@ class TextInputMethodHandlerImpl implements TextInputMethodHandler { private sendKeyboardStatusCallback = (state: inputMethod.KeyboardStatus) => { this.keyboardStatus = state; - if (state == inputMethod.KeyboardStatus.HIDE) { - this.plugin.textInputChannel.onConnectionClosed(this.inputTarget.id); - } } private selectByRangeCallback = (range: inputMethod.Range) => { diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/platform/PlatformViewsController.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/platform/PlatformViewsController.ets index 5c929c84186bf8f3e27de4978f6e83107b079e9e..45c4177ae286ebcf583a6b14fef02292f91e36db 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/platform/PlatformViewsController.ets +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/platform/PlatformViewsController.ets @@ -65,6 +65,20 @@ class DVModelJson { this.build = build; } } +enum TouchEventType { + /// Action code for when a primary pointer touched the screen. + ACTION_DOWN = 0, + /// Action code for when a primary pointer stopped touching the screen. + ACTION_UP = 1, + /// Action code for when the event only includes information about pointer movement. + ACTION_MOVE = 2, + /// Action code for when a motion event has been canceled. + ACTION_CANCEL = 3, + /// Action code for when a secondary pointer touched the screen. + ACTION_POINTER_DOWN = 5, + /// Action code for when a secondary pointer touched the screen. + ACTION_POINTER_UP = 6, +} const TAG = "PlatformViewsController" @@ -203,12 +217,12 @@ export default class PlatformViewsController implements PlatformViewsAccessibili let dvModel = viewWrapper.getDvModel() let params = dvModel.getLayoutParams() as Record; //接收到点击类型为down的时候 - if (touch.action == 0) { + if (touch.action === TouchEventType.ACTION_DOWN) { //将当前点击状态设置为true params['down'] = true //首次收到触控点击类型为 OH_NATIVEXCOMPONENT_DOWN ,则将存到列表中的事件分发出去 let touchEventArray: Array | undefined = params['touchEvent'] as Array - if (touchEventArray != undefined) { + if (touchEventArray !== undefined) { let nodeController = params['nodeController'] as EmbeddingNodeController; for (let it of touchEventArray) { nodeController.postEvent(it) @@ -216,9 +230,9 @@ export default class PlatformViewsController implements PlatformViewsAccessibili //首次执行完之后,将列表数据置空 params['touchEvent'] = undefined } - //当前接收的事件类型为up的时候 - } else if (touch.action == 1) { - //手指抬起之后,将当前点击状态设置为false。测试了一下,多个手指突然抬起,最后返回的状态也是1 + //当前接收的事件类型为up的时候 + } else if (touch.action === TouchEventType.ACTION_UP) { + //手指抬起之后,将当前点击状态设置为false。测试了一下,多个手指突然抬起,最后返回的状态也是ACTION_UP //所以,这边就以状态抬起,代表当前用户不点击platformview了 params['down'] = false } diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/view/AccessibilityBridge.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/view/AccessibilityBridge.ets index c7122f48701bd5fa6365bcb72e97a38b460ef132..c1cca165b662746188ce2ba82f76576f3a092578 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/view/AccessibilityBridge.ets +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/view/AccessibilityBridge.ets @@ -18,46 +18,8 @@ import Log from '../util/Log'; const TAG = "AccessibilityBridge"; -export default class AccessibilityBridge implements AccessibilityMessageHandler { - - private accessibilityChannel: AccessibilityChannel | null = null; - - constructor(){ - - } - - announce(message: string): void { - throw new Error('Method not implemented.'); - // android -> rootAccessibilityView.announceForAccessibility(message); - } - - onTap(nodeId: number): void { - throw new Error('Method not implemented.'); - // android -> sendAccessibilityEvent(nodeId, AccessibilityEvent.TYPE_VIEW_CLICKED); - } - - onLongPress(nodeId: number): void { - throw new Error('Method not implemented.'); - // android -> sendAccessibilityEvent(nodeId, AccessibilityEvent.TYPE_VIEW_LONG_CLICKED); - } - - onTooltip(nodeId: string): void { - throw new Error('Method not implemented.'); - } - - updateSemantics(buffer: ByteBuffer, strings: string[], stringAttributeArgs: ByteBuffer[]): void { - Log.d(TAG, "AccessibilityBridge.ets updateSemantics is called"); - } - - updateCustomAccessibilityActions(buffer: ByteBuffer, strings: string[]): void { - Log.d(TAG, "AccessibilityBridge.ets updateCustomAccessibilityActions is called"); - - } - - accessibilityStateChange(state: Boolean): void{ - Log.d(TAG, "AccessibilityBridge.ets accessibilityStateChange is called"); - } - +export default class AccessibilityBridge { + constructor() {} } export class AccessibilityManager { 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 c8b2fd67425f49e057dd98f78fe0623c9a08ed6d..c38327f4fbf6261bcf4236c81a9c3d3c7d6d3a5c 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 @@ -12,6 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import FlutterEngine from '../embedding/engine/FlutterEngine'; import Log from '../util/Log'; import { DVModel, DVModelChildren, DVModelEvents, DVModelParameters } from './DynamicView/dynamicView'; @@ -47,6 +48,7 @@ export class ViewportMetrics { systemGestureInsetBottom: number = 0; systemGestureInsetLeft: number = 0; physicalTouchSlop: number = -1; + displayFeatures: ArrayList = new ArrayList(); clone(): ViewportMetrics { const copy = new ViewportMetrics(); @@ -66,6 +68,7 @@ export class ViewportMetrics { copy.systemGestureInsetBottom = this.systemGestureInsetBottom; copy.systemGestureInsetLeft = this.systemGestureInsetLeft; copy.physicalTouchSlop = this.physicalTouchSlop; + copy.displayFeatures = this.displayFeatures; return copy; } @@ -85,10 +88,67 @@ export class ViewportMetrics { this.systemGestureInsetRight === other.systemGestureInsetRight && this.systemGestureInsetBottom === other.systemGestureInsetBottom && this.systemGestureInsetLeft === other.systemGestureInsetLeft && - this.physicalTouchSlop === other.physicalTouchSlop; + this.physicalTouchSlop === other.physicalTouchSlop && + this.displayFeatures === other.displayFeatures; + } +} + +export class DisplayFeature { + bounds: display.Rect[]; + type: DisplayFeatureType; + state: DisplayFeatureState; + + constructor(bounds: display.Rect[], type: DisplayFeatureType, state: DisplayFeatureState) { + this.bounds = bounds; + this.type = type; + this.state = state; + } + + getBounds(): display.Rect[] { + return this.bounds; + } + + getType(): DisplayFeatureType { + return this.type; + } + + getState(): DisplayFeatureState { + return this.state + } + + setBounds(bounds: display.Rect[]): void { + this.bounds = bounds; + } + + setType(type: DisplayFeatureType): void { + this.type = type; + } + + setState(state: DisplayFeatureState): void { + this.state = state; } } +export enum DisplayFeatureType{ + UNKNOWN = 0, + FOLD = 1, + HINGE = 2, + CUTOUT = 3 +}; + +export enum DisplayFeatureState{ + UNKNOWN = 0, + POSTURE_FLAT = 1, + POSTURE_HALF_OPENED = 2, +}; + +export enum DisplayFoldStatus{ + FOLD_STATUS_UNKNOWN = 0, + FOLD_STATUS_EXPANDED = 1, + FOLD_STATUS_FOLDED = 2, + FOLD_STATUS_HALF_FOLDED = 3 +}; + export class PlatformViewParas { width: number = 0.0; height: number = 0.0; @@ -144,6 +204,7 @@ export class FlutterView { this.id = viewId this.displayInfo = display.getDefaultDisplaySync(); this.viewportMetrics.devicePixelRatio = this.displayInfo?.densityPixels; + this.buildDisplayFeatures(display.getFoldStatus()); this.mainWindow = FlutterManager.getInstance() .getWindowStage(FlutterManager.getInstance().getUIAbility(context)) .getMainWindowSync(); @@ -164,6 +225,12 @@ export class FlutterView { this.gestureAvoidArea = this.mainWindow?.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM_GESTURE); this.keyboardAvoidArea = this.mainWindow?.getWindowAvoidArea(window.AvoidAreaType.TYPE_KEYBOARD); + // 监听折叠状态的改变 + display?.on('foldStatusChange', (data: display.FoldStatus) => { + Log.d(TAG, `Fold status change to ${JSON.stringify(data)}`) + this.buildDisplayFeatures(data); + }) + // Subscribes to display changes. Example: event that the display size is changed. try { display.on("change", ()=>{ @@ -179,6 +246,50 @@ export class FlutterView { } } + private async buildDisplayFeatures(foldStatus: display.FoldStatus) { + let displayFeatures: ArrayList = new ArrayList(); + let bound: display.Rect[]; + let state: DisplayFeatureState = DisplayFeatureState.UNKNOWN; + let type: DisplayFeatureType = DisplayFeatureType.FOLD; + const displayInfos = display.getDefaultDisplaySync(); + if (display.isFoldable()) { + switch (foldStatus) { + case display.FoldStatus.FOLD_STATUS_EXPANDED: + type = DisplayFeatureType.FOLD; + state = DisplayFeatureState.POSTURE_FLAT; + break; + case display.FoldStatus.FOLD_STATUS_HALF_FOLDED: + type = DisplayFeatureType.FOLD; + state = DisplayFeatureState.POSTURE_HALF_OPENED; + break; + case display.FoldStatus.FOLD_STATUS_UNKNOWN: + type = DisplayFeatureType.UNKNOWN; + state = DisplayFeatureState.UNKNOWN; + break; + default: + state = DisplayFeatureState.UNKNOWN; + type = DisplayFeatureType.FOLD; + break; + } + const displays = await display.getAllDisplays(); + for (let i = 0; i < displays.length; i++) { + let cutoutInfo = await displays[i].getCutoutInfo(); + bound = cutoutInfo.boundingRects; + displayFeatures.add(new DisplayFeature(bound, type, state)); + } + Log.d(TAG, `FOLD device displayFeatures is : ${JSON.stringify(displayFeatures)}`) + } else { + type = DisplayFeatureType.CUTOUT; + state = DisplayFeatureState.UNKNOWN; + let infos = await displayInfos?.getCutoutInfo(); + bound = infos.boundingRects; + displayFeatures.add(new DisplayFeature(bound, type, state)); + Log.d(TAG, `UNFold device displayFeatures is : ${JSON.stringify(displayFeatures)}`) + } + this.viewportMetrics.displayFeatures = displayFeatures; + this.updateViewportMetrics(); + } + private windowSizeChangeCallback = (data: window.Size) => { Log.i(TAG, "windowSizeChangeCallback w:" + data.width + ", h:" + data.height); if (this.isAttachedToFlutterEngine()) { @@ -213,7 +324,7 @@ export class FlutterView { Log.i(TAG, "keyboardHeightChangeCallback " + data); this.keyboardAvoidArea.bottomRect.height = data; if (this.isAttachedToFlutterEngine()) { - this.onAreaChange(null); + this.onAreaChange(null); } }; @@ -270,6 +381,9 @@ export class FlutterView { Log.i(TAG, `unsubscribe accessibility state change, result: ${JSON.stringify(data)}`); }); this.mainWindow?.off('keyboardHeightChange', this.keyboardHeightChangeCallback); + display.off('foldStatusChange', (status: display.FoldStatus) => { + Log.d(TAG, `foldStatusChange listner destory`); + }) } catch (e) { Log.e(TAG, "mainWindow off error: " + JSON.stringify(e)); } @@ -378,6 +492,14 @@ export class FlutterView { } } + onAccessibilityIsOpen() { + let accessibilityState: boolean = accessibility.isOpenAccessibilitySync(); + if(accessibilityState) { + this.flutterEngine?.getFlutterNapi()?.accessibilityStateChange(accessibilityState) + } + Log.i(TAG, `accessibility isOpen state -> ${JSON.stringify(accessibilityState)}`); + } + onAreaChange(newArea: Area | null, setFullScreen: boolean = false) { const originalMetrics = this.viewportMetrics.clone(); @@ -387,17 +509,23 @@ export class FlutterView { } // 根据是否全屏显示,设置标题栏高度(若全屏,则及时规避) - if (this.checkFullScreen && (setFullScreen || this.mainWindow?.getWindowProperties().isLayoutFullScreen)) { // 全屏显示 - this.viewportMetrics.physicalViewPaddingTop = this.systemAvoidArea?.topRect.height ?? 0; - this.viewportMetrics.physicalViewPaddingBottom = this.navigationAvoidArea?.bottomRect.height ?? 0; + let isUseFullScreen = FlutterManager.getInstance().getFullScreenListener().useFullScreen(); + let isLayoutFullScreen = this.mainWindow?.getWindowProperties().isLayoutFullScreen; + if (this.checkFullScreen && (setFullScreen || isLayoutFullScreen || isUseFullScreen)) { // 全屏显示 + this.viewportMetrics.physicalViewPaddingTop = + this.systemAvoidArea?.topRect.height ?? this.viewportMetrics.physicalViewPaddingTop; + this.viewportMetrics.physicalViewPaddingBottom = + this.navigationAvoidArea?.bottomRect.height ?? this.viewportMetrics.physicalViewPaddingBottom; } else { // 非全屏显示(保持规避效果) // 顶部状态栏和底部导航栏规避为0,无平滑过渡效果 this.viewportMetrics.physicalViewPaddingTop = 0; this.viewportMetrics.physicalViewPaddingBottom = 0; } - this.viewportMetrics.physicalViewPaddingLeft = this.systemAvoidArea?.leftRect.width ?? 0; - this.viewportMetrics.physicalViewPaddingRight = this.systemAvoidArea?.rightRect.width ?? 0; + this.viewportMetrics.physicalViewPaddingLeft = + this.systemAvoidArea?.leftRect.width ?? this.viewportMetrics.physicalViewPaddingLeft; + this.viewportMetrics.physicalViewPaddingRight = + this.systemAvoidArea?.rightRect.width ?? this.viewportMetrics.physicalViewPaddingRight; this.onKeyboardAreaChange() this.onGestureAreaChange() @@ -410,10 +538,14 @@ export class FlutterView { private onKeyboardAreaChange() { if (this.checkKeyboard) { - this.viewportMetrics.physicalViewInsetTop = this.keyboardAvoidArea?.topRect.height ?? 0 - this.viewportMetrics.physicalViewInsetLeft = this.keyboardAvoidArea?.leftRect.width ?? 0 - this.viewportMetrics.physicalViewInsetBottom = this.keyboardAvoidArea?.bottomRect.height ?? 0 - this.viewportMetrics.physicalViewInsetRight = this.keyboardAvoidArea?.rightRect.width ?? 0 + this.viewportMetrics.physicalViewInsetTop = + this.keyboardAvoidArea?.topRect.height ?? this.viewportMetrics.physicalViewInsetTop + this.viewportMetrics.physicalViewInsetLeft = + this.keyboardAvoidArea?.leftRect.width ?? this.viewportMetrics.physicalViewInsetLeft + this.viewportMetrics.physicalViewInsetBottom = + this.keyboardAvoidArea?.bottomRect.height ?? this.viewportMetrics.physicalViewInsetBottom + this.viewportMetrics.physicalViewInsetRight = + this.keyboardAvoidArea?.rightRect.width ?? this.viewportMetrics.physicalViewInsetRight } else { this.viewportMetrics.physicalViewInsetTop = 0 this.viewportMetrics.physicalViewInsetLeft = 0 @@ -424,10 +556,14 @@ export class FlutterView { private onGestureAreaChange() { if (this.checkGesture) { - this.viewportMetrics.systemGestureInsetTop = this.gestureAvoidArea?.topRect.height ?? 0 - this.viewportMetrics.systemGestureInsetLeft = this.gestureAvoidArea?.leftRect.width ?? 0 - this.viewportMetrics.systemGestureInsetBottom = this.gestureAvoidArea?.bottomRect.height ?? 0 - this.viewportMetrics.systemGestureInsetRight = this.gestureAvoidArea?.rightRect.width ?? 0 + this.viewportMetrics.systemGestureInsetTop = + this.gestureAvoidArea?.topRect.height ?? this.viewportMetrics.systemGestureInsetTop + this.viewportMetrics.systemGestureInsetLeft = + this.gestureAvoidArea?.leftRect.width ?? this.viewportMetrics.systemGestureInsetLeft + this.viewportMetrics.systemGestureInsetBottom = + this.gestureAvoidArea?.bottomRect.height ?? this.viewportMetrics.systemGestureInsetBottom + this.viewportMetrics.systemGestureInsetRight = + this.gestureAvoidArea?.rightRect.width ?? this.viewportMetrics.systemGestureInsetRight } else { this.viewportMetrics.systemGestureInsetTop = 0 this.viewportMetrics.systemGestureInsetLeft = 0 @@ -444,6 +580,26 @@ export class FlutterView { if (this.isAttachedToFlutterEngine()) { Log.i(TAG, 'updateViewportMetrics devicePixelRatio:' + this.viewportMetrics.devicePixelRatio); + const displayFeatures = this.viewportMetrics.displayFeatures; + let boundCount = 0; + for (let i = 0; i < displayFeatures.length; i++) { + boundCount = boundCount + displayFeatures[i].getBounds().length; + } + let displayFeatureBound: number[] = new Array(boundCount * 4); + let displayFeatureType: number[] = new Array(displayFeatures.length); + let displayFeatureStatus: number[] = new Array(displayFeatures.length); + for (let i = 0; i < displayFeatures.length; i++) { + let singleFeatureBound = displayFeatures[i].getBounds(); + for (let j = 0; j < singleFeatureBound.length; j++) { + displayFeatureBound[4*i + 4*j] = singleFeatureBound[j].left; + displayFeatureBound[4*i + 4*j + 1] = singleFeatureBound[j].top + displayFeatureBound[4*i + 4*j + 2] = singleFeatureBound[j].width; + displayFeatureBound[4*i + 4*j + 3] = singleFeatureBound[j].height; + } + displayFeatureType[i] = displayFeatures[i].getType(); + displayFeatureStatus[i] = displayFeatures[i].getState(); + } + this?.flutterEngine?.getFlutterNapi()?.setViewportMetrics(this.viewportMetrics.devicePixelRatio, this.viewportMetrics.physicalWidth, this.viewportMetrics.physicalHeight, @@ -460,9 +616,9 @@ export class FlutterView { this.viewportMetrics.systemGestureInsetBottom, this.viewportMetrics.systemGestureInsetLeft, this.viewportMetrics.physicalTouchSlop, - new Array(0), - new Array(0), - new Array(0)) + displayFeatureBound, + displayFeatureType, + displayFeatureStatus) return true; } return false; diff --git a/shell/platform/ohos/library_loader.cpp b/shell/platform/ohos/library_loader.cpp index 4f7216d73ef7d48af4a53c339d42817fff345a46..91ceec89565658c1b61231a5120bfba3d1b4c18f 100644 --- a/shell/platform/ohos/library_loader.cpp +++ b/shell/platform/ohos/library_loader.cpp @@ -146,8 +146,17 @@ static napi_value Init(napi_env env, napi_value exports) { "nativeAccessibilityStateChange", flutter::PlatformViewOHOSNapi::nativeAccessibilityStateChange), DECLARE_NAPI_FUNCTION( - "nativeAnnounce", - flutter::PlatformViewOHOSNapi::nativeAnnounce), + "nativeAccessibilityAnnounce", + flutter::PlatformViewOHOSNapi::nativeAccessibilityAnnounce), + DECLARE_NAPI_FUNCTION( + "nativeAccessibilityOnTap", + flutter::PlatformViewOHOSNapi::nativeAccessibilityOnTap), + DECLARE_NAPI_FUNCTION( + "nativeAccessibilityOnLongPress", + flutter::PlatformViewOHOSNapi::nativeAccessibilityOnLongPress), + DECLARE_NAPI_FUNCTION( + "nativeAccessibilityOnTooltip", + flutter::PlatformViewOHOSNapi::nativeAccessibilityOnTooltip), DECLARE_NAPI_FUNCTION( "nativeSetSemanticsEnabled", flutter::PlatformViewOHOSNapi::nativeSetSemanticsEnabled), @@ -181,6 +190,9 @@ static napi_value Init(napi_env env, napi_value exports) { DECLARE_NAPI_FUNCTION( "nativeUnicodeIsRegionalIndicatorSymbol", flutter::PlatformViewOHOSNapi::nativeUnicodeIsRegionalIndicatorSymbol), + DECLARE_NAPI_FUNCTION( + "nativeGetXComponentId", + flutter::PlatformViewOHOSNapi::nativeGetXComponentId), }; FML_DLOG(INFO) << "Init NAPI size=" << sizeof(desc) / sizeof(desc[0]); diff --git a/shell/platform/ohos/napi/platform_view_ohos_napi.cpp b/shell/platform/ohos/napi/platform_view_ohos_napi.cpp index ef196b0b6c15e9ae77a4084999e21b7aa0c308eb..78f4cc842fae59bc8718a4f6e48a5be5356ab156 100644 --- a/shell/platform/ohos/napi/platform_view_ohos_napi.cpp +++ b/shell/platform/ohos/napi/platform_view_ohos_napi.cpp @@ -40,6 +40,7 @@ namespace flutter { napi_env PlatformViewOHOSNapi::env_; std::vector PlatformViewOHOSNapi::system_languages; int64_t PlatformViewOHOSNapi::napi_shell_holder_id_; +const int32_t PlatformViewOHOSNapi::OHOS_API_VERSION = OH_GetSdkApiVersion(); /** * @brief send empty PlatformMessage @@ -1849,14 +1850,14 @@ napi_value PlatformViewOHOSNapi::nativeAccessibilityStateChange( << ret; return nullptr; } - int64_t shell_holder_id; - ret = napi_get_value_int64(env, args[0], &shell_holder_id); + + int64_t shellHolder = 0; + ret = napi_get_value_int64(env, args[0], &shellHolder); if (ret != napi_ok) { - FML_DLOG(ERROR) << "PlatformViewOHOSNapi::nativeAccessibilityStateChange " - "napi_get_value_int64 error:" - << ret; + LOGE("nativeAccessibilityStateChange shellHolder napi_get_value_int64 error"); return nullptr; } + bool state = false; ret = napi_get_value_bool(env, args[1], &state); if (ret != napi_ok) { @@ -1865,20 +1866,76 @@ napi_value PlatformViewOHOSNapi::nativeAccessibilityStateChange( << ret; return nullptr; } - LOGD( - "PlatformViewOHOSNapi::nativeAccessibilityStateChange state is: " - "%{public}s", - (state ? "true" : "false")); + LOGD("PlatformViewOHOSNapi::nativeAccessibilityStateChange state is: " + "%{public}s, shellholderId: %{public}ld", (state ? "true" : "false"), shellHolder); //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; + if (OHOS_API_VERSION >= 13) { + OhosAccessibilityBridge::GetInstance()->OnOhosAccessibilityStateChange(state, shellHolder); + } + return nullptr; +} + +napi_value PlatformViewOHOSNapi::nativeAccessibilityAnnounce( + napi_env env, + napi_callback_info info) { + size_t argc = 1; + napi_value args[1] = {nullptr}; + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + size_t length = 0; + napi_get_value_string_utf8(env, args[0], nullptr, 0, &length); + + auto null_terminated_length = length + 1; + auto char_array = std::make_unique(null_terminated_length); + napi_get_value_string_utf8(env, args[0], char_array.get(), + null_terminated_length, nullptr); + LOGD("PlatformViewOHOSNapi::nativeAccessibilityAnnounce message: %{public}s", char_array.get()); + + if (OHOS_API_VERSION >= 13) { + auto handler = std::make_shared(); + handler->Announce(char_array); + } + return nullptr; +} + +napi_value PlatformViewOHOSNapi::nativeAccessibilityOnTap( + napi_env env, + napi_callback_info info) { + size_t argc = 1; + napi_value args[1] = {nullptr}; + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + int32_t nodeId; + napi_get_value_int32(env, args[0], &nodeId); + + if (OHOS_API_VERSION >= 13) { + auto handler = std::make_shared(); + handler->OnTap(nodeId); + LOGI("nativeAccessibilityOnTap -> nodeId:%{public}d", nodeId); + } + return nullptr; +} + +napi_value PlatformViewOHOSNapi::nativeAccessibilityOnLongPress( + napi_env env, + napi_callback_info info) { + size_t argc = 1; + napi_value args[1] = {nullptr}; + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + int32_t nodeId; + napi_get_value_int32(env, args[0], &nodeId);; + + if (OHOS_API_VERSION >= 13) { + auto handler = std::make_shared(); + handler->OnLongPress(nodeId); + LOGI("nativeAccessibilityOnLongPress -> nodeId:%{public}d", nodeId); + } return nullptr; } -napi_value PlatformViewOHOSNapi::nativeAnnounce( +napi_value PlatformViewOHOSNapi::nativeAccessibilityOnTooltip( napi_env env, napi_callback_info info) { size_t argc = 1; @@ -1892,9 +1949,12 @@ napi_value PlatformViewOHOSNapi::nativeAnnounce( auto char_array = std::make_unique(null_terminated_length); 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 handler = std::make_shared(); - handler->Announce(char_array); + LOGD("PlatformViewOHOSNapi::nativeAccessibilityOnTooltip message: %{public}s", char_array.get()); + +if (OHOS_API_VERSION >= 13) { + auto handler = std::make_shared(); + handler->OnTooltip(char_array); + } return nullptr; } @@ -2103,8 +2163,7 @@ napi_value PlatformViewOHOSNapi::nativeGetFlutterNavigationAction(napi_env env, return nullptr; } - auto ohosAccessibilityBridge = OhosAccessibilityBridge::GetInstance(); - ohosAccessibilityBridge->IS_FLUTTER_NAVIGATE = isNavigate; + OhosAccessibilityBridge::GetInstance()->isFlutterNavigated_ = isNavigate; FML_DLOG(INFO) << "PlatformViewOHOSNapi::nativeGetFlutterNavigationAction -> "<currentXComponentId_ = xcomponentId; + FML_DLOG(ERROR) << "nativeGetXComponentId -> xcomponentId: " << xcomponentId; + return nullptr; +} + } // namespace flutter \ No newline at end of file diff --git a/shell/platform/ohos/napi/platform_view_ohos_napi.h b/shell/platform/ohos/napi/platform_view_ohos_napi.h index 34be921e978e026d0d0550abc25ad0ce87b0d52d..84ea45af1ed65a9fe9e27a1fe1bb5072ac4c63cc 100644 --- a/shell/platform/ohos/napi/platform_view_ohos_napi.h +++ b/shell/platform/ohos/napi/platform_view_ohos_napi.h @@ -16,6 +16,7 @@ #ifndef PLATFORM_VIEW_OHOS_NAPI_H #define PLATFORM_VIEW_OHOS_NAPI_H #include +#include #include "flutter/assets/directory_asset_bundle.h" #include "flutter/common/settings.h" #include "flutter/fml/file.h" @@ -218,7 +219,16 @@ class PlatformViewOHOSNapi { static napi_value nativeAccessibilityStateChange( napi_env env, napi_callback_info info); - static napi_value nativeAnnounce( + static napi_value nativeAccessibilityAnnounce( + napi_env env, + napi_callback_info info); + static napi_value nativeAccessibilityOnTap( + napi_env env, + napi_callback_info info); + static napi_value nativeAccessibilityOnLongPress( + napi_env env, + napi_callback_info info); + static napi_value nativeAccessibilityOnTooltip( napi_env env, napi_callback_info info); static napi_value nativeSetSemanticsEnabled(napi_env env, napi_callback_info info); @@ -259,12 +269,17 @@ class PlatformViewOHOSNapi { napi_env env, napi_callback_info info); + static napi_value nativeGetXComponentId( + napi_env env, + napi_callback_info info); + private: static napi_env env_; napi_ref ref_napi_obj_; static std::vector system_languages; fml::RefPtr platform_task_runner_; static int64_t napi_shell_holder_id_; + static const int32_t OHOS_API_VERSION; }; } // namespace flutter diff --git a/shell/platform/ohos/ohos_external_texture_gl.cpp b/shell/platform/ohos/ohos_external_texture_gl.cpp index f160e09469ace687db0b6cd5c68f5cf8cd91e85a..69b1a5646bb35fb5578898cd7dcfacefe04f79fd 100755 --- a/shell/platform/ohos/ohos_external_texture_gl.cpp +++ b/shell/platform/ohos/ohos_external_texture_gl.cpp @@ -104,7 +104,6 @@ OHOSExternalTextureGL::OHOSExternalTextureGL( backGroundPixelMap_ = nullptr; lastImage_ = nullptr; isEmulator_ = OhosMain::IsEmulator(); - frameData_ = nullptr; } OHOSExternalTextureGL::~OHOSExternalTextureGL() @@ -125,24 +124,37 @@ OHOSExternalTextureGL::~OHOSExternalTextureGL() lastImage_ = nullptr; } -void OnNativeImageFrameAvailable(void *data) +void OnNativeImageFrameAvailable(void *context) { - auto frameData = reinterpret_cast(data); - if (frameData == nullptr) { - FML_LOG(ERROR) << "OnNativeImageFrameAvailable, frameData is null."; + auto ohosExternalTextureGL = reinterpret_cast(context); + if (ohosExternalTextureGL == nullptr) { + FML_LOG(ERROR) << "OnNativeImageFrameAvailable, ohosExternalTextureGL is null."; return; } - frameData->OnPlatformViewMarkTextureFrameAvailable(); + + if (ohosExternalTextureGL != nullptr) { + auto wp_ohosExternalTextureGL = std::weak_ptr( + ohosExternalTextureGL->shared_from_this()); + fml::TaskRunner::RunNowOrPostTask( + ohosExternalTextureGL->task_runners_.GetPlatformTaskRunner(), + [wp_ohosExternalTextureGL]() { + if (auto sp_ohosExternalTextureGL = wp_ohosExternalTextureGL.lock()) { + PlatformView::Delegate& delegate = + sp_ohosExternalTextureGL->delegate_; + delegate.OnPlatformViewMarkTextureFrameAvailable(sp_ohosExternalTextureGL->Id()); + } + }); + } } -bool RegisterFrameAvailableListener(OH_NativeImage *nativeImage, OhosImageFrameData *frameData) +bool RegisterFrameAvailableListener(OH_NativeImage *nativeImage, void *context) { - if (frameData == nullptr) { - FML_LOG(ERROR) << "Error with RegisterFrameAvailableListener, frameData is null"; + if (context == nullptr) { + FML_LOG(ERROR) << "Error with RegisterFrameAvailableListener, context is null"; return false; } OH_OnFrameAvailableListener listener; - listener.context = frameData; + listener.context = context; listener.onFrameAvailable = OnNativeImageFrameAvailable; int64_t ret = OH_NativeImage_SetOnFrameAvailableListener(nativeImage, listener); if (ret != 0) { @@ -191,12 +203,7 @@ void OHOSExternalTextureGL::Attach() FML_LOG(ERROR) << "OHOSExternalTextureGL OH_NativeImage_AttachContext err code:" << ret; } - if (frameData_ == nullptr) { - frameData_ = new OhosImageFrameData(this, Id()); - } - if (!RegisterFrameAvailableListener(nativeImage_, (OhosImageFrameData *)frameData_)) { - delete (OhosImageFrameData *)frameData_; - frameData_ = nullptr; + if (!RegisterFrameAvailableListener(nativeImage_, this)) { return; } state_ = AttachmentState::attached; @@ -273,14 +280,74 @@ void OHOSExternalTextureGL::Paint(PaintContext& context, } } +void OHOSExternalTextureGL::Show() +{ + if (state_ != AttachmentState::hide) { + FML_LOG(WARNING) << "OHOSExternalTextureGL show, state is not hide, ignore this call"; + return; + } + OHOSSurface* ohos_surface_ptr = ohos_surface_.get(); + OhosSurfaceGLSkia* ohosSurfaceGLSkia_ = (OhosSurfaceGLSkia*)ohos_surface_ptr; + if (ohosSurfaceGLSkia_->GetOnscreenSurface() == nullptr) { + FML_LOG(ERROR) << "OHOSExternalTextureGL show, GetSurface failed"; + return; + } + auto result = ohosSurfaceGLSkia_->GLContextMakeCurrent(); + if (result->GetResult()) { + FML_DLOG(INFO) << "OHOSExternalTextureGL show, MakeCurrent successed"; + glGenTextures(1, &texture_name_); + FML_DLOG(INFO) << "OHOSExternalTextureGL show, glGenTextures texture_name_=" + << texture_name_ << ", Id()=" << Id(); + int32_t ret = OH_NativeImage_AttachContext(nativeImage_, texture_name_); + if (ret != 0) { + FML_LOG(ERROR) << "OHOSExternalTextureGL show, AttachContext failed, err code:" << ret; + } + state_ = AttachmentState::attached; + fml::TaskRunner::RunNowOrPostTask( + task_runners_.GetPlatformTaskRunner(), + [this]() { + delegate_.OnPlatformViewMarkTextureFrameAvailable(Id()); + }); + } else { + FML_LOG(ERROR) << "OHOSExternalTextureGL show, MakeCurrent failed"; + return; + } +} + void OHOSExternalTextureGL::OnGrContextCreated() { FML_DLOG(INFO) << " OHOSExternalTextureGL::OnGrContextCreated" << ", texture_name_=" << texture_name_ << ", Id()=" << Id(); - if (state_ == AttachmentState::attached) { - delegate_.OnPlatformViewMarkTextureFrameAvailable(Id()); + fml::TaskRunner::RunNowOrPostTask( + task_runners_.GetRasterTaskRunner(), + [this]() { + Show(); + }); +} + +void OHOSExternalTextureGL::Hide() +{ + if (state_ != AttachmentState::attached) { + FML_LOG(WARNING) << "OHOSExternalTextureGL hide, state is not attached, ignore this call"; + return; + } + if (nativeImage_ != nullptr) { + OH_NativeImage_DetachContext(nativeImage_); + if (backGroundTextureName_ != 0) { + glDeleteTextures(1, &texture_name_); + texture_name_ = 0; + } + } + if (backGroundNativeWindow_ != nullptr) { + OH_NativeImage_DetachContext(backGroundNativeImage_); + if (backGroundTextureName_ != 0) { + infoMap.erase(backGroundTextureName_); + glDeleteTextures(1, &backGroundTextureName_); + backGroundTextureName_ = 0; + } } + state_ = AttachmentState::hide; } void OHOSExternalTextureGL::OnGrContextDestroyed() @@ -288,6 +355,11 @@ void OHOSExternalTextureGL::OnGrContextDestroyed() FML_DLOG(INFO) << " OHOSExternalTextureGL::OnGrContextDestroyed" << ", texture_name_=" << texture_name_ << ", Id()=" << Id(); + fml::TaskRunner::RunNowOrPostTask( + task_runners_.GetRasterTaskRunner(), + [this]() { + Hide(); + }); } void OHOSExternalTextureGL::MarkNewFrameAvailable() @@ -313,10 +385,14 @@ void OHOSExternalTextureGL::OnTextureUnregistered() << ", nativeImage_=" << nativeImage_ << ", backGroundNativeImage_=" << backGroundNativeImage_; first_update_ = false; - if (state_ == AttachmentState::attached) { - Detach(); - state_ = AttachmentState::detached; - } + fml::TaskRunner::RunNowOrPostTask( + task_runners_.GetRasterTaskRunner(), + [this]() { + if (state_ == AttachmentState::attached || state_ == AttachmentState::hide) { + Detach(); + state_ = AttachmentState::detached; + } + }); } bool OHOSExternalTextureGL::IsContextCurrent() @@ -343,7 +419,7 @@ bool OHOSExternalTextureGL::IsContextCurrent() void OHOSExternalTextureGL::Update() { FML_DLOG(INFO) << "OHOSExternalTextureGL::Update, texture_name_=" << texture_name_; - if (!IsContextCurrent() && context_) { + if (!IsContextCurrent() && context_ && display_ && draw_surface_ && read_surface_) { if (eglMakeCurrent(display_, draw_surface_, read_surface_, context_) != EGL_TRUE) { FML_LOG(WARNING) << "eglMakeCurrent in update failed"; } @@ -365,27 +441,27 @@ void OHOSExternalTextureGL::Update() void OHOSExternalTextureGL::Detach() { FML_LOG(INFO) << "OHOSExternalTextureGL::Detach, texture_name_=" << texture_name_; - if (state_ != AttachmentState::attached) { - FML_LOG(ERROR) << "OHOSExternalTextureGL::Detach, the current status is not attached"; + if (state_ != AttachmentState::attached && state_ != AttachmentState::hide) { + FML_LOG(ERROR) << "OHOSExternalTextureGL::Detach, the current status is not attached or hide"; return; } if (nativeImage_ != nullptr) { - OH_NativeImage_DetachContext(nativeImage_); + if (state_ == AttachmentState::attached) { + OH_NativeImage_DetachContext(nativeImage_); + } OH_NativeImage_UnsetOnFrameAvailableListener(nativeImage_); OH_NativeImage_Destroy(&nativeImage_); nativeImage_ = nullptr; } - if (frameData_ != nullptr) { - delete (OhosImageFrameData *)frameData_; - frameData_ = nullptr; - } if (nativeWindow_ != nullptr) { OH_NativeWindow_DestroyNativeWindow(nativeWindow_); nativeWindow_ = nullptr; } if (backGroundNativeImage_ != nullptr) { - OH_NativeImage_DetachContext(backGroundNativeImage_); + if (state_ == AttachmentState::attached) { + OH_NativeImage_DetachContext(backGroundNativeImage_); + } OH_NativeImage_Destroy(&backGroundNativeImage_); backGroundNativeImage_ = nullptr; } @@ -393,10 +469,12 @@ void OHOSExternalTextureGL::Detach() OH_NativeWindow_DestroyNativeWindow(backGroundNativeWindow_); backGroundNativeWindow_ = nullptr; } - glDeleteTextures(1, &texture_name_); - glDeleteTextures(1, &backGroundTextureName_); - if (backGroundTextureName_ != 0) { - infoMap.erase(backGroundTextureName_); + if (state_ == AttachmentState::attached) { + glDeleteTextures(1, &texture_name_); + glDeleteTextures(1, &backGroundTextureName_); + if (backGroundTextureName_ != 0) { + infoMap.erase(backGroundTextureName_); + } } } @@ -770,28 +848,4 @@ void OHOSExternalTextureGL::DispatchBackGroundPixelMap(NativePixelMap* pixelMap) } } -OhosImageFrameData::OhosImageFrameData( - OHOSExternalTextureGL *ohosExternalTextureGL, - int64_t textureId) - : ohosExternalTextureGL(ohosExternalTextureGL), - textureId_(textureId) -{} - -OhosImageFrameData::~OhosImageFrameData() -{ - ohosExternalTextureGL = nullptr; - textureId_ = 0; -} - -void OhosImageFrameData::OnPlatformViewMarkTextureFrameAvailable() -{ - if (ohosExternalTextureGL != nullptr) { - fml::TaskRunner::RunNowOrPostTask( - ohosExternalTextureGL->task_runners_.GetPlatformTaskRunner(), [textureId = textureId_, this]() { - PlatformView::Delegate& dalegate = this->ohosExternalTextureGL->delegate_; - dalegate.OnPlatformViewMarkTextureFrameAvailable(textureId); - }); - } -} - } // namespace flutter \ No newline at end of file diff --git a/shell/platform/ohos/ohos_external_texture_gl.h b/shell/platform/ohos/ohos_external_texture_gl.h index 24beb3279de48788e6d3b945b06c0caa96859db1..113aeb52968852bb2066d01174413bd424d29a6b 100755 --- a/shell/platform/ohos/ohos_external_texture_gl.h +++ b/shell/platform/ohos/ohos_external_texture_gl.h @@ -36,7 +36,8 @@ // maybe now unused namespace flutter { -class OHOSExternalTextureGL : public flutter::Texture { +// Represents an external texture for OHOS platform, using std::weak_ptr to avoid circular reference. +class OHOSExternalTextureGL : public flutter::Texture, public std::enable_shared_from_this { public: explicit OHOSExternalTextureGL(int64_t id, const std::shared_ptr& ohos_surface); explicit OHOSExternalTextureGL(int64_t id, const std::shared_ptr& ohos_surface, @@ -52,8 +53,6 @@ class OHOSExternalTextureGL : public flutter::Texture { OH_NativeImage *backGroundNativeImage_; - void *frameData_; - bool first_update_ = false; void Paint(PaintContext& context, @@ -88,6 +87,10 @@ class OHOSExternalTextureGL : public flutter::Texture { void Detach(); + void Hide(); + + void Show(); + void UpdateTransform(OH_NativeImage *image); EGLDisplay GetPlatformEglDisplay(EGLenum platform, void *native_display, const EGLint *attrib_list); @@ -102,7 +105,7 @@ class OHOSExternalTextureGL : public flutter::Texture { void ProducePixelMapToBackGroundImage(); - enum class AttachmentState { uninitialized, attached, detached }; + enum class AttachmentState { uninitialized, attached, detached, hide }; AttachmentState state_; @@ -145,22 +148,5 @@ class OHOSExternalTextureGL : public flutter::Texture { bool IsContextCurrent(); }; -class OhosImageFrameData { - public: - OhosImageFrameData(OHOSExternalTextureGL *ohosExternalTextureGL, int64_t textureId); - - OhosImageFrameData() = delete; - - ~OhosImageFrameData(); - - void OnPlatformViewMarkTextureFrameAvailable(); - - private: - - OHOSExternalTextureGL *ohosExternalTextureGL; - - int64_t textureId_; -}; - } // namespace flutter #endif \ No newline at end of file diff --git a/shell/platform/ohos/ohos_xcomponent_adapter.cpp b/shell/platform/ohos/ohos_xcomponent_adapter.cpp index e9a0e82d033a8de6ec55b9df7f5a3142f49311ba..68d1a5debffc9939cf9441438bfebee98d232918 100644 --- a/shell/platform/ohos/ohos_xcomponent_adapter.cpp +++ b/shell/platform/ohos/ohos_xcomponent_adapter.cpp @@ -18,6 +18,7 @@ #include "types.h" #include "ohos_logging.h" #include +#include "flutter/fml/logging.h" namespace flutter { @@ -194,12 +195,15 @@ void OnSurfaceChangedCB(OH_NativeXComponent* component, void* window) { } void OnSurfaceDestroyedCB(OH_NativeXComponent* component, void* window) { + std::lock_guard lock(XComponentAdapter::GetInstance()->mutex_); for(auto it = XComponentAdapter::GetInstance()->xcomponetMap_.begin(); it != XComponentAdapter::GetInstance()->xcomponetMap_.end();) { if(it->second->nativeXComponent_ == component) { it->second->OnSurfaceDestroyed(component, window); delete it->second; + // 将当前要销毁的xcomponent对应的无障碍provider指针置nullptr + it->second->accessibilityProvider_ = nullptr; it = XComponentAdapter::GetInstance()->xcomponetMap_.erase(it); } else { ++it; @@ -247,9 +251,8 @@ int32_t FindAccessibilityNodeInfosById( int32_t requestId, ArkUI_AccessibilityElementInfoList* elementList) { - auto ohosAccessibilityBridge = OhosAccessibilityBridge::GetInstance(); - ohosAccessibilityBridge->FindAccessibilityNodeInfosById(elementId, mode, requestId, elementList); - LOGD("accessibilityProviderCallback_.FindAccessibilityNodeInfosById"); + OhosAccessibilityBridge::GetInstance()->FindAccessibilityNodeInfosById(elementId, mode, requestId, elementList); + FML_DLOG(INFO) << "accessibilityProviderCallback_.FindAccessibilityNodeInfosById"; return 0; } @@ -260,8 +263,7 @@ int32_t FindAccessibilityNodeInfosByText( int32_t requestId, ArkUI_AccessibilityElementInfoList* elementList) { - auto ohosAccessibilityBridge = OhosAccessibilityBridge::GetInstance(); - ohosAccessibilityBridge->FindAccessibilityNodeInfosByText(elementId, text, requestId, elementList); + OhosAccessibilityBridge::GetInstance()->FindAccessibilityNodeInfosByText(elementId, text, requestId, elementList); LOGD("accessibilityProviderCallback_.FindAccessibilityNodeInfosByText"); return 0; } @@ -273,8 +275,7 @@ int32_t FindFocusedAccessibilityNode( int32_t requestId, ArkUI_AccessibilityElementInfo* elementinfo) { - auto ohosAccessibilityBridge = OhosAccessibilityBridge::GetInstance(); - ohosAccessibilityBridge->FindFocusedAccessibilityNode(elementId, focusType, requestId, elementinfo); + OhosAccessibilityBridge::GetInstance()->FindFocusedAccessibilityNode(elementId, focusType, requestId, elementinfo); LOGD("accessibilityProviderCallback_.FindFocusedAccessibilityNode"); return 0; } @@ -286,8 +287,7 @@ int32_t FindNextFocusAccessibilityNode( int32_t requestId, ArkUI_AccessibilityElementInfo *elementList) { - auto ohosAccessibilityBridge = OhosAccessibilityBridge::GetInstance(); - ohosAccessibilityBridge->FindNextFocusAccessibilityNode(elementId, direction, requestId, elementList); + OhosAccessibilityBridge::GetInstance()->FindNextFocusAccessibilityNode(elementId, direction, requestId, elementList); LOGD("accessibilityProviderCallback_.FindNextFocusAccessibilityNode"); return 0; } @@ -299,8 +299,7 @@ int32_t ExecuteAccessibilityAction( ArkUI_AccessibilityActionArguments* actionArguments, int32_t requestId) { - auto ohosAccessibilityBridge = OhosAccessibilityBridge::GetInstance(); - ohosAccessibilityBridge->ExecuteAccessibilityAction(elementId, action, actionArguments, requestId); + OhosAccessibilityBridge::GetInstance()->ExecuteAccessibilityAction(elementId, action, actionArguments, requestId); LOGD("accessibilityProviderCallback_.ExecuteAccessibilityAction"); return 0; } @@ -318,8 +317,7 @@ int32_t GetAccessibilityNodeCursorPosition( int32_t requestId, int32_t* index) { - auto ohosAccessibilityBridge = OhosAccessibilityBridge::GetInstance(); - ohosAccessibilityBridge->GetAccessibilityNodeCursorPosition(elementId, requestId, index); + OhosAccessibilityBridge::GetInstance()->GetAccessibilityNodeCursorPosition(elementId, requestId, index); LOGD("accessibilityProviderCallback_.GetAccessibilityNodeCursorPosition"); return 0; } @@ -369,47 +367,54 @@ void XComponentBase::DetachFlutterEngine() { isEngineAttached_ = false; } +ArkUI_AccessibilityProvider* XComponentAdapter::GetAccessibilityProvider(const std::string& xcompId) +{ + auto it = xcomponetMap_.find(xcompId); + if (it != xcomponetMap_.end()) { + return it->second->accessibilityProvider_; + } else { + return nullptr; + } +} + +void XComponentBase::RegisterArkUIAccessibilityService(OH_NativeXComponent* nativeXComponent) +{ + BindAccessibilityProviderCallback(); + + auto OH_NativeXComponent_GetNativeAccessibilityProvider = + OhosAccessibilityDDL::DLLoadGetNativeA11yProvider(ArkUIAccessibilityConstant::OH_GET_A11Y_PROVIDER); + CHECK_DLL_NULL_PTR(OH_NativeXComponent_GetNativeAccessibilityProvider); + + ArkUI_AccessibilityProvider* a11yProvider = nullptr; + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_NativeXComponent_GetNativeAccessibilityProvider(nativeXComponent, &a11yProvider) + ); + + auto OH_ArkUI_AccessibilityProviderRegisterCallback = + OhosAccessibilityDDL::DLLoadRegisterFunc(ArkUIAccessibilityConstant::ARKUI_REGISTER_CALLBACK); + CHECK_DLL_NULL_PTR(OH_ArkUI_AccessibilityProviderRegisterCallback); + CHECK_NULL_PTR(a11yProvider, RegisterArkUIAccessibilityService); + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityProviderRegisterCallback(a11yProvider, &accessibilityProviderCallback_) + ); + + std::lock_guard lock(XComponentAdapter::GetInstance()->mutex_); + auto* base = XComponentAdapter::GetInstance()->xcomponetMap_[id_]; + base->accessibilityProvider_ = a11yProvider; + base->nativeXComponent_ = nativeXComponent; + + FML_DLOG(INFO) << "RegisterArkUIAccessibilityService is finished"; +} + void XComponentBase::SetNativeXComponent(OH_NativeXComponent* nativeXComponent){ nativeXComponent_ = nativeXComponent; if (nativeXComponent_ != nullptr) { BindXComponentCallback(); OH_NativeXComponent_RegisterCallback(nativeXComponent_, &callback_); OH_NativeXComponent_RegisterMouseEventCallback(nativeXComponent_, &mouseCallback_); - - if (OH_GetSdkApiVersion() >= 13) { - LOGD("api version: %{public}d", OH_GetSdkApiVersion()); - BindAccessibilityProviderCallback(); - - int32_t (*OH_NativeXComponent_GetNativeAccessibilityProvider)(OH_NativeXComponent*, ArkUI_AccessibilityProvider**) = - OhosAccessibilityDDL::DLLoadGetNativeA11yProvider("OH_NativeXComponent_GetNativeAccessibilityProvider"); - if (OH_NativeXComponent_GetNativeAccessibilityProvider == nullptr) { - LOGE("OH_NativeXComponent_GetNativeAccessibilityProvider is null, %{public}s", dlerror()); - } - ArkUI_AccessibilityProvider* accessibilityProvider = nullptr; - int32_t ret1 = OH_NativeXComponent_GetNativeAccessibilityProvider(nativeXComponent_, &accessibilityProvider); - if (ret1 != 0) { - LOGE("OH_NativeXComponent_GetNativeAccessibilityProvider is failed"); - return; - } - - int32_t (*OH_ArkUI_AccessibilityProviderRegisterCallback)(ArkUI_AccessibilityProvider*, ArkUI_AccessibilityProviderCallbacks*) = - OhosAccessibilityDDL::DLLoadRegisterFunc("OH_ArkUI_AccessibilityProviderRegisterCallback"); - if (OH_ArkUI_AccessibilityProviderRegisterCallback == nullptr) { - LOGE("OH_ArkUI_AccessibilityProviderRegisterCallback is null, %{public}s", dlerror()); - } - int32_t ret2 = OH_ArkUI_AccessibilityProviderRegisterCallback(accessibilityProvider, &accessibilityProviderCallback_); - if (ret2 != 0) { - LOGE("OH_ArkUI_AccessibilityProviderRegisterCallback is failed"); - return; - } - LOGE("OH_ArkUI_AccessibilityProviderRegisterCallback is %{public}d", ret2); - - //将ArkUI_AccessibilityProvider传到无障碍bridge类 - auto ohosAccessibilityBridge = OhosAccessibilityBridge::GetInstance(); - ohosAccessibilityBridge->provider_ = accessibilityProvider; - - LOGI("XComponentBase::SetNativeXComponent OH_ArkUI_AccessibilityProviderRegisterCallback is succeed"); - } + // register the OH_ArkUI accessibility callbacks + if (OH_GetSdkApiVersion() < 13) { return; } + RegisterArkUIAccessibilityService(nativeXComponent_); } } diff --git a/shell/platform/ohos/ohos_xcomponent_adapter.h b/shell/platform/ohos/ohos_xcomponent_adapter.h index d2c14146134bffd6d364ddf3e8a57f8326fba305..632e9d216d8b3118a563793d352b03f0ac8177fd 100644 --- a/shell/platform/ohos/ohos_xcomponent_adapter.h +++ b/shell/platform/ohos/ohos_xcomponent_adapter.h @@ -20,12 +20,13 @@ #include #include #include +#include #include "flutter/shell/platform/ohos/ohos_touch_processor.h" #include "flutter/shell/platform/ohos/napi/platform_view_ohos_napi.h" #include "napi/native_api.h" #include "napi_common.h" #include "flutter/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h" - +#include "flutter/shell/platform/ohos/utils/ddl_utils.h" namespace flutter { class XComponentBase @@ -50,6 +51,9 @@ public: void OnDispatchMouseEvent(OH_NativeXComponent* component, void* window); void OnDispatchMouseWheelEvent(mouseWheelEvent event); + void RegisterArkUIAccessibilityService( + OH_NativeXComponent* nativeXComponent); + OH_NativeXComponent_TouchEvent touchEvent_; OH_NativeXComponent_Callback callback_; OH_NativeXComponent_MouseEvent_Callback mouseCallback_; @@ -64,7 +68,7 @@ public: uint64_t width_; uint64_t height_; OhosTouchProcessor ohosTouchProcessor_; - + ArkUI_AccessibilityProvider* accessibilityProvider_; }; class XComponentAdapter { @@ -79,8 +83,12 @@ class XComponentAdapter { void DetachFlutterEngine(std::string& id); void OnMouseWheel(std::string& id, mouseWheelEvent event); + ArkUI_AccessibilityProvider* GetAccessibilityProvider(const std::string& xcompId); + public: std::map xcomponetMap_; + std::string currentXComponentId_; + std::mutex mutex_; private: static XComponentAdapter mXComponentAdapter; diff --git a/shell/platform/ohos/platform_view_ohos.cpp b/shell/platform/ohos/platform_view_ohos.cpp index b1aca3a69c025b1c28c7870d49ea4e43f4af1521..6d860f66aa1bd0d2d71161f8ed44301f1093a5e7 100644 --- a/shell/platform/ohos/platform_view_ohos.cpp +++ b/shell/platform/ohos/platform_view_ohos.cpp @@ -27,6 +27,7 @@ #include "flutter/shell/platform/ohos/platform_view_ohos_delegate.h" #include + namespace flutter { OhosSurfaceFactoryImpl::OhosSurfaceFactoryImpl( @@ -117,15 +118,16 @@ PlatformViewOHOS::PlatformViewOHOS( PlatformViewOHOS::~PlatformViewOHOS() { FML_LOG(INFO) << "PlatformViewOHOS::~PlatformViewOHOS"; - for (std::map>::iterator it = external_texture_gl_.begin(); - it != external_texture_gl_.end(); ++it) { - if (it->second != nullptr) { - OH_NativeImage_Destroy(&(it->second->nativeImage_)); - it->second->nativeImage_ = nullptr; + for (auto const &it : external_texture_gl_) { + if (it.second != nullptr) { + FML_LOG(INFO) << " nativeImage of textureId " << it.first << " will destroy"; + if (it.second->nativeImage_ != nullptr) { + OH_NativeImage_Destroy(&(it.second->nativeImage_)); + it.second->nativeImage_ = nullptr; + } } } external_texture_gl_.clear(); - FML_LOG(INFO) << "PlatformViewOHOS::~PlatformViewOHOS finish"; } void PlatformViewOHOS::NotifyCreate( @@ -296,9 +298,12 @@ void PlatformViewOHOS::UpdateAssetResolverByType( void PlatformViewOHOS::UpdateSemantics( flutter::SemanticsNodeUpdates update, flutter::CustomAccessibilityActionUpdates actions) { - FML_DLOG(INFO) << "PlatformViewOHOS::UpdateSemantics is called"; - auto nativeAccessibilityChannel_ = std::make_shared(); - nativeAccessibilityChannel_->UpdateSemantics(update, actions); + task_runners_.GetPlatformTaskRunner()->PostTask( + [update = std::move(update), actions = std::move(actions)]() { + auto nativeAccessibilityChannel_ = std::make_shared(); + nativeAccessibilityChannel_->UpdateSemantics(update, actions); + FML_DLOG(INFO) << "PlatformViewOHOS::UpdateSemantics is called"; + }); } // |PlatformView| diff --git a/shell/platform/ohos/utils/arkui_accessibility_constant.h b/shell/platform/ohos/utils/arkui_accessibility_constant.h new file mode 100644 index 0000000000000000000000000000000000000000..a5226aad6abc1028cfb2b1be891b43a9632f6ce6 --- /dev/null +++ b/shell/platform/ohos/utils/arkui_accessibility_constant.h @@ -0,0 +1,88 @@ +/* + * 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 ARKUI_ACCESSIBILITY_CONSTANT_H +#define ARKUI_ACCESSIBILITY_CONSTANT_H +namespace flutter { + +/** + * 封装ArkUI无障碍C-API的符号表中接口名称常量, + * 方便动态加载libflutter_accessiblity.so中的无障碍接口 + */ +class ArkUIAccessibilityConstant { +public: + static constexpr char OH_GET_A11Y_PROVIDER[] = "OH_NativeXComponent_GetNativeAccessibilityProvider"; + static constexpr char ARKUI_REGISTER_CALLBACK[] = "OH_ArkUI_AccessibilityProviderRegisterCallback"; + static constexpr char ARKUI_SEND_A11Y_EVENT[] = "OH_ArkUI_SendAccessibilityAsyncEvent"; + static constexpr char ARKUI_GET_A11Y_NODE[] = "OH_ArkUI_AddAndGetAccessibilityElementInfo"; + + static constexpr char ARKUI_CREATE_NODE[] = "OH_ArkUI_CreateAccessibilityElementInfo"; + static constexpr char ARKUI_DESTORY_NODE[] = "OH_ArkUI_DestoryAccessibilityElementInfo"; + static constexpr char ARKUI_CREATE_EVENT[] = "OH_ArkUI_CreateAccessibilityEventInfo"; + static constexpr char ARKUI_DESTORY_EVENT[] = "OH_ArkUI_DestoryAccessibilityEventInfo"; + + static constexpr char ARKUI_SET_NODE_ID[] = "OH_ArkUI_AccessibilityElementInfoSetElementId"; + static constexpr char ARKUI_SET_PARENT_ID[] = "OH_ArkUI_AccessibilityElementInfoSetParentId"; + static constexpr char ARKUI_SET_COMPONENT_TYPE[] = "OH_ArkUI_AccessibilityElementInfoSetComponentType"; + static constexpr char ARKUI_SET_CONTENTS[] = "OH_ArkUI_AccessibilityElementInfoSetContents"; + static constexpr char ARKUI_SET_HINT[] = "OH_ArkUI_AccessibilityElementInfoSetHintText"; + static constexpr char ARKUI_SET_A11Y_TEXT[] = "OH_ArkUI_AccessibilityElementInfoSetAccessibilityText"; + static constexpr char ARKUI_SET_A11Y_DESC[] = "OH_ArkUI_AccessibilityElementInfoSetAccessibilityDescription"; + static constexpr char ARKUI_SET_CHILD_IDS[] = "OH_ArkUI_AccessibilityElementInfoSetChildNodeIds"; + static constexpr char ARKUI_SET_ACTIONS[] = "OH_ArkUI_AccessibilityElementInfoSetOperationActions"; + static constexpr char ARKUI_SET_SCREEN_RECT[] = "OH_ArkUI_AccessibilityElementInfoSetScreenRect"; + static constexpr char ARKUI_SET_CHECKABLE[] = "OH_ArkUI_AccessibilityElementInfoSetCheckable"; + static constexpr char ARKUI_SET_CHECKED[] = "OH_ArkUI_AccessibilityElementInfoSetChecked"; + static constexpr char ARKUI_SET_FOCUSABLE[] = "OH_ArkUI_AccessibilityElementInfoSetFocusable"; + static constexpr char ARKUI_SET_FOCUSED[] = "OH_ArkUI_AccessibilityElementInfoSetFocused"; + static constexpr char ARKUI_SET_VISIBLE[] = "OH_ArkUI_AccessibilityElementInfoSetVisible"; + static constexpr char ARKUI_SET_A11Y_FOCUSED[] = "OH_ArkUI_AccessibilityElementInfoSetAccessibilityFocused"; + static constexpr char ARKUI_SET_SELECTED[] = "OH_ArkUI_AccessibilityElementInfoSetSelected"; + static constexpr char ARKUI_SET_CLICKABLE[] = "OH_ArkUI_AccessibilityElementInfoSetClickable"; + static constexpr char ARKUI_SET_LONG_PRESS[] = "OH_ArkUI_AccessibilityElementInfoSetLongClickable"; + static constexpr char ARKUI_SET_ENABLED[] = "OH_ArkUI_AccessibilityElementInfoSetEnabled"; + static constexpr char ARKUI_SET_IS_PASSWORD[] = "OH_ArkUI_AccessibilityElementInfoSetIsPassword"; + static constexpr char ARKUI_SET_SCROLLABLE[] = "OH_ArkUI_AccessibilityElementInfoSetScrollable"; + static constexpr char ARKUI_SET_EDITABLE[] = "OH_ArkUI_AccessibilityElementInfoSetEditable"; + static constexpr char ARKUI_SET_IS_HINT[] = "OH_ArkUI_AccessibilityElementInfoSetIsHint"; + static constexpr char ARKUI_SET_A11Y_GROUP[] = "OH_ArkUI_AccessibilityElementInfoSetAccessibilityGroup"; + static constexpr char ARKUI_SET_A11Y_LEVEL[] = "OH_ArkUI_AccessibilityElementInfoSetAccessibilityLevel"; + + static constexpr char ARKUI_SET_CURR_ITEM_IDX[] = "OH_ArkUI_AccessibilityElementInfoSetCurrentItemIndex"; + static constexpr char ARKUI_SET_START_ITEM_IDX[] = "OH_ArkUI_AccessibilityElementInfoSetStartItemIndex"; + static constexpr char ARKUI_SET_END_ITEM_IDX[] = "OH_ArkUI_AccessibilityElementInfoSetEndItemIndex"; + static constexpr char ARKUI_SET_ITEM_COUNT[] = "OH_ArkUI_AccessibilityElementInfoSetItemCount"; + + static constexpr char ARKUI_SET_EVENT_TYPE[] = "OH_ArkUI_AccessibilityEventSetEventType"; + static constexpr char ARKUI_SET_ANNOUNCED_TEXT[] = "OH_ArkUI_AccessibilityEventSetTextAnnouncedForAccessibility"; + static constexpr char ARKUI_SET_REQ_FOCUSED_ID[] = "OH_ArkUI_AccessibilityEventSetRequestFocusId"; + static constexpr char ARKUI_EVENT_SET_NODE[] = "OH_ArkUI_AccessibilityEventSetElementInfo"; + + static constexpr char ARKUI_SET_SELECTED_START[] = "OH_ArkUI_AccessibilityElementInfoSetSelectedTextStart"; + static constexpr char ARKUI_SET_SELECTED_END[] = "OH_ArkUI_AccessibilityElementInfoSetSelectedTextEnd"; + static constexpr char ARKUI_FIND_ACTION_ARG_BY_KEY[] = "OH_ArkUI_FindAccessibilityActionArgumentByKey"; + + static constexpr char ARKUI_SET_RANGE_INFO[] = "OH_ArkUI_AccessibilityElementInfoSetRangeInfo"; + static constexpr char ARKUI_SET_GRID_INFO[] = "OH_ArkUI_AccessibilityElementInfoSetGridInfo"; + static constexpr char ARKUI_SET_A11Y_OFFSET[] = "OH_ArkUI_AccessibilityElementInfoSetAccessibilityOffset"; + static constexpr char ARKUI_SET_Z_INDEX[] = "OH_ArkUI_AccessibilityElementInfoSetZIndex"; + static constexpr char ARKUI_SET_A11Y_OPACITY[] = "OH_ArkUI_AccessibilityElementInfoSetAccessibilityOpacity"; + static constexpr char ARKUI_SET_BACKGROUND_COLOR[] = "OH_ArkUI_AccessibilityElementInfoSetBackgroundColor"; + static constexpr char ARKUI_SET_BRACKGROUND_IMG[] = "OH_ArkUI_AccessibilityElementInfoSetBackgroundImage"; + static constexpr char ARKUI_SET_BLUR[] = "OH_ArkUI_AccessibilityElementInfoSetBlur"; + static constexpr char ARKUI_SET_HIT_TEST_BEHAVIOR[] = "OH_ArkUI_AccessibilityElementInfoSetHitTestBehavior"; +}; + +} +#endif \ No newline at end of file diff --git a/shell/platform/ohos/utils/ddl_utils.h b/shell/platform/ohos/utils/ddl_utils.h index 5ddbb0e954e9df73b55e955b54b266fa1adca117..60f89db6d3c38387acfa069180bea25f67514840 100644 --- a/shell/platform/ohos/utils/ddl_utils.h +++ b/shell/platform/ohos/utils/ddl_utils.h @@ -21,5 +21,54 @@ using LIBHANDLE = void*; #define LOAD_LIB(libPath) dlopen(libPath, RTLD_LAZY|RTLD_LOCAL) #define CLOSE_LIB(libHandle) dlclose(libHandle) #define LOAD_SYM(libHandle, symbol) dlsym(libHandle, symbol) +#define LOAD_ERROR() dlerror() + +#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 function %{public}s call, error code:%{public}d",\ + #X, RET); \ + } \ + } while (false) \ + +#define CHECK_DLL_NULL_PTR(func) \ + do { \ + if (func == nullptr) { \ + LOGE("Error: Function %{public}s is nullptr, %{public}s", \ + #func, LOAD_ERROR()); \ + } \ + } while (false) \ + +#define CHECK_NULL_PTR(PARAM, FUNC) \ + do { \ + if (PARAM == nullptr) { \ + LOGE("Error: %{public}s -> %{public}s is nullptr", \ + #FUNC, #PARAM); \ + } \ + } while (false) \ + +#define CHECK_NULL_PTR_WITH_RET(PARAM, FUNC) \ + do { \ + if (PARAM == nullptr) { \ + LOGE("Error: %{public}s -> %{public}s is nullptr", \ + #FUNC, #PARAM); \ + return ARKUI_FAILED_CODE; \ + } \ + } while (false) \ + +#define CHECK_NULL_PTR_RET_VOID(PARAM, FUNC) \ + do { \ + if (PARAM == nullptr) { \ + LOGE("Error: %{public}s -> %{public}s is nullptr", \ + #FUNC, #PARAM); \ + return; \ + } \ + } while (false) \ #endif // FOUNDATION_ACE_INTERFACE_INNERKITS_ACE_UTILS_H diff --git a/shell/platform/ohos/utils/ohos_utils.cpp b/shell/platform/ohos/utils/ohos_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1d4058f08600b61c0f7aca60cbb7bf1c87580d60 --- /dev/null +++ b/shell/platform/ohos/utils/ohos_utils.cpp @@ -0,0 +1,86 @@ +/* + * 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 "ohos_utils.h" +namespace flutter { + +OHOSUtils::OHOSUtils() {}; +OHOSUtils::~OHOSUtils() {}; + +/** + * 判断源字符串是否包含目标字符串 + */ +bool OHOSUtils::Contains(const std::string source, + const std::string target) +{ + return source.find(target) != std::string::npos; +} + +/** + * 将string序列化为uint8字节数组 + */ +void OHOSUtils::SerializeString(const std::string& str, std::vector& buffer) +{ + // store the length of the string as a uint8_t + uint32_t length = str.size(); + buffer.insert(buffer.end(), + reinterpret_cast(&length), + reinterpret_cast(&length) + sizeof(length)); + // store the actual string data + buffer.insert(buffer.end(), str.begin(), str.end()); +} + +/** + * 将map序列化为uint8字节数组 + */ +std::vector OHOSUtils::SerializeStringIntMap(const std::map& mp) +{ + std::vector buffer; + + // Store the number of elements in the map + uint32_t mapSize = mp.size(); + buffer.insert(buffer.end(), + reinterpret_cast(&mapSize), + reinterpret_cast(&mapSize) + sizeof(mapSize)); + + // Iterate over the map and serialize each key-value pair + for (const auto& it : mp) { + SerializeString(it.first, buffer); + buffer.insert(buffer.end(), + reinterpret_cast(&it.second), + reinterpret_cast(&it.second) + sizeof(it.second)); + } + + return buffer; +} + +/** + * convert char* type to int32_t type with a safe way + */ +void OHOSUtils::CharArrayToInt32(const char* str, int32_t& target) +{ + char* end; + long int num = std::strtol(str, &end, 10); + + // Check if the entire string was converted + if (*end == '\0') { + target = static_cast(num); + LOGD("The int32_t value is: %{public}d", target); + } else { + target = 0; + LOGE("Conversion error, non-convertible part: %{public}s", end); + } +} + +} \ No newline at end of file diff --git a/shell/platform/ohos/utils/ohos_utils.h b/shell/platform/ohos/utils/ohos_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..e9d6b7b6831a6b75f7d8a207513cdc95a5812e1e --- /dev/null +++ b/shell/platform/ohos/utils/ohos_utils.h @@ -0,0 +1,38 @@ +/* + * 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_UTILS_H +#define OHOS_UTILS_H +#include +#include +#include +#include +#include +#include "flutter/shell/platform/ohos/ohos_logging.h" +namespace flutter { + +class OHOSUtils { +public: + OHOSUtils(); + ~OHOSUtils(); + + static bool Contains(const std::string source, const std::string target); + static void SerializeString(const std::string& str, std::vector& buffer); + static std::vector SerializeStringIntMap(const std::map& mp); + static void CharArrayToInt32(const char* str, int32_t& target); +}; + +} +#endif