diff --git a/BUILD.gn b/BUILD.gn index 7a102d594bf570c401e4a55e5682fd014a56ab81..efab1e976b3374f1e23dd4d3371057eb572ce37a 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -141,7 +141,7 @@ group("unittests") { } # Compile all unittests targets if enabled. - if (enable_unittests) { + if (enable_unittests && !is_win) { public_deps += [ "//flutter/display_list:display_list_rendertests", "//flutter/display_list:display_list_unittests", @@ -152,9 +152,6 @@ group("unittests") { "//flutter/runtime:no_dart_plugin_registrant_unittests", "//flutter/runtime:runtime_unittests", "//flutter/shell/common:shell_unittests", - "//flutter/shell/platform/embedder:embedder_a11y_unittests", - "//flutter/shell/platform/embedder:embedder_proctable_unittests", - "//flutter/shell/platform/embedder:embedder_unittests", "//flutter/testing:testing_unittests", "//flutter/testing/dart", "//flutter/testing/smoke_test_failure", @@ -162,6 +159,21 @@ group("unittests") { "//flutter/third_party/txt:txt_unittests", ] + # ohos does not support vulkan + if (!is_ohos) { + public_deps += [ + "//flutter/shell/platform/embedder:embedder_a11y_unittests", + "//flutter/shell/platform/embedder:embedder_proctable_unittests", + "//flutter/shell/platform/embedder:embedder_unittests", + ] + } + + if (is_ohos) { + public_deps += [ + "//flutter/shell/platform/ohos:flutter_ohos_unittests", + ] + } + # The accessibility library only supports Mac and Windows at the moment. if (is_mac || is_win) { public_deps += @@ -181,7 +193,7 @@ group("unittests") { [ "//flutter/shell/platform/darwin:flutter_channels_unittests" ] } - if (!is_win && !is_fuchsia) { + if (!is_win && !is_fuchsia && !is_ohos) { public_deps += [ "//flutter/shell/platform/android/external_view_embedder:android_external_view_embedder_unittests", "//flutter/shell/platform/android/jni:jni_unittests", diff --git a/COMMITTERS.md b/COMMITTERS.md new file mode 100644 index 0000000000000000000000000000000000000000..c6fed253df75e3930ffb6eda8e6caaa81c0c4488 --- /dev/null +++ b/COMMITTERS.md @@ -0,0 +1,8 @@ +## Committers列表 + +### 以下是此项目的committer人员 +不区分先后顺序 + +- [zjzhu](https://gitee.com/appproject) +- [aibin](https://gitee.com/binai) +- [lihui](https://gitee.com/lihui868) \ No newline at end of file diff --git a/OAT.xml b/OAT.xml index a1e1a7950dadf713a2dde6ce10a619cc69c1ada6..1f5876088898c9ce3f7c46c84ba1023bf5801f27 100644 --- a/OAT.xml +++ b/OAT.xml @@ -137,8 +137,12 @@ used to filter file path. desc="Apache-2.0 文档类文件" /> + + diff --git a/README.OpenSource b/README.OpenSource index d0011eeaca00e7fc9a203f1c48151d3c2b060271..f67241e17a8791d11d8da8230d9381e006b13a5d 100644 --- a/README.OpenSource +++ b/README.OpenSource @@ -1,7 +1,7 @@ [ { "Name": "engine", - "License": "BSD 3-Clause License", + "License": "BSD-3-Clause License", "License File": "LICENSE", "Version Number": "3.7.12", "Owner": "aibin@openvalley.net", diff --git a/README.md b/README.md index 53e171f7932d4487e9ce5deb2d44058ab7403aeb..16a40eda07f0aac888170c266e273952ecfe3eb0 100644 --- a/README.md +++ b/README.md @@ -83,6 +83,8 @@ Flutter Engine 5. 由于windows和mac、linux对换行符处理方式不同,在应用dart补丁时会造成dart vm snapshot hash结果不同,可通过以下方法获取当前snapshot hash值 +6. MediaQuery组件暂不支持displayFeatureType和displayFeatureState信息 + ```shell python xxx/src/third_party/dart/tools/make_version.py --format='{{SNAPSHOT_HASH}}' ``` diff --git a/attachment/repos/angle.patch b/attachment/repos/angle.patch index e4a0952dd4dce8a288dd5aaead27e49bc803628b..837d591f23ed85f2ab797186e1ea5ba54b4f9b58 100644 --- a/attachment/repos/angle.patch +++ b/attachment/repos/angle.patch @@ -1,8 +1,19 @@ diff --git a/BUILD.gn b/BUILD.gn -index efaf09033..73af49870 100644 +index efaf090339..cc0398c0e4 100644 --- a/BUILD.gn +++ b/BUILD.gn -@@ -83,7 +83,7 @@ if (angle_build_all) { +@@ -11,7 +11,9 @@ if (angle_use_wayland) { + import("//build_overrides/wayland.gni") + } + if (angle_has_build) { +- import("//build/config/linux/pkg_config.gni") ++ if (!is_ohos) { ++ import("//build/config/linux/pkg_config.gni") ++ } + import("//build/config/sanitizers/sanitizers.gni") + import("//build/config/ui.gni") + import("//testing/libfuzzer/fuzzer_test.gni") +@@ -83,7 +85,7 @@ if (angle_build_all) { ":translator_fuzzer", ":xxhash_fuzzer", "$angle_root/samples:angle_samples", @@ -11,18 +22,43 @@ index efaf09033..73af49870 100644 ] if (angle_enable_cl) { deps += [ "$angle_root/src/libOpenCL:angle_cl" ] -@@ -486,7 +486,8 @@ angle_static_library("angle_image_util") { - sources = libangle_image_util_sources +@@ -141,7 +143,7 @@ config("internal_config") { + if (angle_is_winuwp) { + defines += [ "ANGLE_IS_WINUWP" ] + } +- } else if (is_linux || is_chromeos) { ++ } else if (is_linux || is_chromeos || is_ohos) { + defines += [ "ANGLE_IS_LINUX" ] + } + +@@ -443,7 +445,7 @@ angle_static_library("angle_common") { + all_dependent_configs = [ ":angle_disable_pool_alloc" ] + } + +- if (is_linux || is_chromeos) { ++ if (is_linux || is_chromeos || is_ohos) { + libs = [ "dl" ] + } + +@@ -487,6 +489,7 @@ angle_static_library("angle_image_util") { public_configs += [ ":angle_image_util_config" ] public_deps = [ ":angle_image_util_headers" ] -- -+ + + angle_has_astc_encoder = false if (angle_has_astc_encoder) { public_deps += [ "third_party/astc-encoder:astcenc" ] include_dirs = [ "third_party/astc-encoder/src/Source/" ] +@@ -561,7 +564,7 @@ angle_static_library("angle_gpu_info_util") { + libs += [ "dxgi.lib" ] + } + +- if (is_linux || is_chromeos) { ++ if (is_linux || is_chromeos || is_ohos) { + sources += libangle_gpu_info_util_linux_sources + + if (angle_use_x11 && angle_has_build) { diff --git a/gni/angle.gni b/gni/angle.gni -index b8086660a..d82d056d6 100644 +index b8086660a1..d82d056d65 100644 --- a/gni/angle.gni +++ b/gni/angle.gni @@ -60,8 +60,7 @@ if (angle_has_build) { @@ -65,7 +101,7 @@ index b8086660a..d82d056d6 100644 angle_build_vulkan_system_info = angle_has_build && !angle_is_winuwp diff --git a/include/EGL/eglplatform.h b/include/EGL/eglplatform.h -index 9ebaf00a9..fe111d115 100644 +index 9ebaf00a9b..fe111d115d 100644 --- a/include/EGL/eglplatform.h +++ b/include/EGL/eglplatform.h @@ -117,13 +117,19 @@ typedef khronos_uintptr_t EGLNativeWindowType; @@ -95,7 +131,7 @@ index 9ebaf00a9..fe111d115 100644 #elif defined(__APPLE__) diff --git a/src/common/angle_version.h b/src/common/angle_version.h -index d9d7e8929..a97e3844b 100644 +index d9d7e8929d..a97e3844ba 100644 --- a/src/common/angle_version.h +++ b/src/common/angle_version.h @@ -14,8 +14,12 @@ @@ -112,7 +148,7 @@ index d9d7e8929..a97e3844b 100644 #define ANGLE_STRINGIFY(x) #x #define ANGLE_MACRO_STRINGIFY(x) ANGLE_STRINGIFY(x) diff --git a/src/compiler/translator/BuildSPIRV.h b/src/compiler/translator/BuildSPIRV.h -index d67bd812b..00d22d025 100644 +index d67bd812ba..00d22d025d 100644 --- a/src/compiler/translator/BuildSPIRV.h +++ b/src/compiler/translator/BuildSPIRV.h @@ -110,6 +110,8 @@ struct SpirvType @@ -124,3 +160,38 @@ index d67bd812b..00d22d025 100644 struct SpirvIdAndIdList { spirv::IdRef id; +diff --git a/src/libANGLE/renderer/gl/BUILD.gn b/src/libANGLE/renderer/gl/BUILD.gn +index c675c26074..6cba114ef8 100644 +--- a/src/libANGLE/renderer/gl/BUILD.gn ++++ b/src/libANGLE/renderer/gl/BUILD.gn +@@ -125,7 +125,7 @@ if (angle_use_x11) { + ] + } + +-if (is_android || is_linux || is_chromeos) { ++if (is_android || is_linux || is_chromeos || is_ohos) { + _gl_backend_sources += [ + "egl/ContextEGL.cpp", + "egl/ContextEGL.h", +@@ -264,7 +264,7 @@ angle_source_set("angle_gl_backend") { + "Xext", + ] + } +- if (is_android || is_linux || is_chromeos) { ++ if (is_android || is_linux || is_chromeos || is_ohos) { + deps += [ "$angle_root/src/common/linux:angle_dma_buf" ] + } + if (is_apple) { +diff --git a/src/libGLESv2.gni b/src/libGLESv2.gni +index 723d7f99f2..dab8b887ce 100644 +--- a/src/libGLESv2.gni ++++ b/src/libGLESv2.gni +@@ -87,7 +87,7 @@ xxhash_sources = [ + "src/common/third_party/xxhash/xxhash.h", + ] + +-if (is_linux || is_chromeos || is_android || is_fuchsia) { ++if (is_linux || is_chromeos || is_android || is_fuchsia || is_ohos) { + libangle_common_sources += [ + "src/common/system_utils_linux.cpp", + "src/common/system_utils_posix.cpp", diff --git a/attachment/repos/build.patch b/attachment/repos/build.patch index bbe17f9809dd6752ee533c0b15c1ec6c84574e57..84c50014e1c32ce13efa69e053f54a61fca03a3e 100644 --- a/attachment/repos/build.patch +++ b/attachment/repos/build.patch @@ -102,16 +102,16 @@ index b8d0f47..a3d1ed9 100644 @@ -313,7 +334,7 @@ if (!is_clang && using_sanitizer) { is_clang = true } - + -use_flutter_cxx = is_clang && (is_linux || is_android || is_mac || is_ios) +use_flutter_cxx = is_clang && (is_linux || is_android || is_mac || is_ios || is_ohos ) - + if (is_msan && !is_linux) { assert(false, "Memory sanitizer is only available on Linux.") @@ -365,7 +386,9 @@ if (is_posix) { ] } - + -if (is_linux) { +if (is_ohos || (is_linux && host_os == "mac")) { + _native_compiler_configs += [ "//build/config/ohos:sdk" ] @@ -160,7 +160,7 @@ index b8d0f47..a3d1ed9 100644 if (is_clang) { host_toolchain = "//build/toolchain/linux:clang_$host_cpu" diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn -index ba20010..17e0487 100644 +index ba20010..5f27c8c 100644 --- a/build/config/compiler/BUILD.gn +++ b/build/config/compiler/BUILD.gn @@ -191,10 +191,16 @@ config("compiler") { @@ -185,7 +185,7 @@ index ba20010..17e0487 100644 } else if (current_cpu == "x86") { cflags += [ "-m32" ] @@ -315,7 +321,7 @@ config("compiler") { - + # Linux/Android common flags setup. # --------------------------------- - if (is_linux || is_android) { @@ -193,8 +193,8 @@ index ba20010..17e0487 100644 cflags += [ "-fPIC", "-pipe", # Use pipes for communicating between sub-processes. Faster. -@@ -334,7 +340,16 @@ config("compiler") { - +@@ -334,7 +340,28 @@ config("compiler") { + # Linux-specific compiler flags setup. # ------------------------------------ - if (is_linux) { @@ -202,7 +202,19 @@ index ba20010..17e0487 100644 + cflags += [ "-pthread" ] + ldflags += [ "-pthread" ] + -+ if (current_cpu == "arm64") { ++ if (current_cpu == "x86") { ++ cflags += [ "--target=x86-linux-ohos" ] ++ ldflags += [ "--target=x86-linux-ohos" ] ++ cflags += [ "-DBORINGSSL_CLANG_SUPPORTS_DOT_ARCH" ] ++ } else if (current_cpu == "x64") { ++ cflags += [ "--target=x86_64-linux-ohos" ] ++ ldflags += [ "--target=x86_64-linux-ohos" ] ++ cflags += [ "-DBORINGSSL_CLANG_SUPPORTS_DOT_ARCH" ] ++ } else if (current_cpu == "arm") { ++ cflags += [ "--target=aarch-linux-ohos" ] ++ ldflags += [ "--target=aarch-linux-ohos" ] ++ cflags += [ "-DBORINGSSL_CLANG_SUPPORTS_DOT_ARCH" ] ++ } else if (current_cpu == "arm64") { + cflags += [ "--target=aarch64-linux-ohos" ] + ldflags += [ "--target=aarch64-linux-ohos" ] + cflags += [ "-DBORINGSSL_CLANG_SUPPORTS_DOT_ARCH" ] @@ -210,8 +222,8 @@ index ba20010..17e0487 100644 + } else if (is_linux) { cflags += [ "-pthread" ] ldflags += [ "-pthread" ] - -@@ -521,9 +536,13 @@ config("runtime_library") { + +@@ -521,9 +548,13 @@ config("runtime_library") { ldflags += [ "-nostdlib++" ] } include_dirs = [ @@ -224,9 +236,9 @@ index ba20010..17e0487 100644 + include_dirs += [ "//third_party/libcxx/include" ] + } } - + # Android standard library setup. -@@ -860,17 +879,35 @@ config("optimize") { +@@ -860,12 +891,14 @@ config("optimize") { cflags = [ "-Oz" ] + common_optimize_on_cflags # Favor size over speed. } else if (is_wasm) { cflags = [ "-Oz" ] @@ -235,34 +247,13 @@ index ba20010..17e0487 100644 } else { cflags = [ "-O2" ] + common_optimize_on_cflags } - + lto_flags = [] - if (enable_lto && (is_ios || is_android || is_fuchsia || is_wasm)) { + if (enable_lto && (is_ios || is_android || is_fuchsia || is_wasm || is_ohos)) { lto_flags += [ "-flto" ] } - -+ if (is_ohos) { -+ cflags += [ -+ "-mcpu=tsv110", -+ "-fwhole-program-vtables", -+ ] -+ } -+ - ldflags = common_optimize_on_ldflags + lto_flags - cflags += lto_flags -+ -+ if (is_ohos) { -+ ldflags += [ -+ "-Wl,--lto-O2", -+ "-Wl,--plugin-opt=-mcpu=tsv110", -+ "-Wl,-mllvm", -+ "-Wl,-wholeprogramdevirt-check=fallback", -+ ] -+ } - } - - # Turn off optimizations. + diff --git a/build/config/ohos/BUILD.gn b/build/config/ohos/BUILD.gn new file mode 100644 index 0000000..b2675d2 @@ -300,10 +291,10 @@ index 0000000..b2675d2 +} diff --git a/build/config/ohos/config.gni b/build/config/ohos/config.gni new file mode 100644 -index 0000000..0022d70 +index 0000000..add7249 --- /dev/null +++ b/build/config/ohos/config.gni -@@ -0,0 +1,13 @@ +@@ -0,0 +1,32 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. @@ -311,7 +302,26 @@ index 0000000..0022d70 +# This file contains common system config stuff for the Ohos build. + +if (is_ohos) { -+ if (current_cpu == "arm64") { ++ # Defines host_os ++ if (host_os == "linux") { ++ ohos_host_os = "linux" ++ } else if (host_os == "mac") { ++ ohos_host_os = "darwin" ++ } else if (host_os == "win") { ++ ohos_host_os = "win" ++ } else { ++ assert(false, "Need Ohos toolchain support for your build OS.") ++ } ++ ++ ++ # ABI ------------------------------------------------------------------------ ++ if (current_cpu == "x86") { ++ ohos_app_abi = "x86" ++ } else if (current_cpu == "x64") { ++ ohos_app_abi = "x86_64" ++ } else if (current_cpu == "arm") { ++ ohos_app_abi = "armeabi-v7a" ++ } else if (current_cpu == "arm64") { + ohos_app_abi = "arm64-v8a" + } else { + assert(false, "Unknown Ohos ABI: " + current_cpu) @@ -864,7 +874,7 @@ index cad6cbc..c17950b 100644 +++ b/build/secondary/third_party/glfw/BUILD.gn @@ -47,6 +47,34 @@ source_set("glfw") { ] - + defines = [ "_GLFW_WIN32" ] + } else if (is_ohos) { + sources += [ @@ -914,6 +924,6 @@ index 65b1623..a89742a 100644 + readelf = "${toolchain_bin}/llvm-readelf" + nm = "${toolchain_bin}/llvm-nm" + strip = "${toolchain_bin}/llvm-strip" - + target_triple_flags = "--target=${custom_target_triple}" sysroot_flags = "--sysroot ${custom_sysroot}" diff --git a/attachment/repos/dart.patch0 b/attachment/repos/dart.patch0 index 04ca043cec6ffd71361c290ec56a2728f68b4704..8094cc2e317d80592662f557836994999c0b947c 100644 --- a/attachment/repos/dart.patch0 +++ b/attachment/repos/dart.patch0 @@ -1,4 +1,4 @@ -diff --git a/pkg/dds/lib/dds.dart b/pkg/dds/lib/dds.dart +diff --git a/pkg/dds/lib/dds.dart b/pkg/dds/lib/dds.dart index 177a9265649..c7038c56ad7 100644 --- a/pkg/dds/lib/dds.dart +++ b/pkg/dds/lib/dds.dart @@ -75,6 +75,60 @@ index 33be98fc0aa..eda146a0580 100644 String? get authCode => _authCode; String? _authCode; +diff --git a/pkg/vm/lib/transformations/ffi/abi.dart b/pkg/vm/lib/transformations/ffi/abi.dart +index cc2d86bafd7..e703419eed7 100644 +--- a/pkg/vm/lib/transformations/ffi/abi.dart ++++ b/pkg/vm/lib/transformations/ffi/abi.dart +@@ -40,6 +40,7 @@ enum _OS { + linux, + macos, + windows, ++ ohos, + } + + /// 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; + ++ /// 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; + +@@ -131,6 +135,7 @@ class Abi { + androidX64, + fuchsiaArm64, + fuchsiaX64, ++ ohosX64, + iosArm, + iosArm64, + iosX64, +@@ -176,6 +181,7 @@ class Abi { + static const _androidX64 = Abi._(_Architecture.x64, _OS.android); + 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 = { + Abi.androidX64: 'androidX64', + 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 = { + // _wordSize64 + Abi.androidArm64: _wordSize64, + Abi.androidX64: _wordSize64, ++ Abi.ohosX64: _wordSize64, + Abi.fuchsiaArm64: _wordSize64, + Abi.fuchsiaX64: _wordSize64, + Abi.iosArm64: _wordSize64, diff --git a/runtime/BUILD.gn b/runtime/BUILD.gn index 13bfd0a724b..042b6a45f7e 100644 --- a/runtime/BUILD.gn @@ -5575,27 +5629,28 @@ index 66fa5a8d564..cc5eb834b3d 100644 #if DART_TARGET_OS_MACOS_IOS #define DART_TARGET_OS_NAME IOS diff --git a/runtime/vm/compiler/ffi/abi.h b/runtime/vm/compiler/ffi/abi.h -index b693ef85255..54b15f48890 100644 +index b693ef85255..6a3f42bd949 100644 --- a/runtime/vm/compiler/ffi/abi.h +++ b/runtime/vm/compiler/ffi/abi.h -@@ -24,6 +24,8 @@ enum class Abi { +@@ -24,6 +24,9 @@ enum class Abi { kAndroidArm64, kAndroidIA32, kAndroidX64, + kOhosArm, + kOhosArm64, ++ kOhosX64, kFuchsiaArm64, kFuchsiaX64, kIOSArm, -@@ -49,9 +51,9 @@ const int64_t num_abis = static_cast(Abi::kWindowsX64) + 1; +@@ -49,9 +52,9 @@ const int64_t num_abis = static_cast(Abi::kWindowsX64) + 1; // - runtime/vm/compiler/frontend/kernel_to_il.cc static_assert(static_cast(Abi::kAndroidArm) == 0, "Enum value unexpected."); -static_assert(static_cast(Abi::kWindowsX64) == 19, -+static_assert(static_cast(Abi::kWindowsX64) == 21, ++static_assert(static_cast(Abi::kWindowsX64) == 22, "Enum value unexpected."); -static_assert(num_abis == 20, "Enum value unexpected."); -+static_assert(num_abis == 22, "Enum value unexpected."); ++static_assert(num_abis == 23, "Enum value unexpected."); // The target ABI. Defines sizes and alignment of native types. Abi TargetAbi(); @@ -7619,6 +7674,166 @@ index b7e5be3eab5..8a8f873f6c5 100644 bool _isAllowedOrigin(String origin) { Uri uri; +diff --git a/sdk/lib/ffi/abi.dart b/sdk/lib/ffi/abi.dart +index e6f08b37d25..5af605a8764 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; + ++ /// 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; + +@@ -94,6 +97,7 @@ class Abi { + androidX64, + fuchsiaArm64, + fuchsiaX64, ++ ohosX64, + iosArm, + iosArm64, + iosX64, +@@ -136,6 +140,7 @@ class Abi { + static const _androidX64 = Abi._(_Architecture.x64, _OS.android); + 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 { + linux, + macos, + windows, ++ ohos, + } +diff --git a/sdk/lib/ffi/c_type.dart b/sdk/lib/ffi/c_type.dart +index ee358c2f79d..1f9e629beb9 100644 +--- a/sdk/lib/ffi/c_type.dart ++++ b/sdk/lib/ffi/c_type.dart +@@ -29,6 +29,7 @@ part of dart.ffi; + Abi.androidX64: 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 { + Abi.androidX64: 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 { + Abi.androidX64: 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 { + Abi.androidX64: 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 { + Abi.androidX64: 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 { + Abi.androidX64: 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 { + Abi.androidX64: 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 { + Abi.androidX64: 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 { + Abi.androidX64: 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 { + Abi.androidX64: 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 { + Abi.androidX64: 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 { + Abi.androidX64: 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 { + Abi.androidX64: 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 { + Abi.androidX64: 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 { + Abi.androidX64: 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/swiftshader.patch b/attachment/repos/swiftshader.patch new file mode 100644 index 0000000000000000000000000000000000000000..4aec1116344c4d142cf0b154553fabdce16760f9 --- /dev/null +++ b/attachment/repos/swiftshader.patch @@ -0,0 +1,98 @@ +diff --git a/src/Reactor/BUILD.gn b/src/Reactor/BUILD.gn +index 676f99f1a..36a581f10 100644 +--- a/src/Reactor/BUILD.gn ++++ b/src/Reactor/BUILD.gn +@@ -95,7 +95,7 @@ if (supports_subzero) { + if (is_win) { + include_dirs += + [ "../../third_party/llvm-subzero/build/Windows/include/" ] +- } else if (is_linux || is_chromeos) { ++ } else if (is_linux || is_chromeos || is_ohos) { + include_dirs += [ "../../third_party/llvm-subzero/build/Linux/include/" ] + } else if (is_fuchsia) { + include_dirs += +@@ -328,7 +328,7 @@ if (supports_llvm) { + "$llvm_dir/configs/common/include/", + ] + +- if (is_linux || is_chromeos) { ++ if (is_linux || is_chromeos || is_ohos) { + include_dirs += [ "$llvm_dir/configs/linux/include/" ] + } else if (is_fuchsia) { + include_dirs += [ "$llvm_dir/configs/fuchsia/include/" ] +diff --git a/src/Reactor/reactor.gni b/src/Reactor/reactor.gni +index 04fad6f81..324003e35 100644 +--- a/src/Reactor/reactor.gni ++++ b/src/Reactor/reactor.gni +@@ -14,7 +14,7 @@ declare_args() { + } + + declare_args() { +- supports_llvm = is_linux || is_chromeos || is_fuchsia || is_win || is_android ++ supports_llvm = is_linux || is_chromeos || is_fuchsia || is_win || is_android || is_ohos + # LLVM uses C++17 features which require macOS 10.12, while Chrome's minimum platform for x86 is 10.11. + # Don't build LLVM on Mac, unless we have to. This only happens on ARM64 devices, which launched with 11.0. + # TODO(b/174843857): Remove check for !supports_subzero once Chrome supports macOS 10.12 +diff --git a/src/System/BUILD.gn b/src/System/BUILD.gn +index 6f61d9f76..bed58a57b 100644 +--- a/src/System/BUILD.gn ++++ b/src/System/BUILD.gn +@@ -29,7 +29,7 @@ swiftshader_source_set("System_headers") { + "SwiftConfig.hpp", + "Timer.hpp", + ] +- if (is_linux || is_chromeos || is_android) { ++ if (is_linux || is_chromeos || is_android || is_ohos) { + sources += [ + "Linux/MemFd.hpp", + ] +@@ -48,7 +48,7 @@ swiftshader_source_set("System") { + "SwiftConfig.cpp", + "Timer.cpp", + ] +- if (is_linux || is_chromeos || is_android) { ++ if (is_linux || is_chromeos || is_android || is_ohos) { + sources += [ + "Linux/MemFd.cpp", + ] +diff --git a/third_party/llvm-10.0/BUILD.gn b/third_party/llvm-10.0/BUILD.gn +index 6c40b2c00..6076f2bea 100644 +--- a/third_party/llvm-10.0/BUILD.gn ++++ b/third_party/llvm-10.0/BUILD.gn +@@ -100,7 +100,7 @@ llvm_include_dirs = [ + "configs/common/lib/Transforms/InstCombine/", + ] + +-if (is_linux || is_chromeos) { ++if (is_linux || is_chromeos || is_ohos) { + llvm_include_dirs += [ "configs/linux/include/" ] + } else if (is_fuchsia) { + llvm_include_dirs += [ "configs/fuchsia/include/" ] +diff --git a/third_party/marl/src/thread.cpp b/third_party/marl/src/thread.cpp +index 30897f020..a6c3031c2 100644 +--- a/third_party/marl/src/thread.cpp ++++ b/third_party/marl/src/thread.cpp +@@ -154,14 +154,6 @@ Thread::Affinity Thread::Affinity::all( + auto thread = pthread_self(); + cpu_set_t cpuset; + CPU_ZERO(&cpuset); +- if (pthread_getaffinity_np(thread, sizeof(cpu_set_t), &cpuset) == 0) { +- int count = CPU_COUNT(&cpuset); +- for (int i = 0; i < count; i++) { +- Core core; +- core.pthread.index = static_cast(i); +- affinity.cores.emplace_back(std::move(core)); +- } +- } + #elif defined(__FreeBSD__) + auto thread = pthread_self(); + cpuset_t cpuset; +@@ -385,8 +377,6 @@ class Thread::Impl { + for (size_t i = 0; i < count; i++) { + CPU_SET(affinity[i].pthread.index, &cpuset); + } +- auto thread = pthread_self(); +- pthread_setaffinity_np(thread, sizeof(cpu_set_t), &cpuset); + #elif defined(__FreeBSD__) + cpuset_t cpuset; + CPU_ZERO(&cpuset); diff --git a/attachment/scripts/config.json b/attachment/scripts/config.json index 9092b1a9391fc583a49e8d2837226597c069ae72..62ec1a4f35c30a76bb80f93234e2f02164c9622b 100644 --- a/attachment/scripts/config.json +++ b/attachment/scripts/config.json @@ -70,5 +70,11 @@ "target": "third_party/boringssl", "type": "patch", "file_path": "flutter/attachment/repos/boringssl.patch" + }, + { + "name": "swiftshader", + "target": "third_party/swiftshader", + "type": "patch", + "file_path": "flutter/attachment/repos/swiftshader.patch" } ] diff --git a/attachment/scripts/config_pre.json b/attachment/scripts/config_pre.json index 9092b1a9391fc583a49e8d2837226597c069ae72..62ec1a4f35c30a76bb80f93234e2f02164c9622b 100644 --- a/attachment/scripts/config_pre.json +++ b/attachment/scripts/config_pre.json @@ -70,5 +70,11 @@ "target": "third_party/boringssl", "type": "patch", "file_path": "flutter/attachment/repos/boringssl.patch" + }, + { + "name": "swiftshader", + "target": "third_party/swiftshader", + "type": "patch", + "file_path": "flutter/attachment/repos/swiftshader.patch" } ] diff --git a/attachment/scripts/ohos.py b/attachment/scripts/ohos.py index 49f44d38657caa856a78706731ed16738aaf13d7..d60c405775fcb9c163d2784360cc1b7097be03d3 100644 --- a/attachment/scripts/ohos.py +++ b/attachment/scripts/ohos.py @@ -28,6 +28,12 @@ from datetime import datetime SUPPORT_BUILD_NAMES = ("clean", "config", "har", "compile", "zip", "zip2", "upload") SUPPORT_BUILD_TYPES = ("debug", "profile", "release") +SUPPORT_ABIS = { + "x86": "x86", + "x64": "x86_64", + "arm": "armeabi-v7a", + "arm64": "arm64-v8a", +} DIR_ROOT = os.path.abspath(os.path.join(sys.argv[0], os.pardir)) OS_NAME = platform.system().lower() IS_WINDOWS = OS_NAME.startswith("win") @@ -61,14 +67,12 @@ class BuildInfo: buildType="release", targetOS="ohos", targetArch="arm64", - targetTriple="arm64-%s-ohos" % OS_NAME, - abi="arm64-v8a", ): self.buildType = buildType self.targetOS = targetOS self.targetArch = targetArch - self.targetTriple = targetTriple - self.abi = abi + self.targetTriple = "%s-%s-%s" % (targetArch, OS_NAME, targetOS) + self.abi = SUPPORT_ABIS[targetArch] def __repr__(self): return "BuildInfo(buildType=%s)" % (self.buildType) @@ -328,11 +332,14 @@ def addParseParam(parser): help='Extra param to src/flutter/tools/gn. Such as: -g "\\--enable-unittests"', ) parser.add_argument( - "--ohos_api_int", type=int, choices=[11, 12], default=12, help="Ohos api int." + "--ohos_api_int", type=int, default=13, help="Ohos api int. Deprecated." ) parser.add_argument( "--har-unstripped", action="store_true", help="Use so.unstripped or not." ) + parser.add_argument( + "--ohos-cpu", type=str, choices=['x64', 'x86', 'arm64', 'arm'], default="arm64" + ) def updateCode(args): @@ -365,7 +372,7 @@ def buildByNameAndType(args): for buildType in SUPPORT_BUILD_TYPES: if not buildType in buildTypes: continue - buildInfo = BuildInfo(buildType=buildType) + buildInfo = BuildInfo(buildType=buildType, targetArch=args.ohos_cpu) for buildName in SUPPORT_BUILD_NAMES: if not buildName in buildNames: continue diff --git a/attachment/scripts/ohos_create_flutter_har.py b/attachment/scripts/ohos_create_flutter_har.py index bf21568bdfe8b10c5f4c6e61513f67daccb386c3..cc481911fe2dfe8a7faf5db65e6d39e3ad93c2c2 100644 --- a/attachment/scripts/ohos_create_flutter_har.py +++ b/attachment/scripts/ohos_create_flutter_har.py @@ -24,76 +24,12 @@ import subprocess import sys -HAR_CONFIG_TEMPLATE = """ -{ - "app": { - "signingConfigs": [], - "products": [ - { - "name": "default", - "signingConfig": "default", - "compileSdkVersion": "%s", - "compatibleSdkVersion": "%s", - "runtimeOS": "HarmonyOS", - } - ], - "buildModeSet": [ - { - "name": "debug", - }, - { - "name": "release" - }, - { - "name": "profile" - }, - ] - }, - "modules": [ - { - "name": "flutter", - "srcPath": "./flutter" - } - ] -} -""" - - -HVIGOR_CONFIG = """ -{ - "modelVersion": "5.0.0", - "dependencies": { - } -} -""" - - def runGitCommand(command): result = subprocess.run(command, capture_output=True, text=True, shell=True) if result.returncode != 0: raise Exception(f"Git command failed: {result.stderr}") return result.stdout.strip() -# 更新har的配置文件,指定编译使用的api版本 -def updateConfig(buildDir, apiInt): - apiVersionMap = { - 11: "4.1.0(11)", - 12: "5.0.0(12)", - } - apiStr = apiVersionMap[apiInt] - with open( - os.path.join(buildDir, "build-profile.json5"), "w", encoding="utf-8" - ) as file: - file.write(HAR_CONFIG_TEMPLATE % (apiStr, apiStr)) - - if apiInt != 11: - with open( - os.path.join(buildDir, "hvigor", "hvigor-config.json5"), - "w", - encoding="utf-8", - ) as file: - file.write(HVIGOR_CONFIG) - # 自动更新flutter.har的版本号,把日期加到末尾。如: 1.0.0-20240731 def updateVersion(buildDir): @@ -137,7 +73,6 @@ def runCommand(command, checkCode=True, timeout=None): # 编译har文件,通过hvigorw的命令行参数指定编译类型(debug/release/profile) def buildHar(buildDir, apiInt, buildType): - updateConfig(buildDir, apiInt) updateVersion(buildDir) hvigorwCommand = "hvigorw" if apiInt != 11 else (".%shvigorw" % os.sep) runCommand( @@ -160,7 +95,7 @@ def main(): parser.add_argument("--native_lib", action="append", help="Native code library.") parser.add_argument("--ohos_abi", help="Native code ABI.") parser.add_argument( - "--ohos_api_int", type=int, choices=[11, 12], help="Ohos api int." + "--ohos_api_int", type=int, default=13, help="Ohos api int. Deprecated." ) options = parser.parse_args() # copy source code diff --git a/fml/BUILD.gn b/fml/BUILD.gn index 03d286857c2d7308c91dca9f445e59e484069b50..bc70dd0f79a47a5b4df373ce29a00f62158a833d 100644 --- a/fml/BUILD.gn +++ b/fml/BUILD.gn @@ -364,6 +364,9 @@ if (enable_unittests) { "time/time_delta_unittest.cc", "time/time_point_unittest.cc", "time/time_unittest.cc", + "platform/ohos/timerfd_unittests.cpp", + "platform/ohos/paths_ohos_unittests.cpp", + "platform/ohos/napi_util_unittests.cpp", ] if (is_mac) { diff --git a/fml/platform/ohos/message_loop_ohos.cc b/fml/platform/ohos/message_loop_ohos.cc index 5e528abe9991ce6d8d7a6b48d4ca7be19db9532a..c918e9e66ccc861f3218867f7bc9b90fdd76148a 100644 --- a/fml/platform/ohos/message_loop_ohos.cc +++ b/fml/platform/ohos/message_loop_ohos.cc @@ -33,7 +33,7 @@ void MessageLoopOhos::OnPollCallback(uv_poll_t* handle, int status, int events) { if (status < 0) { - FML_DLOG(ERROR) << "Poll error:" << uv_strerror(status); + FML_LOG(ERROR) << "Poll error:" << uv_strerror(status); return; } diff --git a/fml/platform/ohos/napi_util_unittests.cpp b/fml/platform/ohos/napi_util_unittests.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a5e67eb19f777e1800dc2b32cacbc27256398165 --- /dev/null +++ b/fml/platform/ohos/napi_util_unittests.cpp @@ -0,0 +1,62 @@ +/* + * 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 "flutter/fml/platform/ohos/napi_util.h" +#include "gtest/gtest.h" + +namespace fml { +namespace { +TEST(NapiUtilTest, NapiUtil01) { + napi_env env = nullptr; + napi_value value = nullptr; + EXPECT_EQ(napi::NapiIsNull(env, value), true); +} + +TEST(NapiUtilTest, NapiUtil02) { + napi_env env = nullptr; + napi_value value = nullptr; + std::string str = "test"; + EXPECT_EQ(napi::GetString(env, value, str), napi::ERROR_TYPE); +} + +TEST(NapiUtilTest, NapiUtil03) { + napi_env env = nullptr; + napi_value value = nullptr; + std::vector vectorStr = {}; + EXPECT_NE(napi::GetArrayString(env, value, vectorStr), napi::SUCCESS); +} + +TEST(NapiUtilTest, NapiUtil04) { + napi_env env = nullptr; + napi_value value = nullptr; + void** message = nullptr; + size_t lenth = 0; + EXPECT_NE(napi::GetArrayBuffer(env, value, message, &lenth), napi::SUCCESS); +} + +TEST(NapiUtilTest, NapiUtil05) { + napi_env env = nullptr; + napi_value value = nullptr; + EXPECT_EQ(napi::NapiIsType(env, value, napi_number), false); +} + +TEST(NapiUtilTest, NapiUtil06) { + napi_env env = nullptr; + napi_ref ref_napi_obj = nullptr; + EXPECT_GT(napi::InvokeJsMethod(env, ref_napi_obj, nullptr, 0, nullptr), 0); +} + +} // namespace +} // namespace fml \ No newline at end of file diff --git a/fml/platform/ohos/paths_ohos_unittests.cpp b/fml/platform/ohos/paths_ohos_unittests.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2267050aad4fcb5ece960c3593c2a31457bedec8 --- /dev/null +++ b/fml/platform/ohos/paths_ohos_unittests.cpp @@ -0,0 +1,29 @@ +/* + * 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 "flutter/fml/platform/ohos/paths_ohos.h" +#include "gtest/gtest.h" + +namespace fml { +namespace { +TEST(PathsTest, PathsOhosTest01) { + fml::paths::InitializeOhosCachesPath("test"); + fml::UniqueFD resultFD = fml::paths::GetCachesDirectory(); + EXPECT_FALSE(resultFD.is_valid()); +} + + +} // namespace +} // namespace fml \ No newline at end of file diff --git a/fml/platform/ohos/timerfd_unittests.cpp b/fml/platform/ohos/timerfd_unittests.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6da8a3f2f74cda75708b49593684aa15bb501dba --- /dev/null +++ b/fml/platform/ohos/timerfd_unittests.cpp @@ -0,0 +1,72 @@ +/* + * 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 +#include +#include +#include +#include "flutter/fml/platform/ohos/timerfd.h" + +#include "gtest/gtest.h" + +using fml::TimePoint; +namespace fml { +namespace { + +class MockFileDescriptor { +public: + MockFileDescriptor() + { + pipe(mFdArray); + } + + ~MockFileDescriptor() + { + close(mFdArray[0]); + close(mFdArray[1]); + } + + int GetReadFd() const { return mFdArray[0]; } + int GetWriteFd() const { return mFdArray[1]; } + + void WriteFireCount(uint64_t count) + { + write(mFdArray[1], &count, sizeof(count)); + } + +private: + int mFdArray[2]; +}; +TEST(TimerfdTest, TimerRearmTest) { + TimePoint timeP; + EXPECT_EQ(TimerRearm(0, timeP), false); +} + +TEST(TimerDrainTest, ReadsFireCountSuccessfully) { + MockFileDescriptor mockFd; + uint64_t expected_count = 1; + mockFd.WriteFireCount(expected_count); + EXPECT_TRUE(TimerDrain(mockFd.GetReadFd())); +} + +TEST(TimerfdTest, TimerFdCreateTest) { + EXPECT_TRUE(timerfd_create(0, 0)); +} + +TEST(TimerfdTest, TimerFdSettimeTest) { + EXPECT_EQ(timerfd_settime(0, 0, nullptr, nullptr), -1); +} + +} // namespace +} // namespace fml \ No newline at end of file diff --git a/lib/ui/window/platform_configuration.cc b/lib/ui/window/platform_configuration.cc index 5972d4aee99239553df92eb69c069d6c293b26ac..07afbfd75d4fd7ae32d0bdbcc42674cb4c8afd32 100644 --- a/lib/ui/window/platform_configuration.cc +++ b/lib/ui/window/platform_configuration.cc @@ -6,13 +6,13 @@ #include +#include "flutter/fml/trace_event.h" #include "flutter/lib/ui/compositing/scene.h" #include "flutter/lib/ui/ui_dart_state.h" #include "flutter/lib/ui/window/platform_message_response_dart.h" #include "flutter/lib/ui/window/platform_message_response_dart_port.h" #include "flutter/lib/ui/window/viewport_metrics.h" #include "flutter/lib/ui/window/window.h" -#include "flutter/fml/trace_event.h" #include "third_party/tonic/converter/dart_converter.h" #include "third_party/tonic/dart_args.h" #include "third_party/tonic/dart_library_natives.h" @@ -145,9 +145,6 @@ void PlatformConfiguration::DispatchPlatformMessage( std::shared_ptr dart_state = dispatch_platform_message_.dart_state().lock(); - FML_DLOG(INFO) - << "DispatchPlatformMessage channel: " - << message->channel(); if (!dart_state) { FML_DLOG(WARNING) << "Dropping platform message for lack of DartState on channel: " @@ -181,9 +178,7 @@ void PlatformConfiguration::DispatchSemanticsAction(int32_t id, fml::MallocMapping args) { std::shared_ptr dart_state = dispatch_semantics_action_.dart_state().lock(); - FML_DLOG(INFO) - << "DispatchSemanticsAction : " - << id ; + if (!dart_state) { return; } @@ -195,7 +190,6 @@ void PlatformConfiguration::DispatchSemanticsAction(int32_t id, if (Dart_IsError(args_handle)) { return; } - tonic::CheckAndHandleError(tonic::DartInvoke( dispatch_semantics_action_.Get(), {tonic::ToDart(id), tonic::ToDart(static_cast(action)), @@ -361,7 +355,6 @@ Dart_Handle PlatformConfigurationNativeApi::SendPortPlatformMessage( void PlatformConfigurationNativeApi::RespondToPlatformMessage( int response_id, const tonic::DartByteData& data) { - FML_DLOG(INFO)<<"PlatformConfigurationNativeApi::RespondToPlatformMessage:" << response_id; if (Dart_IsNull(data.dart_handle())) { UIDartState::Current() ->platform_configuration() diff --git a/shell/common/BUILD.gn b/shell/common/BUILD.gn index 7fa0c1b23ae702ec61d968210891c412fdc6f482..2f8b67095e0e5ba42ac68e68c4f625f00f6b1b01 100644 --- a/shell/common/BUILD.gn +++ b/shell/common/BUILD.gn @@ -185,6 +185,10 @@ if (enable_unittests) { "fixtures/shelltest_screenshot.png", "fixtures/hello_loop_2.gif", ] + + if (is_ohos) { + dest = "/data/flutter_unittests/common" + } } shell_host_executable("shell_benchmarks") { @@ -284,16 +288,12 @@ if (enable_unittests) { testonly = true sources = [ - "animator_unittests.cc", "canvas_spy_unittests.cc", "context_options_unittests.cc", "engine_unittests.cc", - "input_events_unittests.cc", - "persistent_cache_unittests.cc", "pipeline_unittests.cc", "rasterizer_unittests.cc", "resource_cache_limit_calculator_unittests.cc", - "shell_unittests.cc", "switches_unittests.cc", "variable_refresh_rate_display_unittests.cc", "vsync_waiter_unittests.cc", @@ -310,6 +310,15 @@ if (enable_unittests) { "//third_party/googletest:gmock", ] + if (!is_ohos) { + sources += [ + "animator_unittests.cc", + "input_events_unittests.cc", + "persistent_cache_unittests.cc", + "shell_unittests.cc", + ] + } + if (is_fuchsia) { sources += [ "shell_fuchsia_unittests.cc" ] @@ -319,7 +328,7 @@ if (enable_unittests) { "$fuchsia_sdk_root/pkg:fidl_cpp", "$fuchsia_sdk_root/pkg:sys_cpp", ] - } else { + } else if (!is_ohos) { # TODO(63837): This test is hard-coded to use a TestGLSurface so it cannot run on fuchsia. sources += [ "shell_io_manager_unittests.cc" ] diff --git a/shell/config.gni b/shell/config.gni index 85dd360cbc036d5c4276303906ecb56fbcab19ac..4db04f8b5c834f51ceed3be23d295e548416cde7 100644 --- a/shell/config.gni +++ b/shell/config.gni @@ -17,6 +17,6 @@ declare_args() { test_enable_metal = shell_enable_metal # The Vulkan unittests are combined with the GL unittests. - test_enable_vulkan = is_fuchsia || shell_enable_gl + test_enable_vulkan = (is_fuchsia || shell_enable_gl) && !is_ohos test_enable_software = shell_enable_software } diff --git a/shell/gpu/gpu_surface_vulkan.cc b/shell/gpu/gpu_surface_vulkan.cc index ba8383c1343cf63020cb05440406d3b285fe206a..7743289f593248bb944aa77fbe40634c7ea11f1d 100644 --- a/shell/gpu/gpu_surface_vulkan.cc +++ b/shell/gpu/gpu_surface_vulkan.cc @@ -98,6 +98,7 @@ sk_sp GPUSurfaceVulkan::CreateSurfaceFromVulkanImage( const VkImage image, const VkFormat format, const SkISize& size) { +#ifdef SK_VULKAN GrVkImageInfo image_info = { .fImage = image, .fImageTiling = VK_IMAGE_TILING_OPTIMAL, @@ -126,6 +127,9 @@ sk_sp GPUSurfaceVulkan::CreateSurfaceFromVulkanImage( SkColorSpace::MakeSRGB(), // color space &surface_properties // surface properties ); +#else + return nullptr; +#endif // SK_VULKAN } SkColorType GPUSurfaceVulkan::ColorTypeFromFormat(const VkFormat format) { diff --git a/shell/platform/embedder/BUILD.gn b/shell/platform/embedder/BUILD.gn index 56335f45afd715add78c6f571d03c3d1239f4886..b4bd71a775873e98bc3bf9ac15f38bbe42a528a5 100644 --- a/shell/platform/embedder/BUILD.gn +++ b/shell/platform/embedder/BUILD.gn @@ -217,7 +217,7 @@ test_fixtures("fixtures") { ] } -if (enable_unittests) { +if (enable_unittests && !is_ohos) { source_set("embedder_unittests_library") { testonly = true diff --git a/shell/platform/ohos/BUILD.gn b/shell/platform/ohos/BUILD.gn index c8e36f5796a88e0230a7095e12d56d603d38c046..84548cee193d2a885072d0b358a0806dd746d674 100644 --- a/shell/platform/ohos/BUILD.gn +++ b/shell/platform/ohos/BUILD.gn @@ -84,7 +84,13 @@ source_set("flutter_ohos_sources") { "ohos_surface_gl_skia.h", "types.h", "ohos_logging.h", + "platform_view_ohos_delegate.h", + "./accessibility/ohos_accessibility_bridge.h", "./accessibility/ohos_accessibility_features.h", + "./accessibility/ohos_accessibility_manager.h", + "./accessibility/native_accessibility_channel.h", + "./accessibility/ohos_accessibility_ddl.h", + "./utils/ddl_utils.h" ] #configs += [ "//flutter/shell/platform/ohos/config:gtk" ] @@ -115,7 +121,12 @@ source_set("flutter_ohos_sources") { "ohos_image_generator.cpp", "ohos_external_texture_gl.cpp", "./surface/ohos_snapshot_surface_producer.cpp", + "platform_view_ohos_delegate.cpp", + "./accessibility/ohos_accessibility_bridge.cpp", "./accessibility/ohos_accessibility_features.cpp", + "./accessibility/ohos_accessibility_manager.cpp", + "./accessibility/native_accessibility_channel.cpp", + "./accessibility/ohos_accessibility_ddl.cpp" ] # Set flag to stop headers being directly included (library users should not do this) @@ -153,6 +164,28 @@ source_set("flutter_ohos_sources") { } +# accessibility-relevant source set +source_set("flutter_ohos_accessibility_sources") { + public = _public_headers + [ + "./compatibility/ohos_accessibility_interface.h" + ] + + sources = [] + + # Set flag to stop headers being directly included (library users should not do this) + defines = [ + "FLUTTER_LINUX_COMPILATION", + "FLUTTER_ENGINE_NO_PROTOTYPES", + "OHOS_PLATFORM" , + "__MUSL__", + ] + + deps = [] + + public_deps = [] + ldflags = ["-lace_ndk.z"] +} + source_set("flutter_ohos_src") { configs += [ #"//flutter/shell/platform/ohos/config:gtk", @@ -176,10 +209,22 @@ executable("flutter_ohos_unittests") { sources = [ #"testing/mock_texture_registrar.cc", + "testing/ohos_assert_provider_unittests.cpp", + "testing/ohos_context_gl_skia_uinttests.cpp", + "testing/ohos_display_uinttests.cpp", + "testing/ohos_egl_surface_unittests.cpp", + "testing/ohos_environment_gl_unittests.cpp", + "testing/ohos_external_texture_gl_unittests.cpp", + "testing/ohos_surface_gl_skia_unittests.cpp", + "testing/ohos_surface_software_unittests.cpp", + "testing/ohos_touch_processor_unittests.cpp", + "testing/ohos_xcomponent_adapter_unittests.cpp", + "testing/vsync_waiter_ohos_unittests.cpp", ] public_configs = [ "//flutter:config" ] + cflags = ["-Wno-deprecated-declarations"] defines = [ "FLUTTER_ENGINE_NO_PROTOTYPES", @@ -197,6 +242,15 @@ executable("flutter_ohos_unittests") { "//flutter/shell/platform/embedder:embedder_test_utils", "//flutter/testing", ] + + ldflags = ["-lace_ndk.z"] + ldflags += ["-lnative_window"] + ldflags += ["-lnative_vsync"] + ldflags += ["-limage_ndk.z"] + ldflags += ["-lrawfile.z"] + ldflags += ["-lnative_image"] + ldflags += ["-lpixelmap_ndk.z"] + ldflags += ["-lqos"] } shared_library("flutter_shell_native") { @@ -205,26 +259,18 @@ shared_library("flutter_shell_native") { ldflags = ["--rtlib=compiler-rt", "-fuse-ld=lld", -# "-static-libstdc++", -# "-Wl", "--build-id=sha1", -# "-Wl,","--warn-shared-textrel", -# "-Wl,","--fatal-warnings -lunwind", -# "-Wl,","--no-undefined -Qunused-arguments", -# "-Wl,","-z,noexecstack" ] - #ldflags = [ "-Wl,-rpath,\$ORIGIN" ] - #ldflags += ["-L{$OHOS_NDK_LIB}","-lnative_window"] ldflags += ["-lnative_window"] ldflags += ["-lnative_vsync"] ldflags += ["-lace_napi.z"] ldflags += ["-lace_ndk.z"] ldflags += ["-lhilog_ndk.z"] + ldflags += ["-ldeviceinfo_ndk.z"] ldflags += ["-luv"] ldflags += ["-lrawfile.z"] ldflags += ["-lEGL"] ldflags += ["-lGLESv3"] - # ldflags += ["-lGLESv2"] ldflags += ["-limage_ndk.z"] ldflags += ["-lnative_image"] @@ -236,45 +282,19 @@ shared_library("flutter_shell_native") { public_configs = [ "//flutter:config" ] } -#copy("publish_headers_ohos") { -# sources = _public_headers -# outputs = [ "$root_out_dir/flutter_ohos/{{source_file_part}}" ] -#} - -#zip_bundle("flutter_gtk") { -# prefix = "$full_target_platform_name/" -# if (flutter_runtime_mode != "debug" || -# (flutter_runtime_mode == "debug" && target_cpu != "x64")) { -# prefix = "$full_target_platform_name-$flutter_runtime_mode/" -# } -# output = "${prefix}${full_target_platform_name}-flutter-gtk.zip" -# deps = [ -# ":flutter_ohos_gtk", -# ":publish_headers_ohos", -# "//third_party/dart/runtime/bin:gen_snapshot", -# ] -# sources = get_target_outputs(":publish_headers_ohos") -# tmp_files = [] -# foreach(source, sources) { -# tmp_files += [ -# { -# source = source -# destination = rebase_path(source, "$root_build_dir") -# }, -# ] -# } -# tmp_files += [ -# { -# source = "$root_build_dir/libflutter_${host_os}_gtk.so" -# destination = "libflutter_${host_os}_gtk.so" -# }, -# { -# source = "$root_build_dir/gen_snapshot" -# destination = "gen_snapshot" -# }, -# ] -# files = tmp_files -#} +# accessibility-relevant .so +shared_library("flutter_shell_native_accessibility") { + output_name = "flutter_accessibility" + deps = [ ":flutter_ohos_accessibility_sources" ] + + ldflags = ["--rtlib=compiler-rt", + "-fuse-ld=lld", + ] + + ldflags += ["-lace_ndk.z"] + + public_configs = [ "//flutter:config" ] +} declare_args() { embedding_artifact_id = "flutter_embedding_$flutter_runtime_mode" @@ -296,8 +316,10 @@ action("ohos_har") { if (stripped_symbols) { engine_library = "libflutter.so" + accessibility_library = "libflutter_accessibility.so" } else { engine_library = "so.unstripped/libflutter.so" + accessibility_library = "libflutter_accessibility.so" } inputs = [ @@ -321,6 +343,8 @@ action("ohos_har") { rebase_path("flutter.har", root_build_dir, root_build_dir), "--native_lib", rebase_path("$engine_library", root_build_dir, root_build_dir), + "--native_lib", + rebase_path("$accessibility_library", root_build_dir, root_build_dir), "--ohos_abi", ohos_app_abi, "--ohos_api_int", @@ -328,7 +352,8 @@ action("ohos_har") { ] deps = [ - ":flutter_shell_native" + ":flutter_shell_native", + ":flutter_shell_native_accessibility" ] if (flutter_runtime_mode == "profile") { diff --git a/shell/platform/ohos/accessibility/native_accessibility_channel.cpp b/shell/platform/ohos/accessibility/native_accessibility_channel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1d3e8a7a3aa374ae7bbfcaea280754673fbfa46d --- /dev/null +++ b/shell/platform/ohos/accessibility/native_accessibility_channel.cpp @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "native_accessibility_channel.h" +#include "flutter/shell/platform/ohos/ohos_shell_holder.h" +#include "flutter/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h" + +namespace flutter { + + NativeAccessibilityChannel::NativeAccessibilityChannel() {} + + NativeAccessibilityChannel::~NativeAccessibilityChannel() {} + + /** + * 通知flutter框架ohos平台无障碍屏幕朗读已开启 + */ + void NativeAccessibilityChannel::OnOhosAccessibilityEnabled(int64_t shellHolderId) + { + FML_DLOG(INFO) << "NativeAccessibilityChannel -> OnOhosAccessibilityEnabled"; + this->SetSemanticsEnabled(shellHolderId, true); + } + + /** + * 通知flutter框架ohos平台无障碍屏幕朗读未开启 + */ + void NativeAccessibilityChannel::OnOhosAccessibilityDisabled(int64_t shellHolderId) + { + FML_DLOG(INFO) << "NativeAccessibilityChannel -> OnOhosAccessibilityDisabled"; + this->SetSemanticsEnabled(shellHolderId, false); + } + + /** + * Native无障碍通道传递语义感知,若开启则实时更新语义树信息 + */ + void NativeAccessibilityChannel::SetSemanticsEnabled(int64_t shellHolderId, + bool enabled) + { + auto ohos_shell_holder = + reinterpret_cast(shellHolderId); + ohos_shell_holder->GetPlatformView()->SetSemanticsEnabled(enabled); + } + + /** + * Native无障碍通道设置无障碍特征类型,如:无障碍导航、字体加粗等 + */ + void NativeAccessibilityChannel::SetAccessibilityFeatures(int64_t shellHolderId, + int32_t flags) + { + auto ohos_shell_holder = + reinterpret_cast(shellHolderId); + ohos_shell_holder->GetPlatformView()->SetAccessibilityFeatures(flags); + } + + /** + * Native无障碍通道分发flutter屏幕语义动作,如:点击、滑动等 + */ + void NativeAccessibilityChannel::DispatchSemanticsAction( + int64_t shellHolderId, + int32_t id, + flutter::SemanticsAction action, + fml::MallocMapping args) + { + auto ohos_shell_holder = + reinterpret_cast(shellHolderId); + ohos_shell_holder->GetPlatformView()->PlatformView::DispatchSemanticsAction(id, action, fml::MallocMapping()); + } + + /** + * 更新flutter无障碍相关语义信息 + */ + void NativeAccessibilityChannel::UpdateSemantics( + flutter::SemanticsNodeUpdates update, + flutter::CustomAccessibilityActionUpdates actions) + { + auto ohos_a11y_bridge = OhosAccessibilityBridge::GetInstance(); + ohos_a11y_bridge->updateSemantics(update, actions); + } + + /** + * 设置无障碍消息处理器,通过无障碍通道发送处理dart侧传递的相关信息 + */ + void NativeAccessibilityChannel::SetAccessibilityMessageHandler( + std::shared_ptr handler) + { + this->handler = handler; + } + + /** + * 利用通道内部类AccessibilityMessageHandler处理主动播报事件 + */ + void NativeAccessibilityChannel::AccessibilityMessageHandler::Announce( + std::unique_ptr& message) + { + auto ohos_a11y_bridge = OhosAccessibilityBridge::GetInstance(); + ohos_a11y_bridge->Announce(message); + } +} \ No newline at end of file diff --git a/shell/platform/ohos/accessibility/native_accessibility_channel.h b/shell/platform/ohos/accessibility/native_accessibility_channel.h new file mode 100644 index 0000000000000000000000000000000000000000..29d6e895c459d9ab18537c3e57330d0774021bd2 --- /dev/null +++ b/shell/platform/ohos/accessibility/native_accessibility_channel.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef OHOS_NATIVE_ACCESSIBILITY_CHANNEL_H +#define OHOS_NATIVE_ACCESSIBILITY_CHANNEL_H +#include +#include "flutter/fml/mapping.h" +#include "flutter/lib/ui/semantics/semantics_node.h" +#include "flutter/lib/ui/semantics/custom_accessibility_action.h" +namespace flutter { + +class NativeAccessibilityChannel { + public: + NativeAccessibilityChannel(); + ~NativeAccessibilityChannel(); + + void OnOhosAccessibilityEnabled(int64_t shellHolderId); + + void OnOhosAccessibilityDisabled(int64_t shellHolderId); + + void SetSemanticsEnabled(int64_t shellHolderId, bool enabled); + + void SetAccessibilityFeatures(int64_t shellHolderId, int32_t flags); + + void DispatchSemanticsAction(int64_t shellHolderId, + int32_t id, + flutter::SemanticsAction action, + fml::MallocMapping args); + + void UpdateSemantics(flutter::SemanticsNodeUpdates update, + flutter::CustomAccessibilityActionUpdates actions); + + class AccessibilityMessageHandler { + public: + void Announce(std::unique_ptr& message); + + void OnTap(int32_t nodeId); + + void OnLongPress(int32_t nodeId); + + void OnTooltip(std::unique_ptr& message); + }; + + void SetAccessibilityMessageHandler( + std::shared_ptr handler); + + private: + std::shared_ptr handler; +}; +} + +#endif \ No newline at end of file diff --git a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5bda8bfaea0e5a4f3de851e011763c650b5243fb --- /dev/null +++ b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.cpp @@ -0,0 +1,2470 @@ +/* + * 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_accessibility_bridge.h" +#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) \ + +namespace flutter { + +OhosAccessibilityBridge* OhosAccessibilityBridge::bridgeInstance = nullptr; + +OhosAccessibilityBridge* OhosAccessibilityBridge::GetInstance() +{ + if(!bridgeInstance) { + bridgeInstance = new OhosAccessibilityBridge(); + } + return bridgeInstance; +} + +void OhosAccessibilityBridge::DestroyInstance() { + delete bridgeInstance; + bridgeInstance = nullptr; +} + +OhosAccessibilityBridge::OhosAccessibilityBridge() {} + +/** + * 监听当前ohos平台是否开启无障碍屏幕朗读服务 + */ +void OhosAccessibilityBridge::OnOhosAccessibilityStateChange( + int64_t shellHolderId, + bool ohosAccessibilityEnabled) +{ + native_shell_holder_id_ = shellHolderId; + nativeAccessibilityChannel_ = std::make_shared(); + accessibilityFeatures_ = std::make_shared(); + + if (ohosAccessibilityEnabled) { + nativeAccessibilityChannel_->OnOhosAccessibilityEnabled(native_shell_holder_id_); + } else { + accessibilityFeatures_->SetAccessibleNavigation(false, native_shell_holder_id_); + nativeAccessibilityChannel_->OnOhosAccessibilityDisabled(native_shell_holder_id_); + } +} + +void OhosAccessibilityBridge::SetNativeShellHolderId(int64_t id) +{ + this->native_shell_holder_id_ = id; +} + +/** + * 从dart侧传递到c++侧的flutter无障碍语义树节点更新过程 + */ +void OhosAccessibilityBridge::updateSemantics( + flutter::SemanticsNodeUpdates update, + flutter::CustomAccessibilityActionUpdates actions) +{ + FML_DLOG(INFO) << ("OhosAccessibilityBridge::UpdateSemantics()"); + + // 当flutter页面更新时,自动请求id=0节点组件获焦(滑动组件除外) + if (IS_FLUTTER_NAVIGATE) { + RequestFocusWhenPageUpdate(); + IS_FLUTTER_NAVIGATE = 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 ==="; +} + +/** + * flutter可滑动组件的滑动逻辑处理实现 + */ +void OhosAccessibilityBridge::FlutterScrollExecution( + flutter::SemanticsNode 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 (node.HasAction(ACTIONS_::kScrollUp) || + node.HasAction(ACTIONS_::kScrollDown)) { + } else if (node.HasAction(ACTIONS_::kScrollLeft) || + node.HasAction(ACTIONS_::kScrollRight)) { + } + + // 当可滑动组件存在滑动子节点 + 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) + ); + } + } +} + +/** + * 当页面内容/状态更新事件,在页面转换、切换、调整大小时发送页面状态更新事件 + */ +void OhosAccessibilityBridge::FlutterPageUpdate( + ArkUI_AccessibilityEventType eventType) +{ + if (provider_ == nullptr) { + FML_DLOG(ERROR) << "PageStateUpdate ->" + "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* 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()); + } + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityEventSetEventType(pageUpdateEventInfo, eventType) + ); + + 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_, pageUpdateEventInfo, 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(pageUpdateEventInfo); + pageUpdateEventInfo = nullptr; + } +} + +/** + * 特定节点的焦点请求 (当页面更新时自动请求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::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()); + + auto callback = [](int32_t errorCode) { + FML_DLOG(WARNING) << "announce 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_, announceEventInfo, 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(announceEventInfo); + announceEventInfo = nullptr; + } +} + +//获取根节点 +flutter::SemanticsNode OhosAccessibilityBridge::GetFlutterRootSemanticsNode() +{ + if (!g_flutterSemanticsTree.size()) { + FML_DLOG(ERROR) + << "GetFlutterRootSemanticsNode -> g_flutterSemanticsTree.size()=0"; + return {}; + } + if (g_flutterSemanticsTree.find(0) == g_flutterSemanticsTree.end()) { + FML_DLOG(ERROR) << "GetFlutterRootSemanticsNode -> g_flutterSemanticsTree " + "has no keys = 0"; + return {}; + } + return g_flutterSemanticsTree.at(0); +} + +/** + * 根据nodeid获取或创建flutter语义节点 + */ +flutter::SemanticsNode 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; + 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"; + return ARKUI_ACCESSIBILITY_ROOT_PARENT_ID; + } + if (elementId == -1) { + return ARKUI_ACCESSIBILITY_ROOT_PARENT_ID; + } + int32_t childElementId = static_cast(elementId); + for (const auto& item : g_parentChildIdVec) { + if (item.second == childElementId) { + return item.first; + } + } + return RET_ERROR_STATE_CODE; +} + +/** + * 设置并获取xcomponet上渲染的组件的屏幕绝对坐标rect + */ +void OhosAccessibilityBridge::SetAbsoluteScreenRect(int32_t flutterNodeId, + 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"; +} + +std::pair, std::pair> +OhosAccessibilityBridge::GetAbsoluteScreenRect(int32_t flutterNodeId) +{ + if (!g_screenRectMap.empty() && g_screenRectMap.count(flutterNodeId) > 0) { + return g_screenRectMap.at(flutterNodeId); + } else { + FML_DLOG(ERROR) << "GetAbsoluteScreenRect -> flutterNodeId=" + << flutterNodeId << " is not found !"; + return {}; + } +} + +/** + * 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 << ")}"; +} + +/** + * 实现对特定id的flutter节点到arkui的elementinfo节点转化 + */ +void OhosAccessibilityBridge::FlutterNodeToElementInfoById( + ArkUI_AccessibilityElementInfo* elementInfoFromList, + int64_t elementId) +{ + 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)); + + 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)); + + 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")); + + 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(elementInfoFromList, flutterNode.label.c_str())); + } else { + //当elementId >= 1时,根据flutter节点信息配置elementinfo无障碍属性 + FlutterSetElementInfoProperties(elementInfoFromList, elementId); + } + } + FML_DLOG(INFO) << "=== OhosAccessibilityBridge::FlutterNodeToElementInfoById is end ==="; +} + +/** + * 判断源字符串是否包含目标字符串 + */ +bool OhosAccessibilityBridge::Contains(const std::string source, + const std::string target) +{ + return source.find(target) != std::string::npos; +} + +/** + * 配置arkui节点的可操作动作类型 + */ +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 = "获取焦点"; + + 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 = "点击动作"; + + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetOperationActions(elementInfoFromList, actionTypeNum, actions) + ); + } + } +} + +/** + * 根据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()); + } + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetElementId(elementInfoFromList, flutterNode.id) + ); + + // 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()); + } + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetScreenRect(elementInfoFromList, &rect) + ); + 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()); + } + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetParentId(elementInfoFromList, parentId) + ); + FML_DLOG(INFO) << "FlutterNodeToElementInfoById GetParentId = " << parentId; + + // set accessibility text for announcing + std::string text = flutterNode.label; + 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, text.c_str()) + ); + 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()); + } + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetContents(elementInfoFromList, text.c_str()) + ); + + 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()); + } + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetHintText(elementInfoFromList, hint.c_str()) + ); + + // 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()); + } + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetChildNodeIds(elementInfoFromList, childCount, childNodeIds) + ); + + /** + * 根据当前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()); + } + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetAccessibilityLevel(elementInfoFromList, "yes"); + ); + // 无障碍组,设置为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()); + } + ARKUI_ACCESSIBILITY_CALL_CHECK( + OH_ArkUI_AccessibilityElementInfoSetAccessibilityGroup(elementInfoFromList, false); + ); + } +} + +/** + * 将flutter无障碍语义树的转化为层次遍历顺序存储, + * 并按该顺序构建arkui语义树,以实现DevEco Testing + * UIViewer、Hypium自动化测试工具对flutter组件树的可视化 + */ +std::vector OhosAccessibilityBridge::GetLevelOrderTraversalTree(int32_t rootId) +{ + std::vector levelOrderTraversalTree; + std::queue semanticsQue; + + auto root = GetFlutterSemanticsNode(rootId); + semanticsQue.push(root); + + while (!semanticsQue.empty()) { + uint32_t queSize = semanticsQue.size(); + for (uint32_t i=0; i(currNode.id)); + + std::sort(currNode.childrenInTraversalOrder.begin(), + currNode.childrenInTraversalOrder.end()); + for (const auto& childId: currNode.childrenInTraversalOrder) { + auto childNode = GetFlutterSemanticsNode(childId); + semanticsQue.push(childNode); + } + } + } + return levelOrderTraversalTree; +} + +/** + * 创建并配置完整arkui无障碍语义树 + */ +void OhosAccessibilityBridge::BuildArkUISemanticsTree( + int64_t elementId, + ArkUI_AccessibilityElementInfo* elementInfoFromList, + ArkUI_AccessibilityElementInfoList* elementList) +{ + 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); + } + } + } +} + +/** + * 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) +{ + FML_DLOG(INFO) + << "#### FindAccessibilityNodeInfosById input-params ####: elementId = " + << elementId << " mode=" << mode << " requestId=" << requestId + << " elementList= " << elementList; + + if (g_flutterSemanticsTree.size() == 0) { + FML_DLOG(INFO) + << "FindAccessibilityNodeInfosById g_flutterSemanticsTree is null"; + return ARKUI_ACCESSIBILITY_NATIVE_RESULT_FAILED; + } + if (elementList == nullptr) { + FML_DLOG(INFO) << "FindAccessibilityNodeInfosById elementList is null"; + return ARKUI_ACCESSIBILITY_NATIVE_RESULT_FAILED; + } + // 开启无障碍导航功能 + if(elementId == -1 || elementId == 0) { + accessibilityFeatures_->SetAccessibleNavigation(true, native_shell_holder_id_); + } + + 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; + } + + // 过滤非当前屏幕显示的语义节点创建、配置,防止溢出屏幕坐标绘制bug以及优化性能开销 + auto flutterNode = GetFlutterSemanticsNode(static_cast(elementId)); + + 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; +} + +/** + * 解析flutter语义动作,并通过NativAccessibilityChannel分发 + */ +void OhosAccessibilityBridge::DispatchSemanticsAction( + int32_t id, + flutter::SemanticsAction action, + fml::MallocMapping args) +{ + nativeAccessibilityChannel_->DispatchSemanticsAction(native_shell_holder_id_, + id, + action, + fml::MallocMapping()); +} + +/** + * 执行语义动作解析,当FindAccessibilityNodeInfosById找到相应的elementinfo时才会触发该回调函数 + */ +int32_t OhosAccessibilityBridge::ExecuteAccessibilityAction( + int64_t elementId, + ArkUI_Accessibility_ActionType action, + ArkUI_AccessibilityActionArguments* actionArguments, + int32_t requestId) +{ + FML_DLOG(INFO) << "ExecuteAccessibilityAction input-params-> elementId=" + << elementId << " action=" << action + << " requestId=" << requestId + << " *actionArguments=" << actionArguments; + + if (actionArguments == nullptr) { + FML_DLOG(ERROR) << "OhosAccessibilityBridge::ExecuteAccessibilityAction " + "actionArguments = null"; + return ARKUI_ACCESSIBILITY_NATIVE_RESULT_FAILED; + } + + // 获取当前elementid对应的flutter语义节点 + auto flutterNode = GetFlutterSemanticsNode(static_cast(elementId)); + + // 根据当前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, + {}); + 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, {}); + 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); + } + 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 << ")"; + 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 << ")"; + } + 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 << ")"; + } + 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, {}); + 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, {}); + 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, {}); + 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 << ")"; + // 输入框文本选择操作 + 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 << ")"; + // 输入框设置文本 + 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 << ")"; + 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 << ")"; + break; + } + default: { + /** custom semantics action */ + } + } + FML_DLOG(INFO) << "--- ExecuteAccessibilityAction is end ---"; + return ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL; +} + +/** + * Called to obtain element information based on a specified node and text + * content. + */ +int32_t OhosAccessibilityBridge::FindAccessibilityNodeInfosByText( + int64_t elementId, + const char* text, + int32_t requestId, + ArkUI_AccessibilityElementInfoList* elementList) +{ + FML_DLOG(INFO) << "=== FindAccessibilityNodeInfosByText() ==="; + return 0; +} +int32_t OhosAccessibilityBridge::FindFocusedAccessibilityNode( + int64_t elementId, + ArkUI_AccessibilityFocusType focusType, + int32_t requestId, + ArkUI_AccessibilityElementInfo* elementinfo) +{ + FML_DLOG(INFO) << "=== FindFocusedAccessibilityNode() ==="; + return 0; +} +int32_t OhosAccessibilityBridge::FindNextFocusAccessibilityNode( + int64_t elementId, + ArkUI_AccessibilityFocusMoveDirection direction, + int32_t requestId, + ArkUI_AccessibilityElementInfo* elementList) { + FML_DLOG(INFO) << "=== FindNextFocusAccessibilityNode() ==="; + return 0; +} + +int32_t OhosAccessibilityBridge::ClearFocusedFocusAccessibilityNode() +{ + FML_DLOG(INFO) << "=== ClearFocusedFocusAccessibilityNode() ==="; + return 0; +} +int32_t OhosAccessibilityBridge::GetAccessibilityNodeCursorPosition( + int64_t elementId, + int32_t requestId, + int32_t* index) +{ + FML_DLOG(INFO) << "=== GetAccessibilityNodeCursorPosition() ==="; + return 0; +} + +/** + * 将arkui的action类型转化为flutter的action类型 + */ +flutter::SemanticsAction OhosAccessibilityBridge::ArkuiActionsToFlutterActions( + ArkUI_Accessibility_ActionType arkui_action) +{ + switch (arkui_action) { + case ArkUI_Accessibility_ActionType:: + ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_CLICK: + return ACTIONS_::kTap; + + case ArkUI_Accessibility_ActionType:: + ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_LONG_CLICK: + return ACTIONS_::kLongPress; + + case ArkUI_Accessibility_ActionType:: + ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SCROLL_FORWARD: + return ACTIONS_::kScrollUp; + + case ArkUI_Accessibility_ActionType:: + ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SCROLL_BACKWARD: + return ACTIONS_::kScrollDown; + + case ArkUI_Accessibility_ActionType:: + ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_COPY: + return ACTIONS_::kCopy; + + case ArkUI_Accessibility_ActionType:: + ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_CUT: + return ACTIONS_::kCut; + + case ArkUI_Accessibility_ActionType:: + ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_GAIN_ACCESSIBILITY_FOCUS: + return ACTIONS_::kDidGainAccessibilityFocus; + + case ArkUI_Accessibility_ActionType:: + ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_CLEAR_ACCESSIBILITY_FOCUS: + return ACTIONS_::kDidLoseAccessibilityFocus; + + // Text selection action, requiring the setting of selectTextBegin, + // TextEnd, and TextInForward parameters to select a text + // segment in the text box. */ + case ArkUI_Accessibility_ActionType:: + ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SELECT_TEXT: + return ACTIONS_::kSetSelection; + + case ArkUI_Accessibility_ActionType:: + ARKUI_ACCESSIBILITY_NATIVE_ACTION_TYPE_SET_TEXT: + return ACTIONS_::kSetText; + + default: + // might not match to the valid action in arkui + return ACTIONS_::kCustomAction; + } +} + +/** + * 自定义无障碍异步事件发送 + */ +void OhosAccessibilityBridge::Flutter_SendAccessibilityAsyncEvent( + int64_t elementId, + 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; +} + +/** + * 判断当前语义节点是否获焦 + */ +bool OhosAccessibilityBridge::IsNodeFocusable( + const flutter::SemanticsNode& 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(); +} + +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) +{ + if (node.HasFlag(FLAGS_::kIsButton)) { + return "Button"; + } + if (node.HasFlag(FLAGS_::kIsTextField)) { + return "TextField"; + } + if (node.HasFlag(FLAGS_::kIsMultiline)) { + return "TextArea"; + } + if (node.HasFlag(FLAGS_::kIsLink)) { + return "Link"; + } + if (node.HasFlag(FLAGS_::kIsSlider) || node.HasAction(ACTIONS_::kIncrease) || + node.HasAction(ACTIONS_::kDecrease)) { + return "Slider"; + } + if (node.HasFlag(FLAGS_::kIsHeader)) { + return "Header"; + } + if (node.HasFlag(FLAGS_::kIsImage)) { + return "Image"; + } + if (node.HasFlag(FLAGS_::kHasCheckedState)) { + if (node.HasFlag(FLAGS_::kIsInMutuallyExclusiveGroup)) { + // arkui没有RadioButton,这里透传为RadioButton + return "RadioButton"; + } else { + return "Checkbox"; + } + } + if (node.HasFlag(FLAGS_::kHasToggledState)) { + return "Switch"; + } + if (node.HasAction(ACTIONS_::kIncrease) || + node.HasAction(ACTIONS_::kDecrease)) { + return "SeekBar"; + } + if (node.HasFlag(FLAGS_::kHasImplicitScrolling)) { + if (node.HasAction(ACTIONS_::kScrollLeft) || + node.HasAction(ACTIONS_::kScrollRight)) { + return "HorizontalScrollView"; + } else { + return "ScrollView"; + } + } + if ((!node.label.empty() || !node.tooltip.empty() || !node.hint.empty())) { + return "Text"; + } + return "Widget"; +} + +/** + * 判断当前节点是否为textfield文本框 + */ +bool OhosAccessibilityBridge::IsTextField(flutter::SemanticsNode flutterNode) +{ + return flutterNode.HasFlag(FLAGS_::kIsTextField); +} +/** + * 判断当前节点是否为滑动条slider类型 + */ +bool OhosAccessibilityBridge::IsSlider(flutter::SemanticsNode flutterNode) +{ + return flutterNode.HasFlag(FLAGS_::kIsSlider); +} +/** + * 判断当前flutter节点组件是否可点击 + */ +bool OhosAccessibilityBridge::IsNodeClickable( + flutter::SemanticsNode flutterNode) +{ + return flutterNode.HasAction(ACTIONS_::kTap); + flutterNode.HasFlag(FLAGS_::kHasCheckedState) || + flutterNode.HasFlag(FLAGS_::kIsButton) || + flutterNode.HasFlag(FLAGS_::kIsTextField) || + flutterNode.HasFlag(FLAGS_::kIsImage) || + flutterNode.HasFlag(FLAGS_::kIsLiveRegion) || + flutterNode.HasFlag(FLAGS_::kIsMultiline) || + flutterNode.HasFlag(FLAGS_::kIsLink) || + flutterNode.HasFlag(FLAGS_::kIsSlider) || + flutterNode.HasFlag(FLAGS_::kIsKeyboardKey) || + flutterNode.HasFlag(FLAGS_::kHasToggledState) || + flutterNode.HasFlag(FLAGS_::kHasImplicitScrolling); +} +/** + * 判断当前flutter节点组件是否可显示 + */ +bool OhosAccessibilityBridge::IsNodeVisible( + flutter::SemanticsNode flutterNode) +{ + return flutterNode.HasFlag(FLAGS_::kIsHidden) ? false : true; +} +/** + * 判断当前flutter节点组件是否具备checkable属性 + */ +bool OhosAccessibilityBridge::IsNodeCheckable( + flutter::SemanticsNode flutterNode) +{ + return flutterNode.HasFlag(FLAGS_::kHasCheckedState) || + flutterNode.HasFlag(FLAGS_::kHasToggledState); +} +/** + * 判断当前flutter节点组件是否checked/unchecked(checkbox、radio button) + */ +bool OhosAccessibilityBridge::IsNodeChecked( + flutter::SemanticsNode flutterNode) +{ + return flutterNode.HasFlag(FLAGS_::kIsChecked) || + flutterNode.HasFlag(FLAGS_::kIsToggled); +} +/** + * 判断当前flutter节点组件是否选中 + */ +bool OhosAccessibilityBridge::IsNodeSelected( + flutter::SemanticsNode flutterNode) +{ + return flutterNode.HasFlag(FLAGS_::kIsSelected); +} +/** + * 判断当前flutter节点组件是否为密码输入框 + */ +bool OhosAccessibilityBridge::IsNodePassword( + flutter::SemanticsNode flutterNode) +{ + return flutterNode.HasFlag(FLAGS_::kIsTextField) && + flutterNode.HasFlag(FLAGS_::kIsObscured); +} +/** + * 判断当前flutter节点组件是否支持长按功能 + */ +bool OhosAccessibilityBridge::IsNodeHasLongPress( + flutter::SemanticsNode flutterNode) +{ + return flutterNode.HasAction(ACTIONS_::kLongPress); +} +/** + * 判断当前flutter节点是否enabled + */ +bool OhosAccessibilityBridge::IsNodeEnabled( + flutter::SemanticsNode flutterNode) +{ + return !flutterNode.HasFlag(FLAGS_::kHasEnabledState) || + flutterNode.HasFlag(FLAGS_::kIsEnabled); +} +/** + * 判断当前节点是否已经滑动 + */ +bool OhosAccessibilityBridge::HasScrolled( + const flutter::SemanticsNode& flutterNode) +{ + return flutterNode.scrollPosition != std::nan(""); +} +/** + * 判断是否可滑动 + */ +bool OhosAccessibilityBridge::IsNodeScrollable( + flutter::SemanticsNode flutterNode) +{ + return flutterNode.HasAction(ACTIONS_::kScrollLeft) || + flutterNode.HasAction(ACTIONS_::kScrollRight) || + flutterNode.HasAction(ACTIONS_::kScrollUp) || + flutterNode.HasAction(ACTIONS_::kScrollDown); +} +/** + * 判断当前节点组件是否是滑动组件,如: listview, gridview等 + */ +bool OhosAccessibilityBridge::IsScrollableWidget( + flutter::SemanticsNode flutterNode) +{ + return flutterNode.HasFlag(FLAGS_::kHasImplicitScrolling); +} + +void OhosAccessibilityBridge::AddRouteNodes( + std::vector edges, + flutter::SemanticsNode node) +{ + if (node.HasFlag(FLAGS_::kScopesRoute)) { + edges.emplace_back(node); + } + for (auto& childNodeId : node.childrenInTraversalOrder) { + auto childNode = GetFlutterSemanticsNode(childNodeId); + AddRouteNodes(edges, childNode); + } +} + +std::string OhosAccessibilityBridge::GetRouteName(flutter::SemanticsNode node) +{ + if (node.HasFlag(FLAGS_::kNamesRoute) && !node.label.empty()) { + return node.label; + } + for (auto& childNodeId : node.childrenInTraversalOrder) { + auto childNode = GetFlutterSemanticsNode(childNodeId); + std::string newName = GetRouteName(childNode); + if (!newName.empty()) { + return newName; + } + } + return ""; +} + +void OhosAccessibilityBridge::onWindowNameChange(flutter::SemanticsNode route) +{ + std::string routeName = GetRouteName(route); + if (routeName.empty()) { + routeName = " "; + } + Flutter_SendAccessibilityAsyncEvent( + static_cast(route.id), + ArkUI_AccessibilityEventType::ARKUI_ACCESSIBILITY_NATIVE_EVENT_TYPE_PAGE_CONTENT_UPDATE); +} + +void OhosAccessibilityBridge::removeSemanticsNode( + flutter::SemanticsNode nodeToBeRemoved) +{ + if (!g_flutterSemanticsTree.size()) { + FML_DLOG(ERROR) << "OhosAccessibilityBridge::removeSemanticsNode -> " + "g_flutterSemanticsTree.szie()=0"; + return; + } + if (g_flutterSemanticsTree.find(nodeToBeRemoved.id) == + g_flutterSemanticsTree.end()) { + FML_DLOG(INFO) << "Attempted to remove a node that is not in the tree."; + } + int32_t nodeToBeRemovedParentId = GetParentId(nodeToBeRemoved.id); + for (auto it = g_parentChildIdVec.begin(); it != g_parentChildIdVec.end(); it++) { + if (it->first == nodeToBeRemovedParentId && + it->second == nodeToBeRemoved.id) { + g_parentChildIdVec.erase(it); + } + } +} + +/** + * when the system accessibility service is shut down, + * clear all the flutter semantics-relevant caches like maps, vectors + */ +void OhosAccessibilityBridge::ClearFlutterSemanticsCaches() +{ + g_flutterSemanticsTree.clear(); + g_parentChildIdVec.clear(); + g_screenRectMap.clear(); + g_actions_mp.clear(); + g_flutterNavigationVec.clear(); +} + +/** + * extent common struct SemanticsNode to + * derived struct SemanticsNodeExtent + */ +SemanticsNodeExtent OhosAccessibilityBridge::SetAndGetSemanticsNodeExtent( + flutter::SemanticsNode node) +{ + SemanticsNodeExtent nodeEx = SemanticsNodeExtent(); + nodeEx.id = std::move(node.id); + nodeEx.flags = std::move(node.flags); + nodeEx.actions = std::move(node.actions); + nodeEx.maxValueLength = std::move(node.maxValueLength); + nodeEx.currentValueLength = std::move(node.currentValueLength); + nodeEx.textSelectionBase = std::move(node.textSelectionBase); + nodeEx.textSelectionExtent = std::move(node.textSelectionExtent); + nodeEx.platformViewId = std::move(node.platformViewId); + nodeEx.scrollChildren = std::move(node.scrollChildren); + nodeEx.scrollIndex = std::move(node.scrollIndex); + nodeEx.scrollPosition = std::move(node.scrollPosition); + nodeEx.scrollExtentMax = std::move(node.scrollExtentMax); + nodeEx.scrollExtentMin = std::move(node.scrollExtentMin); + nodeEx.elevation = std::move(node.elevation); + nodeEx.thickness = std::move(node.thickness); + nodeEx.label = std::move(node.label); + nodeEx.labelAttributes = std::move(node.labelAttributes); + nodeEx.hint = std::move(node.hint); + nodeEx.hintAttributes = std::move(node.hintAttributes); + nodeEx.value = std::move(node.value); + nodeEx.valueAttributes = std::move(node.valueAttributes); + nodeEx.increasedValue = std::move(node.increasedValue); + nodeEx.increasedValueAttributes = std::move(node.increasedValueAttributes); + nodeEx.decreasedValue = std::move(node.decreasedValue); + nodeEx.decreasedValueAttributes = std::move(node.decreasedValueAttributes); + nodeEx.tooltip = std::move(node.tooltip); + nodeEx.textDirection = std::move(node.textDirection); + + nodeEx.rect = std::move(node.rect); + nodeEx.transform = std::move(node.transform); + nodeEx.childrenInTraversalOrder = std::move(node.childrenInTraversalOrder); + nodeEx.childrenInHitTestOrder = std::move(node.childrenInHitTestOrder); + nodeEx.customAccessibilityActions = + std::move(node.customAccessibilityActions); + return nodeEx; +} + +void OhosAccessibilityBridge::GetSemanticsNodeDebugInfo( + flutter::SemanticsNode node) +{ + 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.tooltip=" << node.tooltip; + FML_DLOG(INFO) << "node.hint=" << node.hint; + FML_DLOG(INFO) << "node.flags=" << node.flags; + FML_DLOG(INFO) << "node.actions=" << node.actions; + FML_DLOG(INFO) << "node.rect= {" << node.rect.fLeft << ", " << node.rect.fTop + << ", " << node.rect.fRight << ", " << node.rect.fBottom + << "}"; + FML_DLOG(INFO) << "node.transform -> kMScaleX=" + << _transform.get(SkMatrix::kMScaleX); + FML_DLOG(INFO) << "node.transform -> kMSkewX=" + << _transform.get(SkMatrix::kMSkewX); + FML_DLOG(INFO) << "node.transform -> kMTransX=" + << _transform.get(SkMatrix::kMTransX); + FML_DLOG(INFO) << "node.transform -> kMSkewY=" + << _transform.get(SkMatrix::kMSkewY); + FML_DLOG(INFO) << "node.transform -> kMScaleY=" + << _transform.get(SkMatrix::kMScaleY); + FML_DLOG(INFO) << "node.transform -> kMTransY=" + << _transform.get(SkMatrix::kMTransY); + FML_DLOG(INFO) << "node.transform -> kMPersp0=" + << _transform.get(SkMatrix::kMPersp0); + FML_DLOG(INFO) << "node.transform -> kMPersp1=" + << _transform.get(SkMatrix::kMPersp1); + FML_DLOG(INFO) << "node.transform -> 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.textSelectionExtent=" << node.textSelectionExtent; + FML_DLOG(INFO) << "node.textSelectionBase=" << node.textSelectionBase; + 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.scrollIndex=" << node.scrollIndex; + FML_DLOG(INFO) << "node.scrollPosition=" << node.scrollPosition; + FML_DLOG(INFO) << "node.scrollExtentMax=" << node.scrollExtentMax; + FML_DLOG(INFO) << "node.scrollExtentMin=" << node.scrollExtentMin; + 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(); + for (uint32_t i = 0; i < node.childrenInTraversalOrder.size(); i++) { + FML_DLOG(INFO) << "node.childrenInTraversalOrder[" << i + << "]=" << node.childrenInTraversalOrder[i]; + } + FML_DLOG(INFO) << "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]; + } + FML_DLOG(INFO) << "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]; + } + FML_DLOG(INFO) << "------------------SemanticsNode-----------------"; +} + +void OhosAccessibilityBridge::GetSemanticsFlagsDebugInfo( + flutter::SemanticsNode node) +{ + FML_DLOG(INFO) << "----------------SemanticsFlags-------------------------"; + FML_DLOG(INFO) << "node.id=" << node.id; + FML_DLOG(INFO) << "node.label=" << node.label; + FML_DLOG(INFO) << "kHasCheckedState: " + << node.HasFlag(FLAGS_::kHasCheckedState); + FML_DLOG(INFO) << "kIsChecked:" << node.HasFlag(FLAGS_::kIsChecked); + FML_DLOG(INFO) << "kIsSelected:" << node.HasFlag(FLAGS_::kIsSelected); + FML_DLOG(INFO) << "kIsButton:" << node.HasFlag(FLAGS_::kIsButton); + FML_DLOG(INFO) << "kIsTextField:" << node.HasFlag(FLAGS_::kIsTextField); + FML_DLOG(INFO) << "kIsFocused:" << node.HasFlag(FLAGS_::kIsFocused); + FML_DLOG(INFO) << "kHasEnabledState:" + << node.HasFlag(FLAGS_::kHasEnabledState); + FML_DLOG(INFO) << "kIsEnabled:" << node.HasFlag(FLAGS_::kIsEnabled); + FML_DLOG(INFO) << "kIsInMutuallyExclusiveGroup:" + << node.HasFlag(FLAGS_::kIsInMutuallyExclusiveGroup); + FML_DLOG(INFO) << "kIsHeader:" << node.HasFlag(FLAGS_::kIsHeader); + FML_DLOG(INFO) << "kIsObscured:" << node.HasFlag(FLAGS_::kIsObscured); + FML_DLOG(INFO) << "kScopesRoute:" << node.HasFlag(FLAGS_::kScopesRoute); + FML_DLOG(INFO) << "kNamesRoute:" << node.HasFlag(FLAGS_::kNamesRoute); + FML_DLOG(INFO) << "kIsHidden:" << node.HasFlag(FLAGS_::kIsHidden); + FML_DLOG(INFO) << "kIsImage:" << node.HasFlag(FLAGS_::kIsImage); + FML_DLOG(INFO) << "kIsLiveRegion:" << node.HasFlag(FLAGS_::kIsLiveRegion); + FML_DLOG(INFO) << "kHasToggledState:" + << node.HasFlag(FLAGS_::kHasToggledState); + FML_DLOG(INFO) << "kIsToggled:" << node.HasFlag(FLAGS_::kIsToggled); + FML_DLOG(INFO) << "kHasImplicitScrolling:" + << node.HasFlag(FLAGS_::kHasImplicitScrolling); + FML_DLOG(INFO) << "kIsMultiline:" << node.HasFlag(FLAGS_::kIsMultiline); + FML_DLOG(INFO) << "kIsReadOnly:" << node.HasFlag(FLAGS_::kIsReadOnly); + FML_DLOG(INFO) << "kIsFocusable:" << node.HasFlag(FLAGS_::kIsFocusable); + FML_DLOG(INFO) << "kIsLink:" << node.HasFlag(FLAGS_::kIsLink); + FML_DLOG(INFO) << "kIsSlider:" << node.HasFlag(FLAGS_::kIsSlider); + FML_DLOG(INFO) << "kIsKeyboardKey:" << node.HasFlag(FLAGS_::kIsKeyboardKey); + FML_DLOG(INFO) << "kIsCheckStateMixed:" + << node.HasFlag(FLAGS_::kIsCheckStateMixed); + FML_DLOG(INFO) << "----------------SemanticsFlags--------------------"; + } + + void OhosAccessibilityBridge::GetCustomActionDebugInfo( + flutter::CustomAccessibilityAction customAccessibilityAction) + { + FML_DLOG(INFO) << "--------------CustomAccessibilityAction------------"; + FML_DLOG(INFO) << "customAccessibilityAction.id=" + << customAccessibilityAction.id; + FML_DLOG(INFO) << "customAccessibilityAction.overrideId=" + << customAccessibilityAction.overrideId; + FML_DLOG(INFO) << "customAccessibilityAction.label=" + << customAccessibilityAction.label; + FML_DLOG(INFO) << "customAccessibilityAction.hint=" + << customAccessibilityAction.hint; + FML_DLOG(INFO) << "------------CustomAccessibilityAction--------------"; +} +} // namespace flutter diff --git a/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h new file mode 100644 index 0000000000000000000000000000000000000000..5f03fdc839f5ec12e06b19a5cadd4e57f21eeb61 --- /dev/null +++ b/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h @@ -0,0 +1,342 @@ +/* + * 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_ACCESSIBILITY_BRIDGE_H +#define OHOS_ACCESSIBILITY_BRIDGE_H +#include +#include +#include +#include +#include +#include +#include "flutter/fml/mapping.h" +#include "flutter/lib/ui/semantics/custom_accessibility_action.h" +#include "flutter/lib/ui/semantics/semantics_node.h" +#include "native_accessibility_channel.h" +#include "ohos_accessibility_features.h" +#include "ohos_accessibility_ddl.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}; + } +}; + +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; +}; + +/** + * 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); +}; + +enum class AccessibilityAction : int32_t { + kTap = 1 << 0, + kLongPress = 1 << 1, + kScrollLeft = 1 << 2, + kScrollRight = 1 << 3, + kScrollUp = 1 << 4, + kScrollDown = 1 << 5, + kIncrease = 1 << 6, + kDecrease = 1 << 7, + kShowOnScreen = 1 << 8, + kMoveCursorForwardByCharacter = 1 << 9, + kMoveCursorBackwardByCharacter = 1 << 10, + kSetSelection = 1 << 11, + kCopy = 1 << 12, + kCut = 1 << 13, + kPaste = 1 << 14, + kDidGainAccessibilityFocus = 1 << 15, + kDidLoseAccessibilityFocus = 1 << 16, + kCustomAction = 1 << 17, + kDismiss = 1 << 18, + kMoveCursorForwardByWord = 1 << 19, + kMoveCursorBackwardByWord = 1 << 20, + kSetText = 1 << 21, +}; + +enum class AccessibilityFlags : int32_t { + kHasCheckedState = 1 << 0, + kIsChecked = 1 << 1, + kIsSelected = 1 << 2, + kIsButton = 1 << 3, + kIsTextField = 1 << 4, + kIsFocused = 1 << 5, + kHasEnabledState = 1 << 6, + kIsEnabled = 1 << 7, + kIsInMutuallyExclusiveGroup = 1 << 8, + kIsHeader = 1 << 9, + kIsObscured = 1 << 10, + kScopesRoute = 1 << 11, + kNamesRoute = 1 << 12, + kIsHidden = 1 << 13, + kIsImage = 1 << 14, + kIsLiveRegion = 1 << 15, + kHasToggledState = 1 << 16, + kIsToggled = 1 << 17, + kHasImplicitScrolling = 1 << 18, + kIsMultiline = 1 << 19, + kIsReadOnly = 1 << 20, + kIsFocusable = 1 << 21, + kIsLink = 1 << 22, + kIsSlider = 1 << 23, + kIsKeyboardKey = 1 << 24, + kIsCheckStateMixed = 1 << 25, +}; + +} // namespace flutter +#endif // OHOS_ACCESSIBILITY_BRIDGE_H diff --git a/shell/platform/ohos/accessibility/ohos_accessibility_ddl.cpp b/shell/platform/ohos/accessibility/ohos_accessibility_ddl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..39ea57e8a991583519592ae3fd4e3d206c2e3786 --- /dev/null +++ b/shell/platform/ohos/accessibility/ohos_accessibility_ddl.cpp @@ -0,0 +1,287 @@ +/* + * 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_accessibility_ddl.h" + +namespace flutter { + +OhosAccessibilityDDL::OhosAccessibilityDDL() = default; +OhosAccessibilityDDL::~OhosAccessibilityDDL() = default; + +RegisterFunc OhosAccessibilityDDL::DLLoadRegisterFunc(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; +} + +SendAsyncEventFunc OhosAccessibilityDDL::DLLoadSendAsyncEventFunc(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; +} + +GetElemFunc OhosAccessibilityDDL::DLLoadGetElemFunc(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; +} + +CreateElemInfoFunc OhosAccessibilityDDL::DLLoadCreateElemInfoFunc(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; +} + +CreateEventInfoFunc OhosAccessibilityDDL::DLLoadCreateEventInfoFunc(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; +} + +DestroyElemFunc OhosAccessibilityDDL::DLLoadDestroyElemFunc(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; +} + +DestroyEventFunc OhosAccessibilityDDL::DLLoadDestroyEventFunc(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; +} + + +SetElemIntFunc OhosAccessibilityDDL::DLLoadSetElemIntFunc(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; +} +SetElemStringFunc OhosAccessibilityDDL::DLLoadSetElemStringFunc(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; +} +SetElemBoolFunc OhosAccessibilityDDL::DLLoadSetElemBoolFunc(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; +} +SetElemChildFunc OhosAccessibilityDDL::DLLoadSetElemChildFunc(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; +} + + +SetElemOperActionsFunc OhosAccessibilityDDL::DLLoadSetElemOperActionsFunc(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; +} +SetElemSreenRectFunc OhosAccessibilityDDL::DLLoadSetElemSreenRectFunc(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; +} +SetEventFunc OhosAccessibilityDDL::DLLoadSetEventFunc(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; +} +SetEventElemFunc OhosAccessibilityDDL::DLLoadSetEventElemFunc(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; +} + +SetReqFocusFunc OhosAccessibilityDDL::DLLoadSetReqFocusFunc(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; +} + +SetEventStringFunc OhosAccessibilityDDL::DLLoadSetEventStringFunc(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; +} + +GetNativeA11yProvider OhosAccessibilityDDL::DLLoadGetNativeA11yProvider(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 new file mode 100644 index 0000000000000000000000000000000000000000..c5d6c3263147685c653237323624f99b5b7cfa81 --- /dev/null +++ b/shell/platform/ohos/accessibility/ohos_accessibility_ddl.h @@ -0,0 +1,82 @@ +/* + * 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_ACCESSIBILITY_DDL_H +#define OHOS_ACCESSIBILITY_DDL_H +#include +#include +#include "flutter/shell/platform/ohos/utils/ddl_utils.h" + +namespace flutter { + +using RegisterFunc = int32_t (*)(ArkUI_AccessibilityProvider*, ArkUI_AccessibilityProviderCallbacks*); +using SendAsyncEventFunc = void (*)(ArkUI_AccessibilityProvider*, ArkUI_AccessibilityEventInfo*, void (*)(int32_t)); +using GetElemFunc = ArkUI_AccessibilityElementInfo* (*)(ArkUI_AccessibilityElementInfoList*); + +using CreateElemInfoFunc = ArkUI_AccessibilityElementInfo* (*)(void); +using CreateEventInfoFunc = ArkUI_AccessibilityEventInfo* (*)(void); +using DestroyElemFunc = void (*)(ArkUI_AccessibilityElementInfo*); +using DestroyEventFunc = void (*)(ArkUI_AccessibilityEventInfo*); + +using SetElemIntFunc = int32_t (*)(ArkUI_AccessibilityElementInfo*, int32_t); +using SetElemStringFunc = int32_t (*)(ArkUI_AccessibilityElementInfo*, const char*); +using SetEventStringFunc = int32_t (*)(ArkUI_AccessibilityEventInfo*, const char*); +using SetElemBoolFunc = int32_t (*)(ArkUI_AccessibilityElementInfo*, bool); +using SetElemChildFunc = int32_t (*)(ArkUI_AccessibilityElementInfo*, int32_t, int64_t*); + +using SetElemOperActionsFunc = int32_t (*)(ArkUI_AccessibilityElementInfo*, int32_t, ArkUI_AccessibleAction*); +using SetElemSreenRectFunc = int32_t (*)(ArkUI_AccessibilityElementInfo*, ArkUI_AccessibleRect*); +using SetEventFunc = int32_t (*)(ArkUI_AccessibilityEventInfo*, ArkUI_AccessibilityEventType); +using SetEventElemFunc = int32_t (*)(ArkUI_AccessibilityEventInfo*, ArkUI_AccessibilityElementInfo*); + +using SetReqFocusFunc = int32_t (*)(ArkUI_AccessibilityEventInfo*, int32_t); +using GetNativeA11yProvider = int32_t (*)(OH_NativeXComponent*, ArkUI_AccessibilityProvider**); + +class OhosAccessibilityDDL { +public: + OhosAccessibilityDDL(); + ~OhosAccessibilityDDL(); + + static constexpr char ACCESSIBILITY_LIB_NAME[] = "libflutter_accessibility.so"; + + static RegisterFunc DLLoadRegisterFunc(const char* symbolName); + static SendAsyncEventFunc DLLoadSendAsyncEventFunc(const char* symbolName); + static GetElemFunc DLLoadGetElemFunc(const char* symbolName); + + static CreateElemInfoFunc DLLoadCreateElemInfoFunc(const char* symbolName); + static CreateEventInfoFunc DLLoadCreateEventInfoFunc(const char* symbolName); + static DestroyElemFunc DLLoadDestroyElemFunc(const char* symbolName); + static DestroyEventFunc DLLoadDestroyEventFunc(const char* symbolName); + + static SetElemIntFunc DLLoadSetElemIntFunc(const char* symbolName); + static SetElemStringFunc DLLoadSetElemStringFunc(const char* symbolName); + static SetEventStringFunc DLLoadSetEventStringFunc(const char* symbolName); + static SetElemBoolFunc DLLoadSetElemBoolFunc(const char* symbolName); + static SetElemChildFunc DLLoadSetElemChildFunc(const char* symbolName); + + static SetElemOperActionsFunc DLLoadSetElemOperActionsFunc(const char* symbolName); + static SetElemSreenRectFunc DLLoadSetElemSreenRectFunc(const char* symbolName); + static SetEventFunc DLLoadSetEventFunc(const char* symbolName); + static SetEventElemFunc DLLoadSetEventElemFunc(const char* symbolName); + static SetReqFocusFunc DLLoadSetReqFocusFunc(const char* symbolName); + + static GetNativeA11yProvider DLLoadGetNativeA11yProvider(const char* symbolName); + + +}; + + +} // namespace flutter + +#endif \ No newline at end of file diff --git a/shell/platform/ohos/accessibility/ohos_accessibility_features.cpp b/shell/platform/ohos/accessibility/ohos_accessibility_features.cpp index 6953998fe39973bcde04d3c9f1f9a9d1539d0f40..9f4c87850842da1609d0bf3d683d362b0b0c83be 100644 --- a/shell/platform/ohos/accessibility/ohos_accessibility_features.cpp +++ b/shell/platform/ohos/accessibility/ohos_accessibility_features.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd. + * Copyright (C) 2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -12,48 +12,69 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "flutter/shell/platform/ohos/accessibility/ohos_accessibility_features.h" -#include "flutter/shell/platform/ohos/ohos_shell_holder.h" +#include "ohos_accessibility_features.h" #include "flutter/fml/logging.h" +#include "flutter/shell/platform/ohos/ohos_shell_holder.h" namespace flutter { - OhosAccessibilityFeatures OhosAccessibilityFeatures::instance; +OhosAccessibilityFeatures::OhosAccessibilityFeatures() +{ + nativeAccessibilityChannel_ = std::make_shared(); +}; - OhosAccessibilityFeatures::OhosAccessibilityFeatures() {}; - OhosAccessibilityFeatures::~OhosAccessibilityFeatures() {}; +OhosAccessibilityFeatures::~OhosAccessibilityFeatures() {}; - OhosAccessibilityFeatures* OhosAccessibilityFeatures::GetInstance() { - return &OhosAccessibilityFeatures::instance; +/** + * 无障碍特征之无障碍导航 + */ +void OhosAccessibilityFeatures::SetAccessibleNavigation( + bool isAccessibleNavigation, + int64_t shell_holder_id) +{ + if (ACCESSIBLE_NAVIGATION == isAccessibleNavigation) { + return; } + ACCESSIBLE_NAVIGATION = isAccessibleNavigation; + if (ACCESSIBLE_NAVIGATION) { + accessibilityFeatureFlags |= + static_cast(AccessibilityFeatures::AccessibleNavigation); + FML_DLOG(INFO) << "SetAccessibleNavigation -> accessibilityFeatureFlags: " + << accessibilityFeatureFlags; + } else { + accessibilityFeatureFlags &= + ~static_cast(AccessibilityFeatures::AccessibleNavigation); + } + SendAccessibilityFlags(shell_holder_id); +} - /** - * bold text for AccessibilityFeature - */ - void OhosAccessibilityFeatures::SetBoldText(double fontWeightScale, int64_t shell_holder_id) { - bool shouldBold = fontWeightScale > 1.0; - - if (shouldBold) { - accessibilityFeatureFlags |= static_cast(flutter::AccessibilityFeatureFlag::kBoldText); - FML_DLOG(INFO) << "SetBoldText -> accessibilityFeatureFlags: "<(flutter::AccessibilityFeatureFlag::kBoldText); - } - - SendAccessibilityFlags(shell_holder_id); +/** + * 无障碍特征之字体加粗 + */ +void OhosAccessibilityFeatures::SetBoldText(double fontWeightScale, + int64_t shell_holder_id) { + bool shouldBold = fontWeightScale > 1.0; + if (shouldBold) { + accessibilityFeatureFlags |= + static_cast(AccessibilityFeatures::BoldText); + FML_DLOG(INFO) << "SetBoldText -> accessibilityFeatureFlags: " + << accessibilityFeatureFlags; + } else { + accessibilityFeatureFlags &= + static_cast(AccessibilityFeatures::BoldText); } - - /** - * send the accessibility flags to flutter dart sdk - */ - void OhosAccessibilityFeatures::SendAccessibilityFlags(int64_t shell_holder_id) { - auto ohos_shell_holder = reinterpret_cast(shell_holder_id); - ohos_shell_holder->GetPlatformView()->PlatformView::SetAccessibilityFeatures(accessibilityFeatureFlags); - FML_DLOG(INFO) << "SendAccessibilityFlags -> accessibilityFeatureFlags = " - << accessibilityFeatureFlags; - // set accessibility feature flag to 0 - accessibilityFeatureFlags = 0; - } + SendAccessibilityFlags(shell_holder_id); +} + +/** + * send the accessibility flags to flutter dart sdk + */ +void OhosAccessibilityFeatures::SendAccessibilityFlags( + int64_t shell_holder_id) { + nativeAccessibilityChannel_->SetAccessibilityFeatures(shell_holder_id, accessibilityFeatureFlags); + FML_DLOG(INFO) << "SendAccessibilityFlags -> accessibilityFeatureFlags = " + << accessibilityFeatureFlags; + accessibilityFeatureFlags = 0; +} -} \ No newline at end of file +} // namespace flutter \ No newline at end of file diff --git a/shell/platform/ohos/accessibility/ohos_accessibility_features.h b/shell/platform/ohos/accessibility/ohos_accessibility_features.h index b6abf906b0166c9115ea3932ea239afe8c1bee52..1163180d65194e5bc38ac4aeb66112dafa7634ba 100644 --- a/shell/platform/ohos/accessibility/ohos_accessibility_features.h +++ b/shell/platform/ohos/accessibility/ohos_accessibility_features.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd. + * Copyright (C) 2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -16,27 +16,43 @@ #define OHOS_ACCESSIBILITY_FEATURES_H #include #include "flutter/lib/ui/window/platform_configuration.h" +#include "native_accessibility_channel.h" #include "flutter/shell/platform/ohos/napi/platform_view_ohos_napi.h" - namespace flutter { class OhosAccessibilityFeatures { - public: - OhosAccessibilityFeatures(); - ~OhosAccessibilityFeatures(); + public: + OhosAccessibilityFeatures(); + ~OhosAccessibilityFeatures(); + + bool ACCESSIBLE_NAVIGATION = false; - static OhosAccessibilityFeatures* GetInstance(); + void SetAccessibleNavigation(bool isAccessibleNavigation, + int64_t shell_holder_id); + void SetBoldText(double fontWeightScale, int64_t shell_holder_id); - void SetBoldText(double fontWeightScale, int64_t shell_holder_id); - void SendAccessibilityFlags(int64_t shell_holder_id); + void SendAccessibilityFlags(int64_t shell_holder_id); - private: - static OhosAccessibilityFeatures instance; + private: + std::shared_ptr nativeAccessibilityChannel_; + int32_t accessibilityFeatureFlags = 0; +}; - // Font weight adjustment (FontWeight.Bold - FontWeight.Normal = w700 - w400 = 300) - static const int32_t BOLD_TEXT_WEIGHT_ADJUSTMENT = 300; - int32_t accessibilityFeatureFlags = 0; +/** + * 无障碍特征枚举类(flutter平台通用) + * 注意:必须同src/flutter/lib/ui/window/platform_configuration.h + * 中的`AccessibilityFeatureFlag`枚举类保持一致 + */ +enum AccessibilityFeatures : int32_t { + AccessibleNavigation = 1 << 0, + InvertColors = 1 << 1, + DisableAnimations = 1 << 2, + BoldText = 1 << 3, + ReduceMotion = 1 << 4, + HighContrast = 1 << 5, + OnOffSwitchLabels = 1 << 6, }; - -} -#endif \ No newline at end of file + +} // namespace flutter + +#endif \ No newline at end of file diff --git a/shell/platform/ohos/accessibility/ohos_accessibility_manager.cpp b/shell/platform/ohos/accessibility/ohos_accessibility_manager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e9b1499f702b7dd1a5adcb535340ca0d9b280b2c --- /dev/null +++ b/shell/platform/ohos/accessibility/ohos_accessibility_manager.cpp @@ -0,0 +1,39 @@ +/* + * 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_accessibility_manager.h" + +namespace flutter { + +OhosAccessibilityManager::OhosAccessibilityManager() {} + +OhosAccessibilityManager::~OhosAccessibilityManager() {} + +/** + * 监听ohos平台是否开启无障碍屏幕朗读功能 + */ +void OhosAccessibilityManager::OnAccessibilityStateChanged( + bool ohosAccessibilityEnabled) {} + +void OhosAccessibilityManager::SetOhosAccessibilityEnabled(bool isEnabled) +{ + this->isOhosAccessibilityEnabled_ = isEnabled; +} + +bool OhosAccessibilityManager::GetOhosAccessibilityEnabled() +{ + return this->isOhosAccessibilityEnabled_; +} + +} // namespace flutter diff --git a/shell/platform/ohos/accessibility/ohos_accessibility_manager.h b/shell/platform/ohos/accessibility/ohos_accessibility_manager.h new file mode 100644 index 0000000000000000000000000000000000000000..e3c873fe8c3113875d1ae2a6028c5507b899c36c --- /dev/null +++ b/shell/platform/ohos/accessibility/ohos_accessibility_manager.h @@ -0,0 +1,40 @@ +/* + * 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_ACCESSIBILITY_MANAGER_H +#define OHOS_ACCESSIBILITY_MANAGER_H +#include + +namespace flutter { +/** + * 无障碍辅助管理类 + */ +class OhosAccessibilityManager { + public: + OhosAccessibilityManager(); + ~OhosAccessibilityManager(); + + void OnAccessibilityStateChanged(bool ohosAccessibilityEnabled); + + bool GetOhosAccessibilityEnabled(); + + void SetOhosAccessibilityEnabled(bool isEnabled); + + private: + bool isOhosAccessibilityEnabled_; +}; + +} // namespace flutter + +#endif \ No newline at end of file diff --git a/shell/platform/ohos/compatibility/ohos_accessibility_interface.h b/shell/platform/ohos/compatibility/ohos_accessibility_interface.h new file mode 100644 index 0000000000000000000000000000000000000000..5a4ca0769d3a91c1466bd57753302175836bc932 --- /dev/null +++ b/shell/platform/ohos/compatibility/ohos_accessibility_interface.h @@ -0,0 +1,703 @@ +/* + * 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. + */ + +/** + * @addtogroup ArkUI_Accessibility + * @{ + * + * @brief Describes the native capabilities supported by ArkUI Accessibility, such as querying accessibility nodes and + * reporting accessibility events. + * + * @since 13 + */ + +/** + * @file native_interface_accessibility.h + * + * @brief Declares the APIs used to access the native Accessibility. + * + * @library libace_ndk.z.so + * @syscap SystemCapability.ArkUI.ArkUI.Full + * @kit ArkUI + * @since 13 + */ +#ifndef OHOS_ACCESSIBILITY_INTERFACE_H +#define OHOS_ACCESSIBILITY_INTERFACE_H + +#include +#include +#ifdef __cplusplus +#include +#else +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Obtains the pointer to the ArkUI_AccessibilityProvider + * instance of this OH_NativeXComponent instance. + * + * @param component Indicates the pointer to the OH_NativeXComponent instance. + * @param handle Indicates the pointer to the ArkUI_AccessibilityProvider instance. + * @return Returns {@link OH_NATIVEXCOMPONENT_RESULT_SUCCESS} if the operation is successful. + * Returns {@link OH_NATIVEXCOMPONENT_RESULT_BAD_PARAMETER} if a parameter error occurs. + * @since 13 + */ +int32_t OH_NativeXComponent_GetNativeAccessibilityProvider( + OH_NativeXComponent* component, ArkUI_AccessibilityProvider** handle); + +/** + * @brief Registers a callback for this ArkUI_AccessibilityProvider instance. + * + * @param provider Indicates the pointer to the ArkUI_AccessibilityProvider instance. + * @param callbacks Indicates the pointer to the GetAccessibilityNodeCursorPosition callback. + * @return Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL} if the operation is successful. + * Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_BAD_PARAMETER} if a parameter is incorrect. + * @since 13 + */ +int32_t OH_ArkUI_AccessibilityProviderRegisterCallback( + ArkUI_AccessibilityProvider* provider, ArkUI_AccessibilityProviderCallbacks* callbacks); + +/** + * @brief Sends accessibility event information. + * + * @param provider Indicates the pointer to the ArkUI_AccessibilityProvider instance. + * @param eventInfo Indicates the pointer to the accessibility event information. + * @param callback Indicates the pointer to the callback that is called after the event is sent. + * @since 13 + */ +void OH_ArkUI_SendAccessibilityAsyncEvent( + ArkUI_AccessibilityProvider* provider, ArkUI_AccessibilityEventInfo* eventInfo, + void (*callback)(int32_t errorCode)); + +/** + * @brief Adds and obtains the pointer to an ArkUI_AccessibilityElementInfo object. + * + * @param list Indicates the pointer to an ArkUI_AccessibilityElementInfoList object. + * @return Returns the pointer to the ArkUI_AccessibilityElementInfo object. + * @since 13 + */ +ArkUI_AccessibilityElementInfo* OH_ArkUI_AddAndGetAccessibilityElementInfo( + ArkUI_AccessibilityElementInfoList* list); + +/** +* @brief Sets the element ID for an ArkUI_AccessibilityElementInfo object. +* +* @param elementInfo Indicates the pointer to an ArkUI_AccessibilityElementInfo object. +* @param elementId Indicates the element ID. +* @return Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL} if the operation is successful. +* Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_BAD_PARAMETER} if a parameter is incorrect. +* @since 13 +*/ +int32_t OH_ArkUI_AccessibilityElementInfoSetElementId( + ArkUI_AccessibilityElementInfo* elementInfo, int32_t elementId); + +/** +* @brief Sets the parent ID for an ArkUI_AccessibilityElementInfo object. +* +* @param elementInfo Indicates the pointer to an ArkUI_AccessibilityElementInfo object. +* @param parentId Indicates the parent ID. +* @return Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL} if the operation is successful. +* Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_BAD_PARAMETER} if a parameter is incorrect. +* @since 13 +*/ +int32_t OH_ArkUI_AccessibilityElementInfoSetParentId( + ArkUI_AccessibilityElementInfo* elementInfo, int32_t parentId); + +/** +* @brief Sets the component type for an ArkUI_AccessibilityElementInfo object. +* +* @param elementInfo Indicates the pointer to an ArkUI_AccessibilityElementInfo object. +* @param componentType Indicates the component type. +* @return Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL} if the operation is successful. +* Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_BAD_PARAMETER} if a parameter is incorrect. +* @since 13 +*/ +int32_t OH_ArkUI_AccessibilityElementInfoSetComponentType( + ArkUI_AccessibilityElementInfo* elementInfo, const char* componentType); + +/** +* @brief Sets the component content for an ArkUI_AccessibilityElementInfo object. +* +* @param elementInfo Indicates the pointer to an ArkUI_AccessibilityElementInfo object. +* @param contents Indicates the component content. +* @return Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL} if the operation is successful. +* Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_BAD_PARAMETER} if a parameter is incorrect. +* @since 13 +*/ +int32_t OH_ArkUI_AccessibilityElementInfoSetContents( + ArkUI_AccessibilityElementInfo* elementInfo, const char* contents); + +/** +* @brief Sets the hint text for an ArkUI_AccessibilityElementInfo object. +* +* @param elementInfo Indicates the pointer to an ArkUI_AccessibilityElementInfo object. +* @param hintText Indicates the hint text. +* @return Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL} if the operation is successful. +* Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_BAD_PARAMETER} if a parameter is incorrect. +* @since 13 +*/ +int32_t OH_ArkUI_AccessibilityElementInfoSetHintText( + ArkUI_AccessibilityElementInfo* elementInfo, const char* hintText); + +/** +* @brief Sets the accessibility text for an ArkUI_AccessibilityElementInfo object. +* +* @param elementInfo Indicates the pointer to an ArkUI_AccessibilityElementInfo object. +* @param accessibilityText Indicates the accessibility text. +* @return Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL} if the operation is successful. +* Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_BAD_PARAMETER} if a parameter is incorrect. +* @since 13 +*/ +int32_t OH_ArkUI_AccessibilityElementInfoSetAccessibilityText( + ArkUI_AccessibilityElementInfo* elementInfo, const char* accessibilityText); + +/** +* @brief Sets the accessibility description for an ArkUI_AccessibilityElementInfo object. +* +* @param elementInfo Indicates the pointer to an ArkUI_AccessibilityElementInfo object. +* @param accessibilityDescription Indicates the accessibility description. +* @return Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL} if the operation is successful. +* Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_BAD_PARAMETER} if a parameter is incorrect. +* @since 13 +*/ +int32_t OH_ArkUI_AccessibilityElementInfoSetAccessibilityDescription( + ArkUI_AccessibilityElementInfo* elementInfo, const char* accessibilityDescription); + +/** +* @brief Set the number of child nodes and child node IDs for an ArkUI_AccessibilityElementInfo object. +* +* @param elementInfo Indicates the pointer to an ArkUI_AccessibilityElementInfo object. +* @param childCount Indicates the number of child nodes. +* @param childNodeIds Indicates an array of child node IDs. +* @return Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL} if the operation is successful. +* Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_BAD_PARAMETER} if a parameter is incorrect. +* @since 13 +*/ +int32_t OH_ArkUI_AccessibilityElementInfoSetChildNodeIds( + ArkUI_AccessibilityElementInfo* elementInfo, int32_t childCount, int64_t* childNodeIds); + +/** +* @brief Sets the operation actions for an ArkUI_AccessibilityElementInfo object. +* +* @param elementInfo Indicates the pointer to an ArkUI_AccessibilityElementInfo object. +* @param operationCount Indicates the operation count. +* @param operationActions Indicates the operation actions. +* @return Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL} if the operation is successful. +* Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_BAD_PARAMETER} if a parameter is incorrect. +* @since 13 +*/ +int32_t OH_ArkUI_AccessibilityElementInfoSetOperationActions(ArkUI_AccessibilityElementInfo* elementInfo, + int32_t operationCount, ArkUI_AccessibleAction* operationActions); + +/** +* @brief Sets the screen area for an ArkUI_AccessibilityElementInfo object. +* +* @param elementInfo Indicates the pointer to an ArkUI_AccessibilityElementInfo object. +* @param screenRect Indicates the screen area. +* @return Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL} if the operation is successful. +* Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_BAD_PARAMETER} if a parameter is incorrect. +* @since 13 +*/ +int32_t OH_ArkUI_AccessibilityElementInfoSetScreenRect( + ArkUI_AccessibilityElementInfo* elementInfo, ArkUI_AccessibleRect* screenRect); + +/** +* @brief Sets whether the element is checkable for an ArkUI_AccessibilityElementInfo object. +* +* @param elementInfo Indicates the pointer to an ArkUI_AccessibilityElementInfo object. +* @param checkable Indicates whether the element is checkable. +* @return Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL} if the operation is successful. +* Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_BAD_PARAMETER} if a parameter is incorrect. +* @since 13 +*/ +int32_t OH_ArkUI_AccessibilityElementInfoSetCheckable( + ArkUI_AccessibilityElementInfo* elementInfo, bool checkable); + +/** +* @brief Sets whether the element is checked for an ArkUI_AccessibilityElementInfo object. +* +* @param elementInfo Indicates the pointer to an ArkUI_AccessibilityElementInfo object. +* @param checked Indicates whether the element is checked. +* @return Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL} if the operation is successful. +* Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_BAD_PARAMETER} if a parameter is incorrect. +* @since 13 +*/ +int32_t OH_ArkUI_AccessibilityElementInfoSetChecked( + ArkUI_AccessibilityElementInfo* elementInfo, bool checked); + +/** +* @brief Sets whether the element is focusable for an ArkUI_AccessibilityElementInfo object. +* @param elementInfo Indicates the pointer to an ArkUI_AccessibilityElementInfo object. +* @param focusable Indicates whether the element is focusable. +* @return Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL} if the operation is successful. +* Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_BAD_PARAMETER} if a parameter is incorrect. +* @since 13 +*/ +int32_t OH_ArkUI_AccessibilityElementInfoSetFocusable( + ArkUI_AccessibilityElementInfo* elementInfo, bool focusable); + +/** +* @brief Sets whether the element is focused for an ArkUI_AccessibilityElementInfo object. +* +* @param elementInfo Indicates the pointer to an ArkUI_AccessibilityElementInfo object. +* @param isFocused Indicates whether the element is focused. +* @return Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL} if the operation is successful. +* Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_BAD_PARAMETER} if a parameter is incorrect. +* @since 13 +*/ +int32_t OH_ArkUI_AccessibilityElementInfoSetFocused( + ArkUI_AccessibilityElementInfo* elementInfo, bool isFocused); + +/** +* @brief Sets whether the element is visible for an ArkUI_AccessibilityElementInfo object. +* +* @param elementInfo Indicates the pointer to an ArkUI_AccessibilityElementInfo object. +* @param isVisible Indicates whether the element is visible. +* @return Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL} if the operation is successful. +* Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_BAD_PARAMETER} if a parameter is incorrect. +* @since 13 +*/ +int32_t OH_ArkUI_AccessibilityElementInfoSetVisible( + ArkUI_AccessibilityElementInfo* elementInfo, bool isVisible); + +/** +* @brief Sets the accessibility focus state for an ArkUI_AccessibilityElementInfo object. +* +* @param elementInfo Indicates the pointer to an ArkUI_AccessibilityElementInfo object. +* @param accessibilityFocused Indicates whether the element has accessibility focus. +* @return Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL} if the operation is successful. +* Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_BAD_PARAMETER} if a parameter is incorrect. +* @since 13 +*/ +int32_t OH_ArkUI_AccessibilityElementInfoSetAccessibilityFocused( + ArkUI_AccessibilityElementInfo* elementInfo, bool accessibilityFocused); + +/** +* @brief Sets whether the element is selected for an ArkUI_AccessibilityElementInfo object. +* +* @param elementInfo Indicates the pointer to an ArkUI_AccessibilityElementInfo object. +* @param selected Indicates whether the element is selected. +* @return Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL} if the operation is successful. +* Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_BAD_PARAMETER} if a parameter is incorrect. +* @since 13 +*/ +int32_t OH_ArkUI_AccessibilityElementInfoSetSelected( + ArkUI_AccessibilityElementInfo* elementInfo, bool selected); + +/** +* @brief Sets whether the element is clickable for an ArkUI_AccessibilityElementInfo object. +* +* @param elementInfo Indicates the pointer to an ArkUI_AccessibilityElementInfo object. +* @param clickable Indicates whether the element is clickable. +* @return Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL} if the operation is successful. +* Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_BAD_PARAMETER} if a parameter is incorrect. +* @since 13 +*/ +int32_t OH_ArkUI_AccessibilityElementInfoSetClickable( + ArkUI_AccessibilityElementInfo* elementInfo, bool clickable); + +/** +* @brief Sets whether the element is long clickable for an ArkUI_AccessibilityElementInfo object. +* +* @param elementInfo Indicates the pointer to an ArkUI_AccessibilityElementInfo object. +* @param longClickable Indicates whether the element is long clickable. +* @return Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL} if the operation is successful. +* Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_BAD_PARAMETER} if a parameter is incorrect. +* @since 13 +*/ +int32_t OH_ArkUI_AccessibilityElementInfoSetLongClickable( + ArkUI_AccessibilityElementInfo* elementInfo, bool longClickable); + +/** +* @brief Sets whether the element is enabled for an ArkUI_AccessibilityElementInfo object. +* +* @param elementInfo Indicates the pointer to an ArkUI_AccessibilityElementInfo object. +* @param isEnabled Indicates whether the element is enabled. +* @return Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL} if the operation is successful. +* Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_BAD_PARAMETER} if a parameter is incorrect. +* @since 13 +*/ +int32_t OH_ArkUI_AccessibilityElementInfoSetEnabled( + ArkUI_AccessibilityElementInfo* elementInfo, bool isEnabled); + +/** +* @brief Sets whether the element is a password for an ArkUI_AccessibilityElementInfo object. +* +* @param elementInfo Indicates the pointer to an ArkUI_AccessibilityElementInfo object. +* @param isPassword Indicates whether the element is a password. +* @return Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL} if the operation is successful. +* Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_BAD_PARAMETER} if a parameter is incorrect. +* @since 13 +*/ +int32_t OH_ArkUI_AccessibilityElementInfoSetIsPassword( + ArkUI_AccessibilityElementInfo* elementInfo, bool isPassword); + +/** +* @brief Sets whether the element is scrollable for an ArkUI_AccessibilityElementInfo object. +* +* @param elementInfo Indicates the pointer to an ArkUI_AccessibilityElementInfo object. +* @param scrollable Indicates whether the element is scrollable. +* @return Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL} if the operation is successful. +* Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_BAD_PARAMETER} if a parameter is incorrect. +* @since 13 +*/ +int32_t OH_ArkUI_AccessibilityElementInfoSetScrollable( + ArkUI_AccessibilityElementInfo* elementInfo, bool scrollable); + +/** +* @brief Sets whether the element is editable for an ArkUI_AccessibilityElementInfo object. +* +* @param elementInfo Indicates the pointer to an ArkUI_AccessibilityElementInfo object. +* @param editable Indicates whether the element is editable. +* @return Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL} if the operation is successful. +* Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_BAD_PARAMETER} if a parameter is incorrect. +* @since 13 +*/ +int32_t OH_ArkUI_AccessibilityElementInfoSetEditable( + ArkUI_AccessibilityElementInfo* elementInfo, bool editable); + +/** +* @brief Sets whether the element is a hint for an ArkUI_AccessibilityElementInfo object. +* +* @param elementInfo Indicates the pointer to an ArkUI_AccessibilityElementInfo object. +* @param isHint Indicates whether the element is a hint. +* @return Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL} if the operation is successful. +* Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_BAD_PARAMETER} if a parameter is incorrect. +* @since 13 +*/ +int32_t OH_ArkUI_AccessibilityElementInfoSetIsHint( + ArkUI_AccessibilityElementInfo* elementInfo, bool isHint); + +/** +* @brief Sets the range information for an ArkUI_AccessibilityElementInfo object. +* +* @param elementInfo Indicates the pointer to an ArkUI_AccessibilityElementInfo object. +* @param rangeInfo Indicates the range information. +* @return Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL} if the operation is successful. +* Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_BAD_PARAMETER} if a parameter is incorrect. +* @since 13 +*/ +int32_t OH_ArkUI_AccessibilityElementInfoSetRangeInfo( + ArkUI_AccessibilityElementInfo* elementInfo, ArkUI_AccessibleRangeInfo* rangeInfo); + +/** +* @brief Sets the grid information for an ArkUI_AccessibilityElementInfo object. +* +* @param elementInfo Indicates the pointer to an ArkUI_AccessibilityElementInfo object. +* @param gridInfo Indicates the grid information. +* @return Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL} if the operation is successful. +* Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_BAD_PARAMETER} if a parameter is incorrect. +* @since 13 +*/ +int32_t OH_ArkUI_AccessibilityElementInfoSetGridInfo( + ArkUI_AccessibilityElementInfo* elementInfo, ArkUI_AccessibleGridInfo* gridInfo); + +/** +* @brief Sets the grid item for an ArkUI_AccessibilityElementInfo object. +* +* @param elementInfo Indicates the pointer to an ArkUI_AccessibilityElementInfo object. +* @param gridItem Indicates the grid item. +* @return Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL} if the operation is successful. +* Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_BAD_PARAMETER} if a parameter is incorrect. +* @since 13 +*/ +int32_t OH_ArkUI_AccessibilityElementInfoSetGridItemInfo( + ArkUI_AccessibilityElementInfo* elementInfo, ArkUI_AccessibleGridItemInfo* gridItem); + +/** +* @brief Sets the starting index of the selected text for an ArkUI_AccessibilityElementInfo object. +* +* @param elementInfo Indicates the pointer to an ArkUI_AccessibilityElementInfo object. +* @param selectedTextStart Indicates the starting index of the selected text +* @return Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL} if the operation is successful. +* Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_BAD_PARAMETER} if a parameter is incorrect. +* @since 13 +*/ +int32_t OH_ArkUI_AccessibilityElementInfoSetSelectedTextStart( + ArkUI_AccessibilityElementInfo* elementInfo, int32_t selectedTextStart); + +/** +* @brief Sets the end index of the selected text for an ArkUI_AccessibilityElementInfo object. +* +* @param elementInfo Indicates the pointer to an ArkUI_AccessibilityElementInfo object. +* @param selectedTextEnd Indicates the end index of the selected text +* @return Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL} if the operation is successful. +* Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_BAD_PARAMETER} if a parameter is incorrect. +* @since 13 +*/ +int32_t OH_ArkUI_AccessibilityElementInfoSetSelectedTextEnd( + ArkUI_AccessibilityElementInfo* elementInfo, int32_t selectedTextEnd); + +/** +* @brief Sets the index of the currently selected item for an ArkUI_AccessibilityElementInfo object. +* +* @param elementInfo Indicates the pointer to an ArkUI_AccessibilityElementInfo object. +* @param currentItemIndex Indicates the index of the currently selected item. +* @return Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL} if the operation is successful. +* Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_BAD_PARAMETER} if a parameter is incorrect. +* @since 13 +*/ +int32_t OH_ArkUI_AccessibilityElementInfoSetCurrentItemIndex( + ArkUI_AccessibilityElementInfo* elementInfo, int32_t currentItemIndex); + +/** +* @brief Sets the index of the first item for an ArkUI_AccessibilityElementInfo object. +* +* @param elementInfo Indicates the pointer to an ArkUI_AccessibilityElementInfo object. +* @param startItemIndex Indicates the index of the first item. +* @return Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL} if the operation is successful. +* Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_BAD_PARAMETER} if a parameter is incorrect. +* @since 13 +*/ +int32_t OH_ArkUI_AccessibilityElementInfoSetStartItemIndex( + ArkUI_AccessibilityElementInfo* elementInfo, int32_t startItemIndex); + +/** +* @brief Sets the index of the last item for an ArkUI_AccessibilityElementInfo object. +* +* @param elementInfo Indicates the pointer to an ArkUI_AccessibilityElementInfo object. +* @param endItemIndex Indicates the index of the last item. +* @return Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL} if the operation is successful. +* Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_BAD_PARAMETER} if a parameter is incorrect. +* @since 13 +*/ +int32_t OH_ArkUI_AccessibilityElementInfoSetEndItemIndex( + ArkUI_AccessibilityElementInfo* elementInfo, int32_t endItemIndex); + +/** +* @brief Sets the number of items for an ArkUI_AccessibilityElementInfo object. +* +* @param elementInfo Indicates the pointer to an ArkUI_AccessibilityElementInfo object. +* @param itemCount Indicates the number of items. +* @return Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL} if the operation is successful. +* Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_BAD_PARAMETER} if a parameter is incorrect. +* @since 13 +*/ +int32_t OH_ArkUI_AccessibilityElementInfoSetItemCount( + ArkUI_AccessibilityElementInfo* elementInfo, int32_t itemCount); + +/** +* @brief Sets the offset for an ArkUI_AccessibilityElementInfo object. +* +* @param elementInfo Indicates the pointer to an ArkUI_AccessibilityElementInfo object. +* @param offset Indicates the scroll pixel offset relative to the top of the element. +* @return Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL} if the operation is successful. +* Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_BAD_PARAMETER} if a parameter is incorrect. +* @since 13 +*/ +int32_t OH_ArkUI_AccessibilityElementInfoSetAccessibilityOffset( + ArkUI_AccessibilityElementInfo* elementInfo, int32_t offset); + +/** +* @brief Sets the accessibility group for an ArkUI_AccessibilityElementInfo object. +* +* @param elementInfo Indicates the pointer to an ArkUI_AccessibilityElementInfo object. +* @param accessibilityGroup Indicates the accessibility group. +* @return Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL} if the operation is successful. +* Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_BAD_PARAMETER} if a parameter is incorrect. +* @since 13 +*/ +int32_t OH_ArkUI_AccessibilityElementInfoSetAccessibilityGroup( + ArkUI_AccessibilityElementInfo* elementInfo, bool accessibilityGroup); + +/** +* @brief Sets the accessibility level for an ArkUI_AccessibilityElementInfo object. +* +* @param elementInfo Indicates the pointer to an ArkUI_AccessibilityElementInfo object. +* @param accessibilityLevel Indicates the accessibility level. +* @return Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL} if the operation is successful. +* Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_BAD_PARAMETER} if a parameter is incorrect. +* @since 13 +*/ +int32_t OH_ArkUI_AccessibilityElementInfoSetAccessibilityLevel( + ArkUI_AccessibilityElementInfo* elementInfo, const char* accessibilityLevel); + +/** +* @brief Sets the z-index for an ArkUI_AccessibilityElementInfo object. +* +* @param elementInfo Indicates the pointer to an ArkUI_AccessibilityElementInfo object. +* @param zIndex Indicates the z-index value. +* @return Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL} if the operation is successful. +* Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_BAD_PARAMETER} if a parameter is incorrect. +* @since 13 +*/ +int32_t OH_ArkUI_AccessibilityElementInfoSetZIndex( + ArkUI_AccessibilityElementInfo* elementInfo, int32_t zIndex); + +/** +* @brief Sets the opacity for an ArkUI_AccessibilityElementInfo object. +* +* @param elementInfo Indicates the pointer to an ArkUI_AccessibilityElementInfo object. +* @param opacity Indicates the opacity. +* @return Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL} if the operation is successful. +* Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_BAD_PARAMETER} if a parameter is incorrect. +* @since 13 +*/ +int32_t OH_ArkUI_AccessibilityElementInfoSetAccessibilityOpacity( + ArkUI_AccessibilityElementInfo* elementInfo, float opacity); + +/** +* @brief Sets the background color for an ArkUI_AccessibilityElementInfo object. +* +* @param elementInfo Indicates the pointer to an ArkUI_AccessibilityElementInfo object. +* @param backgroundColor Indicates the background color. +* @return Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL} if the operation is successful. +* Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_BAD_PARAMETER} if a parameter is incorrect. +* @since 13 +*/ +int32_t OH_ArkUI_AccessibilityElementInfoSetBackgroundColor( + ArkUI_AccessibilityElementInfo* elementInfo, const char* backgroundColor); + +/** +* @brief Sets the background image for an ArkUI_AccessibilityElementInfo object. +* +* @param elementInfo Indicates the pointer to an ArkUI_AccessibilityElementInfo object. +* @param backgroundImage Indicates the backgroundImage. +* @return Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL} if the operation is successful. +* Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_BAD_PARAMETER} if a parameter is incorrect. +* @since 13 +*/ +int32_t OH_ArkUI_AccessibilityElementInfoSetBackgroundImage( + ArkUI_AccessibilityElementInfo* elementInfo, const char* backgroundImage); + +/** +* @brief Sets the blur effect for an ArkUI_AccessibilityElementInfo object. +* +* @param elementInfo Indicates the pointer to an ArkUI_AccessibilityElementInfo object. +* @param blur Indicates the blur effect. +* @return Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL} if the operation is successful. +* Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_BAD_PARAMETER} if a parameter is incorrect. +* @since 13 +*/ +int32_t OH_ArkUI_AccessibilityElementInfoSetBlur( + ArkUI_AccessibilityElementInfo* elementInfo, const char* blur); + +/** +* @brief Sets the hit test behavior for an ArkUI_AccessibilityElementInfo object. +* +* @param elementInfo Indicates the pointer to an ArkUI_AccessibilityElementInfo object. +* @param hitTestBehavior Indicates the hit test behavior. +* @return Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL} if the operation is successful. +* Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_BAD_PARAMETER} if a parameter is incorrect. +* @since 13 +*/ +int32_t OH_ArkUI_AccessibilityElementInfoSetHitTestBehavior( + ArkUI_AccessibilityElementInfo* elementInfo, const char* hitTestBehavior); + +/** + * @brief Creates an ArkUI_AccessibilityElementInfo object. + * + * @return Returns the ArkUI_AccessibilityElementInfo object, or NULL if it fails to create. + * The possible reason for failure is that the memory error occurred during object creation. + * @since 13 + * @version 1.0 + */ +ArkUI_AccessibilityElementInfo* OH_ArkUI_CreateAccessibilityElementInfo(void); + +/** + * @brief Destroys an ArkUI_AccessibilityElementInfo object. + * + * @param elementInfo Indicates the pointer to the ArkUI_AccessibilityElementInfo object to destroy. + * @since 13 + * @version 1.0 + */ +void OH_ArkUI_DestoryAccessibilityElementInfo(ArkUI_AccessibilityElementInfo* elementInfo); + +/** + * @brief Creates an ArkUI_AccessibilityEventInfo object. + * + * @return Returns the ArkUI_AccessibilityEventInfo object, or NULL if it fails to create. + * The possible reason for failure is that the memory error occurred during object creation. + * @since 13 + */ +ArkUI_AccessibilityEventInfo* OH_ArkUI_CreateAccessibilityEventInfo(void); + +/** + * @brief Destroys an ArkUI_AccessibilityEventInfo object. + * + * @param eventInfo Indicates the pointer to the ArkUI_AccessibilityEventInfo object to destroy. + * @since 13 + */ +void OH_ArkUI_DestoryAccessibilityEventInfo(ArkUI_AccessibilityEventInfo* eventInfo); + +/** +* @brief Sets the event type for an ArkUI_AccessibilityEventInfo object. +* +* @param eventInfo Indicates the pointer to an ArkUI_AccessibilityEventInfo object. +* @param eventType Indicates the event type. +* @return Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL} if the operation is successful. +* Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_BAD_PARAMETER} if a parameter is incorrect. +* @since 13 +*/ +int32_t OH_ArkUI_AccessibilityEventSetEventType( + ArkUI_AccessibilityEventInfo* eventInfo, ArkUI_AccessibilityEventType eventType); + +/** +* @brief Sets the text announced for accessibility for an ArkUI_AccessibilityEventInfo object. +* +* @param eventInfo Indicates the pointer to an ArkUI_AccessibilityEventInfo object. +* @param textAnnouncedForAccessibility Indicates the text announced for accessibility. +* @return Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL} if the operation is successful. +* Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_BAD_PARAMETER} if a parameter is incorrect. +* @since 13 +*/ +int32_t OH_ArkUI_AccessibilityEventSetTextAnnouncedForAccessibility( + ArkUI_AccessibilityEventInfo* eventInfo, const char* textAnnouncedForAccessibility); + +/** +* @brief Sets the request focus ID for an ArkUI_AccessibilityEventInfo object. +* +* @param eventInfo Indicates the pointer to an ArkUI_AccessibilityEventInfo object. +* @param requestFocusId Indicates the request focus ID. +* @return Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL} if the operation is successful. +* Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_BAD_PARAMETER} if a parameter is incorrect. +* @since 13 +*/ +int32_t OH_ArkUI_AccessibilityEventSetRequestFocusId( + ArkUI_AccessibilityEventInfo* eventInfo, int32_t requestFocusId); + +/** +* @brief Sets the element information for an ArkUI_AccessibilityEventInfo object. +* +* @param eventInfo Indicates the pointer to an ArkUI_AccessibilityEventInfo object. +* @param elementInfo Indicates the pointer to an ArkUI_AccessibilityElementInfo object. +* @return Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL} if the operation is successful. +* Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_BAD_PARAMETER} if a parameter is incorrect. +* @since 13 +*/ +int32_t OH_ArkUI_AccessibilityEventSetElementInfo( + ArkUI_AccessibilityEventInfo* eventInfo, ArkUI_AccessibilityElementInfo* elementInfo); + +/** +* @brief Obtains the value of a key from an ArkUI_AccessibilityActionArguments object. +* +* @param arguments Indicates the pointer to an ArkUI_AccessibilityActionArguments object. +* @param key Indicates the key. +* @param value Indicates the value. +* @return Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_SUCCESSFUL} if the operation is successful. +* Returns {@link ARKUI_ACCESSIBILITY_NATIVE_RESULT_BAD_PARAMETER} if a parameter is incorrect. +* @since 13 +*/ +int32_t OH_ArkUI_FindAccessibilityActionArgumentByKey( + ArkUI_AccessibilityActionArguments* arguments, const char* key, char** value); +#ifdef __cplusplus +}; +#endif +#endif // _NATIVE_INTERFACE_ACCESSIBILITY_H +/** @} */ \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/.gitignore b/shell/platform/ohos/flutter_embedding/.gitignore index c5c48a55d35b577e3812111c745f37f9a3b56e44..c837164ae81179285dbc1ecb343ec163171ae17e 100644 --- a/shell/platform/ohos/flutter_embedding/.gitignore +++ b/shell/platform/ohos/flutter_embedding/.gitignore @@ -1,5 +1,5 @@ /node_modules -/oh_modules +**/oh_modules /.idea **/build /.hvigor diff --git a/shell/platform/ohos/flutter_embedding/application/.gitignore b/shell/platform/ohos/flutter_embedding/application/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..e2713a2779c5a3e0eb879efe6115455592caeea5 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/.gitignore @@ -0,0 +1,6 @@ +/node_modules +/oh_modules +/.preview +/build +/.cxx +/.test \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/build-profile.json5 b/shell/platform/ohos/flutter_embedding/application/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..682d223d55956f1d579037598b4bf59a743f03a0 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/build-profile.json5 @@ -0,0 +1,43 @@ +/* + * 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. + */ +{ + "apiType": "stageMode", + "buildOption": { + }, + "buildOptionSet": [ + { + "name": "release", + "arkOptions": { + "obfuscation": { + "ruleOptions": { + "enable": false, + "files": [ + "./obfuscation-rules.txt" + ] + } + } + } + }, + ], + "targets": [ + { + "name": "default" + }, + { + "name": "ohosTest", + } + ] +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/hvigorfile.ts b/shell/platform/ohos/flutter_embedding/application/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..c71da0f0404c356f45efa2e7937985e219bf0460 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/hvigorfile.ts @@ -0,0 +1,20 @@ +/* + * 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. + */ +import { hapTasks } from '@ohos/hvigor-ohos-plugin'; + +export default { + system: hapTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ + plugins:[] /* Custom plugin to extend the functionality of Hvigor. */ +} diff --git a/shell/platform/ohos/flutter_embedding/application/obfuscation-rules.txt b/shell/platform/ohos/flutter_embedding/application/obfuscation-rules.txt new file mode 100644 index 0000000000000000000000000000000000000000..272efb6ca3f240859091bbbfc7c5802d52793b0b --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/obfuscation-rules.txt @@ -0,0 +1,23 @@ +# Define project specific obfuscation rules here. +# You can include the obfuscation configuration files in the current module's build-profile.json5. +# +# For more details, see +# https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/source-obfuscation-V5 + +# Obfuscation options: +# -disable-obfuscation: disable all obfuscations +# -enable-property-obfuscation: obfuscate the property names +# -enable-toplevel-obfuscation: obfuscate the names in the global scope +# -compact: remove unnecessary blank spaces and all line feeds +# -remove-log: remove all console.* statements +# -print-namecache: print the name cache that contains the mapping from the old names to new names +# -apply-namecache: reuse the given cache file + +# Keep options: +# -keep-property-name: specifies property names that you want to keep +# -keep-global-name: specifies names that you want to keep in the global scope + +-enable-property-obfuscation +-enable-toplevel-obfuscation +-enable-filename-obfuscation +-enable-export-obfuscation \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/oh-package.json5 b/shell/platform/ohos/flutter_embedding/application/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..9472ce464004acd9f5ecb8eced4e8ec9b0d6f099 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/oh-package.json5 @@ -0,0 +1,28 @@ +/* + * 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. + */ +{ + "name": "application", + "version": "1.0.0", + "description": "Please describe the basic information.", + "main": "", + "author": "", + "license": "", + "dependencies": { + "@ohos/flutter_ohos": "file:../flutter", + "@ohos/hypium": "1.0.18" + } +} + diff --git a/shell/platform/ohos/flutter_embedding/application/src/main/ets/applicationability/ApplicationAbility.ets b/shell/platform/ohos/flutter_embedding/application/src/main/ets/applicationability/ApplicationAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..11cc563d8fab01c4fe5bc0d083ec1c665986e25d --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/main/ets/applicationability/ApplicationAbility.ets @@ -0,0 +1,55 @@ +/* + * 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. + */ +import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit'; +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { window } from '@kit.ArkUI'; + +export default class ApplicationAbility extends UIAbility { + onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate'); + } + + onDestroy(): void { + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy'); + } + + onWindowStageCreate(windowStage: window.WindowStage): void { + // Main window is created, set main page for this ability + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); + + windowStage.loadContent('pages/Index', (err) => { + if (err.code) { + hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? ''); + return; + } + hilog.info(0x0000, 'testTag', 'Succeeded in loading the content.'); + }); + } + + onWindowStageDestroy(): void { + // Main window is destroyed, release UI related resources + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy'); + } + + onForeground(): void { + // Ability has brought to foreground + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground'); + } + + onBackground(): void { + // Ability has back to background + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground'); + } +} diff --git a/shell/platform/ohos/flutter_embedding/application/src/main/ets/applicationbackupability/ApplicationBackupAbility.ets b/shell/platform/ohos/flutter_embedding/application/src/main/ets/applicationbackupability/ApplicationBackupAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..10ae96d62540755d875f7583986c0db254c34693 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/main/ets/applicationbackupability/ApplicationBackupAbility.ets @@ -0,0 +1,26 @@ +/* + * 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. + */ +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { BackupExtensionAbility, BundleVersion } from '@kit.CoreFileKit'; + +export default class ApplicationBackupAbility extends BackupExtensionAbility { + async onBackup() { + hilog.info(0x0000, 'testTag', 'onBackup ok'); + } + + async onRestore(bundleVersion: BundleVersion) { + hilog.info(0x0000, 'testTag', 'onRestore ok %{public}s', JSON.stringify(bundleVersion)); + } +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/main/ets/pages/Index.ets b/shell/platform/ohos/flutter_embedding/application/src/main/ets/pages/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..81b53999e62d7f257e58d089da9d919c07340712 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/main/ets/pages/Index.ets @@ -0,0 +1,34 @@ +/* + * 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. + */ +@Entry +@Component +struct Index { + @State message: string = 'Hello World'; + + build() { + RelativeContainer() { + Text(this.message) + .id('HelloWorld') + .fontSize(50) + .fontWeight(FontWeight.Bold) + .alignRules({ + center: { anchor: '__container__', align: VerticalAlign.Center }, + middle: { anchor: '__container__', align: HorizontalAlign.Center } + }) + } + .height('100%') + .width('100%') + } +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/main/module.json5 b/shell/platform/ohos/flutter_embedding/application/src/main/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..8f334feb3a38758d2b7093f6d2170b1448b2a2b6 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/main/module.json5 @@ -0,0 +1,52 @@ +{ + "module": { + "name": "application", + "type": "entry", + "description": "$string:module_desc", + "mainElement": "ApplicationAbility", + "deviceTypes": [ + "phone", + "tablet", + "2in1" + ], + "deliveryWithInstall": true, + "installationFree": false, + "pages": "$profile:main_pages", + "abilities": [ + { + "name": "ApplicationAbility", + "srcEntry": "./ets/applicationability/ApplicationAbility.ets", + "description": "$string:ApplicationAbility_desc", + "icon": "$media:layered_image", + "label": "$string:ApplicationAbility_label", + "startWindowIcon": "$media:startIcon", + "startWindowBackground": "$color:start_window_background", + "exported": true, + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "action.system.home" + ] + } + ] + } + ], + "extensionAbilities": [ + { + "name": "ApplicationBackupAbility", + "srcEntry": "./ets/applicationbackupability/ApplicationBackupAbility.ets", + "type": "backup", + "exported": false, + "metadata": [ + { + "name": "ohos.extension.backup", + "resource": "$profile:backup_config" + } + ], + } + ] + } +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/main/resources/base/element/color.json b/shell/platform/ohos/flutter_embedding/application/src/main/resources/base/element/color.json new file mode 100644 index 0000000000000000000000000000000000000000..3c712962da3c2751c2b9ddb53559afcbd2b54a02 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/main/resources/base/element/color.json @@ -0,0 +1,8 @@ +{ + "color": [ + { + "name": "start_window_background", + "value": "#FFFFFF" + } + ] +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/main/resources/base/element/string.json b/shell/platform/ohos/flutter_embedding/application/src/main/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..a4969eae868447396d719a863b9ee15c146299f0 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/main/resources/base/element/string.json @@ -0,0 +1,16 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "module description" + }, + { + "name": "ApplicationAbility_desc", + "value": "description" + }, + { + "name": "ApplicationAbility_label", + "value": "label" + } + ] +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/main/resources/base/media/background.png b/shell/platform/ohos/flutter_embedding/application/src/main/resources/base/media/background.png new file mode 100644 index 0000000000000000000000000000000000000000..f939c9fa8cc8914832e602198745f592a0dfa34d Binary files /dev/null and b/shell/platform/ohos/flutter_embedding/application/src/main/resources/base/media/background.png differ diff --git a/shell/platform/ohos/flutter_embedding/application/src/main/resources/base/media/foreground.png b/shell/platform/ohos/flutter_embedding/application/src/main/resources/base/media/foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..4483ddad1f079e1089d685bd204ee1cfe1d01902 Binary files /dev/null and b/shell/platform/ohos/flutter_embedding/application/src/main/resources/base/media/foreground.png differ diff --git a/shell/platform/ohos/flutter_embedding/application/src/main/resources/base/media/layered_image.json b/shell/platform/ohos/flutter_embedding/application/src/main/resources/base/media/layered_image.json new file mode 100644 index 0000000000000000000000000000000000000000..fb49920440fb4d246c82f9ada275e26123a2136a --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/main/resources/base/media/layered_image.json @@ -0,0 +1,7 @@ +{ + "layered-image": + { + "background" : "$media:background", + "foreground" : "$media:foreground" + } +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/main/resources/base/media/startIcon.png b/shell/platform/ohos/flutter_embedding/application/src/main/resources/base/media/startIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..205ad8b5a8a42e8762fbe4899b8e5e31ce822b8b Binary files /dev/null and b/shell/platform/ohos/flutter_embedding/application/src/main/resources/base/media/startIcon.png differ diff --git a/shell/platform/ohos/flutter_embedding/application/src/main/resources/base/profile/backup_config.json b/shell/platform/ohos/flutter_embedding/application/src/main/resources/base/profile/backup_config.json new file mode 100644 index 0000000000000000000000000000000000000000..78f40ae7c494d71e2482278f359ec790ca73471a --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/main/resources/base/profile/backup_config.json @@ -0,0 +1,3 @@ +{ + "allowToBackupRestore": true +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/main/resources/base/profile/main_pages.json b/shell/platform/ohos/flutter_embedding/application/src/main/resources/base/profile/main_pages.json new file mode 100644 index 0000000000000000000000000000000000000000..1898d94f58d6128ab712be2c68acc7c98e9ab9ce --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/main/resources/base/profile/main_pages.json @@ -0,0 +1,5 @@ +{ + "src": [ + "pages/Index" + ] +} diff --git a/shell/platform/ohos/flutter_embedding/application/src/main/resources/en_US/element/string.json b/shell/platform/ohos/flutter_embedding/application/src/main/resources/en_US/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..a4969eae868447396d719a863b9ee15c146299f0 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/main/resources/en_US/element/string.json @@ -0,0 +1,16 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "module description" + }, + { + "name": "ApplicationAbility_desc", + "value": "description" + }, + { + "name": "ApplicationAbility_label", + "value": "label" + } + ] +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/main/resources/zh_CN/element/string.json b/shell/platform/ohos/flutter_embedding/application/src/main/resources/zh_CN/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..9e08d1adfed3a76904517f4f9104d7371cc50a71 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/main/resources/zh_CN/element/string.json @@ -0,0 +1,16 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "模块描述" + }, + { + "name": "ApplicationAbility_desc", + "value": "description" + }, + { + "name": "ApplicationAbility_label", + "value": "label" + } + ] +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/mock/mock-config.json5 b/shell/platform/ohos/flutter_embedding/application/src/mock/mock-config.json5 new file mode 100644 index 0000000000000000000000000000000000000000..99db04adcdb49dc11ab59844a6b78fc81baace24 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/mock/mock-config.json5 @@ -0,0 +1,17 @@ +/* + * 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. + */ +{ +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/FlutterInjector.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/FlutterInjector.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..ab342916e2b8c1c8c3cd11b7b9e46402c7702c9e --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/FlutterInjector.test.ets @@ -0,0 +1,31 @@ +/* + * 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. + */ + +import { describe, it, expect } from '@ohos/hypium' +import { FlutterInjector } from "@ohos/flutter_ohos"; + +export default function FlutterInjectorTest() { + describe('FlutterInjectorTest', () => { + it('getInstance', 0, () => { + expect(FlutterInjector.getInstance()).not().assertNull(); + }) + it('getFlutterLoader', 0, () => { + expect(FlutterInjector.getInstance().getFlutterLoader()).not().assertNull(); + }) + it('getFlutterNapi', 0, () => { + expect(FlutterInjector.getInstance().getFlutterNapi()).not().assertNull(); + }) + }) +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/List.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/List.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..80151e3685194032e62e448b1c8e45c70ccc0e4b --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/List.test.ets @@ -0,0 +1,153 @@ +/* + * 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. + */ + +import FlutterAbilityAndEntryDelegateTest from './embedding/ohos/FlutterAbilityAndEntryDelegateTest.test'; +import FlutterAbilityTest from './embedding/ohos/FlutterAbilityTest.test'; +import FlutterEntryTest from './embedding/ohos/FlutterEntryTest.test'; +import FlutterManagerTest from './embedding/ohos/FlutterManagerTest.test'; +import SettingTest from './embedding/ohos/SettingTest.test'; +import BinaryCodecTest from './plugin/common/BinaryCodecTest.test'; +import PlatformViewRegistryImplTest from './plugin/platform/PlatformViewRegistryImplTest.test'; +import PlatformViewWrapperTest from './plugin/platform/PlatformViewWrapperTest.test'; +import PlatformViewsControllerTest from './plugin/platform/PlatformViewsControllerTest.test'; +import RawPointerCoordTest from './plugin/platform/RawPointerCoordTest.test'; +import RootDvModelManagerTest from './plugin/platform/RootDvModelManagerTest.test'; +import ByteBufferTest from './plugin/util/ByteBufferTest.test'; +import PlatformChannelUnitTest from './embedding/engine/systemchannels/PlatformChannel.test'; +import RestorationChannelUnitTest from './embedding/engine/systemchannels/RestorationChannel.test'; +import SettingsChannelUnitTest from './embedding/engine/systemchannels/SettingsChannel.test'; +import TextInputChannelUnitTest from './embedding/engine/systemchannels/TextInputChannel.test'; +import JSONMethodCodecUnitTest from './plugin/common/JSONMethodCodec.test'; +import MethodCallUnitTest from './plugin/common/MethodCall.test'; +import AccessibilityEventsDelegateUnitTest from './plugin/platform/AccessibilityEventsDelegate.test'; + +import DartMessengerTest from './embedding/engine/dart/DartMessengerTest.test' +import ApplicationInfoTest from './embedding/engine/loader/ApplicationInfoTest.test' +import FlutterApplicationInfoTest from './embedding/engine/loader/FlutterApplicationInfoTest.test' +import FlutterLoaderTest from './embedding/engine/loader/FlutterLoaderTest.test' +import FlutterMutatorViewTest from './embedding/engine/mutatorsstack/FlutterMutatorViewTest.test' +import FlutterMutatorsStackTest from './embedding/engine/mutatorsstack/FlutterMutatorsStackTest.test' +import FlutterRendererTest from './embedding/engine/renderer/FlutterRendererTest.test' +import TouchEventProcessorTest from './embedding/ohos/TouchEventProcessorTest.test'; +import TouchEventTrackerTest from './embedding/ohos/TouchEventTrackerTest.test'; +import WindowInfoRepositoryCallbackAdapterWrapperTest from './embedding/ohos/WindowInfoRepositoryCallbackAdapterWrapperTest.test'; +import FlutterEngineTest from './embedding/engine/FlutterEngineTest.test'; +import FlutterEngineCacheTest from './embedding/engine/FlutterEngineCacheTest.test'; +import FlutterEngineConnectionRegistryTest from './embedding/engine/FlutterEngineConnectionRegistryTest.test'; +import FlutterEngineGroupCacheTest from './embedding/engine/FlutterEngineGroupCacheTest.test'; +import FlutterEngineGroupTest from './embedding/engine/FlutterEngineGroupTest.test'; +import FlutterNapiTest from './embedding/engine/FlutterNapiTest.test'; +import FlutterOverlaySurfaceTest from './embedding/engine/FlutterOverlaySurfaceTest.test'; +import FlutterShellArgsTest from './embedding/engine/FlutterShellArgsTest.test'; +import BinaryMessengerTest from './plugin/common/BinaryMessengerTest.test'; +import DartExecutorTest from './embedding/engine/dart/DartExecutorTest.test'; + +import PathUtilsTest from './plugin/util/PathUtils.test'; +import StringUtilsTest from './plugin/util/StringUtils.test'; +import ToolUtilsTest from './plugin/util/ToolUtils.test'; +import MessageChannelUtilsTest from './plugin/util/MessageChannelUtils.test'; +import LogTest from './plugin/util/Log.test'; +import TraceSectionTest from './plugin/util/TraceSection.test'; +import FlutterInjectorTest from './FlutterInjector.test'; +import SendableBinaryCodecTest from './plugin/common/SendableBinaryCodec.test'; +import dynamicViewJsonTest from './view/DynamicView/dynamicViewJson.test'; +import PlatformOverlayViewTest from './plugin/platform/PlatformOverlayView.test'; +import PlatformViewTest from './plugin/platform/PlatformView.test'; +import FlutterRunArgumentsTest from './view/FlutterRunArguments.test'; +import LifecycleChannelTest from './embedding/engine/systemchannels/LifecycleChannel.test'; +import FlutterExceptionTest from './plugin/common/FlutterException.test'; +import JSONMessageCodecTest from './plugin/common/JSONMessageCodec.test'; +import SendableJSONMessageCodecTest from './plugin/common/SendableJSONMessageCodec.test'; +import SendableJSONMethodCodecTest from './plugin/common/SendableJSONMethodCodec.test'; +import SendableStringCodecTest from './plugin/common/SendableStringCodec.test'; +import StandardMessageCodecTest from './plugin/common/StandardMessageCodec.test'; +import StandardMethodCodecTest from './plugin/common/StandardMethodCodec.test'; +import StringCodecTest from './plugin/common/StringCodec.test'; +import ListenableEditingStateTest from './plugin/editing/ListenableEditingState.test'; +import TextEditingDeltaTest from './plugin/editing/TextEditingDelta.test'; +import TextInputPluginTest from './plugin/editing/TextInputPlugin.test'; +import LocalizationPluginTest from './plugin/localization/LocalizationPlugin.test'; +import SendableStandardMessageCodecTest from './plugin/common/SendableStandardMessageCodec.test'; +import SendableStandardMethodCodecTest from './plugin/common/SendableStandardMethodCodec.test'; + +export default function testsuite() { + FlutterAbilityAndEntryDelegateTest(); + FlutterAbilityTest(); + FlutterEntryTest(); + FlutterManagerTest(); + SettingTest(); + BinaryCodecTest(); + PlatformViewRegistryImplTest(); + PlatformViewWrapperTest(); + PlatformViewsControllerTest(); + RawPointerCoordTest(); + RootDvModelManagerTest(); + ByteBufferTest(); + PlatformChannelUnitTest(); + RestorationChannelUnitTest(); + SettingsChannelUnitTest(); + TextInputChannelUnitTest(); + JSONMethodCodecUnitTest(); + MethodCallUnitTest(); + AccessibilityEventsDelegateUnitTest(); + DartMessengerTest(); + ApplicationInfoTest(); + FlutterApplicationInfoTest(); + FlutterLoaderTest() + FlutterMutatorViewTest(); + FlutterMutatorsStackTest(); + FlutterRendererTest(); + TouchEventProcessorTest(); + TouchEventTrackerTest(); + WindowInfoRepositoryCallbackAdapterWrapperTest(); + FlutterEngineTest(); + FlutterEngineCacheTest(); + FlutterEngineConnectionRegistryTest(); + FlutterEngineGroupCacheTest(); + FlutterEngineGroupTest(); + FlutterNapiTest(); + FlutterOverlaySurfaceTest(); + FlutterShellArgsTest(); + BinaryMessengerTest(); + DartExecutorTest(); + PathUtilsTest(); + StringUtilsTest(); + ToolUtilsTest(); + MessageChannelUtilsTest(); + LogTest(); + TraceSectionTest(); + FlutterInjectorTest(); + SendableBinaryCodecTest(); + dynamicViewJsonTest(); + PlatformOverlayViewTest(); + PlatformViewTest(); + PlatformViewTest(); + FlutterRunArgumentsTest(); + LifecycleChannelTest(); + FlutterExceptionTest(); + JSONMessageCodecTest(); + SendableJSONMessageCodecTest(); + SendableJSONMethodCodecTest(); + SendableStandardMessageCodecTest(); + SendableStandardMethodCodecTest(); + SendableStringCodecTest(); + StandardMessageCodecTest(); + StandardMethodCodecTest(); + StringCodecTest(); + ListenableEditingStateTest(); + TextEditingDeltaTest(); + TextInputPluginTest(); + LocalizationPluginTest(); +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/FlutterEngineCacheTest.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/FlutterEngineCacheTest.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..73e9ca9573361219b5d2c9e536f9b7abdf76576d --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/FlutterEngineCacheTest.test.ets @@ -0,0 +1,47 @@ +/* + * 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. + */ +import { describe, it, expect } from '@ohos/hypium'; +import FlutterEngine from '@ohos/flutter_ohos/src/main/ets/embedding/engine/FlutterEngine'; +import FlutterEngineCache from '@ohos/flutter_ohos/src/main/ets/embedding/engine/FlutterEngineCache'; + +export default function FlutterEngineCacheTest() { + const flutterEngineCache: FlutterEngineCache = new FlutterEngineCache(); + + describe('FlutterEngineCacheTest', () => { + + it('getInstance', 0, async (done: Function) => { + console.info("uitest: getInstance begin"); + const getInstance: FlutterEngineCache = FlutterEngineCache.getInstance(); + expect(getInstance).not().assertNull(); + done(); + }) + + it('contains', 0, async (done: Function) => { + console.info("uitest: contains begin"); + const contains: boolean = flutterEngineCache.contains('test'); + expect(contains).not().assertNull(); + done(); + }) + + it('get', 0, async (done: Function) => { + console.info("uitest: contains begin"); + const get: FlutterEngine | null = flutterEngineCache.get('test'); + if(get) { + expect(get).not().assertNull(); + } + done(); + }) + }) +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/FlutterEngineConnectionRegistryTest.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/FlutterEngineConnectionRegistryTest.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..01925e7b0ebc20c1dc447303f8bb65d0e707eaf4 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/FlutterEngineConnectionRegistryTest.test.ets @@ -0,0 +1,68 @@ +/* + * 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. + */ +import { describe, beforeAll, it, expect } from '@ohos/hypium'; +import { FlutterPlugin, } from '@ohos/flutter_ohos/src/main/ets/embedding/engine/plugins/FlutterPlugin'; +import FlutterEngine from '@ohos/flutter_ohos/src/main/ets/embedding/engine/FlutterEngine'; +import PlatformViewsController from '@ohos/flutter_ohos/src/main/ets/plugin/platform/PlatformViewsController' +import common from '@ohos.app.ability.common'; +import FlutterEngineConnectionRegistry from '@ohos/flutter_ohos/src/main/ets/embedding/engine/FlutterEngineConnectionRegistry'; +import AbilityConstant from '@ohos.app.ability.AbilityConstant'; + +export default function FlutterEngineConnectionRegistryTest() { + let flutterEngineConnectionRegistry: FlutterEngineConnectionRegistry; + let flutterEngine: FlutterEngine; + let context: common.UIAbilityContext; + const platformViewsController = new PlatformViewsController(); + const pluginClassName = 'test'; + + describe('FlutterEngineConnectionRegistryTest', () => { + + beforeAll(() => { + context = getContext() as common.UIAbilityContext; + flutterEngine = new FlutterEngine(context, null, null, platformViewsController); + const flutterLoader = flutterEngine.getFlutterLoader(); + flutterEngineConnectionRegistry = new FlutterEngineConnectionRegistry(context, flutterEngine, flutterLoader); + }) + + it('has', 0, async (done: Function) => { + console.info("uitest: has begin"); + if (flutterEngineConnectionRegistry) { + const hasFlag = flutterEngineConnectionRegistry.has(pluginClassName); + expect(hasFlag).not().assertNull(); + } + done(); + }) + + it('get', 0, async (done: Function) => { + console.info("uitest: get begin"); + if (flutterEngineConnectionRegistry) { + const name: FlutterPlugin = flutterEngineConnectionRegistry.get(pluginClassName); + expect(name).not().assertNull(); + } + done(); + }) + + it('onSaveState', 0, async (done: Function) => { + console.info("uitest: onSaveState begin"); + const reason = AbilityConstant.StateType.CONTINUATION; + const wantParam: Record = {}; + if (flutterEngineConnectionRegistry) { + const result: AbilityConstant.OnSaveResult = flutterEngineConnectionRegistry.onSaveState(reason, wantParam); + expect(result).not().assertNull(); + } + done(); + }) + }) +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/FlutterEngineGroupCacheTest.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/FlutterEngineGroupCacheTest.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..647b3e0e8292f03d21e58ad56144f3af5cfd83ce --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/FlutterEngineGroupCacheTest.test.ets @@ -0,0 +1,48 @@ +/* + * 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. + */ +import { describe, expect, it } from '@ohos/hypium'; +import FlutterEngineGroupCache from '@ohos/flutter_ohos/src/main/ets/embedding/engine/FlutterEngineGroupCache'; +import { FlutterEngineGroup } from '@ohos/flutter_ohos'; + +export default function FlutterEngineGroupCacheTest() { + const flutterEngineGroupCache = new FlutterEngineGroupCache(); + const engineGroupId: string = ''; + + describe('FlutterEngineGroupCacheTest', () => { + + it('instance', 0, async (done: Function) => { + console.info("uitest: instance begin"); + const instance = FlutterEngineGroupCache.instance; + expect(instance).not().assertNull(); + done(); + }) + + it('contains', 0, async (done: Function) => { + console.info("uitest: contains begin"); + const flag = flutterEngineGroupCache.contains(engineGroupId); + expect(flag).not().assertNull(); + done(); + }) + + it('get', 0, async (done: Function) => { + console.info("uitest: get begin"); + const engGroupId: FlutterEngineGroup | null = flutterEngineGroupCache.get(engineGroupId); + if (engGroupId) { + expect(engGroupId).not().assertNull(); + } + done(); + }) + }) +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/FlutterEngineGroupTest.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/FlutterEngineGroupTest.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..f0190788bd496bdeefc622de38ef6ccbc1685746 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/FlutterEngineGroupTest.test.ets @@ -0,0 +1,53 @@ +/* + * 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. + */ +import { describe, expect, it } from '@ohos/hypium'; +import FlutterEngineGroup, { Options } from '@ohos/flutter_ohos/src/main/ets/embedding/engine/FlutterEngineGroup'; +import { FlutterEngine } from '@ohos/flutter_ohos'; +import PlatformViewsController from '@ohos/flutter_ohos/src/main/ets/plugin/platform/PlatformViewsController' +import common from '@ohos.app.ability.common'; + +export default function FlutterEngineGroupTest() { + const flutterEngineGroup = new FlutterEngineGroup(); + const platformViewsController = new PlatformViewsController(); + const context = getContext() as common.UIAbilityContext; + const args: Array = []; + + describe('FlutterEngineGroupTest', () => { + + it('checkLoader', 0, async (done: Function) => { + console.info("uitest: checkLoader begin"); + const checkLoaderCallBack = flutterEngineGroup.checkLoader(context, args); + expect(checkLoaderCallBack).not().assertNull(); + done(); + }) + + it('createAndRunEngineByOptions', 0, async (done: Function) => { + console.info("uitest: createAndRunEngineByOptions begin"); + const options = new Options(context); + const createAndRunEngineByOptionsCallBack = flutterEngineGroup.createAndRunEngineByOptions(options); + expect(createAndRunEngineByOptionsCallBack).not().assertNull(); + done(); + }) + + it('createEngine', 0, async (done: Function) => { + console.info("uitest: createEngine begin"); + if(context) { + const fng: FlutterEngine = flutterEngineGroup.createEngine(context, platformViewsController); + expect(fng).not().assertNull(); + } + done(); + }) + }) +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/FlutterEngineTest.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/FlutterEngineTest.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..fc91be86a45e6600bea65db4920ec7b0ed4a2193 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/FlutterEngineTest.test.ets @@ -0,0 +1,263 @@ +/* + * 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. + */ +import { describe, beforeAll, it, expect } from '@ohos/hypium'; +import DartExecutor, { DartEntrypoint } from '@ohos/flutter_ohos/src/main/ets/embedding/engine/dart/DartExecutor'; +import { Options } from '@ohos/flutter_ohos/src/main/ets/embedding/engine/FlutterEngineGroup'; +import { + AccessibilityChannel, + FlutterLoader, + FlutterNapi, + FlutterRenderer, + LifecycleChannel, + LocalizationChannel, + LocalizationPlugin, + MouseCursorChannel, + NavigationChannel, + PlatformChannel, + PluginRegistry, + RestorationChannel, + SettingsChannel, + SystemChannel, + TextInputChannel +} from '@ohos/flutter_ohos'; +import ActivityControlSurface from '@ohos/flutter_ohos/src/main/ets/embedding/engine/plugins/ability/AbilityControlSurface'; +import PlatformViewsController from '@ohos/flutter_ohos/src/main/ets/plugin/platform/PlatformViewsController'; +import FlutterEngine from '@ohos/flutter_ohos/src/main/ets/embedding/engine/FlutterEngine'; +import common from '@ohos.app.ability.common'; + +export default function FlutterEngineTest() { + const platformViewsController = new PlatformViewsController(); + let context: common.UIAbilityContext; + let flutterEngine: FlutterEngine; + + describe('FlutterEngineTest', () => { + + beforeAll(() => { + const context = getContext() as common.UIAbilityContext; + flutterEngine = new FlutterEngine(context, null, null, platformViewsController); + }) + + it('spawn', 0, async (done: Function) => { + console.info("uitest: spawn begin"); + const options = new Options(context); + let dartEntrypoint: DartEntrypoint | null = options.getDartEntrypoint(); + let initialRoute: string = options.getInitialRoute(); + let dartEntrypointArgs: Array = options.getDartEntrypointArgs(); + let eg: FlutterEngine | null = null; + if (dartEntrypoint) { + eg = await flutterEngine.spawn(context, + dartEntrypoint, + initialRoute, + dartEntrypointArgs, + platformViewsController, + false); + if (eg) { + expect(eg).not().assertNull(); + } + } + done(); + }) + + it('getLifecycleChannel', 0, async (done: Function) => { + console.info("uitest: getLifecycleChannel begin"); + if (flutterEngine) { + const lifecycleChannel: LifecycleChannel | null = flutterEngine.getLifecycleChannel(); + if (lifecycleChannel) { + expect(lifecycleChannel).not().assertNull(); + } + } + done(); + }) + + it('getNavigationChannel', 0, async (done: Function) => { + console.info("uitest: getNavigationChannel begin"); + if (flutterEngine) { + const navigationChannel: NavigationChannel | null = flutterEngine.getNavigationChannel(); + if (navigationChannel) { + expect(navigationChannel).not().assertNull(); + } + } + done(); + }) + + it('getTextInputChannel', 0, async (done: Function) => { + console.info("uitest: getTextInputChannel begin"); + if (flutterEngine) { + const textInputChannel: TextInputChannel | null = flutterEngine.getTextInputChannel(); + if (textInputChannel) { + expect(textInputChannel).not().assertNull(); + } + } + done(); + }) + + it('getPlatformChannel', 0, async (done: Function) => { + console.info("uitest: getPlatformChannel begin"); + if (flutterEngine) { + const platformChannel: PlatformChannel | null = flutterEngine.getPlatformChannel(); + if (platformChannel) { + expect(platformChannel).not().assertNull(); + } + } + done(); + }) + + it('getSystemChannel', 0, async (done: Function) => { + console.info("uitest: getSystemChannel begin"); + if (flutterEngine) { + const systemChannel: SystemChannel | null = flutterEngine.getSystemChannel(); + if (systemChannel) { + expect(systemChannel).not().assertNull(); + } + } + done(); + }) + + it('getLocaleChannel', 0, async (done: Function) => { + console.info("uitest: getLocaleChannel begin"); + if (flutterEngine) { + const localizationChannel: LocalizationChannel | null = flutterEngine.getLocaleChannel(); + if (localizationChannel) { + expect(localizationChannel).not().assertNull(); + } + } + done(); + }) + + it('getMouseCursorChannel', 0, async (done: Function) => { + console.info("uitest: getMouseCursorChannel begin"); + if (flutterEngine) { + const mouseCursorChannel: MouseCursorChannel | null = flutterEngine.getMouseCursorChannel(); + if (mouseCursorChannel) { + expect(mouseCursorChannel).not().assertNull(); + } + } + done(); + }) + + it('getFlutterNapi', 0, async (done: Function) => { + console.info("uitest: getFlutterNapi begin"); + if (flutterEngine) { + const flutterNapi: FlutterNapi = flutterEngine.getFlutterNapi(); + expect(flutterNapi).not().assertNull(); + } + done(); + }) + + it('getFlutterRenderer', 0, async (done: Function) => { + console.info("uitest: getFlutterRenderer begin"); + if (flutterEngine) { + const flutterRenderer: FlutterRenderer = flutterEngine.getFlutterRenderer(); + expect(flutterRenderer).not().assertNull(); + } + done(); + }) + + it('getDartExecutor', 0, async (done: Function) => { + console.info("uitest: getDartExecutor begin"); + if (flutterEngine) { + const dartExecutor: DartExecutor = flutterEngine.getDartExecutor(); + expect(dartExecutor).not().assertNull(); + } + done(); + }) + + it('getPlugins', 0, async (done: Function) => { + console.info("uitest: getPlugins begin"); + if (flutterEngine) { + const pluginRegistry: PluginRegistry | null = flutterEngine.getPlugins(); + if (pluginRegistry) { + expect(pluginRegistry).not().assertNull(); + } + } + done(); + }) + + it('getAbilityControlSurface', 0, async (done: Function) => { + console.info("uitest: getAbilityControlSurface begin"); + if (flutterEngine) { + const activityControlSurface: ActivityControlSurface | null = flutterEngine.getAbilityControlSurface(); + if (activityControlSurface) { + expect(activityControlSurface).not().assertNull(); + } + } + done(); + }) + + it('getSettingsChannel', 0, async (done: Function) => { + console.info("uitest: getSettingsChannel begin"); + if (flutterEngine) { + const settingsChannel: SettingsChannel | null = flutterEngine.getSettingsChannel(); + if (settingsChannel) { + expect(settingsChannel).not().assertNull(); + } + } + done(); + }) + + it('getFlutterLoader', 0, async (done: Function) => { + console.info("uitest: getFlutterLoader begin"); + if (flutterEngine) { + const flutterLoader: FlutterLoader = flutterEngine.getFlutterLoader(); + expect(flutterLoader).not().assertNull(); + } + done(); + }) + + it('getRestorationChannel', 0, async (done: Function) => { + console.info("uitest: getRestorationChannel begin"); + if (flutterEngine) { + const restorationChannel: RestorationChannel | null = flutterEngine.getRestorationChannel(); + if (restorationChannel) { + expect(restorationChannel).not().assertNull(); + } + } + done(); + }) + + it('getAccessibilityChannel', 0, async (done: Function) => { + console.info("uitest: getAccessibilityChannel begin"); + if (flutterEngine) { + const accessibilityChannel: AccessibilityChannel | null = flutterEngine.getAccessibilityChannel(); + if (accessibilityChannel) { + expect(accessibilityChannel).not().assertNull(); + } + } + done(); + }) + + it('getLocalizationPlugin', 0, async (done: Function) => { + console.info("uitest: getLocalizationPlugin begin"); + if (flutterEngine) { + const localizationChannel: LocalizationPlugin | null = flutterEngine.getLocalizationPlugin(); + if (localizationChannel) { + expect(localizationChannel).not().assertNull(); + } + } + done(); + }) + + it('getPlatformViewsController', 0, async (done: Function) => { + console.info("uitest: getPlatformViewsController begin"); + if (flutterEngine) { + const platformViewsController: PlatformViewsController | null = flutterEngine.getPlatformViewsController(); + if (platformViewsController) { + expect(platformViewsController).not().assertNull(); + } + } + done(); + }) + }) +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/FlutterNapiTest.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/FlutterNapiTest.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..6ee93ce6ad0f9ac77f61cd50671c57f5b52e5bdd --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/FlutterNapiTest.test.ets @@ -0,0 +1,182 @@ +/* + * 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. + */ +import FlutterNapi from '@ohos/flutter_ohos/src/main/ets/embedding/engine/FlutterNapi'; +import ApplicationInfoLoader from '@ohos/flutter_ohos/src/main/ets/embedding/engine/loader/ApplicationInfoLoader'; +import { FlutterRenderer } from '@ohos/flutter_ohos/src/main/ets/embedding/engine/renderer/FlutterRenderer'; +import { common } from '@kit.AbilityKit'; +import { describe, beforeAll, it, expect } from '@ohos/hypium'; +import { EngineLifecycleListener } from '@ohos/flutter_ohos/src/main/ets/embedding/engine/FlutterEngine' +import { FlutterApplicationInfo, FlutterCallbackInformation } from '@ohos/flutter_ohos'; +import { resourceManager } from '@kit.LocalizationKit'; + +//jit产物默认kenel文件 +const DEFAULT_KERNEL_BLOB = "kernel_blob.bin"; +//文件路径分隔符 +const FILE_SEPARATOR = "/"; + +export default function FlutterNapiTest() { + const flutterNapi = new FlutterNapi(); + const context = getContext() as common.UIAbilityContext; + let textureId = 0; + let initResult: InitResult; + let snapshotAssetPath: string; + let flutterApplicationInfo: FlutterApplicationInfo; + let bundlePath: string; + let event: PanGestureEvent; + let assetManager: resourceManager.ResourceManager; + + describe('FlutterNapiTest', () => { + + beforeAll(() => { + if (context) { + initResult = new InitResult( + `${context.filesDir}/`, + `${context.cacheDir}/`, + `${context.filesDir}`); + snapshotAssetPath = initResult!.dataDirPath + FILE_SEPARATOR + flutterApplicationInfo!.flutterAssetsDir; + bundlePath = snapshotAssetPath + FILE_SEPARATOR + DEFAULT_KERNEL_BLOB; + flutterApplicationInfo = ApplicationInfoLoader.load(context); + assetManager = context.resourceManager; + } + const target: EventTarget = new CustomEventTarget(new CustomArea(0, 0, { + x: 0, y: 0 + }, { + x: 0, y: 0 + })); + const renderer = new FlutterRenderer(flutterNapi); + textureId = renderer.getTextureId(); + event = { + offsetX: 50, + offsetY: 50, + velocityX: 50, + velocityY: 50, + fingerList: [], + velocity: 0, + target: target, + timestamp: 0, + source: SourceType.Unknown, + pressure: 0, + tiltX: 0, + tiltY: 0, + sourceTool: SourceTool.Unknown + } + }) + + it('checkImplemented', 0, async (done: Function) => { + console.info("uitest: checkImplemented begin"); + const methodName = 'test'; + const flag = flutterNapi.checkImplemented(methodName); + expect(flag).not().assertNull(); + done(); + }) + + it('nativeLookupCallbackInformation', 0, async (done: Function) => { + console.info("uitest: nativeLookupCallbackInformation begin"); + try { + const handle = 1; + const flutterCallbackInformation: FlutterCallbackInformation | null = + FlutterNapi.nativeLookupCallbackInformation(handle); + if (flutterCallbackInformation) { + expect(flutterCallbackInformation).not().assertNull(); + } + } catch (e) { + } + done(); + }) + + it('isAttached', 0, async (done: Function) => { + console.info("uitest: isAttached begin"); + const flag: boolean = flutterNapi.isAttached(); + expect(flag).not().assertNull(); + done(); + }) + + it('spawn', 0, async (done: Function) => { + console.info("uitest: spawn begin"); + const entrypointFunctionName = 'test1'; + const pathToEntrypointFunction = 'test2'; + const initialRoute = 'test3'; + const entrypointArgs = ['test4']; + try { + const fnapi: FlutterNapi = + flutterNapi.spawn(entrypointFunctionName, pathToEntrypointFunction, initialRoute, entrypointArgs); + expect(fnapi).not().assertNull(); + } catch (e) { + } + done(); + }) + + it('computePlatformResolvedLocale', 0, async (done: Function) => { + console.info("uitest: computePlatformResolvedLocale begin"); + const strings = []; + const arr = flutterNapi.computePlatformResolvedLocale(strings); + expect(arr).not().assertNull(); + done(); + }) + + it('registerTexture', 0, async (done: Function) => { + console.info("uitest: registerTexture begin"); + const id = flutterNapi.registerTexture(textureId); + expect(id).not().assertNull(); + done(); + }) + }) +} + +class InitResult { + appStoragePath: string; + engineCachesPath: string; + dataDirPath: string; + + constructor(appStoragePath: string, + engineCachesPath: string, + dataDirPath: string) { + this.appStoragePath = appStoragePath; + this.engineCachesPath = engineCachesPath; + this.dataDirPath = dataDirPath; + } +} + +class CurEngineLifecycleListener implements EngineLifecycleListener { + onPreEngineRestart() { + + } + + onEngineWillDestroy() { + + } +} + +class CustomEventTarget implements EventTarget { + area: Area = new CustomArea(0, 0, { x: 0, y: 0 }, { x: 0, y: 0 }); + + constructor(area: Area) { + this.area = area; + } +} + +class CustomArea implements Area { + width: Length = 0; + height: Length = 0; + position: Position = { x: 0, y: 0 }; + globalPosition: Position = { x: 0, y: 0 }; + + constructor(width: Length, height: Length, position: Position, globalPosition: Position) { + this.width = width; + this.height = height; + this.position = position; + this.globalPosition = globalPosition; + } +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/FlutterOverlaySurfaceTest.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/FlutterOverlaySurfaceTest.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..b98eaccdbeee59bb2c66bd0868981ee204bda1d1 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/FlutterOverlaySurfaceTest.test.ets @@ -0,0 +1,35 @@ +/* + * 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. + */ +import { describe, beforeAll, expect, it } from '@ohos/hypium'; +import { FlutterOverlaySurface } from '@ohos/flutter_ohos/src/main/ets/embedding/engine/FlutterOverlaySurface'; + +export default function FlutterOverlaySurfaceTest() { + let flutterOverlaySurface: FlutterOverlaySurface; + + describe('FlutterOverlaySurfaceTest', () => { + + beforeAll(() => { + const id = 2356; + flutterOverlaySurface = new FlutterOverlaySurface(id); + }) + + it('getId', 0, async (done: Function) => { + console.info("uitest: getId begin"); + const id = flutterOverlaySurface.getId(); + expect(id).not().assertNull(); + done(); + }) + }) +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/FlutterShellArgsTest.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/FlutterShellArgsTest.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..b92df1429d92e30c588cb5ffbe5d55eeb0090512 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/FlutterShellArgsTest.test.ets @@ -0,0 +1,62 @@ +/* + * 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. + */ +import { describe, expect, it } from '@ohos/hypium'; +import { abilityDelegatorRegistry } from '@kit.TestKit'; +import { Want } from '@kit.AbilityKit'; +import FlutterShellArgs from '@ohos/flutter_ohos/src/main/ets/embedding/engine/FlutterShellArgs'; + +const bundleName = abilityDelegatorRegistry.getArguments().bundleName; + +export default function FlutterShellArgsTest() { + const flutterShellArgs: FlutterShellArgs = new FlutterShellArgs(); + const want: Want = { + bundleName: bundleName, + abilityName: 'EntryAbility' + } + + describe('FlutterShellArgsTest', () => { + + it('fromWant', 0, async (done: Function) => { + console.info("uitest: fromWant begin"); + try { + const flutterShellArgs = FlutterShellArgs.fromWant(want); + if (flutterShellArgs) { + expect(flutterShellArgs).not().assertNull(); + } + } catch (e) { + } + done(); + }) + + it('checkArg', 0, async (done: Function) => { + console.info("uitest: checkArg begin"); + const argKey = 'argKey'; + const argFlag = 'argFlag'; + try { + const flutterShellArgs = FlutterShellArgs.fromWant(want); + FlutterShellArgs.checkArg(argKey, argFlag, want, flutterShellArgs); + } catch (e) { + } + done(); + }) + + it('toArray', 0, async (done: Function) => { + console.info("uitest: toArray begin"); + const toArray = flutterShellArgs.toArray(); + expect(toArray).not().assertNull(); + done(); + }) + }) +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/dart/DartExecutorTest.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/dart/DartExecutorTest.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..6577fa556cb0f9eeffe2c09f6450da5dbdb91d21 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/dart/DartExecutorTest.test.ets @@ -0,0 +1,70 @@ +/* + * 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. + */ +import { describe, beforeAll, expect, it } from '@ohos/hypium'; +import { common } from '@kit.AbilityKit'; +import { Options } from '@ohos/flutter_ohos/src/main/ets/embedding/engine/FlutterEngineGroup'; +import { DartEntrypoint } from '@ohos/flutter_ohos/src/main/ets/embedding/engine/dart/DartExecutor'; +import { resourceManager } from '@kit.LocalizationKit'; +import DartExecutor from '@ohos/flutter_ohos/src/main/ets/embedding/engine/dart/DartExecutor'; +import FlutterNapi from '@ohos/flutter_ohos/src/main/ets/embedding/engine/FlutterNapi'; + +export default function DartExecutorTest() { + const flutterNapi = new FlutterNapi(); + let context: common.UIAbilityContext; + let dartExecutor: DartExecutor; + let options: Options; + let assetManager: resourceManager.ResourceManager; + let dartEntrypoint: DartEntrypoint | null = null; + let resourceManager: resourceManager.ResourceManager; + + describe('DartExecutorTest', () => { + + beforeAll(() => { + context = getContext() as common.UIAbilityContext; + assetManager = context.resourceManager; + resourceManager = context.resourceManager; + dartExecutor = new DartExecutor(flutterNapi, assetManager); + options = new Options(context); + dartEntrypoint = options.getDartEntrypoint(); + }) + + it('isExecutingDart', 0, async (done: Function) => { + console.info("uitest: isExecutingDart begin"); + if (dartExecutor) { + const isExecutingDart = dartExecutor.isExecutingDart(); + expect(isExecutingDart).not().assertNull(); + } + done(); + }) + + it('getBinaryMessenger', 0, async (done: Function) => { + console.info("uitest: getBinaryMessenger begin"); + if (dartExecutor) { + const binaryMessenger = dartExecutor.getBinaryMessenger(); + expect(binaryMessenger).not().assertNull(); + } + done(); + }) + + it('makeBackgroundTaskQueue', 0, async (done: Function) => { + console.info("uitest: makeBackgroundTaskQueue begin"); + if (dartExecutor) { + const taskQueue = dartExecutor.makeBackgroundTaskQueue(); + expect(taskQueue).not().assertNull(); + } + done(); + }) + }) +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/dart/DartMessengerTest.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/dart/DartMessengerTest.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..c48bad263fdf8725e88eaa658ec3acb6a53daf08 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/dart/DartMessengerTest.test.ets @@ -0,0 +1,47 @@ +/* + * 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. + */ + +import { DartMessenger} from '@ohos/flutter_ohos/src/main/ets/embedding/engine/dart/DartMessenger' +import { describe,it, expect } from '@ohos/hypium'; +import FlutterNapi from '@ohos/flutter_ohos/src/main/ets/embedding/engine/FlutterNapi' +import { + TaskQueue, +} from '@ohos/flutter_ohos/src/main/ets/plugin/common/BinaryMessenger' +export default function DartMessengerTest() { + describe('FlutterDartMessengerTest', () => { + it('TestMakeBackgroundTaskQueue', 0, async (done: Function) => { + const flutterNapi: FlutterNapi = new FlutterNapi(); + const dartMessage = new DartMessenger(flutterNapi); + let taskQueue: TaskQueue = dartMessage.makeBackgroundTaskQueue(); + expect(taskQueue).not().assertNull(); + done(); + }) + + it('TestGetPendingChannelResponseCount', 0, async (done: Function) => { + const flutterNapi: FlutterNapi = new FlutterNapi(); + const messenger = new DartMessenger(flutterNapi); + let count: number = messenger.getPendingChannelResponseCount(); + expect(count).assertEqual(0); + done(); + }) + + it('TestAskQueueFactory', 0, async (done: Function) => { + const flutterNapi: FlutterNapi = new FlutterNapi(); + const messenger = new DartMessenger(flutterNapi); + expect(messenger.taskQueueFactory).not().assertNull(); + done(); + }) + }) +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/loader/ApplicationInfoTest.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/loader/ApplicationInfoTest.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..00fe21a0e9ff9560f6e1ea5c669e18c83d20dff4 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/loader/ApplicationInfoTest.test.ets @@ -0,0 +1,28 @@ +/* + * 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. + */ + +import common from '@ohos.app.ability.common'; +import ApplicationInfoLoader from '@ohos/flutter_ohos/src/main/ets/embedding/engine/loader/ApplicationInfoLoader' +import { describe,it, expect } from '@ohos/hypium'; +export default function ApplicationInfoTest() { + describe('ApplicationInfoTest', () => { + it('TestLoad', 0, async (done: Function) => { + let context: common.Context = getContext(); + let applicationInfo = ApplicationInfoLoader.load(context) + expect(applicationInfo).not().assertNull(); + done(); + }) + }) +} diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/loader/FlutterApplicationInfoTest.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/loader/FlutterApplicationInfoTest.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..7556ae740f126c2e0e213045eb25a60b2b33b58f --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/loader/FlutterApplicationInfoTest.test.ets @@ -0,0 +1,26 @@ +/* + * 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. + */ + +import FlutterApplicationInfo from '@ohos/flutter_ohos/src/main/ets/embedding/engine/loader/FlutterApplicationInfo' +import { describe, it, expect } from '@ohos/hypium'; +export default function FlutterApplicationInfoTest() { + describe('FlutterApplicationInfoTest', () => { + it('TestLoad', 0, async (done: Function) => { + let flutterApplicationInfo = new FlutterApplicationInfo("test", "test", "test", "test", "test", "test", false) + expect(flutterApplicationInfo).not().assertNull(); + done(); + }) + }) +} diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/loader/FlutterLoaderTest.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/loader/FlutterLoaderTest.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..52e231dcd95db99780fcc6631a90c7b57e7adcbf --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/loader/FlutterLoaderTest.test.ets @@ -0,0 +1,52 @@ +/* + * 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. + */ + +import common from '@ohos.app.ability.common'; +import FlutterLoader from '@ohos/flutter_ohos/src/main/ets/embedding/engine/loader/FlutterLoader' +import { describe,it, expect } from '@ohos/hypium'; +import FlutterNapi from '@ohos/flutter_ohos/src/main/ets/embedding/engine/FlutterNapi' +export default function FlutterLoaderTest() { + describe('FlutterLoaderTest', () => { + it('initializationTest', 0, async (done: Function) => { + let flutterNapi: FlutterNapi = new FlutterNapi(); + let flutterLoader: FlutterLoader = new FlutterLoader(flutterNapi); + expect(flutterLoader.initialized).assertFalse(); + done(); + }) + + it('initResultTest', 0, async (done: Function) => { + let flutterNapi: FlutterNapi = new FlutterNapi(); + let flutterLoader: FlutterLoader = new FlutterLoader(flutterNapi); + expect(flutterLoader.initResult).assertNull(); + done(); + }) + + it('flutterNapiTest', 0, async (done: Function) => { + let flutterNapi: FlutterNapi = new FlutterNapi(); + let flutterLoader: FlutterLoader = new FlutterLoader(flutterNapi); + expect(flutterLoader.flutterNapi).not().assertNull(); + done(); + }) + + it('startInitializationTest', 0, async (done: Function) => { + let flutterNapi: FlutterNapi = new FlutterNapi(); + let flutterLoader: FlutterLoader = new FlutterLoader(flutterNapi); + let context: common.Context = getContext(); + expect(flutterLoader.initialized).assertFalse(); + flutterLoader.startInitialization(context); + done(); + }) + }) +} diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/mutatorsstack/FlutterMutatorViewTest.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/mutatorsstack/FlutterMutatorViewTest.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..4924e8b78ad3cde41b4c74e0f07a4cb33fab9234 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/mutatorsstack/FlutterMutatorViewTest.test.ets @@ -0,0 +1,27 @@ +/* + * 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. + */ + +import { FlutterMutatorView } from '@ohos/flutter_ohos/src/main/ets/embedding/engine/mutatorsstack/FlutterMutatorView' +import { describe,it, expect } from '@ohos/hypium'; +export default function FlutterMutatorViewTest() { + describe('FlutterMutatorViewTest', () => { + it('TestGetDvModel', 0, async (done: Function) => { + let flutterMutatorView = new FlutterMutatorView(); + let dvModel = flutterMutatorView.getDvModel(); + expect(dvModel).not().assertNull(); + done(); + }) + }) +} diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/mutatorsstack/FlutterMutatorsStackTest.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/mutatorsstack/FlutterMutatorsStackTest.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..4c633425ba780a04fae007d44cc50f759b5787dd --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/mutatorsstack/FlutterMutatorsStackTest.test.ets @@ -0,0 +1,90 @@ +/* + * 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. + */ + +import common from '@ohos.app.ability.common'; +import { + FlutterMutatorsStack, + FlutterMutator +} from '@ohos/flutter_ohos/src/main/ets/embedding/engine/mutatorsstack/FlutterMutatorsStack' +import { describe,it, expect } from '@ohos/hypium'; +import matrix4 from '@ohos.matrix4' +export default function FlutterMutatorsStackTest() { + describe('FlutterMutatorsStackTest', () => { + it('TestPushClipPath', 0, async (done: Function) => { + let flutterMutatorStack = new FlutterMutatorsStack(); + const width = 100; + const height = 200; + const command = 'M 10 10 L 90 90'; + flutterMutatorStack.pushClipPath(width, height, command); + expect(flutterMutatorStack.getMutators().length).assertEqual(1); + expect(flutterMutatorStack.getFinalClippingPaths().length).assertEqual(1); + done(); + }) + + it('TestPushClipRect1', 0, async (done: Function) => { + let flutterMutatorStack = new FlutterMutatorsStack(); + const width = 100; + const height = 200; + const radius = 10; + flutterMutatorStack.pushClipRect(width, height, radius); + expect(flutterMutatorStack.getMutators().length).assertEqual(1); + done(); + }) + + it('TestPushClipRect2', 0, async (done: Function) => { + let flutterMutatorStack = new FlutterMutatorsStack(); + const width = 100; + const height = 200; + const radius = 10; + flutterMutatorStack.pushClipRect(width, height, radius); + expect(flutterMutatorStack.getFinalClippingRects().length).assertEqual(1); + done(); + }) + + it('TestPushTransform1', 0, async (done: Function) => { + const values = [1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]; + let flutterMutatorStack = new FlutterMutatorsStack(); + flutterMutatorStack.pushTransform(values); + expect(flutterMutatorStack.getMutators().length).assertEqual(1); + done(); + }) + + it('TestPushTransform2', 0, async (done: Function) => { + const values = [1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]; + let flutterMutatorStack = new FlutterMutatorsStack(); + flutterMutatorStack.pushTransform(values); + expect(flutterMutatorStack.getMutators().length).assertEqual(1); + done(); + }) + + it('TestFlutterMutatorsStack1', 0, async (done: Function) => { + let flutterMutatorStack = new FlutterMutatorsStack(); + expect(flutterMutatorStack.getMutators().length).assertEqual(0); + done(); + }) + + it('TestFlutterMutatorsStack2', 0, async (done: Function) => { + let flutterMutatorStack = new FlutterMutatorsStack(); + expect(flutterMutatorStack.getFinalClippingPaths().length).assertEqual(0); + done(); + }) + + it('TestFlutterMutatorsStack3', 0, async (done: Function) => { + let flutterMutatorStack = new FlutterMutatorsStack(); + expect(flutterMutatorStack.getFinalClippingRects().length).assertEqual(0); + done(); + }) + }) +} diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/renderer/FlutterRendererTest.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/renderer/FlutterRendererTest.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..169f510280b480861703ce4c3054f6adaddaf834 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/renderer/FlutterRendererTest.test.ets @@ -0,0 +1,58 @@ +/* + * 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. + */ + +import { describe,it, expect } from '@ohos/hypium'; +import { FlutterRenderer} from '@ohos/flutter_ohos/src/main/ets/embedding/engine/renderer/FlutterRenderer'; +import FlutterNapi from '@ohos/flutter_ohos/src/main/ets/embedding/engine/FlutterNapi' +export default function FlutterRendererTest() { + describe('FlutterRendererTest', () => { + it('TestCreateSurfaceTexture', 0, async (done: Function) => { + let flutterNapi: FlutterNapi = new FlutterNapi(); + let flutterRenderer = new FlutterRenderer(flutterNapi); + let surfaceTextureEntry = flutterRenderer.createSurfaceTexture(); + expect(surfaceTextureEntry).not().assertNull();; + done(); + }) + + it('TestGetTextureId', 0, async (done: Function) => { + let flutterNapi: FlutterNapi = new FlutterNapi(); + let flutterRenderer = new FlutterRenderer(flutterNapi); + let textureId = flutterRenderer.getTextureId(); + expect(textureId == 0).assertFalse(); + done(); + }) + + it('TestRegisterPixelMap', 0, async (done: Function) => { + let flutterNapi: FlutterNapi = new FlutterNapi(); + let flutterRenderer = new FlutterRenderer(flutterNapi); + const pixelMap = {} as PixelMap; + let textureId = flutterRenderer.registerPixelMap(pixelMap); + expect(textureId).assertEqual(1); + done(); + }) + + it('TestRegisterPixelMapMore', 0, async (done: Function) => { + let flutterNapi: FlutterNapi = new FlutterNapi(); + let flutterRenderer = new FlutterRenderer(flutterNapi); + const pixelMap1 = {} as PixelMap; + const pixelMap2 = {} as PixelMap; + const textureId1 = flutterRenderer.registerPixelMap(pixelMap1); + const textureId2 = flutterRenderer.registerPixelMap(pixelMap2); + expect(textureId1).assertEqual(1); // 第一次调用 + expect(textureId2).assertEqual(2); // 第二次调用 + done(); + }) + }) +} diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/systemchannels/LifecycleChannel.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/systemchannels/LifecycleChannel.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..61590d082192e7d588d84d266ad9768c34248ebc --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/systemchannels/LifecycleChannel.test.ets @@ -0,0 +1,71 @@ +/* + * 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. + */ +import { describe, beforeEach, it, expect } from '@ohos/hypium' +import LifecycleChannel from '@ohos/flutter_ohos/src/main/ets/embedding/engine/systemchannels/LifecycleChannel'; +import Any from '@ohos/flutter_ohos/src/main/ets/plugin/common/Any'; + +export default function LifecycleChannelTest() { + describe('LifecycleChannelTest', () => { + let lifecycleChannel: LifecycleChannel; + let dartExecutorMock: Any; + let basicMessageChannelMock: Any; + beforeEach(() => { + dartExecutorMock = { + send: (channelName: string, message: string) => { + } + }; + basicMessageChannelMock = { + send: (message: string) => { + } + }; + lifecycleChannel = new LifecycleChannel(dartExecutorMock as Any); + (lifecycleChannel as Any).channel = basicMessageChannelMock; + }); + it('should send resumed state with focus', 0, () => { + lifecycleChannel.appIsResumed(); + lifecycleChannel.aWindowIsFocused(); + expect(basicMessageChannelMock.send).not().assertEqual('AppLifecycleState.resumed'); + }) + it('should send inactive state without focus', 0, () => { + lifecycleChannel.appIsResumed(); + lifecycleChannel.noWindowsAreFocused(); + expect(basicMessageChannelMock.send).not().assertEqual('AppLifecycleState.inactive'); + }) + it('should send inactive state when app is inactive', 0, () => { + lifecycleChannel.appIsInactive(); + lifecycleChannel.aWindowIsFocused(); + expect(basicMessageChannelMock.send).not().assertEqual('AppLifecycleState.inactive'); + }) + it('should send paused state when app is paused', 0, () => { + lifecycleChannel.appIsPaused(); + lifecycleChannel.aWindowIsFocused(); + expect(basicMessageChannelMock.send).not().assertEqual('AppLifecycleState.paused'); + }) + it('should send detached state when app is detached', 0, () => { + lifecycleChannel.appIsDetached(); + lifecycleChannel.aWindowIsFocused(); + expect(basicMessageChannelMock.send).not().assertEqual('AppLifecycleState.detached'); + }) + it('should not send duplicate state', 0, () => { + lifecycleChannel.appIsResumed(); + lifecycleChannel.aWindowIsFocused(); + (lifecycleChannel as Any).lastFlutterState = 'AppLifecycleState.resumed'; + + lifecycleChannel.appIsResumed(); + lifecycleChannel.aWindowIsFocused(); + expect(basicMessageChannelMock.send).not().assertEqual(1); + }) + }) +} diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/systemchannels/PlatformChannel.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/systemchannels/PlatformChannel.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..1b6bb22329b4c9703ffc87264be2b2ae07c0b4cc --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/systemchannels/PlatformChannel.test.ets @@ -0,0 +1,102 @@ +/* + * 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. + */ +import { describe, expect, it, } from "@ohos/hypium"; +import { AsyncCallback as _AsyncCallback } from '@ohos.base'; +import PlatformChannel, { + Brightness, + ClipboardContentFormat, + DeviceOrientation, + HapticFeedbackType, + SystemUiMode, + SystemUiOverlay +} from "@ohos/flutter_ohos/src/main/ets/embedding/engine/systemchannels/PlatformChannel"; +import { Any, DartExecutor, FlutterNapi, MethodResult } from "@ohos/flutter_ohos"; +import { resourceManager } from "@kit.LocalizationKit"; + +export default function PlatformChannelUnitTest() { + describe('PlatformChannelTest', () => { + it('platformChannel_decodeOrientations', 0, decodeOrientations); + + it('platformChannel_getFeedbackTypeFromValue', 0, getFeedbackTypeFromValue); + + it('platformChannel_getClipboardContentFormatFromValue', 0, getClipboardContentFormatFromValue); + + it('platformChannel_getSystemUiOverlayFromValue', 0, getSystemUiOverlayFromValue); + + it('platformChannel_getSystemUiModeFromValue', 0, getSystemUiModeFromValue); + + it('platformChannel_getBrightnessFromValue', 0, getBrightnessFromValue); + + it('platformChannel_getDeviceOrientationFromValue', 0, getDeviceOrientationFromValue); + }) +} + +function decodeOrientations() { + let channel = getPlatformChannel(); + expect(channel.decodeOrientations([DeviceOrientation.PORTRAIT_UP])).assertInstanceOf("Number") +} + +function getFeedbackTypeFromValue() { + let channel = getPlatformChannel(); + let result = channel.getFeedbackTypeFromValue(HapticFeedbackType.STANDARD); + expect(result).assertInstanceOf("String") +} + +function getClipboardContentFormatFromValue() { + let channel = getPlatformChannel(); + let result = channel.getClipboardContentFormatFromValue(ClipboardContentFormat.PLAIN_TEXT); + expect(result).assertInstanceOf("String") +} + +function getSystemUiOverlayFromValue() { + let channel = getPlatformChannel(); + let result = channel.getSystemUiOverlayFromValue(SystemUiOverlay.BOTTOM_OVERLAYS); + expect(result).assertInstanceOf("String") +} + +function getSystemUiModeFromValue() { + let channel = getPlatformChannel(); + let result = channel.getSystemUiModeFromValue(SystemUiMode.IMMERSIVE); + expect(result).assertInstanceOf("String") +} + +function getBrightnessFromValue() { + let channel = getPlatformChannel(); + let result = channel.getBrightnessFromValue(Brightness.LIGHT); + expect(result).assertInstanceOf("String") +} + +function getDeviceOrientationFromValue() { + let channel = getPlatformChannel(); + let result = channel.getDeviceOrientationFromValue(DeviceOrientation.PORTRAIT_UP); + expect(result).assertInstanceOf("String") +} + +function getPlatformChannel(): PlatformChannel { + let flutterNapi = new FlutterNapi(); + let manager: resourceManager.ResourceManager = getContext().resourceManager; + let dartExecutor = new DartExecutor(flutterNapi, manager); + let channel = new PlatformChannel(dartExecutor); + return channel; +} + +export class MethodResultTest implements MethodResult { + success = (result: Any): void => { + }; + error = (errorCode: string, errorMessage: string, errorDetails: Any): void => { + }; + notImplemented = (): void => { + } +} diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/systemchannels/RestorationChannel.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/systemchannels/RestorationChannel.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..7a692e1ad8a4cb8039133306c77e8c75de062f13 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/systemchannels/RestorationChannel.test.ets @@ -0,0 +1,71 @@ +/* + * 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. + */ + +import { + DartExecutor, + FlutterNapi, + MethodCall, + MethodCallHandler, + MethodChannel, + MethodResult, + RestorationChannel, + StandardMethodCodec +} from "@ohos/flutter_ohos"; +import { describe, expect, it } from "@ohos/hypium"; +import { resourceManager } from "@kit.LocalizationKit"; +import { util } from "@kit.ArkTS"; + +let TAG = "RestorationChannel"; + +export default function RestorationChannelUnitTest() { + + describe('RestorationChannelTest', () => { + it("RestorationChannel_getRestorationData", 0, getRestorationData); + }) +} + +function getRestorationData() { + let channel = getRestorationChannel(); + expect(channel.getRestorationData()).assertInstanceOf("Uint8Array") +} + +function getRestorationChannel(): RestorationChannel { + let flutterNapi = new FlutterNapi(); + let manager: resourceManager.ResourceManager = getContext().resourceManager; + let dartExecutor = new DartExecutor(flutterNapi, manager); + let rawChannel = new MethodChannel(dartExecutor, "flutter/mousecursor", StandardMethodCodec.INSTANCE); + let restorationChannel = new RestorationChannel(rawChannel, false); + return restorationChannel; +} + +class TestMethodCallHandler implements MethodCallHandler { + onMethodCall(call: MethodCall, result: MethodResult): void { + } +} + +/** + * string转Uint8Array + * @param value + * @returns + */ +export function stringToUint8Array(str: string): Uint8Array { + try { + let textEncoder = new util.TextEncoder("utf-8"); + let array: Uint8Array = textEncoder.encodeInto(str); + return array + } catch (err) { + return new Uint8Array() + } +} diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/systemchannels/SettingsChannel.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/systemchannels/SettingsChannel.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..ae6ac3ed607cbaba74fe39bf5fd1582ce7777f13 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/systemchannels/SettingsChannel.test.ets @@ -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. + */ + +import { describe, expect, it } from "@ohos/hypium"; +import { resourceManager } from "@kit.LocalizationKit"; +import { DartExecutor, FlutterNapi, SettingsChannel } from "@ohos/flutter_ohos"; + +export default function SettingsChannelUnitTest() { + describe('SettingsChannelTest', () => { + it("SettingsChannel_startMessage", 0, startMessage); + }) +} + +function startMessage() { + let channel = getSettingsChannel(); + let result = channel.startMessage(); + expect(result).assertInstanceOf("Object"); +} + +function getSettingsChannel(): SettingsChannel { + let flutterNapi = new FlutterNapi(); + let manager: resourceManager.ResourceManager = getContext().resourceManager; + let dartExecutor = new DartExecutor(flutterNapi, manager); + let channel = new SettingsChannel(dartExecutor); + return channel; +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/systemchannels/TextInputChannel.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/systemchannels/TextInputChannel.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..5266cefa3ce4b7bff9e407f60965f64d7d152ea8 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/engine/systemchannels/TextInputChannel.test.ets @@ -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. + */ + +import { describe, expect, it } from "@ohos/hypium"; +import { resourceManager } from "@kit.LocalizationKit"; +import { DartExecutor, FlutterNapi, TextInputChannel } from "@ohos/flutter_ohos"; + +export default function TextInputChannelUnitTest() { + describe('TextInputChannel', () => { + it("TextInputChannel_createEditingStateJSON", 0, createEditingStateJSON); + }) +} + +function createEditingStateJSON() { + let textInputChannel = getTextInputChannel(); + let result = textInputChannel.createEditingStateJSON("test", 0, 1, 0, 2); + expect(result).assertInstanceOf("Object"); +} + +function getTextInputChannel(): TextInputChannel { + let flutterNapi = new FlutterNapi(); + let manager: resourceManager.ResourceManager = getContext().resourceManager; + let dartExecutor = new DartExecutor(flutterNapi, manager); + let channel = new TextInputChannel(dartExecutor); + return channel; +} diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/ohos/FlutterAbilityAndEntryDelegateTest.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/ohos/FlutterAbilityAndEntryDelegateTest.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..3c7d611d7804e28e8dc217abb1687506f3709afe --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/ohos/FlutterAbilityAndEntryDelegateTest.test.ets @@ -0,0 +1,78 @@ +/* + * 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. + */ +import { describe, it, expect } from '@ohos/hypium'; +import { abilityDelegatorRegistry } from '@kit.TestKit'; +import AbilityConstant from '@ohos.app.ability.AbilityConstant'; +import { FlutterAbilityAndEntryDelegate } from "@ohos/flutter_ohos"; +import { Options } from '@ohos/flutter_ohos/src/main/ets/embedding/engine/FlutterEngineGroup'; +import { Want } from '@kit.AbilityKit'; + +const bundleName = abilityDelegatorRegistry.getArguments().bundleName; + +export default function FlutterAbilityAndEntryDelegateTest() { + describe('FlutterAbilityAndEntryDelegateTest', () => { + + it('TestAddEntrypointOptions', 0, async (done: Function) => { + const flutterAbilityAndEntryDelegate: FlutterAbilityAndEntryDelegate = new FlutterAbilityAndEntryDelegate(); + const options: Options = new Options(getContext()); + const result = flutterAbilityAndEntryDelegate.addEntrypointOptions(options); + expect(result).not().assertNull(); + done(); + }) + + it('TestShouldDispatchAppLifecycleState', 0, async (done: Function) => { + const flutterAbilityAndEntryDelegate: FlutterAbilityAndEntryDelegate = new FlutterAbilityAndEntryDelegate(); + const result = flutterAbilityAndEntryDelegate.shouldDispatchAppLifecycleState(); + expect(result).not().assertNull(); + done(); + }) + + it('TestGetFlutterNapi', 0, async (done: Function) => { + const flutterAbilityAndEntryDelegate: FlutterAbilityAndEntryDelegate = new FlutterAbilityAndEntryDelegate(); + const result = flutterAbilityAndEntryDelegate.getFlutterNapi(); + expect(result).assertNull(); + done(); + }) + + it('TestOnSaveState', 0, async (done: Function) => { + const flutterAbilityAndEntryDelegate: FlutterAbilityAndEntryDelegate = new FlutterAbilityAndEntryDelegate(); + const reason: AbilityConstant.StateType = AbilityConstant.StateType.CONTINUATION + const want: Want = { + bundleName: bundleName, + abilityName: 'EntryAbility' + } + const wantParam: Record = { + "testParams": want + } + const result = flutterAbilityAndEntryDelegate.onSaveState(reason, wantParam); + expect(result).assertEqual(5); + done(); + }) + + it('TestIsFlutterEngineFromHost', 0, async (done: Function) => { + const flutterAbilityAndEntryDelegate: FlutterAbilityAndEntryDelegate = new FlutterAbilityAndEntryDelegate(); + const result = flutterAbilityAndEntryDelegate.isFlutterEngineFromHost(); + expect(result).not().assertNull(); + done(); + }) + + it('TestGetFlutterEngine', 0, async (done: Function) => { + const flutterAbilityAndEntryDelegate: FlutterAbilityAndEntryDelegate = new FlutterAbilityAndEntryDelegate(); + const result = flutterAbilityAndEntryDelegate.getFlutterEngine(); + expect(result).assertNull(); + done(); + }) + }) +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/ohos/FlutterAbilityTest.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/ohos/FlutterAbilityTest.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..7954b9f73bd6029d45d078d538a5b4d5b64844fa --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/ohos/FlutterAbilityTest.test.ets @@ -0,0 +1,158 @@ +/* + * 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. + */ +import { describe, it, expect } from '@ohos/hypium'; +import { abilityDelegatorRegistry } from '@kit.TestKit'; +import { Want } from '@kit.AbilityKit'; +import AbilityConstant from '@ohos.app.ability.AbilityConstant'; +import { FlutterView, FlutterAbility, FlutterEngine, FlutterPlugin } from "@ohos/flutter_ohos"; +import { FlutterPluginBinding } from '@ohos/flutter_ohos/src/main/ets/embedding/engine/plugins/FlutterPlugin'; + +const bundleName = abilityDelegatorRegistry.getArguments().bundleName; +const want: Want = { + bundleName: bundleName, + abilityName: 'EntryAbility' +} + +function sleep(time: number) { + return new Promise((resolve: Function) => setTimeout(resolve, time)); +} + +export default function FlutterAbilityTest() { + describe('FlutterAbilityTest', () => { + it('FlutterAbilityTest', 0, async (done: Function) => { + const flutterAbility: FlutterAbility = new FlutterAbility(); + const flutterView: FlutterView | null = flutterAbility.getFlutterView(); + expect(flutterView).assertNull(); + await sleep(1000); + const pagePath: string = flutterAbility.pagePath(); + expect(pagePath).assertEqual("pages/Index"); + done(); + }) + + it('TestFlutterAbilityOnSaveState', 0, async (done: Function) => { + const flutterAbility: FlutterAbility = new FlutterAbility(); + const reason: AbilityConstant.StateType = AbilityConstant.StateType.CONTINUATION + const wantParam: Record = { + "testParams": want + } + await sleep(1000); + const result = flutterAbility.onSaveState(reason, wantParam); + expect(result).not().assertNull(); + done(); + }) + + it('TestGetWant', 0, async (done: Function) => { + const flutterAbility: FlutterAbility = new FlutterAbility(); + const result = flutterAbility.getWant(); + expect(result).assertUndefined(); + done(); + }) + + it('TestGetFlutterAbilityAndEntryDelegate', 0, async (done: Function) => { + const flutterAbility: FlutterAbility = new FlutterAbility(); + const result = flutterAbility.getFlutterAbilityAndEntryDelegate(); + expect(result).assertNull(); + done(); + }) + + it('TestShouldDispatchAppLifecycleState', 0, async (done: Function) => { + const flutterAbility: FlutterAbility = new FlutterAbility(); + const result = flutterAbility.shouldDispatchAppLifecycleState(); + expect(result).assertTrue(); + done(); + }) + + it('TestProvideFlutterEngine', 0, async (done: Function) => { + const flutterAbility: FlutterAbility = new FlutterAbility(); + const result = flutterAbility.provideFlutterEngine(getContext()); + expect(result).assertNull(); + done(); + }) + + it('TestProvidePlatformPlugin', 0, async (done: Function) => { + const flutterAbility: FlutterAbility = new FlutterAbility(); + const flutterEngine = new FlutterEngine(getContext(), null, null, null); + const result = flutterAbility.providePlatformPlugin(flutterEngine); + expect(result).not().assertNull(); + done(); + }) + + it('TestPopSystemNavigator', 0, async (done: Function) => { + const flutterAbility: FlutterAbility = new FlutterAbility(); + const result = flutterAbility.popSystemNavigator(); + expect(result).assertFalse(); + done(); + }) + + it('TestShouldAttachEngineToAbility', 0, async (done: Function) => { + const flutterAbility: FlutterAbility = new FlutterAbility(); + const result = flutterAbility.shouldAttachEngineToAbility(); + expect(result).assertTrue(); + done(); + }) + + it('TestGetDartEntrypointLibraryUri', 0, async (done: Function) => { + const flutterAbility: FlutterAbility = new FlutterAbility(); + const result = flutterAbility.getDartEntrypointLibraryUri(); + expect(result).assertEqual(""); + done(); + }) + + it('TestGetAppBundlePath', 0, async (done: Function) => { + const flutterAbility: FlutterAbility = new FlutterAbility(); + const result = flutterAbility.getAppBundlePath(); + expect(result).assertEqual(""); + done(); + }) + + it('TestAttachToEngineAutomatically', 0, async (done: Function) => { + const flutterAbility: FlutterAbility = new FlutterAbility(); + const result = flutterAbility.attachToEngineAutomatically(); + expect(result).assertTrue(); + done(); + }) + + it('TestGetExclusiveAppComponent', 0, async (done: Function) => { + const flutterAbility: FlutterAbility = new FlutterAbility(); + const result = flutterAbility.getExclusiveAppComponent(); + expect(result).assertNull(); + done(); + }) + + it('TestGetFlutterEngine', 0, async (done: Function) => { + const flutterAbility: FlutterAbility = new FlutterAbility(); + const result = flutterAbility.getFlutterEngine(); + expect(result).assertNull(); + done(); + }) + }) + +} + +class TestFlutterPlugin implements FlutterPlugin { + getUniqueClassName(): string { + return "engine test"; + } + + onAttachedToEngine(binding: FlutterPluginBinding): void { + console.info("uitest: onAttachedToEngine"); + } + + onDetachedFromEngine(binding: FlutterPluginBinding): void { + console.info("uitest: onAttachedToEngine"); + } +} + +let plugin: FlutterPlugin = new TestFlutterPlugin(); diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/ohos/FlutterEntryTest.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/ohos/FlutterEntryTest.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..5d9ba80399bee3221d96352e3a837e7dbace6bcd --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/ohos/FlutterEntryTest.test.ets @@ -0,0 +1,181 @@ +/* + * 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. + */ +import { describe, it, expect } from '@ohos/hypium'; +import { FlutterEngine, FlutterPlugin, FlutterEntry } from "@ohos/flutter_ohos"; +import { FlutterPluginBinding } from '@ohos/flutter_ohos/src/main/ets/embedding/engine/plugins/FlutterPlugin'; + +function sleep(time: number) { + return new Promise((resolve: Function) => setTimeout(resolve, time)); +} + +export default function FlutterEntryTest() { + describe('FlutterEntryTest', () => { + + it('TestGetFlutterView', 0, async (done: Function) => { + const flutterEntry: FlutterEntry = new FlutterEntry(getContext()); + const result = flutterEntry.getFlutterView(); + expect(result).assertNull(); + done(); + }) + + it('TestGetFlutterEngine', 0, async (done: Function) => { + const flutterEntry: FlutterEntry = new FlutterEntry(getContext()); + const result = flutterEntry.getFlutterEngine(); + expect(result).not().assertNull(); + done(); + }) + + it('TestShouldDispatchAppLifecycleState', 0, async (done: Function) => { + const flutterEntry: FlutterEntry = new FlutterEntry(getContext()); + const result = flutterEntry.shouldDispatchAppLifecycleState(); + expect(result).assertTrue(); + done(); + }) + + it('TestProvideFlutterEngine', 0, async (done: Function) => { + const flutterEntry: FlutterEntry = new FlutterEntry(getContext()); + const result = flutterEntry.provideFlutterEngine(getContext()); + expect(result).assertNull(); + done(); + }) + + it('TestProvidePlatformPlugin', 0, async (done: Function) => { + const flutterEntry: FlutterEntry = new FlutterEntry(getContext()); + const flutterEngine = new FlutterEngine(getContext(), null, null, null); + const result = flutterEntry.providePlatformPlugin(flutterEngine); + expect(result).not().assertNull(); + done(); + }) + + it('TestGetFlutterShellArgs', 0, async (done: Function) => { + const flutterEntry: FlutterEntry = new FlutterEntry(getContext()); + const result = flutterEntry.getFlutterShellArgs(); + expect(result).not().assertNull(); + done(); + }) + + it('TestGetDartEntrypointArgs', 0, async (done: Function) => { + const flutterEntry: FlutterEntry = new FlutterEntry(getContext()); + const result = flutterEntry.getDartEntrypointArgs(); + expect(result).not().assertNull(); + done(); + }) + + it('TestPopSystemNavigator', 0, async (done: Function) => { + const flutterEntry: FlutterEntry = new FlutterEntry(getContext()); + const result = flutterEntry.popSystemNavigator(); + expect(result).assertFalse(); + done(); + }) + + it('TestShouldAttachEngineToAbility', 0, async (done: Function) => { + const flutterEntry: FlutterEntry = new FlutterEntry(getContext()); + const result = flutterEntry.shouldAttachEngineToAbility(); + expect(result).assertUndefined(); + done(); + }) + + it('TestGetDartEntrypointLibraryUri', 0, async (done: Function) => { + const flutterEntry: FlutterEntry = new FlutterEntry(getContext()); + const result = flutterEntry.getDartEntrypointLibraryUri(); + expect(result).assertEqual(""); + done(); + }) + + it('TestGetAppBundlePath', 0, async (done: Function) => { + const flutterEntry: FlutterEntry = new FlutterEntry(getContext()); + const result = flutterEntry.getAppBundlePath(); + expect(result).assertEqual(""); + done(); + }) + + it('TestGetDartEntrypointFunctionName', 0, async (done: Function) => { + const flutterEntry: FlutterEntry = new FlutterEntry(getContext()); + const result = flutterEntry.getDartEntrypointFunctionName(); + expect(result).not().assertNull(); + done(); + }) + + it('TestGetInitialRoute', 0, async (done: Function) => { + const flutterEntry: FlutterEntry = new FlutterEntry(getContext()); + const result = flutterEntry.getInitialRoute(); + expect(result).not().assertNull(); + done(); + }) + + it('TestAttachToEngineAutomatically', 0, async (done: Function) => { + const flutterEntry: FlutterEntry = new FlutterEntry(getContext()); + const result = flutterEntry.attachToEngineAutomatically(); + expect(result).assertTrue(); + done(); + }) + + it('TestShouldRestoreAndSaveState', 0, async (done: Function) => { + const flutterEntry: FlutterEntry = new FlutterEntry(getContext()); + const result = flutterEntry.shouldRestoreAndSaveState(); + expect(result).not().assertNull(); + done(); + }) + + it('TestGetExclusiveAppComponent', 0, async (done: Function) => { + const flutterEntry: FlutterEntry = new FlutterEntry(getContext()); + const result = flutterEntry.getExclusiveAppComponent(); + expect(result).assertNull(); + done(); + }) + + it('TestGetCachedEngineId', 0, async (done: Function) => { + const flutterEntry: FlutterEntry = new FlutterEntry(getContext()); + const result = flutterEntry.getCachedEngineId(); + expect(result).assertUndefined(); + done(); + }) + + it('TestGetCachedEngineGroupId', 0, async (done: Function) => { + const flutterEntry: FlutterEntry = new FlutterEntry(getContext()); + const result = flutterEntry.getCachedEngineGroupId(); + expect(result).assertUndefined(); + done(); + }) + + it('TestAddPlugin', 0, async (done: Function) => { + const flutterEntry: FlutterEntry = new FlutterEntry(getContext()); + flutterEntry.addPlugin(plugin); + done(); + }) + + it('TestRemovePlugin', 0, async (done: Function) => { + const flutterEntry: FlutterEntry = new FlutterEntry(getContext()); + flutterEntry.removePlugin(plugin); + done(); + }) + }) +} + +class TestFlutterPlugin implements FlutterPlugin { + getUniqueClassName(): string { + return "engine test"; + } + + onAttachedToEngine(binding: FlutterPluginBinding): void { + console.info("uitest: onAttachedToEngine"); + } + + onDetachedFromEngine(binding: FlutterPluginBinding): void { + console.info("uitest: onAttachedToEngine"); + } +} + +let plugin: FlutterPlugin = new TestFlutterPlugin(); diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/ohos/FlutterManagerTest.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/ohos/FlutterManagerTest.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..3740524e877cbe889f73c3ee07783605ca8bbaf9 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/ohos/FlutterManagerTest.test.ets @@ -0,0 +1,79 @@ +/* + * 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. + */ +import { describe, it, expect, beforeAll } from '@ohos/hypium'; +import { FlutterManager } from "@ohos/flutter_ohos"; +import { window } from '@kit.ArkUI'; +import { FullScreenListener } from '@ohos/flutter_ohos/src/main/ets/embedding/ohos/FlutterManager'; + +function sleep(time: number) { + return new Promise((resolve: Function) => setTimeout(resolve, time)); +} + +const flutterManager: FlutterManager = FlutterManager.getInstance(); +const uiAbility = flutterManager.getUIAbility(getContext()); + +export default function FlutterManagerTest() { + describe('FlutterManagerTest', () => { + beforeAll(async () => { + const windowStage = flutterManager.getWindowStage(uiAbility); + await sleep(1000); + flutterManager.pushWindowStage(uiAbility, windowStage); + await sleep(1000); + flutterManager.popWindowStage(uiAbility); + await sleep(1000); + flutterManager.pushUIAbility(uiAbility); + await sleep(1000); + flutterManager.popUIAbility(uiAbility); + + }) + + it('TestGetFlutterViewList', 0, async (done: Function) => { + const result = flutterManager.getFlutterViewList(); + expect(result).not().assertNull(); + done(); + }) + + it('TestSetFullScreenListener', 0, async (done: Function) => { + class MyFullScreenListener implements FullScreenListener { + useFullScreen(): boolean { + return true; + } + + setUseFullScreen(useFullScreen: boolean): void { + console.info("uitest: setUseFullScreen useFullScreen " + useFullScreen); + } + + onScreenStateChanged(data: window.WindowStatusType): void { + console.info("uitest: onScreenStateChanged"); + } + } + + const listener: FullScreenListener = new MyFullScreenListener(); + flutterManager.setFullScreenListener(listener); + await sleep(1000); + const result = flutterManager.getFullScreenListener(); + expect(result).not().assertNull(); + done(); + }) + + it('TestFullScreen', 0, async (done: Function) => { + const result = flutterManager.useFullScreen(); + expect(result).assertTrue(); + flutterManager.setUseFullScreen(result); + flutterManager.clear(); + done(); + }) + }) +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/ohos/SettingTest.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/ohos/SettingTest.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..d9a0489034f3d8134bfa5f65309f0b3532385f0d --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/ohos/SettingTest.test.ets @@ -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. + */ +import { describe, it, expect } from '@ohos/hypium'; +import { Settings } from "@ohos/flutter_ohos"; +import { MediaQuery } from '@kit.ArkUI'; +import { PlatformBrightness } from '@ohos/flutter_ohos/src/main/ets/embedding/engine/systemchannels/SettingsChannel'; + +const settings: Settings = new Settings(null); + +export default function SettingTest() { + describe('SettingTest', () => { + it('TestGetTextScaleFactor', 0, async (done: Function) => { + const result: number = settings.getTextScaleFactor(); + expect(result).not().assertNull(); + done(); + }) + + it('TestGetThemeMode', 0, async (done: Function) => { + const mediaQuery: MediaQuery = new MediaQuery(); + settings.sendSettings(mediaQuery); + const result: PlatformBrightness = settings.getThemeMode(mediaQuery); + expect(result).not().assertNull(); + done(); + }) + }) +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/ohos/TouchEventProcessorTest.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/ohos/TouchEventProcessorTest.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..dc72a1450d2c27e4f03ed6d48e08d6eb0c04af15 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/ohos/TouchEventProcessorTest.test.ets @@ -0,0 +1,41 @@ +/* + * 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. + */ +import { describe, it, expect } from '@ohos/hypium'; +import TouchEventProcessor from '@ohos/flutter_ohos/src/main/ets/embedding/ohos/TouchEventProcessor'; +import { CustomTouchEvent } from '@ohos/flutter_ohos/src/main/ets/plugin/platform/CustomTouchEvent'; + +export default function TouchEventProcessorTest() { + const touchEventProcessor: TouchEventProcessor = new TouchEventProcessor(); + + describe('TouchEventProcessorTest', () => { + + it('getInstance', 0, async (done: Function) => { + console.info("uitest: getInstance begin"); + const getInstance: TouchEventProcessor = TouchEventProcessor.getInstance(); + expect(getInstance).not().assertNull(); + done(); + }) + + it('decodeTouchPacket', 0, async (done: Function) => { + console.info("uitest: decodeTouchPacket begin"); + const strings = ['test1', 'test2', 'test3']; + const top = 10; + const left = 10; + const decodeTouchPacket: CustomTouchEvent = touchEventProcessor.constureCustomTouchEvent(strings, top, left); + expect(decodeTouchPacket).not().assertNull(); + done(); + }) + }) +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/ohos/TouchEventTrackerTest.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/ohos/TouchEventTrackerTest.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..fc93b33e7bf0e95e7b8efab23c6a36d504c92a02 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/ohos/TouchEventTrackerTest.test.ets @@ -0,0 +1,51 @@ +/* + * 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. + */ +import { describe, it, expect } from '@ohos/hypium'; +import { TouchEventId, TouchEventTracker } from '@ohos/flutter_ohos/src/main/ets/embedding/ohos/TouchEventTracker'; +import { TouchEvent } from '@ohos.multimodalInput.touchEvent'; + +export default function TouchEventTrackerTest() { + const touchEventTracker: TouchEventTracker = new TouchEventTracker(); + + describe('TouchEventTrackerTest', () => { + + it('getInstance', 0, async (done: Function) => { + console.info("uitest: getInstance begin"); + const getInstance: TouchEventTracker = TouchEventTracker.getInstance(); + expect(getInstance).not().assertNull(); + done(); + }) + + it('track', 0, async (done: Function) => { + console.info("uitest: decodeTouchPacket begin"); + const event: TouchEvent | null = null; + if(event) { + const decodeTouchPacket: TouchEventId = touchEventTracker.track(event); + expect(decodeTouchPacket).not().assertNull(); + } + done(); + }) + + it('pop', 0, async (done: Function) => { + console.info("uitest: pop begin"); + const eventId: TouchEventId | null = null; + if(eventId) { + const tuchEvent: TouchEvent = touchEventTracker.pop(eventId); + expect(tuchEvent).not().assertNull(); + } + done(); + }) + }) +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/ohos/WindowInfoRepositoryCallbackAdapterWrapperTest.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/ohos/WindowInfoRepositoryCallbackAdapterWrapperTest.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..92a803725bdb47d4cd8f18837ca9897e8bfab434 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/embedding/ohos/WindowInfoRepositoryCallbackAdapterWrapperTest.test.ets @@ -0,0 +1,29 @@ +/* + * 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. + */ +import { describe, it, expect } from '@ohos/hypium'; +import WindowInfoRepositoryCallbackAdapterWrapper from '@ohos/flutter_ohos/src/main/ets/embedding/ohos/WindowInfoRepositoryCallbackAdapterWrapper'; + +export default function WindowInfoRepositoryCallbackAdapterWrapperTest() { + + describe('WindowInfoRepositoryCallbackAdapterWrapper', () => { + + it('WindowInfoRepositoryCallbackAdapterWrapper', 0, async (done: Function) => { + console.info("uitest: WindowInfoRepositoryCallbackAdapterWrapper begin"); + const windowInfoRepositoryCallbackAdapterWrapper: WindowInfoRepositoryCallbackAdapterWrapper = new WindowInfoRepositoryCallbackAdapterWrapper(); + expect(windowInfoRepositoryCallbackAdapterWrapper).not().assertNull(); + done(); + }) + }) +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/common/BinaryCodecTest.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/common/BinaryCodecTest.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..cd1f7813dd991c0d0c271cfb08abd7f4208124e5 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/common/BinaryCodecTest.test.ets @@ -0,0 +1,37 @@ +/* + * 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. + */ +import { describe, it, expect } from '@ohos/hypium'; +import { BinaryCodec } from "@ohos/flutter_ohos"; +import { buffer } from '@kit.ArkTS'; + +const binaryCodec: BinaryCodec = new BinaryCodec(true); + +export default function BinaryCodecTest() { + describe('BinaryCodecTest', () => { + it('TestBinaryCodecEncodeMessageSend', 0, async (done: Function) => { + let blobValue: buffer.Blob = new buffer.Blob(['name', 'age', 'sex']); + let message: ArrayBuffer = await blobValue.arrayBuffer(); + const result: ArrayBuffer = binaryCodec.encodeMessage(message); + expect(result).not().assertNull(); + done(); + }) + + it('TestBinaryCodecDecodeMessage', 0, async (done: Function) => { + const result = binaryCodec.decodeMessage(null); + expect(result).not().assertNull(); + done(); + }) + }) +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/common/BinaryMessengerTest.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/common/BinaryMessengerTest.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..b746c7968235d512006395e13bc835e68f500904 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/common/BinaryMessengerTest.test.ets @@ -0,0 +1,51 @@ +/* + * 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. + */ +import { describe, expect, it } from '@ohos/hypium'; +import { + BinaryMessageHandler, + BinaryMessenger, + BinaryReply, + TaskQueue, + TaskQueueOptions +} from '@ohos/flutter_ohos/src/main/ets/plugin/common/BinaryMessenger'; + +export default function BinaryMessengerTest() { + let binaryMessenger: CurBinaryMessenger = new CurBinaryMessenger(); + + describe('BinaryMessengerTest', () => { + + it('makeBackgroundTaskQueue', 0, async (done: Function) => { + console.info("uitest: makeBackgroundTaskQueue begin"); + const options = new TaskQueueOptions(); + const taskQueue: TaskQueue = binaryMessenger.makeBackgroundTaskQueue(options); + expect(taskQueue).not().assertNull(); + done(); + }) + }) +} + +class CurBinaryMessenger implements BinaryMessenger { + makeBackgroundTaskQueue(options?: TaskQueueOptions | undefined): TaskQueue { + return {}; + } + + send(channel: String, message: ArrayBuffer, callback?: BinaryReply | null | undefined) { + + } + + setMessageHandler(channel: String, handler: BinaryMessageHandler | BinaryMessageHandler | null, taskQueue?: TaskQueue, + ...args: Object[]) { + } +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/common/FlutterException.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/common/FlutterException.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..fbdeee4dbff3e606214ea352bc00a90e348587f2 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/common/FlutterException.test.ets @@ -0,0 +1,58 @@ +/* + * 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. + */ +import { describe, it, expect } from '@ohos/hypium'; +import FlutterException from '@ohos/flutter_ohos/src/main/ets/plugin/common/FlutterException'; + +interface keyValue { + key: string; +} + +interface anotherKey { + anotherKey: string; +} + +interface defaultKey { + defaultKey: string; +} + +export default function FlutterExceptionTest() { + describe('FlutterExceptionTest', () => { + it('should initialize with correct values', 0, () => { + const code = 'ERROR_CODE_123'; + const message = 'This is an error message'; + const details:keyValue = { key: 'value' }; + const exception = new FlutterException(code, message, details); + expect(exception.message).assertEqual(message); + expect(exception.code).assertEqual(code); + expect(exception.name).assertEqual(''); + }) + it('should have a stack property if provided', 0, () => { + const code = 'ERROR_CODE_456'; + const message = 'Another error message'; + const details: anotherKey = { anotherKey: 'anotherValue' }; + const stack = 'Error stack trace'; + const exception = new FlutterException(code, message, details); + exception.stack = stack; + expect(exception.stack).assertEqual(stack); + }) + it('should default name to an empty string if not provided', 0, () => { + const code = 'ERROR_CODE_789'; + const message = 'Default name test'; + const details: defaultKey = { defaultKey: 'defaultValue' }; + const exception = new FlutterException(code, message, details); + expect(exception.name).assertEqual(''); + }) + }) +} diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/common/JSONMessageCodec.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/common/JSONMessageCodec.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..72e75a218edd09f4eb51904755eabd34cc45568a --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/common/JSONMessageCodec.test.ets @@ -0,0 +1,29 @@ +/* + * 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. + */ +import { describe, it, expect } from '@ohos/hypium' +import JSONMessageCodec from '@ohos/flutter_ohos/src/main/ets/plugin/common/JSONMessageCodec'; +import StringUtils from '@ohos/flutter_ohos/src/main/ets/util/StringUtils'; + +export default function JSONMessageCodecTest() { + describe('JSONMessageCodecTest', () => { + const codec = JSONMessageCodec.INSTANCE; + it('should encode and decode a null message', 0, () => { + const originalMessage = null; + const encodedMessage = codec.encodeMessage(originalMessage); + const decodedMessage = StringUtils.arrayBufferToString(encodedMessage); + expect(decodedMessage).assertEqual(""); + }) + }) +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/common/JSONMethodCodec.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/common/JSONMethodCodec.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..9e4a471e515ac93b7b676c01cec9693a4601fa4a --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/common/JSONMethodCodec.test.ets @@ -0,0 +1,57 @@ +/* + * 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. + */ +import { Any, JSONMethodCodec, MethodCall } from "@ohos/flutter_ohos"; +import { describe, expect, it, MockKit, when } from "@ohos/hypium"; + +export default function JSONMethodCodecUnitTest() { + describe('JSONMethodCodec', () => { + it("JSONMethodCodec_encodeMethodCall", 0, encodeMethodCall); + + it("JSONMethodCodec_encodeSuccessEnvelope", 0, encodeSuccessEnvelope); + + it("JSONMethodCodec_decodeEnvelope", 0, decodeEnvelope); + + }) +} + +function encodeMethodCall() { + let mocker = new MockKit(); + let ob = JSONMethodCodec.INSTANCE; + let mockFunc = mocker.mockFunc(ob, ob.encodeMethodCall); + let params = new MethodCall("key", "value"); + let r = new ArrayBuffer(4096); + when(mockFunc)(params).afterReturn(r); + let result = ob.encodeMethodCall(params); + expect(result).assertEqual(r); +} + +function encodeSuccessEnvelope() { + let mocker = new MockKit(); + let ob = JSONMethodCodec.INSTANCE; + let mockFunc = mocker.mockFunc(ob, ob.encodeSuccessEnvelope); + let r = new ArrayBuffer(4096); + when(mockFunc)(null).afterReturn(r); + expect(ob.encodeSuccessEnvelope(null)).assertEqual(r); +} + +function decodeEnvelope() { + let mocker = new MockKit(); + let ob = JSONMethodCodec.INSTANCE; + let mockFunc = mocker.mockFunc(ob, ob.decodeEnvelope); + let r = new ArrayBuffer(4096); + when(mockFunc)(r).afterReturn("any"); + let result: Any = ob.decodeEnvelope(r); + expect(result).assertEqual("any"); +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/common/MethodCall.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/common/MethodCall.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..0d69393e7d0baa9f828eb648b41e74bf726f1c37 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/common/MethodCall.test.ets @@ -0,0 +1,34 @@ +/* + * 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. + */ +import { MethodCall } from "@ohos/flutter_ohos"; +import { describe, expect, it } from "@ohos/hypium"; + +export default function MethodCallUnitTest() { + describe('MethodCall', () => { + it("MethodCall_argument", 0, argument); + + it("MethodCall_hasArgument", 0, hasArgument); + }) +} + +function argument() { + let ob = new MethodCall("get", null); + expect(ob.argument("key")).assertNull(); +} + +function hasArgument() { + let ob = new MethodCall("get", null); + expect(ob.hasArgument("key")).assertFalse(); +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/common/SendableBinaryCodec.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/common/SendableBinaryCodec.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..f8174e51fb2dcf352b0fa49da12a453a7bf5729f --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/common/SendableBinaryCodec.test.ets @@ -0,0 +1,37 @@ +/* + * 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. + */ + +import { describe, it, expect } from '@ohos/hypium' +import { SendableBinaryCodec } from '@ohos/flutter_ohos'; +import { buffer } from '@kit.ArkTS'; + +export default function SendableBinaryCodecTest() { + describe('SendableBinaryCodecTest', () => { + it('encodeMessage', 0, async (done: Function) => { + let blobValue: buffer.Blob = new buffer.Blob(['name', 'age', 'sex']); + let message: ArrayBuffer = await blobValue.arrayBuffer(); + expect(SendableBinaryCodec.INSTANCE_DIRECT.encodeMessage(message)) + .not() + .assertNull(); + done(); + }) + + it('decodeMessage', 0, () => { + expect(SendableBinaryCodec.INSTANCE_DIRECT.decodeMessage(null)) + .not() + .assertNull(); + }); + }) +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/common/SendableJSONMessageCodec.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/common/SendableJSONMessageCodec.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..4ee7d40da6f3aae759a6e5ca65facc5c00978b81 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/common/SendableJSONMessageCodec.test.ets @@ -0,0 +1,29 @@ +/* + * 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. + */ +import { describe, it, expect } from '@ohos/hypium'; +import SendableJSONMessageCodec from '@ohos/flutter_ohos/src/main/ets/plugin/common/SendableJSONMessageCodec'; +import StringUtils from '@ohos/flutter_ohos/src/main/ets/util/StringUtils' + +export default function SendableJSONMessageCodecTest() { + describe('SendableJSONMessageCodecTest', () => { + const codec = SendableJSONMessageCodec.INSTANCE; + it('encodeMessage and decodeMessage with a null message', 0, () => { + const originalMessage = null; + const encodedMessage = codec.encodeMessage(originalMessage); + const decodedMessage = StringUtils.arrayBufferToString(encodedMessage); + expect(decodedMessage).assertEqual(""); + }) + }) +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/common/SendableJSONMethodCodec.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/common/SendableJSONMethodCodec.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..225ab226f07e4cd02cd9fbe942f2cb24f4960c48 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/common/SendableJSONMethodCodec.test.ets @@ -0,0 +1,41 @@ +/* + * 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. + */ +import { describe, it, expect } from '@ohos/hypium'; +import SendableJSONMethodCodec from '@ohos/flutter_ohos/src/main/ets/plugin/common/SendableJSONMethodCodec'; + +export default function SendableJSONMethodCodecTest() { + describe('SendableJSONMethodCodecTest', () => { + const codec = SendableJSONMethodCodec.INSTANCE; + it('throws an error for invalid JSON', 0, () => { + const invalidJSON = new ArrayBuffer(1); + + try { + codec.decodeMethodCall(invalidJSON); + //fail('Expected an error to be thrown'); + throw new Error('Expected an error to be thrown'); + } catch (e) { + expect(e.message).assertContain('Invalid JSON') + } + + try { + codec.decodeEnvelope(invalidJSON); + //fail('Expected an error to be thrown'); + throw new Error('Expected an error to be thrown'); + } catch (e) { + expect(e.message).assertContain('Invalid JSON') + } + }) + }) +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/common/SendableStandardMessageCodec.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/common/SendableStandardMessageCodec.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..b86d5cfe1cb0f46cea0563213c5d640c485d8f0d --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/common/SendableStandardMessageCodec.test.ets @@ -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. + */ +import { describe, it, expect } from '@ohos/hypium' +import Any from '@ohos/flutter_ohos/src/main/ets/plugin/common/Any'; +import SendableStandardMessageCodec from '@ohos/flutter_ohos/src/main/ets/plugin/common/SendableStandardMessageCodec'; + +export default function SendableStandardMessageCodecTest() { + describe('SendableStandardMessageCodecTest', () => { + const codec = SendableStandardMessageCodec.INSTANCE; + + it('testEncodeDecodeNull', 0, () => { + const encoded = codec.encodeMessage(null); + const decoded:Any = codec.decodeMessage(encoded); + expect(decoded).assertNull(); + }) + + it('testEncodeDecodeBoolean', 0, () => { + const encodedTrue = codec.encodeMessage(true); + const decodedTrue:Any = codec.decodeMessage(encodedTrue); + expect(decodedTrue).assertTrue(); + + const encodedFalse = codec.encodeMessage(false); + const decodedFalse:Any = codec.decodeMessage(encodedFalse); + expect(decodedFalse).assertFalse(); + }) + + it('testEncodeDecodeNumber', 0, () => { + const int32Value = 123456; + const encodedInt32 = codec.encodeMessage(int32Value); + const decodedInt32:Any = codec.decodeMessage(encodedInt32); + expect(decodedInt32).assertEqual(int32Value); + + const int64Value = BigInt(9007199254740991); // Max safe integer + const encodedInt64 = codec.encodeMessage(int64Value); + const decodedInt64:Any = codec.decodeMessage(encodedInt64); + expect(decodedInt64).assertEqual(int64Value); + + const float64Value = 3.14159; + const encodedFloat64 = codec.encodeMessage(float64Value); + const decodedFloat64:Any = codec.decodeMessage(encodedFloat64); + expect(decodedFloat64).assertClose(float64Value, 5); + + }) + + it('testEncodeDecodeUint8Array', 0, () => { + const uint8Array = new Uint8Array([1, 2, 3, 4, 5]); + const encodedArray = codec.encodeMessage(uint8Array); + const decodedArray:Any = codec.decodeMessage(encodedArray); + expect(decodedArray).assertDeepEquals(uint8Array); + }) + + it('testEncodeDecodeInt32Array', 0, () => { + const int32Array = new Int32Array([1, 2, 3, 4, 5]); + const encodedArray = codec.encodeMessage(int32Array); + const decodedArray:Any = codec.decodeMessage(encodedArray); + expect(decodedArray).assertDeepEquals(int32Array); + }) + + it('testEncodeDecodeBigInt64Array', 0, () => { + const bigInt64Array = new BigInt64Array([BigInt(1), BigInt(2), BigInt(3), BigInt(4), BigInt(5)]); + const encodedArray = codec.encodeMessage(bigInt64Array); + const decodedArray:Any = codec.decodeMessage(encodedArray); + expect(decodedArray.length).assertEqual(bigInt64Array.length); + for (let i = 0; i < bigInt64Array.length; i++) { + expect(decodedArray[i]).assertEqual(bigInt64Array[i]); + } + }) + + it('testEncodeDecodeFloat64Array', 0, () => { + const float64Array = new Float64Array([1.1, 2.2, 3.3, 4.4, 5.5]); + const encodedArray = codec.encodeMessage(float64Array); + const decodedArray:Any = codec.decodeMessage(encodedArray); + expect(decodedArray).assertDeepEquals(float64Array); + }) + }) +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/common/SendableStandardMethodCodec.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/common/SendableStandardMethodCodec.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..7257b488ba54ea90442f429e6e53c0411f9686fa --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/common/SendableStandardMethodCodec.test.ets @@ -0,0 +1,35 @@ +/* + * 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. + */ +import { describe, it, expect } from '@ohos/hypium'; +import SendableStandardMethodCodec from '@ohos/flutter_ohos/src/main/ets/plugin/common/SendableStandardMethodCodec'; + +export default function SendableStandardMethodCodecTest() { + describe('SendableStandardMethodCodecTest', () => { + const codec = SendableStandardMethodCodec.INSTANCE; + it('decodeMethodCall_shouldThrowErrorOnCorruptedMethodCall', 0, () => { + const corruptedBuffer = new ArrayBuffer(2); + const bufferView = new Uint8Array(corruptedBuffer); + bufferView[0] = 0; + bufferView[1] = 1; + + try { + codec.decodeMethodCall(corruptedBuffer); + expect(false).assertEqual(true); + } catch (e) { + expect(e.message).assertEqual('Method call corrupted'); + } + }) + }) +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/common/SendableStringCodec.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/common/SendableStringCodec.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..7a5d4a3b8b0fbeab9018b13e4d91b0b02b7e663a --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/common/SendableStringCodec.test.ets @@ -0,0 +1,43 @@ +/* + * 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. + */ +import { describe, it, expect } from '@ohos/hypium' +import StringCodec from '@ohos/flutter_ohos/src/main/ets/plugin/common/SendableStringCodec' +import StringUtils from '@ohos/flutter_ohos/src/main/ets/util/StringUtils' + +export default function SendableStringCodecTest() { + describe('SendableStringCodecTest', () => { + const codec = StringCodec.INSTANCE; + it('encodeMessage_emptyString_ReturnEmptyString', 0, () => { + const testString = ""; + const encodedMessage = codec.encodeMessage(testString); + const decodedString = StringUtils.arrayBufferToString(encodedMessage); + expect(decodedString).assertEqual(testString); + }) + it('encodeMessage_null_ReturnEmptyString', 0, () => { + const encodedMessage = codec.encodeMessage(""); + const decodedString = StringUtils.arrayBufferToString(encodedMessage); + expect(decodedString).assertEqual(""); + }) + it('decodeMessage_emptyString_ReturnEmptyString', 0, () => { + const encodedMessage = new ArrayBuffer(0); + const decodedString = codec.decodeMessage(encodedMessage); + expect(decodedString).assertEqual(""); + }) + it('decodeMessage_null_ReturnEmptyString', 0, () => { + const decodedString = codec.decodeMessage(null); + expect(decodedString).assertEqual(""); + }) + }) +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/common/StandardMessageCodec.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/common/StandardMessageCodec.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..21ce334f7975ae9195e540c7f9e7af5b1d22d073 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/common/StandardMessageCodec.test.ets @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { describe, it, expect } from '@ohos/hypium' +import Any from '@ohos/flutter_ohos/src/main/ets/plugin/common/Any'; +import StandardMessageCodec from '@ohos/flutter_ohos/src/main/ets/plugin/common/StandardMessageCodec'; + +export default function StandardMessageCodecTest() { + describe('StandardMessageCodecTest', () => { + const codec = StandardMessageCodec.INSTANCE; + it('should encode and decode null', 0, () => { + const encoded = codec.encodeMessage(null); + const decoded:Any = codec.decodeMessage(encoded); + expect(decoded).assertNull(); + }) + it('should encode and decode boolean', 0, () => { + const encodedTrue = codec.encodeMessage(true); + const decodedTrue:Any = codec.decodeMessage(encodedTrue); + expect(decodedTrue).assertTrue(); + + const encodedFalse = codec.encodeMessage(false); + const decodedFalse:Any = codec.decodeMessage(encodedFalse); + expect(decodedFalse).assertFalse(); + }) + it('should encode and decode number (int32)', 0, () => { + const number = 123456; + const encoded = codec.encodeMessage(number); + const decoded:Any = codec.decodeMessage(encoded); + expect(decoded).assertEqual(number); + }) + it('should encode and decode number (int64)', 0, () => { + const number = BigInt(1234567890123456789); + const encoded = codec.encodeMessage(number); + const decoded:Any = codec.decodeMessage(encoded); + expect(decoded).assertEqual(number); + }) + it('should encode and decode number (float64)', 0, ()=> { + const number = 3.14159;; + const encoded = codec.encodeMessage(number); + const decoded:Any = codec.decodeMessage(encoded); + expect(decoded).assertClose(number,5) + }) + it('should encode and decode Uint8Array', 0, () => { + const array = new Uint8Array([1, 2, 3, 4, 5]); + const encoded = codec.encodeMessage(array); + const decoded:Any = codec.decodeMessage(encoded); + expect(decoded).assertDeepEquals(array); + }) + it('should encode and decode Int32Array', 0, () => { + const array = new Int32Array([1, 2, 3, 4, 5]); + const encoded = codec.encodeMessage(array); + const decoded:Any = codec.decodeMessage(encoded); + expect(decoded).assertDeepEquals(array); + }) + it('should encode and decode BigInt64Array', 0, () => { + const array = new BigInt64Array([BigInt(1), BigInt(2), BigInt(3), BigInt(4), BigInt(5)]); + const encoded = codec.encodeMessage(array); + const decoded:Any = codec.decodeMessage(encoded); + expect(decoded.length).assertEqual(array.length); + for (let i = 0; i < array.length; i++) { + expect(decoded[i]).assertEqual(array[i]); + } + }) + it('should encode and decode Float32Array', 0, () => { + const array = new Float32Array([1.1, 2.2, 3.3, 4.4, 5.5]); + const encoded = codec.encodeMessage(array); + const decoded:Any = codec.decodeMessage(encoded); + for (let i = 0; i < array.length; i++) { + expect(decoded[i]).assertEqual(array[i]); + } + }) + it('should encode and decode Float64Array', 0, () => { + const array = new Float64Array([1.1, 2.2, 3.3, 4.4, 5.5]); + const encoded = codec.encodeMessage(array); + const decoded:Any = codec.decodeMessage(encoded); + for (let i = 0; i < array.length; i++) { + expect(decoded[i]).assertEqual(array[i]); + } + }) + }) +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/common/StandardMethodCodec.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/common/StandardMethodCodec.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..034ddafc1f3f800251b42ba84e4fcd11d6b447da --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/common/StandardMethodCodec.test.ets @@ -0,0 +1,32 @@ +/* + * 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. + */ +import { describe, it, expect } from '@ohos/hypium' +import StandardMethodCodec from '@ohos/flutter_ohos/src/main/ets/plugin/common/StandardMethodCodec'; + +export default function StandardMethodCodecTest() { + describe('StandardMethodCodecTest', () => { + const codec = StandardMethodCodec.INSTANCE; + it('should throw an error for a corrupted method call', 0, () => { + const corruptedMethodCall = new ArrayBuffer(2); // Just an invalid ArrayBuffer + try { + codec.decodeMethodCall(corruptedMethodCall); + //fail('Expected an error to be thrown'); + throw new Error('Expected an error to be thrown'); + } catch (e) { + expect(e.message).assertEqual('Method call corrupted'); + } + }); + }) +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/common/StringCodec.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/common/StringCodec.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..74780cd0851e1b109553120ece81627956e79f70 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/common/StringCodec.test.ets @@ -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. + */ +import { describe, it, expect } from '@ohos/hypium' +import StringCodec from '@ohos/flutter_ohos/src/main/ets/plugin/common/StringCodec' +import StringUtils from '@ohos/flutter_ohos/src/main/ets/util/StringUtils' + +export default function StringCodecTest() { + describe('StringCodecTest', () => { + const codec = StringCodec.INSTANCE; + it('encodeMessage_emptyString_ReturnEmptyString', 0, () => { + const testString = ""; + const encodedMessage = codec.encodeMessage(testString); + const decodedString = StringUtils.arrayBufferToString(encodedMessage); + expect(decodedString).assertEqual(testString); + }) + it('decodeMessage_emptyString_ReturnEmptyString', 0, () => { + const encodedMessage = new ArrayBuffer(0); + const decodedString = codec.decodeMessage(encodedMessage); + expect(decodedString).assertEqual(""); + }) + it('decodeMessage_null_ReturnEmptyString', 0, () => { + const decodedString = codec.decodeMessage(null); + expect(decodedString).assertEqual(""); + }) + }) +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/editing/ListenableEditingState.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/editing/ListenableEditingState.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..1c6f9e070af6e0a4c66e92dc288f8fc089b366f8 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/editing/ListenableEditingState.test.ets @@ -0,0 +1,48 @@ +/* + * 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. + */ +import { describe, it, expect } from '@ohos/hypium'; +import { EditingStateWatcher, ListenableEditingState } from '@ohos/flutter_ohos/src/main/ets/plugin/editing/ListenableEditingState'; + +export default function ListenableEditingStateTest() { + describe('ListenableEditingStateTest', () => { + let editingState: ListenableEditingState = new ListenableEditingState(null, 0); + it('should initialize with default values', 0, () => { + expect(editingState.getSelectionStart()).assertEqual(0); + expect(editingState.getSelectionEnd()).assertEqual(0); + expect(editingState.getComposingStart()).assertEqual(-1); + expect(editingState.getComposingEnd()).assertEqual(-1); + expect(editingState.getStringCache()).assertEqual(''); + }) + it('should handle insert text event correctly', 0, () => { + editingState.handleInsertTextEvent('hello'); + expect(editingState.getStringCache()).assertEqual('hello'); + expect(editingState.getSelectionStart()).assertEqual(5); + expect(editingState.getSelectionEnd()).assertEqual(5); + }) + + it('should handle delete event correctly (right)', 0, () => { + editingState.handleDeleteEvent(true, 1); + expect(editingState.getStringCache()).assertEqual('hello'); + expect(editingState.getSelectionStart()).assertEqual(5); + expect(editingState.getSelectionEnd()).assertEqual(5); + }) + it('should handle newline event correctly', 0, () => { + editingState.handleNewlineEvent(); + expect(editingState.getStringCache()).assertEqual('hello\n'); + expect(editingState.getSelectionStart()).assertEqual(6); + expect(editingState.getSelectionEnd()).assertEqual(6); + }) + }) +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/editing/TextEditingDelta.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/editing/TextEditingDelta.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..418797d0ea4efb4fe12770948cdb5ccd118e9651 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/editing/TextEditingDelta.test.ets @@ -0,0 +1,33 @@ +/* + * 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. + */ +import { describe, it, expect } from '@ohos/hypium'; +import { TextEditingDelta } from '@ohos/flutter_ohos/src/main/ets/plugin/editing/TextEditingDelta'; + +export default function TextEditingDeltaTest() { + describe('TextEditingDeltaTest', () => { + it('testToJSON', 0, () => { + const delta = new TextEditingDelta("Old Text", 0, 0, 0, 0, 2, 5, "Delta Text"); + const json = delta.toJSON(); + expect(json.oldText).assertEqual("Old Text"); + expect(json.deltaText).assertEqual("Delta Text"); + expect(json.deltaStart).assertEqual(2); + expect(json.deltaEnd).assertEqual(5); + expect(json.selectionBase).assertEqual(0); + expect(json.selectionExtent).assertEqual(0); + expect(json.composingBase).assertEqual(0); + expect(json.composingExtent).assertEqual(0); + }) + }) +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/editing/TextInputPlugin.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/editing/TextInputPlugin.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..eb05ddadc5a08f19b518bd91805226cf86b9fe9f --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/editing/TextInputPlugin.test.ets @@ -0,0 +1,46 @@ +/* + * 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. + */ +import { describe, beforeEach, it, expect } from '@ohos/hypium' +import TextInputChannel from '@ohos/flutter_ohos/src/main/ets/embedding/engine/systemchannels/TextInputChannel'; +import TextInputPlugin from '@ohos/flutter_ohos/src/main/ets/plugin/editing/TextInputPlugin'; +import TextInputMethodHandlerImpl from '@ohos/flutter_ohos/src/main/ets/plugin/editing/TextInputPlugin'; +import common from '@ohos.app.ability.common'; +import DartExecutor from '@ohos/flutter_ohos/src/main/ets/embedding/engine/dart/DartExecutor'; +import FlutterInjector from '@ohos/flutter_ohos/src/main/ets/FlutterInjector'; + +export default function TextInputPluginTest() { + describe('TextInputPluginTest', () => { + let textInputPlugin: TextInputPlugin; + let textInputChannelMock: TextInputChannel; + let textInputMethodHandlerImpl: TextInputMethodHandlerImpl; + let dartExecutor: DartExecutor; + beforeEach(() => { + let context: common.Context = getContext(); + const assetManager = context.resourceManager; + const flutterNapi = FlutterInjector.getInstance().getFlutterNapi(); + dartExecutor = new DartExecutor(flutterNapi, assetManager); + textInputChannelMock = new TextInputChannel(dartExecutor); + textInputPlugin = new TextInputPlugin(textInputChannelMock); + textInputMethodHandlerImpl = new TextInputMethodHandlerImpl(textInputChannelMock); + }) + it('should initialize correctly', 0, ()=> { + expect(textInputMethodHandlerImpl).not().assertNull(); + }) + it('Test clearTextInputClient', 0, () => { + textInputPlugin.clearTextInputClient(); + expect(textInputPlugin).not().assertNull(); + }) + }) +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/localization/LocalizationPlugin.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/localization/LocalizationPlugin.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..36d725f79f8c1deeaebaaf23c29239aa4dce3d46 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/localization/LocalizationPlugin.test.ets @@ -0,0 +1,55 @@ +/* + * 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. + */ +import { describe, beforeEach, it, expect } from '@ohos/hypium'; +import LocalizationPlugin from '@ohos/flutter_ohos/src/main/ets/plugin/localization/LocalizationPlugin'; +import common from '@ohos.app.ability.common'; +import LocalizationChannel,{LocalizationMessageHandler} from '@ohos/flutter_ohos/src/main/ets/embedding/engine/systemchannels/LocalizationChannel'; +import intl from '@ohos.intl'; +import DartExecutor from '@ohos/flutter_ohos/src/main/ets/embedding/engine/dart/DartExecutor'; +import FlutterInjector from '@ohos/flutter_ohos/src/main/ets/FlutterInjector'; +import Any from '@ohos/flutter_ohos/src/main/ets/plugin/common/Any'; + +export default function LocalizationPluginTest() { + describe('LocalizationPluginTest', () => { + let localizationChannel: LocalizationChannel; + let localizationPlugin: LocalizationPlugin; + let dartExecutor: DartExecutor; + + beforeEach(() => { + let context: common.Context = getContext(); + const assetManager = context.resourceManager; + const flutterNapi = FlutterInjector.getInstance().getFlutterNapi(); + dartExecutor = new DartExecutor(flutterNapi, assetManager); + localizationChannel = new LocalizationChannel(dartExecutor); // 初始化LocalizationChannel + localizationPlugin = new LocalizationPlugin(context, localizationChannel); + }); + it('test_localeFromString', 0, () => { + let localeString = "zh_CN"; + let expectedLocale = new intl.Locale("zh-Hans-CN"); + let actualLocale = localizationPlugin.localeFromString(localeString); + + expect(actualLocale.language).assertEqual(expectedLocale.language); + expect(actualLocale.region).assertEqual(expectedLocale.region); + expect(actualLocale.script).assertEqual(expectedLocale.script); + }) + it('testSendLocaleToFlutter', 0, () => { + let mockSystemLocale = 'zh-Hans-CN'; + (localizationChannel as Any).sendLocales = (locales:Any) => { + expect(locales).assertContain(mockSystemLocale); + }; + localizationPlugin.sendLocaleToFlutter(); + }) + }) +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/platform/AccessibilityEventsDelegate.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/platform/AccessibilityEventsDelegate.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..847ec183b739227893a48feebf2b316331bf4700 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/platform/AccessibilityEventsDelegate.test.ets @@ -0,0 +1,36 @@ +/* + * 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. + */ +import { AccessibilityBridge, AccessibilityEventsDelegate } from "@ohos/flutter_ohos"; +import { describe, expect, it } from "@ohos/hypium"; + +export default function AccessibilityEventsDelegateUnitTest() { + describe('AccessibilityEventsDelegate', () => { + it("AccessibilityEventsDelegate_requestSendAccessibilityEvent", 0, requestSendAccessibilityEvent); + + it("AccessibilityEventsDelegate_onAccessibilityHoverEvent", 0, onAccessibilityHoverEvent); + }) +} + +function requestSendAccessibilityEvent() { + let delegate = new AccessibilityEventsDelegate(); + let result = delegate.requestSendAccessibilityEvent(new AccessibilityBridge()); + expect(result).assertTrue(); +} + +function onAccessibilityHoverEvent() { + let delegate = new AccessibilityEventsDelegate(); + let result = delegate.onAccessibilityHoverEvent(new AccessibilityBridge()); + expect(result).assertTrue(); +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/platform/PlatformOverlayView.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/platform/PlatformOverlayView.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..4ddd8fe65fb3ba510ada07e9ec41f42fa1d9c448 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/platform/PlatformOverlayView.test.ets @@ -0,0 +1,32 @@ +/* + * 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. + */ + +import { describe, it, expect } from '@ohos/hypium' +import { AccessibilityEventsDelegate, PlatformOverlayView } from '@ohos/flutter_ohos'; + +const platformOverlayView: PlatformOverlayView = + new PlatformOverlayView(getContext(), 800, 800, new AccessibilityEventsDelegate()) + +export default function PlatformOverlayViewTest() { + describe('PlatformOverlayViewTest', () => { + it('PlatformOverlayView', 0, () => { + let overlayLayerViews = new Map(); + expect(overlayLayerViews).not().assertNull(); + }); + it('onHoverEvent', 0, () => { + expect(platformOverlayView.onHoverEvent()).assertFalse(); + }) + }) +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/platform/PlatformView.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/platform/PlatformView.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..4369f8d25fcc52fcb47d0977c21e6c5428a7bf23 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/platform/PlatformView.test.ets @@ -0,0 +1,37 @@ +/* + * 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. + */ + +import { describe, it, expect } from '@ohos/hypium' +import { PlatformView } from '@ohos/flutter_ohos'; +import { Params } from '@ohos/flutter_ohos/src/main/ets/plugin/platform/PlatformView'; + +export default function PlatformViewTest() { + describe('PlatformViewTest', () => { + class TestPlatformView extends PlatformView { + getView(): WrappedBuilder<[Params]> { + throw new Error('Method not implemented.'); + } + + dispose(): void { + throw new Error('Method not implemented.'); + } + } + + const platformView: PlatformView = new TestPlatformView() + it('getType', 0, () => { + expect(platformView.getType()).assertEqual('default') + }) + }) +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/platform/PlatformViewRegistryImplTest.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/platform/PlatformViewRegistryImplTest.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..deaca608fc0efdf7c1ac59a14d5ed7f58385ed00 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/platform/PlatformViewRegistryImplTest.test.ets @@ -0,0 +1,36 @@ +/* + * 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. + */ +import { describe, it, expect } from '@ohos/hypium'; +import { PlatformViewRegistryImpl, PlatformViewFactory } from "@ohos/flutter_ohos"; + +const platformViewRegistryImpl: PlatformViewRegistryImpl = new PlatformViewRegistryImpl(); + +export default function PlatformViewRegistryImplTest() { + describe('PlatformViewRegistryImplTest', () => { + it('TestPlatformViewRegistryImplGetFactory', 0, async (done: Function) => { + const platformViewFactory: PlatformViewFactory = platformViewRegistryImpl.getFactory('test'); + expect(platformViewFactory).not().assertNull(); + done(); + }) + + it('TestPlatformViewRegistryImplRegisterViewFactory', 0, async (done: Function) => { + const platformViewFactory: PlatformViewFactory = platformViewRegistryImpl.getFactory('test'); + expect(platformViewFactory).not().assertNull(); + const result = platformViewRegistryImpl.registerViewFactory('test', platformViewFactory); + expect(result).assertTrue(); + done(); + }) + }) +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/platform/PlatformViewWrapperTest.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/platform/PlatformViewWrapperTest.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..2926252aeba5bf4fdc8d2958138dd324b7de7099 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/platform/PlatformViewWrapperTest.test.ets @@ -0,0 +1,41 @@ +/* + * 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. + */ +import { describe, it, expect } from '@ohos/hypium'; +import { PlatformViewWrapper, OhosTouchProcessor } from "@ohos/flutter_ohos"; +import { DVModel, DVModelParameters } from '@ohos/flutter_ohos/src/main/ets/view/DynamicView/dynamicView'; + +function sleep(time: number) { + return new Promise((resolve: Function) => setTimeout(resolve, time)); +} + +const platformViewWrapper: PlatformViewWrapper = new PlatformViewWrapper(); + +export default function PlatformViewWrapperTest() { + describe('PlatformViewWrapperTest', () => { + it('TestPlatformViewWrapperDvModel', 0, async (done: Function) => { + const newTouchProcessor: OhosTouchProcessor = new OhosTouchProcessor(); + platformViewWrapper.setTouchProcessor(newTouchProcessor); + await sleep(1000); + const dvModel: DVModel = platformViewWrapper.getDvModel(); + expect(dvModel).not().assertNull(); + await sleep(1000); + platformViewWrapper.addDvModel(dvModel); + await sleep(1000); + const parameters: DVModelParameters = new DVModelParameters(); + platformViewWrapper.setLayoutParams(parameters); + done(); + }) + }) +} diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/platform/PlatformViewsControllerTest.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/platform/PlatformViewsControllerTest.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..7bbe3eef5defb416d832201ca8003e3a6c88f89b --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/platform/PlatformViewsControllerTest.test.ets @@ -0,0 +1,50 @@ +/* + * 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. + */ +import { describe, it, expect } from '@ohos/hypium'; +import { + PlatformViewsController, + FlutterOverlaySurface, +} from "@ohos/flutter_ohos"; + +const platformViewsController: PlatformViewsController = new PlatformViewsController(); +const direction: Direction = 100; + +export default function PlatformViewsControllerTest() { + describe('PlatformViewsControllerTest', () => { + + it('TestPlatformViewRegistryImplGetRegistry', 0, async (done: Function) => { + const result = platformViewsController.getRegistry(); + expect(result).not().assertNull(); + done(); + }) + + it('TestCreateOverlaySurface', 0, async (done: Function) => { + const result: FlutterOverlaySurface = platformViewsController.createOverlaySurface(); + expect(result).not().assertNull(); + done(); + }) + it('TestPlatformViewRegistryImplValidateDirection', 0, async (done: Function) => { + const result = platformViewsController.validateDirection(direction); + expect(result).assertFalse(); + done(); + }) + + it('TestPlatformViewRegistryImplGetFlutterView', 0, async (done: Function) => { + const result = platformViewsController.getFlutterView(); + expect(result).assertNull(); + done(); + }) + }) +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/platform/RawPointerCoordTest.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/platform/RawPointerCoordTest.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..c26c4ee7f27c30af6e9c9a3fc1212ae41ae0a974 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/platform/RawPointerCoordTest.test.ets @@ -0,0 +1,44 @@ +/* + * 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. + */ +import { describe, it, expect } from '@ohos/hypium'; +import { RawPointerCoords } from '@ohos/flutter_ohos/src/main/ets/plugin/platform/RawPointerCoord'; + +const orientation: number = 100; +const pressure: number = 100; +const size: number = 100; +const toolMajor: number = 100; +const toolMinor: number = 100; +const touchMajor: number = 100; +const touchMinor: number = 100; +const x: number = 100; +const y: number = 100; +const rawPointerCoords: RawPointerCoords = + new RawPointerCoords(orientation, pressure, size, toolMajor, toolMinor, touchMajor, touchMinor, x, y); + +export default function RawPointerCoordsTest() { + describe('RawPointerCoordsTest', () => { + it('TestRawPointerCoordsGetX', 0, async (done: Function) => { + const pointX = rawPointerCoords.getX(); + expect(pointX).not().assertNull(); + done(); + }) + + it('TestRawPointerCoordsGetY', 0, async (done: Function) => { + const pointY = rawPointerCoords.getY(); + expect(pointY).not().assertNull(); + done(); + }) + }) +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/platform/RootDvModelManagerTest.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/platform/RootDvModelManagerTest.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..3bc489d587d5d382a42ce209527180e2df6169e8 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/platform/RootDvModelManagerTest.test.ets @@ -0,0 +1,36 @@ +/* + * 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. + */ +import { describe, it, expect } from '@ohos/hypium'; +import { PlatformViewWrapper } from '@ohos/flutter_ohos'; +import { RootDvModeManager } from '@ohos/flutter_ohos/src/main/ets/plugin/platform/RootDvModelManager'; +import { DVModel, DVModelContainer } from '@ohos/flutter_ohos/src/main/ets/view/DynamicView/dynamicView'; + +export default function DVModelContainerTest() { + describe('DVModelContainerTest', () => { + it('TestDVModelContainerGetRootDvMode', 0, async (done: Function) => { + const dvModel: DVModelContainer = RootDvModeManager.getRootDvMode(); + expect(dvModel).not().assertNull(); + done(); + }) + + it('TestDVModelAddDvModel', 0, async (done: Function) => { + const platformViewWrapper: PlatformViewWrapper = new PlatformViewWrapper(); + const dvModel: DVModel = platformViewWrapper.getDvModel(); + RootDvModeManager.addDvModel(dvModel); + expect(dvModel).not().assertNull(); + done(); + }) + }) +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/util/ByteBufferTest.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/util/ByteBufferTest.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..536a5aed7110aff664c0a4ed7393874606b97f1d --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/util/ByteBufferTest.test.ets @@ -0,0 +1,317 @@ +/* + * 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. + */ +import { describe, it, expect, afterAll } from '@ohos/hypium'; +import { ByteBuffer } from "@ohos/flutter_ohos"; +import { buffer } from '@kit.ArkTS'; + +let byteBuffer: ByteBuffer; +let byteOffset: number; + +export default function ByteBufferTest() { + describe('ByteBufferTest', () => { + it('TestByteBufferFrom', 0, async (done: Function) => { + const blobValue: buffer.Blob = new buffer.Blob(['name', 'age', 'sex']); + const message: ArrayBuffer = await blobValue.arrayBuffer(); + const result = ByteBuffer.from(message); + expect(result.byteLength).assertEqual(10); + done(); + }) + + it('TestByteBufferByteOffset', 0, async (done: Function) => { + const blobValue: buffer.Blob = new buffer.Blob(['name', 'age', 'sex']); + const message: ArrayBuffer = await blobValue.arrayBuffer(); + byteBuffer = ByteBuffer.from(message); + byteOffset = byteBuffer.byteOffset; + expect(byteOffset).assertEqual(0); + done(); + }) + + it('TestByteBufferByteLength', 0, async (done: Function) => { + const result = byteBuffer.byteLength; + expect(result).assertEqual(10); + done(); + }) + + it('TestByteBufferBytesRemaining', 0, async (done: Function) => { + const result = byteBuffer.bytesRemaining; + expect(result).assertEqual(10); + done(); + }) + + it('TestByteBufferBuffer', 0, async (done: Function) => { + const result = byteBuffer.buffer; + expect(result).assertInstanceOf('ArrayBuffer'); + done(); + }) + + it('TestByteBufferHasRemaining', 0, async (done: Function) => { + const result = byteBuffer.hasRemaining(); + expect(result).assertTrue(); + done(); + }) + + it('TestByteBufferSkip', 0, async (done: Function) => { + const result = byteBuffer.byteLength; + expect(result).assertEqual(10); + byteBuffer.skip(result); + byteBuffer.checkWriteCapacity(10); + done(); + }) + + it('TestByteBufferGetBool', 0, async (done: Function) => { + byteBuffer.setBool(byteOffset, true); + let result = byteBuffer.getBool(byteOffset); + expect(result).assertTrue(); + done(); + }) + + it('TestByteBufferReadBool', 0, async (done: Function) => { + byteBuffer.writeBool(false); + let result = byteBuffer.readBool(); + expect(result).assertFalse(); + done(); + }) + + it('TestByteBufferGetInt8', 0, async (done: Function) => { + byteBuffer.setInt8(byteOffset, 10); + let result = byteBuffer.getInt8(byteOffset); + expect(result).assertEqual(10); + done(); + }) + + it('TestByteBufferReadInt8', 0, async (done: Function) => { + byteBuffer.writeInt8(byteOffset); + let result = byteBuffer.readInt8(); + expect(result).assertEqual(0); + done(); + }) + + it('TestByteBufferGetUint8', 0, async (done: Function) => { + byteBuffer.setUint8(byteOffset, 10); + let result = byteBuffer.getUint8(byteOffset); + expect(result).assertEqual(10); + done(); + }) + + it('TestByteBufferReadUint8', 0, async (done: Function) => { + byteBuffer.writeUint8(byteOffset); + let result = byteBuffer.readUint8(); + expect(result).assertEqual(0); + done(); + }) + + it('TestByteBufferGetInt16', 0, async (done: Function) => { + byteBuffer.setInt16(byteOffset, 10); + let result = byteBuffer.getInt16(byteOffset); + expect(result).assertEqual(10); + done(); + }) + + it('TestByteBufferReadInt16', 0, async (done: Function) => { + byteBuffer.writeInt16(byteOffset); + let result = byteBuffer.readInt16(); + expect(result).assertEqual(0); + done(); + }) + + it('TestByteBufferGetUint16', 0, async (done: Function) => { + byteBuffer.setUint16(byteOffset, 10); + let result = byteBuffer.getUint16(byteOffset); + expect(result).assertEqual(10); + done(); + }) + + it('TestByteBufferReadUint16', 0, async (done: Function) => { + byteBuffer.writeUint16(byteOffset); + let result = byteBuffer.readUint16(); + expect(result).assertEqual(0); + done(); + }) + + it('TestByteBufferGetInt32', 0, async (done: Function) => { + byteBuffer.setInt32(byteOffset, 10); + let result = byteBuffer.getInt32(byteOffset); + expect(result).assertEqual(10); + done(); + }) + + it('TestByteBufferReadInt32', 0, async (done: Function) => { + byteBuffer.writeInt32(byteOffset); + let result = byteBuffer.readInt32(); + expect(result).assertEqual(0); + done(); + }) + + it('TestByteBufferGetUint32', 0, async (done: Function) => { + byteBuffer.setUint32(byteOffset, 10); + let result = byteBuffer.getUint32(byteOffset); + expect(result).assertEqual(10); + done(); + }) + + it('TestByteBufferReadUint32', 0, async (done: Function) => { + byteBuffer.writeUint32(byteOffset); + let result = byteBuffer.readUint32(); + expect(result).assertEqual(0); + done(); + }) + + it('TestByteBufferGetFloat32', 0, async (done: Function) => { + byteBuffer.setFloat32(byteOffset, 10); + let result = byteBuffer.getFloat32(byteOffset); + expect(result).assertEqual(10); + done(); + }) + + it('TestByteBufferReadFloat32', 0, async (done: Function) => { + byteBuffer.writeFloat32(byteOffset); + let result = byteBuffer.readFloat32(); + expect(result).assertEqual(0); + done(); + }) + + it('TestByteBufferGetFloat64', 0, async (done: Function) => { + byteBuffer.setFloat64(byteOffset, 10); + let result = byteBuffer.getFloat64(byteOffset); + expect(result).assertEqual(10); + done(); + }) + + it('TestByteBufferReadFloat64', 0, async (done: Function) => { + byteBuffer.writeFloat64(byteOffset); + let result = byteBuffer.readFloat64(); + expect(result).assertEqual(0); + done(); + }) + + it('TestByteBufferGetBigInt64', 0, async (done: Function) => { + const value: bigint = BigInt(9223372036854775807); + byteBuffer.setBigInt64(byteOffset, value); + let result = byteBuffer.getBigInt64(byteOffset); + expect(result).not().assertNull(); + done(); + }) + + it('TestByteBufferReadBigInt64', 0, async (done: Function) => { + const value: bigint = BigInt(9223372036854775807); + byteBuffer.writeBigInt64(value); + let result = byteBuffer.readBigInt64(); + expect(result).assertEqual(0n); + done(); + }) + + it('TestByteBufferGetBigUint64', 0, async (done: Function) => { + const value: bigint = BigInt(9223372036854775807); + byteBuffer.setBigUint64(byteOffset, value); + let result = byteBuffer.getBigUint64(byteOffset); + expect(result).not().assertNull(); + done(); + }) + + it('TestByteBufferReadBigUint64', 0, async (done: Function) => { + const value: bigint = BigInt(9223372036854775807); + byteBuffer.writeBigUint64(value); + let result = byteBuffer.readBigUint64(); + expect(result).assertEqual(0n); + done(); + }) + + it('TestByteBufferGetInt64', 0, async (done: Function) => { + byteBuffer.setInt64(byteOffset, 10); + let result = byteBuffer.getInt64(byteOffset); + expect(result).assertEqual(10n); + done(); + }) + + it('TestByteBufferReadInt64', 0, async (done: Function) => { + byteBuffer.writeInt64(10); + let result = byteBuffer.readInt64(); + expect(result).assertEqual(0n); + done(); + }) + + it('TestByteBufferGetUint64', 0, async (done: Function) => { + byteBuffer.setUint64(byteOffset, 10); + let result = byteBuffer.getUint64(byteOffset); + expect(result).assertEqual(10); + done(); + }) + + it('TestByteBufferReadUint64', 0, async (done: Function) => { + byteBuffer.writeUint64(10); + let result = byteBuffer.readUint64(); + expect(result).assertEqual(0); + done(); + }) + + it('TestByteBufferGetUint8Array', 0, async (done: Function) => { + const value: Uint8Array = new Uint8Array(); + byteBuffer.setUint8Array(byteOffset, value); + let result = byteBuffer.getUint8Array(byteOffset); + expect(result).assertInstanceOf('Uint8Array'); + done(); + }) + + it('TestByteBufferReadUint8Array', 0, async (done: Function) => { + const value: Uint8Array = new Uint8Array(); + byteBuffer.writeUint8Array(value); + let result = byteBuffer.readUint8Array(); + expect(result).assertInstanceOf('Uint8Array'); + done(); + }) + + it('TestByteBufferGetUint16Array', 0, async (done: Function) => { + const value: Uint16Array = new Uint16Array(); + byteBuffer.setUint16Array(byteOffset, value); + let result = byteBuffer.getUint16Array(byteOffset); + expect(result).assertInstanceOf('Uint16Array'); + done(); + }) + + it('TestByteBufferReadUint16Array', 0, async (done: Function) => { + const value: Uint16Array = new Uint16Array(); + byteBuffer.writeUint16Array(value); + let result = byteBuffer.readUint16Array(); + expect(result).assertInstanceOf('Uint16Array'); + done(); + }) + + it('TestByteBufferGetString', 0, async (done: Function) => { + byteBuffer.setString(byteOffset, 'test'); + let result = byteBuffer.getString(byteOffset); + expect(result).not().assertNull(); + done(); + }) + + it('TestByteBufferReadString', 0, async (done: Function) => { + byteBuffer.writeString('test'); + let result = byteBuffer.readString(); + expect(result).assertUndefined(); + done(); + }) + + it('TestByteBufferToString', 0, async (done: Function) => { + let result = byteBuffer.toString(); + expect(result).not().assertNull(); + done(); + }) + + afterAll(() => { + byteBuffer.reset(); + byteBuffer.clear(); + }) + }) + +} diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/util/Log.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/util/Log.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..5ef0a0618adf56b8a7fe4921de38269c540a02de --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/util/Log.test.ets @@ -0,0 +1,25 @@ +/* + * 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. + */ + +import { describe, it, expect } from '@ohos/hypium' +import { Log } from '@ohos/flutter_ohos'; + +export default function LogTest() { + describe('LogTest', () => { + it('Log', 0, () => { + expect(Log.toString()).not().assertNull(); + }); + }) +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/util/MessageChannelUtils.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/util/MessageChannelUtils.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..60c39c1c12599a1cbfdae18b3a61512fb653b8df --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/util/MessageChannelUtils.test.ets @@ -0,0 +1,25 @@ +/* + * 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. + */ + +import { describe, it, expect } from '@ohos/hypium' +import { MessageChannelUtils } from '@ohos/flutter_ohos'; + +export default function MessageChannelUtilsTest() { + describe('MessageChannelUtilsTest', () => { + it('resizeChannelBuffer', 0, () => { + expect(MessageChannelUtils.toString()).not().assertNull(); + }); + }) +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/util/PathUtils.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/util/PathUtils.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..8f4283281840e0cc21ce3f9cb3999a9844111a3e --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/util/PathUtils.test.ets @@ -0,0 +1,32 @@ +/* + * 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. + */ + +import { describe, it, expect } from '@ohos/hypium' +import { PathUtils } from '@ohos/flutter_ohos'; + +export default function PathUtilsTest() { + describe('PathUtilsTest', () => { + it('getFilesDir', 0, () => { + expect(PathUtils.getFilesDir(getContext())).not().assertNull(); + }); + it('getCacheDirectory', 0, () => { + expect(PathUtils.getCacheDirectory(getContext())).not().assertNull(); + }); + it('getDataDirectory', 0, () => { + const name = "flutter"; + expect(PathUtils.getDataDirectory(getContext())).assertContain(name); + }); + }) +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/util/StringUtils.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/util/StringUtils.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..693d0b188e914694bcd70ec1f73fe1ecdc3efe11 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/util/StringUtils.test.ets @@ -0,0 +1,30 @@ +/* + * 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. + */ + +import { describe, it, expect } from '@ohos/hypium' +import { StringUtils } from '@ohos/flutter_ohos'; + +const TAG: string = "stringUtilsTest"; + +export default function StringUtilsTest() { + describe('StringUtilsTest', () => { + it('isNotEmpty', 0, () => { + expect(StringUtils.isNotEmpty(TAG)).assertTrue(); + }); + it('isEmpty', 0, () => { + expect(StringUtils.isEmpty("")).assertTrue(); + }); + }) +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/util/ToolUtils.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/util/ToolUtils.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..158170ba95c6516332eca4d3779b4a894d2f1ac5 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/util/ToolUtils.test.ets @@ -0,0 +1,26 @@ +/* + * 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. + */ + +import { describe, it, expect } from '@ohos/hypium' +import { ToolUtils } from '@ohos/flutter_ohos'; + +export default function ToolUtilsTest() { + describe('ToolUtilsTest', () => { + it('isObj', 0, () => { + const json = JSON.stringify('object'); + expect(ToolUtils.isObj(json)).assertFalse(); + }); + }) +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/util/TraceSection.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/util/TraceSection.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..b09b01f10931882f64cfb5b4413633b689e3a848 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/plugin/util/TraceSection.test.ets @@ -0,0 +1,34 @@ +/* + * 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. + */ + +import { describe, it, expect } from '@ohos/hypium' +import { TraceSection } from '@ohos/flutter_ohos'; + +export default function TraceSectionTest() { + describe('TraceSectionTest', () => { + it('begin', 0, () => { + const sectionName = "DartExecutor"; + expect(TraceSection.begin(sectionName)).assertLarger(0); + }); + it('end', 0, () => { + const sectionName = "DartExecutor"; + TraceSection.end(sectionName); + }); + it('endWithId', 0, () => { + const sectionName = "DartExecutor"; + TraceSection.endWithId(sectionName, 1); + }); + }) +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/view/DynamicView/dynamicViewJson.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/view/DynamicView/dynamicViewJson.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..610a7f88c6202e029a0a0cdd772ce83e4ef3a0f7 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/view/DynamicView/dynamicViewJson.test.ets @@ -0,0 +1,30 @@ +/* + * 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. + */ + +import { describe, it, expect } from '@ohos/hypium' +import { createDVModelFromJson } from '@ohos/flutter_ohos/src/main/ets/view/DynamicView/dynamicViewJson'; + +const TAG: string = "dynamicViewJsonTest"; + +export default function dynamicViewJsonTest() { + describe('dynamicViewJsonTest', () => { + it('createDVModelFromJson', 0, () => { + let dvModel = createDVModelFromJson(JSON.stringify(TAG)); + expect(dvModel) + .not() + .assertNull(); + }) + }) +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/view/FlutterRunArguments.test.ets b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/view/FlutterRunArguments.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..a9d1a0787213b1e610aa61be37059c28328fdf0d --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/ets/test/view/FlutterRunArguments.test.ets @@ -0,0 +1,28 @@ +/* + * 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. + */ + +import { describe, it, expect } from '@ohos/hypium' +import { FlutterRunArguments } from '@ohos/flutter_ohos'; + +const TAG: string = "FlutterRunArgumentsTest"; + +export default function FlutterRunArgumentsTest() { + describe('FlutterRunArgumentsTest', () => { + it('flutterRunArguments', 0, () => { + const flutterRunArguments = new FlutterRunArguments(TAG, TAG, TAG) + expect(flutterRunArguments.bundlePath).assertEqual(TAG) + }) + }) +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/ohosTest/module.json5 b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..b4bf32fd9ef07bd62331aa8e09cae3029062b33a --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/ohosTest/module.json5 @@ -0,0 +1,28 @@ +/* + * 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. + */ +{ + "module": { + "name": "application_test", + "type": "feature", + "deviceTypes": [ + "phone", + "tablet", + "2in1" + ], + "deliveryWithInstall": true, + "installationFree": false + } +} diff --git a/shell/platform/ohos/flutter_embedding/application/src/test/List.test.ets b/shell/platform/ohos/flutter_embedding/application/src/test/List.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..312f48fb747c89745bf9671ef83f93eabf0f12bc --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/test/List.test.ets @@ -0,0 +1,19 @@ +/* + * 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. + */ +import localUnitTest from './LocalUnit.test'; + +export default function testsuite() { + localUnitTest(); +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/application/src/test/LocalUnit.test.ets b/shell/platform/ohos/flutter_embedding/application/src/test/LocalUnit.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..8ca1b6da13fdc210635bd5e33d64370f1948557e --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/application/src/test/LocalUnit.test.ets @@ -0,0 +1,47 @@ +/* + * 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. + */ +import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'; + +export default function localUnitTest() { + describe('localUnitTest', () => { + // Defines a test suite. Two parameters are supported: test suite name and test suite function. + beforeAll(() => { + // Presets an action, which is performed only once before all test cases of the test suite start. + // This API supports only one parameter: preset action function. + }); + beforeEach(() => { + // Presets an action, which is performed before each unit test case starts. + // The number of execution times is the same as the number of test cases defined by **it**. + // This API supports only one parameter: preset action function. + }); + afterEach(() => { + // Presets a clear action, which is performed after each unit test case ends. + // The number of execution times is the same as the number of test cases defined by **it**. + // This API supports only one parameter: clear action function. + }); + afterAll(() => { + // Presets a clear action, which is performed after all test cases of the test suite end. + // This API supports only one parameter: clear action function. + }); + it('assertContain', 0, () => { + // Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function. + let a = 'abc'; + let b = 'b'; + // Defines a variety of assertion methods, which are used to declare expected boolean conditions. + expect(a).assertContain(b); + expect(a).assertEqual(a); + }); + }); +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/build-profile.json5 b/shell/platform/ohos/flutter_embedding/build-profile.json5 index 4cebb96991c2452fc99cd78dfd665235df58e8f3..c4150bb5a34dad87dcf290216414a834138b28aa 100755 --- a/shell/platform/ohos/flutter_embedding/build-profile.json5 +++ b/shell/platform/ohos/flutter_embedding/build-profile.json5 @@ -20,9 +20,8 @@ { "name": "default", "signingConfig": "default", - "compileSdkVersion": "5.0.0(12)", "compatibleSdkVersion": "5.0.0(12)", - "runtimeOS": "HarmonyOS", + "runtimeOS": "HarmonyOS" } ], "buildModeSet": [ @@ -34,13 +33,25 @@ }, { "name": "profile" - }, + } ] }, "modules": [ { "name": "flutter", "srcPath": "./flutter" + }, + { + "name": "application", + "srcPath": "./application", + "targets": [ + { + "name": "default", + "applyToProducts": [ + "default" + ] + } + ] } ] -} +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/flutter/build-profile.json5 b/shell/platform/ohos/flutter_embedding/flutter/build-profile.json5 index 489faa5430e016fbdc8fd4b331d1b1cd05f51d21..b93937f294390a491253ad2a1f987a53b1d942d4 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/build-profile.json5 +++ b/shell/platform/ohos/flutter_embedding/flutter/build-profile.json5 @@ -20,6 +20,12 @@ "workers": [ "./src/main/ets/embedding/engine/workers/PlatformChannelWorker.ets" ] + }, + "nativeLib": { + "debugSymbol": { + "strip": false, + "exclude": [] + } } }, "buildOptionSet": [ diff --git a/shell/platform/ohos/flutter_embedding/flutter/index.ets b/shell/platform/ohos/flutter_embedding/flutter/index.ets index 91a7282d728dcf4d0806e9730dd02427945798be..8e44d572561bacb5f4f11cf0da363584980be719 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/index.ets +++ b/shell/platform/ohos/flutter_embedding/flutter/index.ets @@ -60,7 +60,7 @@ export { default as FlutterAbilityLaunchConfigs } from './src/main/ets/embedding export { default as FlutterEngineConfigurator } from './src/main/ets/embedding/ohos/FlutterEngineConfigurator'; export { default as FlutterEngineProvider } from './src/main/ets/embedding/ohos/FlutterEngineProvider'; export { default as FlutterEntry } from './src/main/ets/embedding/ohos/FlutterEntry'; -export { default as FlutterManager } from './src/main/ets/embedding/ohos/FlutterManager'; +export { default as FlutterManager, DragDropCallback as DragDropCallback } from './src/main/ets/embedding/ohos/FlutterManager'; export * from './src/main/ets/embedding/ohos/FlutterPage'; export { default as KeyboardManager } from './src/main/ets/embedding/ohos/KeyboardManager'; export { default as OhosTouchProcessor } from './src/main/ets/embedding/ohos/OhosTouchProcessor'; 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 be366b7cb7029b1208a0a17abb6f04a023cb8126..629988a8937eed70c95f0b912e66693a7f247087 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/cpp/types/libflutter/index.d.ets +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/cpp/types/libflutter/index.d.ets @@ -146,7 +146,7 @@ export const nativeSetTextureBufferSize: (nativeShellHolderId: number, textureId */ export const nativeSetAccessibilityFeatures: (accessibilityFeatureFlags: number, responseId: number) => void; -export const nativeAccessibilityStateChange: (state: Boolean) => void; +export const nativeAccessibilityStateChange: (nativeShellHolderId: number, state: Boolean) => void; export const nativeAnnounce: (message: string) => void; @@ -158,6 +158,9 @@ export const nativeGetShellHolderId: (nativeShellHolderId: number) => void; export const nativeLookupCallbackInformation: (callback: FlutterCallbackInformation, handler: number) => number; +export const nativeGetFlutterNavigationAction: (isNavigate: boolean) => void; + + export const nativeUnicodeIsEmoji: (code: number) => number; export const nativeUnicodeIsEmojiModifier: (code: number) => number; diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/FlutterNapi.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/FlutterNapi.ets index 9be47241dc8c077a9e8a39e9fc35869cf54486b2..e36a5666822d8dfde8b31ffe32e10d7ac7b3729a 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/FlutterNapi.ets +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/FlutterNapi.ets @@ -52,7 +52,6 @@ export default class FlutterNapi { private engineLifecycleListeners = new Set(); accessibilityDelegate: AccessibilityDelegate | null = null; localizationPlugin: LocalizationPlugin | null = null; - isDisplayingFlutterUi: boolean = false; accessibilityManager: AccessibilityManager | null = null; @@ -117,7 +116,7 @@ export default class FlutterNapi { Log.e(TAG, "runBundleAndSnapshotFromLibrary this.nativeShellHolderId:" + this.nativeShellHolderId) return; } - flutter.nativeRunBundleAndSnapshotFromLibrary(this.nativeShellHolderId!, bundlePath, entrypointFunctionName, pathToEntrypointFunction, assetManager, entrypointArgs); + flutter.nativeRunBundleAndSnapshotFromLibrary(this.nativeShellHolderId!, bundlePath, entrypointFunctionName as string, pathToEntrypointFunction as string, assetManager, entrypointArgs); }; /** @@ -323,9 +322,10 @@ export default class FlutterNapi { } } - setSemanticsEnabled(enabled: boolean, responseId: number): void { + setSemanticsEnabledWithRespId(enabled: boolean, responseId: number): void { + this.ensureRunningOnMainThread(); if (this.isAttached()) { - this.nativeSetSemanticsEnabled(enabled); + flutter.nativeSetSemanticsEnabled(this.nativeShellHolderId!, enabled); } else { Log.w( TAG, @@ -334,12 +334,20 @@ export default class FlutterNapi { } } - // Send an empty response to a platform message received from Dart. - nativeSetSemanticsEnabled(enabled: boolean):void {} + setSemanticsEnabled(enabled: boolean): void { + this.ensureRunningOnMainThread(); + if (this.isAttached()) { + flutter.nativeSetSemanticsEnabled(this.nativeShellHolderId!, enabled); + } else { + Log.e( + TAG, + "Tried to send a platform message response, but FlutterNapi was detached from native C++. Could not send."); + } + } setAccessibilityFeatures(accessibilityFeatureFlags: number, responseId: number): void { if (this.isAttached()) { - this.nativeSetAccessibilityFeatures(accessibilityFeatureFlags, responseId); + flutter.nativeSetAccessibilityFeatures(accessibilityFeatureFlags, responseId); } else { Log.w( TAG, @@ -374,6 +382,15 @@ export default class FlutterNapi { } } + accessibilityStateChange(state: Boolean): void { + this.ensureRunningOnMainThread(); + if(this.accessibilityDelegate != null) { + this.accessibilityDelegate.accessibilityStateChange(state); + } + Log.d(TAG, "accessibilityStateChange is called"); + flutter.nativeAccessibilityStateChange(this.nativeShellHolderId!, state); + } + setLocalizationPlugin(localizationPlugin: LocalizationPlugin | null): void { this.localizationPlugin = localizationPlugin; } @@ -505,6 +522,7 @@ export default class FlutterNapi { } } + //native c++ get the shell holder id getShellHolderId(): void { this.ensureRunningOnMainThread(); if (this.isAttached()) { @@ -522,6 +540,16 @@ export default class FlutterNapi { } } + setFlutterNavigationAction(isNavigate: boolean): void { + this.ensureRunningOnMainThread(); + if (this.isAttached()) { + Log.i(TAG, "setFlutterNavigationAction: " + isNavigate); + flutter.nativeGetFlutterNavigationAction(isNavigate); + } else { + Log.w(TAG, "setFlutterNavigationAction is detached !"); + } + } + static unicodeIsEmoji(code: number): boolean { return Boolean(flutter.nativeUnicodeIsEmoji(code)); } @@ -548,4 +576,6 @@ export interface AccessibilityDelegate { updateCustomAccessibilityActions(buffer: ByteBuffer, strings: string[]): void; updateSemantics(buffer: ByteBuffer, strings: string[], stringAttributeArgs: ByteBuffer[]): void; + + accessibilityStateChange(state: Boolean): void; } diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/dart/DartMessenger.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/dart/DartMessenger.ets index d2894ebcca73e04dc907e9034a3f251a45d0c825..a1773db5c745c9111fcc3fda82ccde07e0d50bd2 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/dart/DartMessenger.ets +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/dart/DartMessenger.ets @@ -12,7 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { ErrorEvent, Queue, taskpool, worker, MessageEvents } from '@kit.ArkTS'; +import { ErrorEvent, Queue, taskpool, worker, MessageEvents, JSON } from '@kit.ArkTS'; import Log from '../../../util/Log'; import { BinaryMessageHandler, BinaryMessenger, BinaryReply, TaskPriority, TaskQueue, TaskQueueOptions } from '../../../plugin/common/BinaryMessenger'; @@ -97,6 +97,7 @@ export class DartMessenger implements BinaryMessenger, PlatformMessageHandler { } finally { TraceSection.endWithId("DartMessenger#send on " + channel, traceId); } + this.IsFlutterNavigationExecuted(channel); } dispatchMessageToQueue(handlerInfo: HandlerInfo, message: ArrayBuffer, replyId: number): void { @@ -127,6 +128,7 @@ export class DartMessenger implements BinaryMessenger, PlatformMessageHandler { } else { this.invokeHandler(handlerInfo?.handler as BinaryMessageHandler, message, replyId); } + this.IsFlutterNavigationExecuted(channel); } handlePlatformMessageResponse(replyId: number, reply: ArrayBuffer): void { @@ -157,6 +159,14 @@ export class DartMessenger implements BinaryMessenger, PlatformMessageHandler { getPendingChannelResponseCount(): number { return this.pendingReplies.size; } + + //获取当前flutter页面是否路由跳转,并传递到native侧 + IsFlutterNavigationExecuted(channel: String): void { + if(channel == "flutter/navigation") { + this.flutterNapi.setFlutterNavigationAction(true); + Log.d(TAG, "setFlutterNavigationAction -> '" + channel + "'"); + } + } } /** diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/renderer/FlutterRenderer.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/renderer/FlutterRenderer.ets index e64bb55975f5f592e96e55ee8e53fbbbb023137d..9d00c43494d9784aadd88ee16b3f41ae561054f8 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/renderer/FlutterRenderer.ets +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/renderer/FlutterRenderer.ets @@ -105,6 +105,7 @@ export class FlutterRenderer implements TextureRegistry { }) }) } + } export class SurfaceTextureRegistryEntry implements SurfaceTextureEntry { 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 9b2f9ee6cfdcfa5bbee616474617b936344c7e42..bbc5a658ea5c9af1e99f69a45e737b861fabcfd8 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 @@ -22,6 +22,8 @@ import { Action } from '../../../view/AccessibilityBridge' import StandardMessageCodec from '../../../plugin/common/StandardMessageCodec'; import StringUtils from '../../../util/StringUtils'; import Any from '../../../plugin/common/Any'; +import flutter from 'libflutter.so'; +import { ByteBuffer } from '../../../util/ByteBuffer'; /** * 辅助功能channel @@ -31,12 +33,12 @@ export default class AccessibilityChannel implements MessageHandler{ private static CHANNEL_NAME = "flutter/accessibility"; private channel: BasicMessageChannel; private flutterNapi: FlutterNapi; - private handler: AccessibilityMessageHandler | null = null; + private handler: AccessibilityMessageHandler = new DefaultHandler(); private nextReplyId: number = 1; onMessage(message: object, reply: Reply): void { if (this.handler == null) { - Log.i(AccessibilityChannel.TAG, "NULL"); + Log.i(AccessibilityChannel.TAG, "handler = NULL"); reply.reply(StringUtils.stringToArrayBuffer("")); return; } @@ -50,6 +52,7 @@ export default class AccessibilityChannel implements MessageHandler{ Log.i(AccessibilityChannel.TAG, "Announce"); let announceMessage: string = data.get("message"); if (announceMessage != null) { + Log.i(AccessibilityChannel.TAG, "message is " + announceMessage); this.handler.announce(announceMessage); } break; @@ -91,17 +94,20 @@ export default class AccessibilityChannel implements MessageHandler{ onOhosAccessibilityEnabled(): void { let replyId: number = this.nextReplyId++; - this.flutterNapi.setSemanticsEnabled(true, replyId); + this.flutterNapi.setSemanticsEnabledWithRespId(true, replyId); + Log.i(AccessibilityChannel.TAG, "onOhosAccessibilityEnabled = true"); } onOhosAccessibilityFeatures(accessibilityFeatureFlags: number): void { let replyId: number = this.nextReplyId++; this.flutterNapi.setAccessibilityFeatures(accessibilityFeatureFlags, replyId); + Log.i(AccessibilityChannel.TAG, "onOhosAccessibilityFeatures"); } dispatchSemanticsAction(virtualViewId: number, action: Action): void { let replyId: number = this.nextReplyId++; this.flutterNapi.dispatchSemanticsAction(virtualViewId, action, replyId); + Log.i(AccessibilityChannel.TAG, "dispatchSemanticsAction"); } setAccessibilityMessageHandler(handler: AccessibilityMessageHandler): void { @@ -112,9 +118,35 @@ export default class AccessibilityChannel implements MessageHandler{ } -interface AccessibilityMessageHandler extends AccessibilityDelegate { +export interface AccessibilityMessageHandler extends AccessibilityDelegate { announce(message: string): void; onTap(nodeId: number): void; onLongPress(nodeId: number): void; onTooltip(nodeId: string): void; +} + +export class DefaultHandler implements AccessibilityMessageHandler { + private static TAG = "AccessibilityMessageHandler"; + announce(message: string): void { + Log.i(DefaultHandler.TAG, "handler announce."); + flutter.nativeAnnounce(message); + } + onTap(nodeId: number): void { + Log.i(DefaultHandler.TAG, "handler onTap."); + } + onLongPress(nodeId: number): void { + Log.i(DefaultHandler.TAG, "handler onLongPress."); + } + onTooltip(nodeId: string): void { + Log.i(DefaultHandler.TAG, "handler onTooltip."); + } + updateSemantics(buffer: ByteBuffer, strings: string[], stringAttributeArgs: ByteBuffer[]): void { + Log.i(DefaultHandler.TAG, "handler updateSemantics"); + } + updateCustomAccessibilityActions(buffer: ByteBuffer, strings: string[]): void { + Log.i(DefaultHandler.TAG, "handler updateCustomAccessibilityActions"); + } + accessibilityStateChange(state: Boolean): void{ + Log.i(DefaultHandler.TAG, "handler accessibilityStateChange"); + } } \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/TextInputChannel.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/TextInputChannel.ets index df71b3fb156cc5220a0f76d2213783d509ba8c82..f99b0cd27f3fba243e663d187c698e04b4b44b52 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/TextInputChannel.ets +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/TextInputChannel.ets @@ -23,6 +23,9 @@ import inputMethod from '@ohos.inputMethod'; import ArrayList from '@ohos.util.ArrayList'; import { TextEditingDelta, TextEditingDeltaJson } from '../../../plugin/editing/TextEditingDelta'; import Any from '../../../plugin/common/Any'; +import { display } from '@kit.ArkUI' +import { window } from '@kit.ArkUI'; +import { BusinessError, print } from '@kit.BasicServicesKit'; const TAG = "TextInputChannel"; /// 规避换行标识无法显示问题,api修改后再删除 @@ -37,9 +40,10 @@ export default class TextInputChannel { this.channel = new MethodChannel(dartExecutor, TextInputChannel.CHANNEL_NAME, JSONMethodCodec.INSTANCE); } - setTextInputMethodHandler(textInputMethodHandler: TextInputMethodHandler): void { + setTextInputMethodHandler(textInputMethodHandler: TextInputMethodHandler | null): void { this.textInputMethodHandler = textInputMethodHandler; - this.channel.setMethodCallHandler(new TextInputCallback(this.textInputMethodHandler)); + this.channel.setMethodCallHandler(textInputMethodHandler == null + ? null : new TextInputCallback(textInputMethodHandler)); } requestExistingInputState(): void { @@ -178,10 +182,14 @@ export interface TextInputMethodHandler { setEditableSizeAndTransform(width: number, height: number, transform: number[]): void; + setCursorSizeAndPosition(cursorInfo: inputMethod.CursorInfo): void; + setEditingState(editingState: TextEditState): void; clearClient(): void; + handleChangeFocus(focusState: boolean): void; + } export class Configuration { @@ -422,11 +430,53 @@ export class TextEditState { class TextInputCallback implements MethodCallHandler { textInputMethodHandler: TextInputMethodHandler; - + windowPosition: window.Rect = { + left: 0, + top: 0, + width: 0, + height: 0, + }; + cursorPosition: window.Rect = { + left: 0, + top: 0, + width: 0, + height: 0, + } + devicePixelRatio = display.getDefaultDisplaySync()?.densityPixels as number; + inputPosotion: window.Rect = { + left: 0, + top: 0, + width: 0, + height: 0, + } + isListenWindow: boolean = false; constructor(handler: TextInputMethodHandler) { this.textInputMethodHandler = handler; } + setCursorPosition() { + if (!this.isListenWindow) { + this.isListenWindow = true; + const context = getContext(this) as Context + window.getLastWindow(context, (err: BusinessError, data: window.Window) => { + this.windowPosition = data.getWindowProperties().windowRect as window.Rect; + data.on('windowRectChange', (rect: window.RectChangeOptions) => { + this.windowPosition = rect.rect as window.Rect; + this.setCursorPosition(); + }) + }) + } + const left = (this.windowPosition.left as number) + (this.cursorPosition.left + this.inputPosotion.left) * this.devicePixelRatio; + const top = (this.windowPosition.top as number) + (this.cursorPosition.top + this.inputPosotion.top) * this.devicePixelRatio; + this.textInputMethodHandler.setCursorSizeAndPosition({ + left: left, + top: top, + width: 100, + height: 50, + }) + } + + onMethodCall(call: MethodCall, result: MethodResult) { if (this.textInputMethodHandler == null) { return; @@ -464,9 +514,17 @@ class TextInputCallback implements MethodCallHandler { this.textInputMethodHandler.setEditingState(TextEditState.fromJson(args)); result.success(null); break; + case "TextInput.setCaretRect": + this.cursorPosition.top = args.get('y'); + this.cursorPosition.left = args.get('x'); + this.cursorPosition.width = args.get('width'); + this.cursorPosition.height = args.get('height'); + this.setCursorPosition(); + break; case "TextInput.setEditableSizeAndTransform": - //TODO: - result.notImplemented(); + this.inputPosotion.left = args.get('transform')[12]; + this.inputPosotion.top = args.get('transform')[13]; + this.setCursorPosition(); break; case "TextInput.clearClient": this.textInputMethodHandler.clearClient(); diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/EmbeddingNodeController.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/EmbeddingNodeController.ets index a06563f14f4cfe05125abfe315ad3b5c3a738864..b41df1b44d3daacae6530d285ddbcb01ee3ceba6 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/EmbeddingNodeController.ets +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/EmbeddingNodeController.ets @@ -30,7 +30,8 @@ declare class nodeControllerParams { const TAG = 'EmbeddingNodeController' export class EmbeddingNodeController extends NodeController { - private rootNode: BuilderNode<[Params]> | undefined | null = null; + private rootNode : FrameNode | null = null; + private builderNode : BuilderNode<[Params]> | undefined | null = null; private wrappedBuilder: WrappedBuilder<[Params]> | null = null; private platformView: PlatformView | undefined = undefined; private embedId : string = ""; @@ -51,24 +52,25 @@ export class EmbeddingNodeController extends NodeController { this.direction = direction; } - makeNode(uiContext: UIContext): FrameNode | null{ - this.rootNode = new BuilderNode(uiContext, { surfaceId: this.surfaceId, type: this.renderType}); + makeNode(uiContext: UIContext): FrameNode | null { + this.rootNode = new FrameNode(uiContext); + this.builderNode = new BuilderNode(uiContext, { surfaceId: this.surfaceId, type: this.renderType }); if (this.wrappedBuilder) { - this.rootNode.build(this.wrappedBuilder, {direction: this.direction, platformView: this.platformView}); + this.builderNode.build(this.wrappedBuilder, { direction: this.direction, platformView: this.platformView }); } - return this.rootNode.getFrameNode(); + return this.builderNode.getFrameNode(); } - setBuilderNode(rootNode: BuilderNode | null): void{ - this.rootNode = rootNode; + setBuilderNode(builderNode: BuilderNode | null): void { + this.builderNode = builderNode; } - getBuilderNode(): BuilderNode<[Params]> | undefined | null{ - return this.rootNode; + getBuilderNode(): BuilderNode<[Params]> | undefined | null { + return this.builderNode; } updateNode(arg: Object): void { - this.rootNode?.update(arg); + this.builderNode?.update(arg); } getEmbedId() : string { return this.embedId; @@ -82,6 +84,22 @@ export class EmbeddingNodeController extends NodeController { } } + disposeFrameNode() { + if (this.rootNode !== null && this.builderNode !== null) { + this.rootNode.removeChild(this.builderNode?.getFrameNode()); + this.builderNode?.dispose(); + + this.rootNode.dispose(); + } + } + + removeBuilderNode() { + const rootRenderNode = this.rootNode!.getRenderNode(); + if (rootRenderNode !== null && this.builderNode !== null && this.builderNode?.getFrameNode() !== null) { + rootRenderNode.removeChild(this.builderNode!.getFrameNode()!.getRenderNode()); + } + } + postEvent(event: TouchEvent | undefined, isPx: boolean = false): boolean { if (event == undefined) { return false; @@ -117,6 +135,6 @@ export class EmbeddingNodeController extends NodeController { } } - return this.rootNode?.postTouchEvent(event) as boolean + return this.builderNode?.postTouchEvent(event) as boolean } } \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterAbility.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterAbility.ets index 4013fed1897c82c3aa82c1b8480ff80873f29af0..d13fd9859a57ae1231ceec489a091d3f84ec6a63 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,10 +36,10 @@ 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"; -const EVENT_BACK_PRESS = 'EVENT_BACK_PRESS'; /** * flutter ohos基础ability,请在让主ability继承自该类。 @@ -72,6 +72,7 @@ export class FlutterAbility extends UIAbility implements Host { async onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) { // 冷启动通过上下文环境获取到系统当前文字大小,并进行键值存储 AppStorage.setOrCreate('fontSizeScale', this.context.config.fontSizeScale); + Log.i(TAG, "this.context.config.fontSizeScale = " + this.context.config.fontSizeScale); Log.i(TAG, "bundleCodeDir=" + this.context.bundleCodeDir); FlutterManager.getInstance().pushUIAbility(this) @@ -92,10 +93,6 @@ export class FlutterAbility extends UIAbility implements Host { Log.i(TAG, 'MyAbility onCreate'); - this.context.eventHub.on(EVENT_BACK_PRESS, () => { - this.delegate?.flutterEngine?.getNavigationChannel()?.popRoute(); - this.delegate?.flutterEngine?.getPlatformViewsController()?.setBackNodeControllers(); - }); let observer:errorManager.ErrorObserver = { onUnhandledException(errorMsg) { Log.e(TAG, "onUnhandledException, errorMsg:", errorMsg); @@ -110,11 +107,18 @@ 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() { FlutterManager.getInstance().popUIAbility(this); - this.context.eventHub.off(EVENT_BACK_PRESS); + errorManager.off('error', this.errorManagerId); if (this.flutterView != null) { @@ -151,6 +155,7 @@ export class FlutterAbility extends UIAbility implements Host { case window.WindowStageEventType.ACTIVE: // 获焦状态 Log.i(TAG, 'windowStage active.'); if (this.stillAttachedForEvent("onWindowFocusChanged")) { + this.delegate?.getFlutterEngine()?.getTextInputChannel()?.textInputMethodHandler?.handleChangeFocus(true); this?.delegate?.onWindowFocusChanged(true); } break; @@ -179,7 +184,7 @@ export class FlutterAbility extends UIAbility implements Host { Log.i(TAG, 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? ''); }); - FlutterManager.getInstance().setUseFullScreen(true); + FlutterManager.getInstance().setUseFullScreen(true, this.context); } catch (exception) { Log.e(TAG, 'Failed to enable the listener for window stage event changes. Cause:' + JSON.stringify(exception)); } @@ -380,7 +385,7 @@ export class FlutterAbility extends UIAbility implements Host { .send(); //热启动生命周期内,实时监听系统设置环境改变并实时发送相应信息 //实时获取系统字体加粗系数 - this.delegate?.getFlutterNapi()?.setFontWeightScale(config.fontWeightScale == undefined? 0 : config.fontWeightScale); + this.delegate?.getFlutterNapi()?.setFontWeightScale(config.fontWeightScale == undefined? 1.0 : config.fontWeightScale); Log.i(TAG, 'fontWeightScale: ' + JSON.stringify(config.fontWeightScale)); if (config.language != '') { diff --git a/shell/platform/ohos/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 480371d80703aafa8be51b208ed052bb921375bc..df567109745d0c2624d6c72283b277c67e13547c 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 @@ -27,7 +27,6 @@ import FlutterInjector from '../../FlutterInjector'; import UIAbility from '@ohos.app.ability.UIAbility'; import ExclusiveAppComponent from './ExclusiveAppComponent'; import AbilityConstant from '@ohos.app.ability.AbilityConstant'; -import TextInputPlugin from '../../plugin/editing/TextInputPlugin'; import { FlutterPlugin } from '../engine/plugins/FlutterPlugin'; import FlutterEngineCache from '../engine/FlutterEngineCache'; import FlutterEngineGroupCache from '../engine/FlutterEngineGroupCache'; @@ -36,10 +35,12 @@ 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"; const FRAMEWORK_RESTORATION_BUNDLE_KEY = "framework"; +const EVENT_BACK_PRESS = 'EVENT_BACK_PRESS'; /** * 主要职责: @@ -51,11 +52,11 @@ class FlutterAbilityAndEntryDelegate implements ExclusiveAppComponent flutterEngine?: FlutterEngine | null; platformPlugin?: PlatformPlugin; protected context?: common.Context; - protected textInputPlugin?: TextInputPlugin; protected isFlutterEngineFromHostOrCache: boolean = false; private engineGroup?: FlutterEngineGroup; private isHost:boolean = false; - private flutterView?: FlutterView + private flutterView?: FlutterView; + private inputMethodController: inputMethod.InputMethodController = inputMethod.getController(); constructor(host?: Host) { this.host = host; @@ -87,13 +88,20 @@ class FlutterAbilityAndEntryDelegate implements ExclusiveAppComponent //configureFlutterEngine this.isAttached = true; if (this.flutterEngine) { - this.textInputPlugin = new TextInputPlugin(this.flutterEngine.getTextInputChannel()!); this.flutterEngine.getSystemLanguages(); } if (this.flutterEngine && this.flutterView && this.host?.attachToEngineAutomatically()) { this.flutterView.attachToFlutterEngine(this.flutterEngine!!); } this.host?.configureFlutterEngine(this.flutterEngine!!); + this.context.eventHub.on(EVENT_BACK_PRESS, () => { + if (this.flutterView?.getKeyboardHeight() == 0) { + this.flutterEngine?.getNavigationChannel()?.popRoute(); + this.flutterEngine?.getPlatformViewsController()?.setBackNodeControllers(); + } else { + this.inputMethodController.detach(); + } + }); } /** @@ -271,7 +279,6 @@ class FlutterAbilityAndEntryDelegate implements ExclusiveAppComponent release() { this.host = null; this.flutterEngine = null; - this.textInputPlugin = undefined; this.platformPlugin = undefined; } @@ -302,6 +309,7 @@ class FlutterAbilityAndEntryDelegate implements ExclusiveAppComponent } this.isAttached = false; + this.context?.eventHub.off(EVENT_BACK_PRESS); } onLowMemory(): void { 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 124eb6488d1a9d8062a3d9133f34564e798cd57d..38f0192ea066838fc8578c64bd7212ccd363e3ad 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 @@ -75,6 +75,7 @@ export default class FlutterEntry implements Host { break; case window.WindowStageEventType.ACTIVE: // 获焦状态 Log.i(TAG, 'windowStage active.'); + this.delegate?.getFlutterEngine()?.getTextInputChannel()?.textInputMethodHandler?.handleChangeFocus(true); this?.delegate?.onWindowFocusChanged(true); break; case window.WindowStageEventType.INACTIVE: // 失焦状态 diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterManager.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterManager.ets index e2ef4d772b4210ec6d6921108fbfdbc413c901bf..b3e2f0598ce95f13ec55d14b9ba3a46e346727a0 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterManager.ets +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterManager.ets @@ -18,6 +18,8 @@ import { FlutterView } from '../../view/FlutterView'; import UIAbility from '@ohos.app.ability.UIAbility'; import window from '@ohos.window'; import Log from '../../util/Log'; +import HashMap from '@ohos.util.HashMap'; +import List from '@ohos.util.List'; const TAG = "FlutterManager" @@ -37,6 +39,76 @@ export default class FlutterManager { private windowStageList = new Map(); private mFullScreenListener: FullScreenListener = new DefaultFullScreenListener(); + private dragEnterCbId: number = 1; + private dragMoveCbId: number = 1; + private dragLeaveCbId: number = 1; + private dropCbId: number = 1; + + private dragEnterCbs: HashMap = new HashMap(); + private dragMoveCbs: HashMap = new HashMap(); + private dragLeaveCbs: HashMap = new HashMap(); + private dropCbs: HashMap = new HashMap(); + + private getValuesFromMap(map: HashMap): List { + let list: List = new List(); + map.forEach((value, key) => { + list.add(value); + }); + return list; + } + + getDragEnterCbs(): List { + return this.getValuesFromMap(this.dragEnterCbs); + } + + getDragMoveCbs(): List { + return this.getValuesFromMap(this.dragMoveCbs); + } + + getDragLeaveCbs(): List { + return this.getValuesFromMap(this.dragLeaveCbs); + } + + getDropCbs(): List { + return this.getValuesFromMap(this.dropCbs); + } + + addDragEnterCb(callback: DragDropCallback): number { + this.dragEnterCbs.set(this.dragEnterCbId, callback); + return this.dragEnterCbId++; + } + + addDragMoveCb(callback: DragDropCallback): number { + this.dragMoveCbs.set(this.dragMoveCbId, callback); + return this.dragMoveCbId++; + } + + addDragLeaveCb(callback: DragDropCallback): number { + this.dragLeaveCbs.set(this.dragLeaveCbId, callback); + return this.dragLeaveCbId++; + } + + addDropCb(callback: DragDropCallback): number { + this.dropCbs.set(this.dropCbId, callback); + return this.dropCbId++; + } + + removeDragEnterCb(id: number) { + this.dragEnterCbs.remove(id); + } + + removeDragMoveCb(id: number) { + this.dragMoveCbs.remove(id); + } + + removeDragLeaveCb(id: number) { + this.dragLeaveCbs.remove(id); + } + + removeDropCb(id: number) { + this.dropCbs.remove(id); + } + pushUIAbility(uiAbility: UIAbility) { this.uiAbilityList.push(uiAbility); } @@ -109,8 +181,8 @@ export default class FlutterManager { return this.mFullScreenListener; } - setUseFullScreen(use: boolean) { - this.mFullScreenListener.setUseFullScreen(use) + setUseFullScreen(use: boolean, context?: Context | null | undefined) { + this.mFullScreenListener.setUseFullScreen(use, context); } useFullScreen(): boolean { @@ -118,9 +190,13 @@ export default class FlutterManager { } } +export interface DragDropCallback { + do(event: DragEvent, extraParams: string): void; +} + export interface FullScreenListener { useFullScreen(): boolean; - setUseFullScreen(useFullScreen: boolean): void; + setUseFullScreen(useFullScreen: boolean, context?: Context | null | undefined): void; onScreenStateChanged(data: window.WindowStatusType): void; } @@ -132,12 +208,13 @@ export class DefaultFullScreenListener implements FullScreenListener { return this.fullScreen; } - setUseFullScreen(useFullScreen: boolean): void { + setUseFullScreen(useFullScreen: boolean, context?: Context | null | undefined): void { this.fullScreen = useFullScreen; this.skipCheck = true; + context = context??getContext(this); let window = FlutterManager.getInstance() - .getWindowStage(FlutterManager.getInstance().getUIAbility(getContext(this))); + .getWindowStage(FlutterManager.getInstance().getUIAbility(context)); window.getMainWindowSync().setWindowLayoutFullScreen(useFullScreen); Log.i(TAG, "WindowLayoutFullScreen is on") } 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 1634db5f6fdfad4be355fa193fb052a83844f491..f5f641c4ec630bab11a5906ae3928c4ba8b0821e 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 @@ -61,6 +61,7 @@ export struct FlutterPage { Log.d(TAG, "XComponent onDestroy "); this.flutterView?.onSurfaceDestroyed() }) + .renderFit(RenderFit.TOP_LEFT) .backgroundColor(Color.Transparent) if (this.showSplashScreen) { @@ -79,9 +80,34 @@ export struct FlutterPage { } }) .onKeyPreIme((event: KeyEvent) => { - Log.d(TAG, "onKeyEvent " + event.type); - this.flutterView?.onKeyEvent(event); - return false; + return this.flutterView?.onKeyPreIme(event) ?? false; + }) + .onKeyEvent((event: KeyEvent) => { + return this.flutterView?.onKeyEvent(event) ?? false; + }) + .onDragEnter((event: DragEvent, extraParams: string) => { + FlutterManager.getInstance().getDragEnterCbs().forEach(dragEnterCb => { + dragEnterCb.do(event, extraParams); + }); + Log.d(TAG, "onDragEnter"); + }) + .onDragMove((event: DragEvent, extraParams: string) => { + FlutterManager.getInstance().getDragMoveCbs().forEach(dragMoveCb => { + dragMoveCb.do(event, extraParams); + }); + Log.d(TAG, "onDragMove"); + }) + .onDragLeave((event: DragEvent, extraParams: string) => { + FlutterManager.getInstance().getDragLeaveCbs().forEach(dragLeaveCb => { + dragLeaveCb.do(event, extraParams); + }); + Log.d(TAG, "onDragLeave"); + }) + .onDrop((event: DragEvent, extraParams: string) => { + FlutterManager.getInstance().getDropCbs().forEach(dropCb => { + dropCb.do(event, extraParams); + }); + Log.d(TAG, "onDrop"); }) } @Builder mouseWheelPage() { @@ -114,6 +140,7 @@ export struct FlutterPage { Log.d(TAG, "XComponent onDestroy "); this.flutterView?.onSurfaceDestroyed() }) + .renderFit(RenderFit.TOP_LEFT) .backgroundColor(Color.Transparent) if (this.showSplashScreen) { @@ -132,9 +159,34 @@ export struct FlutterPage { } }) .onKeyPreIme((event: KeyEvent) => { - Log.d(TAG, "onKeyEvent " + event.type); - this.flutterView?.onKeyEvent(event); - return false; + return this.flutterView?.onKeyPreIme(event) ?? false; + }) + .onKeyEvent((event: KeyEvent) => { + return this.flutterView?.onKeyEvent(event) ?? false; + }) + .onDragEnter((event: DragEvent, extraParams: string) => { + FlutterManager.getInstance().getDragEnterCbs().forEach(dragEnterCb => { + dragEnterCb.do(event, extraParams); + }); + Log.d(TAG, "onDragEnter"); + }) + .onDragMove((event: DragEvent, extraParams: string) => { + FlutterManager.getInstance().getDragMoveCbs().forEach(dragMoveCb => { + dragMoveCb.do(event, extraParams); + }); + Log.d(TAG, "onDragMove"); + }) + .onDragLeave((event: DragEvent, extraParams: string) => { + FlutterManager.getInstance().getDragLeaveCbs().forEach(dragLeaveCb => { + dragLeaveCb.do(event, extraParams); + }); + Log.d(TAG, "onDragLeave"); + }) + .onDrop((event: DragEvent, extraParams: string) => { + FlutterManager.getInstance().getDropCbs().forEach(dropCb => { + dropCb.do(event, extraParams); + }); + Log.d(TAG, "onDrop"); }) .gesture( PanGesture(this.panOption) @@ -183,7 +235,7 @@ export struct FlutterPage { aboutToDisappear() { this.flutterView?.removeFirstFrameListener(this); - getContext().eventHub.off(OHOS_FLUTTER_PAGE_UPDATE) + getContext()?.eventHub.off(OHOS_FLUTTER_PAGE_UPDATE) } onFirstFrame() { diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/KeyEventHandler.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/KeyEventHandler.ets new file mode 100644 index 0000000000000000000000000000000000000000..58133fd461d8669580f47c2358ae33739957c70d --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/KeyEventHandler.ets @@ -0,0 +1,164 @@ +/* + * 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. + */ + +import { HashMap } from "@kit.ArkTS"; +import deviceInfo from '@ohos.deviceInfo'; +import TextInputPlugin from "../../plugin/editing/TextInputPlugin"; +import Log from "../../util/Log"; +import { KeyCode } from "@kit.InputKit"; + +const TAG = "KeyEventHandler"; + +export class KeyEventHandler { + private textInputPlugin?: TextInputPlugin; + private charMap : HashMap = new HashMap(); + private shiftMap : HashMap = new HashMap(); + private isShiftMode: boolean = false; + + constructor(textInputPlugin?: TextInputPlugin) { + this.textInputPlugin = textInputPlugin; + this.initCharMap(); + this.initShiftMap(); + } + + private initCharMap() { + this.charMap.set(KeyCode.KEYCODE_0, '0') + this.charMap.set(KeyCode.KEYCODE_1, '1') + this.charMap.set(KeyCode.KEYCODE_2, '2') + this.charMap.set(KeyCode.KEYCODE_3, '3') + this.charMap.set(KeyCode.KEYCODE_4, '4') + this.charMap.set(KeyCode.KEYCODE_5, '5') + this.charMap.set(KeyCode.KEYCODE_6, '6') + this.charMap.set(KeyCode.KEYCODE_7, '7') + this.charMap.set(KeyCode.KEYCODE_8, '8') + this.charMap.set(KeyCode.KEYCODE_9, '9') + this.charMap.set(KeyCode.KEYCODE_A, 'a') + this.charMap.set(KeyCode.KEYCODE_B, 'b') + this.charMap.set(KeyCode.KEYCODE_C, 'c') + this.charMap.set(KeyCode.KEYCODE_D, 'd') + this.charMap.set(KeyCode.KEYCODE_E, 'e') + this.charMap.set(KeyCode.KEYCODE_F, 'f') + this.charMap.set(KeyCode.KEYCODE_G, 'g') + this.charMap.set(KeyCode.KEYCODE_H, 'h') + this.charMap.set(KeyCode.KEYCODE_I, 'i') + this.charMap.set(KeyCode.KEYCODE_J, 'j') + this.charMap.set(KeyCode.KEYCODE_K, 'k') + this.charMap.set(KeyCode.KEYCODE_L, 'l') + this.charMap.set(KeyCode.KEYCODE_M, 'm') + this.charMap.set(KeyCode.KEYCODE_N, 'n') + this.charMap.set(KeyCode.KEYCODE_O, 'o') + this.charMap.set(KeyCode.KEYCODE_P, 'p') + this.charMap.set(KeyCode.KEYCODE_Q, 'q') + this.charMap.set(KeyCode.KEYCODE_R, 'r') + this.charMap.set(KeyCode.KEYCODE_S, 's') + this.charMap.set(KeyCode.KEYCODE_T, 't') + this.charMap.set(KeyCode.KEYCODE_U, 'u') + this.charMap.set(KeyCode.KEYCODE_V, 'v') + this.charMap.set(KeyCode.KEYCODE_W, 'w') + this.charMap.set(KeyCode.KEYCODE_X, 'x') + this.charMap.set(KeyCode.KEYCODE_Y, 'y') + this.charMap.set(KeyCode.KEYCODE_Z, 'z') + this.charMap.set(KeyCode.KEYCODE_GRAVE, '`') + this.charMap.set(KeyCode.KEYCODE_MINUS, '-') + this.charMap.set(KeyCode.KEYCODE_EQUALS, '=') + this.charMap.set(KeyCode.KEYCODE_LEFT_BRACKET, '[') + this.charMap.set(KeyCode.KEYCODE_RIGHT_BRACKET, ']') + this.charMap.set(KeyCode.KEYCODE_BACKSLASH, '\\') + this.charMap.set(KeyCode.KEYCODE_SEMICOLON, ';') + this.charMap.set(KeyCode.KEYCODE_APOSTROPHE, '\'') + this.charMap.set(KeyCode.KEYCODE_COMMA, ',') + this.charMap.set(KeyCode.KEYCODE_PERIOD, '.') + this.charMap.set(KeyCode.KEYCODE_SLASH, '/') + this.charMap.set(KeyCode.KEYCODE_SPACE, ' ') + } + + private initShiftMap() { + this.shiftMap.set(KeyCode.KEYCODE_0, ')') + this.shiftMap.set(KeyCode.KEYCODE_1, '!') + this.shiftMap.set(KeyCode.KEYCODE_2, '@') + this.shiftMap.set(KeyCode.KEYCODE_3, '#') + this.shiftMap.set(KeyCode.KEYCODE_4, '$') + this.shiftMap.set(KeyCode.KEYCODE_5, '%') + this.shiftMap.set(KeyCode.KEYCODE_6, '^') + this.shiftMap.set(KeyCode.KEYCODE_7, '&') + this.shiftMap.set(KeyCode.KEYCODE_8, '*') + this.shiftMap.set(KeyCode.KEYCODE_9, '(') + this.shiftMap.set(KeyCode.KEYCODE_A, 'A') + this.shiftMap.set(KeyCode.KEYCODE_B, 'B') + this.shiftMap.set(KeyCode.KEYCODE_C, 'C') + this.shiftMap.set(KeyCode.KEYCODE_D, 'D') + this.shiftMap.set(KeyCode.KEYCODE_E, 'E') + this.shiftMap.set(KeyCode.KEYCODE_F, 'F') + this.shiftMap.set(KeyCode.KEYCODE_G, 'G') + this.shiftMap.set(KeyCode.KEYCODE_H, 'H') + this.shiftMap.set(KeyCode.KEYCODE_I, 'I') + this.shiftMap.set(KeyCode.KEYCODE_J, 'J') + this.shiftMap.set(KeyCode.KEYCODE_K, 'K') + this.shiftMap.set(KeyCode.KEYCODE_L, 'L') + this.shiftMap.set(KeyCode.KEYCODE_M, 'M') + this.shiftMap.set(KeyCode.KEYCODE_N, 'N') + this.shiftMap.set(KeyCode.KEYCODE_O, 'O') + this.shiftMap.set(KeyCode.KEYCODE_P, 'P') + this.shiftMap.set(KeyCode.KEYCODE_Q, 'Q') + this.shiftMap.set(KeyCode.KEYCODE_R, 'R') + this.shiftMap.set(KeyCode.KEYCODE_S, 'S') + this.shiftMap.set(KeyCode.KEYCODE_T, 'T') + this.shiftMap.set(KeyCode.KEYCODE_U, 'U') + this.shiftMap.set(KeyCode.KEYCODE_V, 'V') + this.shiftMap.set(KeyCode.KEYCODE_W, 'W') + this.shiftMap.set(KeyCode.KEYCODE_X, 'X') + this.shiftMap.set(KeyCode.KEYCODE_Y, 'Y') + this.shiftMap.set(KeyCode.KEYCODE_Z, 'Z') + this.shiftMap.set(KeyCode.KEYCODE_GRAVE, '~') + this.shiftMap.set(KeyCode.KEYCODE_MINUS, '_') + this.shiftMap.set(KeyCode.KEYCODE_EQUALS, '+') + this.shiftMap.set(KeyCode.KEYCODE_LEFT_BRACKET, '{') + this.shiftMap.set(KeyCode.KEYCODE_RIGHT_BRACKET, '}') + this.shiftMap.set(KeyCode.KEYCODE_BACKSLASH, '|') + this.shiftMap.set(KeyCode.KEYCODE_SEMICOLON, ':') + this.shiftMap.set(KeyCode.KEYCODE_APOSTROPHE, '"') + this.shiftMap.set(KeyCode.KEYCODE_COMMA, '<') + this.shiftMap.set(KeyCode.KEYCODE_PERIOD, '>') + this.shiftMap.set(KeyCode.KEYCODE_SLASH, '?') + this.shiftMap.set(KeyCode.KEYCODE_SPACE, ' ') + } + + getCharByEvent(event: KeyEvent) : string { + let key = event.keyCode; + if (this.isShiftMode) { + return this.shiftMap.hasKey(key) ? this.shiftMap.get(key) : '' + } else { + return this.charMap.hasKey(key) ? this.charMap.get(key) : '' + } + } + + handleKeyEvent(event: KeyEvent) { + Log.i(TAG, JSON.stringify({ + "name": "handleKeyEvent", + "event": event + })); + if (event.type == KeyType.Up) { + // 处理字符按键相关逻辑 + if (this.charMap.hasKey(event.keyCode)) { + this.textInputPlugin?.getEditingState().handleInsertTextEvent(this.getCharByEvent(event)) + } + // 处理非字符按键 + if (event.keyCode == KeyCode.KEYCODE_DEL) { + this.textInputPlugin?.getEditingState().handleDeleteEvent(false, 0) + } + } + this.isShiftMode = event.keyCode == KeyCode.KEYCODE_SHIFT_LEFT + } +} diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/KeyboardManager.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/KeyboardManager.ets index ec4a02ff789087a3afd90f1a850d295856243e24..21b5c88934ba7443f6dc5ead7fd8974e40db2ac3 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/KeyboardManager.ets +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/KeyboardManager.ets @@ -12,21 +12,31 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import TextInputPlugin from '../../plugin/editing/TextInputPlugin'; import FlutterEngine from '../engine/FlutterEngine'; import KeyEventChannel, { FlutterKeyEvent } from '../engine/systemchannels/KeyEventChannel'; +import { KeyEventHandler } from './KeyEventHandler'; export default class KeyboardManager { private keyEventChannel: KeyEventChannel | null = null + private keyEventHandler: KeyEventHandler; - constructor(engine: FlutterEngine) { + constructor(engine: FlutterEngine, textInputPlugin: TextInputPlugin) { this.keyEventChannel = new KeyEventChannel(engine.dartExecutor) + this.keyEventHandler = new KeyEventHandler(textInputPlugin); } - handleKeyEvent(event: KeyEvent) { + onKeyPreIme(event: KeyEvent) : boolean { this.keyEventChannel?.sendFlutterKeyEvent(new FlutterKeyEvent(event), event.type == KeyType.Up, { onFrameworkResponse: (isEventHandled: boolean): void => { } }) + return false; + } + + onKeyEvent(event: KeyEvent) : boolean { + this.keyEventHandler.handleKeyEvent(event); + return false; } } \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/PlatformPlugin.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/PlatformPlugin.ets index 949480ec65afe8315844cc6b625392e83f9cea49..500390aeb93de65c2cd3eabe284126c1a47918e7 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/PlatformPlugin.ets +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/PlatformPlugin.ets @@ -279,13 +279,13 @@ export class PlatformPluginCallback implements PlatformMessageHandler { let uiConfig: ('status' | 'navigation')[] = []; if (mode == SystemUiMode.LEAN_BACK) { //全屏显示,通过点击显示器上的任何位置都可以显示状态和导航栏 - FlutterManager.getInstance().setUseFullScreen(true); + FlutterManager.getInstance().setUseFullScreen(true, null); } else if (mode == SystemUiMode.IMMERSIVE) { //全屏显示,通过在显示器边缘的滑动手势可以显示状态和导航栏,应用程序不会接收到此手势 - FlutterManager.getInstance().setUseFullScreen(true); + FlutterManager.getInstance().setUseFullScreen(true, null); } else if (mode == SystemUiMode.IMMERSIVE_STICKY) { //全屏显示,通过在显示器边缘的滑动手势可以显示状态和导航栏,此手势由应用程序接收 - FlutterManager.getInstance().setUseFullScreen(true); + FlutterManager.getInstance().setUseFullScreen(true, null); } else if (mode == SystemUiMode.EDGE_TO_EDGE) { uiConfig = ['status', 'navigation']; } else { 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 2d5c4ac2a3126a34a95acdfd54605be16dc2b005..5f3a67c3628f4209dce770b382a28fc442b66431 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 @@ -22,6 +22,7 @@ import inputMethod from '@ohos.inputMethod'; import Log from '../../util/Log'; import { EditingStateWatcher, ListenableEditingState } from './ListenableEditingState'; import Any from '../common/Any'; +import { inputDevice } from '@kit.InputKit'; /// 临时规避缺少newline对应枚举问题 const NEWLINE_KEY_TYPE: number = 8; @@ -45,6 +46,10 @@ export default class TextInputPlugin implements EditingStateWatcher { } + getEditingState() { + return this.mTextInputHandler.mEditable; + } + didChangeEditingState(textChanged: boolean, selectionChanged: boolean, composingRegionChanged: boolean): void { let editable = this.mTextInputHandler.mEditable; let inputTarget = this.mTextInputHandler.inputTarget; @@ -67,6 +72,10 @@ export default class TextInputPlugin implements EditingStateWatcher { } }) } + + destroy() { + this.textInputChannel.setTextInputMethodHandler(null); + } } class TextInputMethodHandlerImpl implements TextInputMethodHandler { @@ -82,6 +91,7 @@ class TextInputMethodHandlerImpl implements TextInputMethodHandler { private inputTypeNone: string = 'NONE'; private keyboardStatus: inputMethod.KeyboardStatus = inputMethod.KeyboardStatus.HIDE; private inputAttribute: inputMethod.InputAttribute = { textInputType: 0, enterKeyType: 1 }; + private keyboardFocusState: boolean = false constructor(plugin: TextInputPlugin | Any) { this.textConfig = { @@ -96,6 +106,7 @@ class TextInputMethodHandlerImpl implements TextInputMethodHandler { /// 通过判断是否是TextInputType.none来决定是否弹出键盘 show(): void { if (this.canShowTextInput()) { + this.keyboardFocusState = true; this.showTextInput(); } else { this.hide(); @@ -103,6 +114,7 @@ class TextInputMethodHandlerImpl implements TextInputMethodHandler { } hide(): void { + this.keyboardFocusState = false; this.hideTextInput(); } @@ -127,6 +139,10 @@ class TextInputMethodHandlerImpl implements TextInputMethodHandler { } + setCursorSizeAndPosition(cursorInfo: inputMethod.CursorInfo) { + this.inputMethodController.updateCursor(cursorInfo) + } + setEditingState(editingState: TextEditState): void { Log.d(TextInputMethodHandlerImpl.TAG, "text:" + editingState.text + " selectionStart:" + editingState.selectionStart + " selectionEnd:" @@ -163,6 +179,31 @@ class TextInputMethodHandlerImpl implements TextInputMethodHandler { } } + handleChangeFocus(focusState: boolean) { + try { + inputDevice.getDeviceList((Error: Error, ids: Array) => { + let isPhysicalKeyboard = false; + for (let i = 0; i < ids.length; i++) { + const type = inputDevice.getKeyboardTypeSync(ids[i]); + if (type == inputDevice.KeyboardType.ALPHABETIC_KEYBOARD || type == inputDevice.KeyboardType.DIGITAL_KEYBOARD) { + isPhysicalKeyboard = true; + break; + } + } + + if(focusState && isPhysicalKeyboard && this.keyboardFocusState) { + this.cancelListenKeyBoardEvent(); + this.inputMethodController.detach().then(async () =>{ + await this.attach(true); + this.listenKeyBoardEvent(); + }) + } + }) + } catch (error) { + Log.e(TextInputMethodHandlerImpl.TAG, `Failed to query device. Code is ${error.code}, message is ${error.message}`) + } + } + async updateAttribute(): Promise { if (this.keyboardStatus != inputMethod.KeyboardStatus.SHOW) { return; @@ -293,12 +334,12 @@ class TextInputMethodHandlerImpl implements TextInputMethodHandler { } cancelListenKeyBoardEvent(): void { - this.inputMethodController.off('insertText', this.insertTextCallback); - this.inputMethodController.off('deleteLeft', this.deleteLeftCallback); - this.inputMethodController.off('deleteRight', this.deleteRightCallback); - this.inputMethodController.off('sendFunctionKey', this.sendFunctionKeyCallback); - this.inputMethodController.off('sendKeyboardStatus', this.sendKeyboardStatusCallback); - this.inputMethodController.off('selectByRange', this.selectByRangeCallback); + this.inputMethodController?.off('insertText', this.insertTextCallback); + this.inputMethodController?.off('deleteLeft', this.deleteLeftCallback); + this.inputMethodController?.off('deleteRight', this.deleteRightCallback); + this.inputMethodController?.off('sendFunctionKey', this.sendFunctionKeyCallback); + this.inputMethodController?.off('sendKeyboardStatus', this.sendKeyboardStatusCallback); + this.inputMethodController?.off('selectByRange', this.selectByRangeCallback); this.imcFlag = false; } diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/platform/AccessibilityEventsDelegate.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/platform/AccessibilityEventsDelegate.ets index ea9450d4aa0f140dceeb4a7925f46383a65d0ea3..aae15ba935e29f71d8f734b5505b8236b49af2d7 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/platform/AccessibilityEventsDelegate.ets +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/platform/AccessibilityEventsDelegate.ets @@ -32,7 +32,7 @@ export class AccessibilityEventsDelegate { return true; } - setAccessibilityBridge (accessibilityBridge: AccessibilityBridge): void { + setAccessibilityBridge (accessibilityBridge: AccessibilityBridge | null): void { this.accessibilityBridge = accessibilityBridge; } } \ No newline at end of file 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 e0552a797a4549025b5fe333704281f5de1492cf..5c929c84186bf8f3e27de4978f6e83107b079e9e 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 @@ -113,11 +113,11 @@ export default class PlatformViewsController implements PlatformViewsAccessibili } attachAccessibilityBridge(accessibilityBridge: AccessibilityBridge): void { - throw new Error('Method not implemented.'); + this.accessibilityEventsDelegate.setAccessibilityBridge(accessibilityBridge); } detachAccessibilityBridge(): void { - throw new Error('Method not implemented.'); + this.accessibilityEventsDelegate.setAccessibilityBridge(null); } createForPlatformViewLayer(request: PlatformViewCreationRequest): void { @@ -142,21 +142,23 @@ export default class PlatformViewsController implements PlatformViewsAccessibili this.textureRegistry!.unregisterTexture(textureId); } - try { - platformView.dispose(); - } catch (err) { - Log.e(TAG, "Disposing platform view threw an exception", err); - } - let viewWrapper: PlatformViewWrapper | null = this.viewWrappers.get(viewId) || null; if (viewWrapper != null) { - this.viewIdWithNodeController.get(viewId)?.setDestroy(true) + this.viewIdWithNodeController.get(viewId)?.removeBuilderNode() + this.viewIdWithNodeController.get(viewId)?.disposeFrameNode() + this.viewIdWithNodeController.delete(viewId); if (this.flutterView) { let index = this.flutterView.getDVModel().children.indexOf(viewWrapper.getDvModel()!); this.flutterView.getDVModel().children.splice(index, 1); } this.viewWrappers.delete(viewId); } + + try { + platformView.dispose(); + } catch (err) { + Log.e(TAG, "Disposing platform view threw an exception", err); + } } setParams: (params: DVModelParameters, key: string, element: Any ) => void = (params: DVModelParameters, key: string, element: Any): void => { @@ -177,7 +179,7 @@ export default class PlatformViewsController implements PlatformViewsAccessibili let viewWrapper = this.viewWrappers.get(request.viewId) let params: DVModelParameters | undefined = viewWrapper?.getDvModel()!.params - + this.setParams(params!, "width", physicalWidth); this.setParams(params!, "height", physicalHeight); @@ -480,9 +482,21 @@ export default class PlatformViewsController implements PlatformViewsAccessibili return; } } - + public render(surfaceId: number, platformView: PlatformView, width: number, height: number, left: number, top: number) { + + let wrapper = this.viewWrappers.get(surfaceId); + if (wrapper != null) { + let params: DVModelParameters | undefined = wrapper?.getDvModel()!.params + + this.setParams(params!, "width", width); + this.setParams(params!, "height", height); + this.setParams(params!, "left", left); + this.setParams(params!, "top", top); + return; + } + this.flutterView!.setSurfaceId(surfaceId.toString()); let wrappedBuilder: WrappedBuilder<[Params]> = platformView.getView(); this.flutterView?.setWrappedBuilder(wrappedBuilder); @@ -491,8 +505,7 @@ export default class PlatformViewsController implements PlatformViewsAccessibili let nodeController = new EmbeddingNodeController(); nodeController.setRenderOption(platformView, surfaceId.toString(), NodeRenderType.RENDER_TYPE_TEXTURE, Direction.Auto); - - this.nodeControllers.push(nodeController); + this.viewIdWithNodeController.set(surfaceId, nodeController); let dvModel = createDVModelFromJson(new DVModelJson("NodeContainer", [], @@ -510,5 +523,6 @@ export default class PlatformViewsController implements PlatformViewsAccessibili viewWrapper.addDvModel(dvModel); this.viewWrappers.set(surfaceId, viewWrapper); this.flutterView?.getDVModel().children.push(viewWrapper.getDvModel()); + this.platformViews.set(surfaceId, platformView!); } } \ No newline at end of file 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 cff9525630a7e0f25ba539247eee391362ddcb79..c7122f48701bd5fa6365bcb72e97a38b460ef132 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 @@ -12,17 +12,52 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import AccessibilityChannel from '../embedding/engine/systemchannels/AccessibilityChannel'; +import AccessibilityChannel, {AccessibilityMessageHandler} from '../embedding/engine/systemchannels/AccessibilityChannel'; import { ByteBuffer } from '../util/ByteBuffer'; import Log from '../util/Log'; const TAG = "AccessibilityBridge"; -export default class AccessibilityBridge { +export default class AccessibilityBridge implements AccessibilityMessageHandler { private accessibilityChannel: AccessibilityChannel | null = null; - constructor(){} + 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 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 3924d55c20703ef1c60121bec2818978ccb80a94..c8b2fd67425f49e057dd98f78fe0623c9a08ed6d 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 @@ -25,6 +25,8 @@ import ArrayList from '@ohos.util.ArrayList'; import { EmbeddingNodeController } from '../embedding/ohos/EmbeddingNodeController'; import PlatformView, { Params } from '../plugin/platform/PlatformView'; import { JSON } from '@kit.ArkTS'; +import { accessibility } from '@kit.AccessibilityKit'; +import TextInputPlugin from '../plugin/editing/TextInputPlugin'; const TAG = "FlutterViewTag"; @@ -120,6 +122,7 @@ export class FlutterView { private keyboardManager: KeyboardManager | null = null; private mainWindow: window.Window | null = null; private mouseCursorPlugin?: MouseCursorPlugin; + private textInputPlugin?: TextInputPlugin; private uiContext?: UIContext | undefined; private settings?: Settings; private mFirstFrameListeners: ArrayList; @@ -141,7 +144,6 @@ export class FlutterView { this.id = viewId this.displayInfo = display.getDefaultDisplaySync(); this.viewportMetrics.devicePixelRatio = this.displayInfo?.densityPixels; - this.mainWindow = FlutterManager.getInstance() .getWindowStage(FlutterManager.getInstance().getUIAbility(context)) .getMainWindowSync(); @@ -150,18 +152,27 @@ export class FlutterView { this.mainWindow?.on('windowSizeChange', this.windowSizeChangeCallback); this.mainWindow?.on('avoidAreaChange', this.avoidAreaChangeCallback); this.mainWindow?.on('windowStatusChange', this.windowStatusChangeCallback); + + //监听系统无障碍服务状态改变 + accessibility.on('accessibilityStateChange', (data: boolean) => { + Log.i(TAG, `subscribe accessibility state change, result: ${JSON.stringify(data)}`); + this.flutterEngine?.getFlutterNapi()?.accessibilityStateChange(data); + }); + this.mainWindow?.on('keyboardHeightChange', this.keyboardHeightChangeCallback); this.systemAvoidArea = this.mainWindow?.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM); this.navigationAvoidArea = this.mainWindow?.getWindowAvoidArea(window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR); this.gestureAvoidArea = this.mainWindow?.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM_GESTURE); this.keyboardAvoidArea = this.mainWindow?.getWindowAvoidArea(window.AvoidAreaType.TYPE_KEYBOARD); - //监听系统设置显示大小改变 + // Subscribes to display changes. Example: event that the display size is changed. try { display.on("change", ()=>{ this.displayInfo = display.getDefaultDisplaySync(); - this.viewportMetrics.devicePixelRatio = this.displayInfo?.densityPixels; - Log.i(TAG, "Display on: " + JSON.stringify(this.displayInfo)) - this.updateViewportMetrics() + if (this.viewportMetrics.devicePixelRatio != this.displayInfo?.densityPixels) { + this.viewportMetrics.devicePixelRatio = this.displayInfo?.densityPixels; + Log.i(TAG, "Display on: " + JSON.stringify(this.displayInfo)) + this.updateViewportMetrics() + } }); } catch (e) { Log.e(TAG, "displayInfo error" + JSON.stringify(e)); @@ -198,6 +209,14 @@ export class FlutterView { } }; + private keyboardHeightChangeCallback = (data: number) => { + Log.i(TAG, "keyboardHeightChangeCallback " + data); + this.keyboardAvoidArea.bottomRect.height = data; + if (this.isAttachedToFlutterEngine()) { + this.onAreaChange(null); + } + }; + getId(): string { return this.id } @@ -238,11 +257,19 @@ export class FlutterView { return this.dVModel } + getKeyboardHeight() { + return this.keyboardAvoidArea.bottomRect.height + } + onDestroy() { try { this.mainWindow?.off('windowSizeChange', this.windowSizeChangeCallback); this.mainWindow?.off('avoidAreaChange', this.avoidAreaChangeCallback); this.mainWindow?.off('windowStatusChange', this.windowStatusChangeCallback); + accessibility.off('accessibilityStateChange', (data: boolean) => { + Log.i(TAG, `unsubscribe accessibility state change, result: ${JSON.stringify(data)}`); + }); + this.mainWindow?.off('keyboardHeightChange', this.keyboardHeightChangeCallback); } catch (e) { Log.e(TAG, "mainWindow off error: " + JSON.stringify(e)); } @@ -275,7 +302,6 @@ export class FlutterView { } Log.i(TAG, "attachToFlutterEngine"); this.flutterEngine = flutterEngine; - this.keyboardManager = new KeyboardManager(flutterEngine); if (this.isSurfaceAvailableForRendering) { this.flutterEngine.getFlutterNapi().xComponentAttachFlutterEngine(this.id) } @@ -296,6 +322,8 @@ export class FlutterView { let windowId = this.mainWindow?.getWindowProperties()?.id ?? 0 this.mouseCursorPlugin = new MouseCursorPlugin(windowId, this.flutterEngine?.getMouseCursorChannel()!); + this.textInputPlugin = new TextInputPlugin(this.flutterEngine?.getTextInputChannel()!); + this.keyboardManager = new KeyboardManager(flutterEngine, this.textInputPlugin!); this.settings = new Settings(this.flutterEngine.getSettingsChannel()!); this.sendSettings(); this.isFlutterUiDisplayed = this.flutterEngine.getFlutterNapi().isDisplayingFlutterUi; @@ -317,6 +345,7 @@ export class FlutterView { this.flutterEngine?.getPlatformViewsController()?.detachFromView(); this.flutterEngine = null; this.keyboardManager = null; + this.textInputPlugin?.destroy(); } onWindowCreated() { @@ -413,7 +442,8 @@ export class FlutterView { private updateViewportMetrics(): boolean { if (this.isAttachedToFlutterEngine()) { - Log.i(TAG, 'updateViewportMetrics devicePixelRatio:' + this.viewportMetrics.devicePixelRatio) + Log.i(TAG, 'updateViewportMetrics devicePixelRatio:' + this.viewportMetrics.devicePixelRatio); + this?.flutterEngine?.getFlutterNapi()?.setViewportMetrics(this.viewportMetrics.devicePixelRatio, this.viewportMetrics.physicalWidth, this.viewportMetrics.physicalHeight, @@ -433,13 +463,17 @@ export class FlutterView { new Array(0), new Array(0), new Array(0)) - return true; + return true; } return false; } - onKeyEvent(event: KeyEvent) { - this.keyboardManager?.handleKeyEvent(event) + onKeyPreIme(event: KeyEvent) : boolean { + return this.keyboardManager?.onKeyPreIme(event) ?? false; + } + + onKeyEvent(event: KeyEvent) : boolean { + return this.keyboardManager?.onKeyEvent(event) ?? false; } onMouseWheel(eventType: string, event: PanGestureEvent) { diff --git a/shell/platform/ohos/flutter_embedding/oh-package.json5 b/shell/platform/ohos/flutter_embedding/oh-package.json5 index 6990a41a16d7d0cedbfca94edf2f197f6d33cdd5..dd166cc567287d35e89516bb40e631c8786e7836 100755 --- a/shell/platform/ohos/flutter_embedding/oh-package.json5 +++ b/shell/platform/ohos/flutter_embedding/oh-package.json5 @@ -24,6 +24,6 @@ "dependencies": { }, "devDependencies": { - "@ohos/hypium": "1.0.6" + "@ohos/hypium": "1.0.18" } } diff --git a/shell/platform/ohos/library_loader.cpp b/shell/platform/ohos/library_loader.cpp index ab9f2df807134c44bface863e2065f255af61cd3..4f7216d73ef7d48af4a53c339d42817fff345a46 100644 --- a/shell/platform/ohos/library_loader.cpp +++ b/shell/platform/ohos/library_loader.cpp @@ -17,8 +17,8 @@ #include "flutter/shell/platform/ohos/ohos_main.h" #include "napi/native_api.h" #include "napi_common.h" -#include "ohos_xcomponent_adapter.h" #include "ohos_logging.h" +#include "ohos_xcomponent_adapter.h" // namespace flutter { @@ -142,18 +142,30 @@ static napi_value Init(napi_env env, napi_value exports) { DECLARE_NAPI_FUNCTION( "nativeUpdateCustomAccessibilityActions", flutter::PlatformViewOHOSNapi::nativeUpdateCustomAccessibilityActions), - - DECLARE_NAPI_FUNCTION( + DECLARE_NAPI_FUNCTION( + "nativeAccessibilityStateChange", + flutter::PlatformViewOHOSNapi::nativeAccessibilityStateChange), + DECLARE_NAPI_FUNCTION( + "nativeAnnounce", + flutter::PlatformViewOHOSNapi::nativeAnnounce), + DECLARE_NAPI_FUNCTION( + "nativeSetSemanticsEnabled", + flutter::PlatformViewOHOSNapi::nativeSetSemanticsEnabled), + DECLARE_NAPI_FUNCTION( "nativeSetFontWeightScale", flutter::PlatformViewOHOSNapi::nativeSetFontWeightScale), - + DECLARE_NAPI_FUNCTION( + "nativeGetShellHolderId", + flutter::PlatformViewOHOSNapi::nativeGetShellHolderId), DECLARE_NAPI_FUNCTION( "nativeDecodeUtf8", flutter::PlatformViewOHOSNapi::nativeDecodeUtf8), - DECLARE_NAPI_FUNCTION( + DECLARE_NAPI_FUNCTION( "nativeLookupCallbackInformation", flutter::PlatformViewOHOSNapi::nativeLookupCallbackInformation), - + DECLARE_NAPI_FUNCTION( + "nativeGetFlutterNavigationAction", + flutter::PlatformViewOHOSNapi::nativeGetFlutterNavigationAction), DECLARE_NAPI_FUNCTION( "nativeUnicodeIsEmoji", flutter::PlatformViewOHOSNapi::nativeUnicodeIsEmoji), diff --git a/shell/platform/ohos/napi/platform_view_ohos_napi.cpp b/shell/platform/ohos/napi/platform_view_ohos_napi.cpp index f6f23e803a185c6d26cd0c1f00e05eef512baf4c..ef196b0b6c15e9ae77a4084999e21b7aa0c308eb 100644 --- a/shell/platform/ohos/napi/platform_view_ohos_napi.cpp +++ b/shell/platform/ohos/napi/platform_view_ohos_napi.cpp @@ -25,20 +25,21 @@ #include "flutter/fml/make_copyable.h" #include "flutter/fml/platform/ohos/napi_util.h" +#include "flutter/shell/platform/ohos/ohos_logging.h" #include "flutter/shell/platform/ohos/ohos_main.h" #include "flutter/shell/platform/ohos/ohos_shell_holder.h" +#include "flutter/shell/platform/ohos/ohos_xcomponent_adapter.h" #include "flutter/shell/platform/ohos/surface/ohos_native_window.h" #include "flutter/shell/platform/ohos/types.h" #include "flutter/lib/ui/plugins/callback_cache.h" #include "unicode/uchar.h" -#include "flutter/shell/platform/ohos/ohos_xcomponent_adapter.h" -#include "flutter/shell/platform/ohos/ohos_logging.h" #define OHOS_SHELL_HOLDER (reinterpret_cast(shell_holder)) namespace flutter { napi_env PlatformViewOHOSNapi::env_; std::vector PlatformViewOHOSNapi::system_languages; +int64_t PlatformViewOHOSNapi::napi_shell_holder_id_; /** * @brief send empty PlatformMessage @@ -354,6 +355,7 @@ std::vector splitString(const std::string& input, char delimiter) { return result; } + flutter::locale PlatformViewOHOSNapi::resolveNativeLocale( std::vector supportedLocales) { if (supportedLocales.empty()) { @@ -416,9 +418,10 @@ void PlatformViewOHOSNapi::DecodeImage(int64_t imageGeneratorAddress, void* inputData, size_t dataSize) { FML_DLOG(INFO) << "start decodeImage"; - platform_task_runner_->PostTask(fml::MakeCopyable( - [imageGeneratorAddress_ = imageGeneratorAddress, - inputData_ = std::move(inputData), dataSize_ = dataSize, this]() mutable { + platform_task_runner_->PostTask( + fml::MakeCopyable([imageGeneratorAddress_ = imageGeneratorAddress, + inputData_ = std::move(inputData), + dataSize_ = dataSize, this]() mutable { napi_value callbackParam[2]; callbackParam[0] = @@ -436,7 +439,9 @@ void PlatformViewOHOSNapi::DecodeImage(int64_t imageGeneratorAddress, })); } -void PlatformViewOHOSNapi::FlutterViewOnTouchEvent(std::shared_ptr touchPacketString, int size) { +void PlatformViewOHOSNapi::FlutterViewOnTouchEvent( + std::shared_ptr touchPacketString, + int size) { if (touchPacketString == nullptr) { FML_LOG(ERROR) << "Input parameter error"; return; @@ -446,11 +451,13 @@ void PlatformViewOHOSNapi::FlutterViewOnTouchEvent(std::shared_ptr( OhosMain::Get().GetSettings(), napi_facade, platform_loop); if (shell_holder->IsValid()) { - int64_t shell_holder_value = - reinterpret_cast(shell_holder.get()); + int64_t shell_holder_value = reinterpret_cast(shell_holder.get()); FML_DLOG(INFO) << "PlatformViewOHOSNapi shell_holder:" << shell_holder_value; napi_value id; @@ -502,6 +508,15 @@ napi_value PlatformViewOHOSNapi::nativeAttach(napi_env env, } } +void PlatformViewOHOSNapi::GetShellHolderId() { + FML_DLOG(INFO) << "GetShellHolderId"; + napi_status status = fml::napi::InvokeJsMethod(env_, ref_napi_obj_, + "getShellHolderId", 0, nullptr); + if (status != napi_ok) { + FML_DLOG(ERROR) << "InvokeJsMethod getShellHolderId fail "; + } +} + /** * 加载dart工程构建产物 */ @@ -579,7 +594,6 @@ napi_value PlatformViewOHOSNapi::nativeUpdateOhosAssetManager( napi_callback_info info) { LOGD("PlatformViewOHOSNapi::nativeUpdateOhosAssetManager"); - // TODO: return nullptr; } @@ -590,14 +604,14 @@ napi_value PlatformViewOHOSNapi::nativeGetPixelMap(napi_env env, napi_callback_info info) { LOGD("PlatformViewOHOSNapi::nativeGetPixelMap"); - // TODO: return nullptr; } /** * 从当前的flutterNapi复制一个新的实例 */ -napi_value PlatformViewOHOSNapi::nativeSpawn(napi_env env, napi_callback_info info) { +napi_value PlatformViewOHOSNapi::nativeSpawn(napi_env env, + napi_callback_info info) { napi_status ret; size_t argc = 6; napi_value args[6] = {nullptr}; @@ -637,12 +651,14 @@ napi_value PlatformViewOHOSNapi::nativeSpawn(napi_env env, napi_callback_info in LOGD(" initialRoute: %{public}s", initial_route.c_str()); std::vector entrypoint_args; - if (fml::napi::SUCCESS != fml::napi::GetArrayString(env, args[4], entrypoint_args)) { + if (fml::napi::SUCCESS != + fml::napi::GetArrayString(env, args[4], entrypoint_args)) { LOGE("nativeRunBundleAndSnapshotFromLibrary GetArrayString error"); return nullptr; } - std::shared_ptr napi_facade = std::make_shared(env); + std::shared_ptr napi_facade = + std::make_shared(env); napi_create_reference(env, args[5], 1, &(napi_facade->ref_napi_obj_)); auto spawned_shell_holder = OHOS_SHELL_HOLDER->Spawn( @@ -654,7 +670,9 @@ napi_value PlatformViewOHOSNapi::nativeSpawn(napi_env env, napi_callback_info in } napi_value shell_holder_id; - napi_create_int64(env, reinterpret_cast(spawned_shell_holder.release()), &shell_holder_id); + napi_create_int64(env, + reinterpret_cast(spawned_shell_holder.release()), + &shell_holder_id); return shell_holder_id; } @@ -1448,9 +1466,8 @@ napi_value PlatformViewOHOSNapi::nativeGetSystemLanguages( napi_value PlatformViewOHOSNapi::nativeInitNativeImage( napi_env env, - napi_callback_info info) -{ - FML_DLOG(INFO)<<"PlatformViewOHOSNapi::nativeInitNativeImage"; + napi_callback_info info) { + FML_DLOG(INFO) << "PlatformViewOHOSNapi::nativeInitNativeImage"; size_t argc = 3; napi_value args[3] = {nullptr}; int64_t shell_holder; @@ -1458,17 +1475,17 @@ napi_value PlatformViewOHOSNapi::nativeInitNativeImage( NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, nullptr, nullptr)); NAPI_CALL(env, napi_get_value_int64(env, args[0], &shell_holder)); NAPI_CALL(env, napi_get_value_int64(env, args[1], &textureId)); - ImageNative *imageNative = OH_Image_InitImageNative(env, args[2]); + ImageNative* imageNative = OH_Image_InitImageNative(env, args[2]); // std::unique_ptr uImage; - OHOS_SHELL_HOLDER->GetPlatformView()->RegisterExternalTextureByImage(textureId, imageNative); + OHOS_SHELL_HOLDER->GetPlatformView()->RegisterExternalTextureByImage( + textureId, imageNative); return nullptr; } napi_value PlatformViewOHOSNapi::nativeRegisterTexture( napi_env env, - napi_callback_info info) -{ - FML_DLOG(INFO)<<"PlatformViewOHOSNapi::nativeRegisterTexture"; + napi_callback_info info) { + FML_DLOG(INFO) << "PlatformViewOHOSNapi::nativeRegisterTexture"; size_t argc = 2; napi_value args[2] = {nullptr}; int64_t shell_holder; @@ -1476,7 +1493,8 @@ napi_value PlatformViewOHOSNapi::nativeRegisterTexture( NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, nullptr, nullptr)); NAPI_CALL(env, napi_get_value_int64(env, args[0], &shell_holder)); NAPI_CALL(env, napi_get_value_int64(env, args[1], &textureId)); - int64_t surfaceId = OHOS_SHELL_HOLDER->GetPlatformView()->RegisterExternalTexture(textureId); + int64_t surfaceId = + OHOS_SHELL_HOLDER->GetPlatformView()->RegisterExternalTexture(textureId); napi_value res; napi_create_int64(env, surfaceId, &res); return res; @@ -1503,10 +1521,9 @@ napi_value PlatformViewOHOSNapi::nativeSetTextureBufferSize( } napi_value PlatformViewOHOSNapi::nativeUnregisterTexture( - napi_env env, - napi_callback_info info) -{ - FML_DLOG(INFO)<<"PlatformViewOHOSNapi::nativeUnregisterTexture"; + napi_env env, + napi_callback_info info) { + FML_DLOG(INFO) << "PlatformViewOHOSNapi::nativeUnregisterTexture"; size_t argc = 2; napi_value args[2] = {nullptr}; int64_t shell_holder; @@ -1519,9 +1536,8 @@ napi_value PlatformViewOHOSNapi::nativeUnregisterTexture( } napi_value PlatformViewOHOSNapi::nativeMarkTextureFrameAvailable( - napi_env env, - napi_callback_info info) -{ + napi_env env, + napi_callback_info info) { size_t argc = 2; napi_value args[2] = {nullptr}; int64_t shell_holder; @@ -1534,10 +1550,9 @@ napi_value PlatformViewOHOSNapi::nativeMarkTextureFrameAvailable( } napi_value PlatformViewOHOSNapi::nativeRegisterPixelMap( - napi_env env, - napi_callback_info info) -{ - FML_DLOG(INFO)<<"PlatformViewOHOSNapi::nativeRegisterPixelMap"; + napi_env env, + napi_callback_info info) { + FML_DLOG(INFO) << "PlatformViewOHOSNapi::nativeRegisterPixelMap"; size_t argc = 3; napi_value args[3] = {nullptr}; int64_t shell_holder; @@ -1545,16 +1560,16 @@ napi_value PlatformViewOHOSNapi::nativeRegisterPixelMap( NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, nullptr, nullptr)); NAPI_CALL(env, napi_get_value_int64(env, args[0], &shell_holder)); NAPI_CALL(env, napi_get_value_int64(env, args[1], &textureId)); - NativePixelMap *nativePixelMap = OH_PixelMap_InitNativePixelMap(env, args[2]); - OHOS_SHELL_HOLDER->GetPlatformView()->RegisterExternalTextureByPixelMap(textureId, nativePixelMap); + NativePixelMap* nativePixelMap = OH_PixelMap_InitNativePixelMap(env, args[2]); + OHOS_SHELL_HOLDER->GetPlatformView()->RegisterExternalTextureByPixelMap( + textureId, nativePixelMap); return nullptr; } napi_value PlatformViewOHOSNapi::nativeSetTextureBackGroundPixelMap( - napi_env env, - napi_callback_info info) -{ - FML_DLOG(INFO)<<"PlatformViewOHOSNapi::nativeSetTextureBackGroundPixelMap"; + napi_env env, + napi_callback_info info) { + FML_DLOG(INFO) << "PlatformViewOHOSNapi::nativeSetTextureBackGroundPixelMap"; size_t argc = 3; napi_value args[3] = {nullptr}; int64_t shell_holder; @@ -1562,8 +1577,9 @@ napi_value PlatformViewOHOSNapi::nativeSetTextureBackGroundPixelMap( NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, nullptr, nullptr)); NAPI_CALL(env, napi_get_value_int64(env, args[0], &shell_holder)); NAPI_CALL(env, napi_get_value_int64(env, args[1], &textureId)); - NativePixelMap *nativePixelMap = OH_PixelMap_InitNativePixelMap(env, args[2]); - OHOS_SHELL_HOLDER->GetPlatformView()->SetExternalTextureBackGroundPixelMap(textureId, nativePixelMap); + NativePixelMap* nativePixelMap = OH_PixelMap_InitNativePixelMap(env, args[2]); + OHOS_SHELL_HOLDER->GetPlatformView()->SetExternalTextureBackGroundPixelMap( + textureId, nativePixelMap); return nullptr; } @@ -1598,36 +1614,41 @@ void PlatformViewOHOSNapi::SetPlatformTaskRunner( */ napi_value PlatformViewOHOSNapi::nativeXComponentAttachFlutterEngine( napi_env env, - napi_callback_info info){ - napi_status ret; - size_t argc = 2; - napi_value args[2] = {nullptr}; - std::string xcomponent_id; - int64_t shell_holder; - ret = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); - if (ret != napi_ok) { - FML_DLOG(ERROR) << "nativeXComponentAttachFlutterEngine napi_get_cb_info error:" - << ret; - return nullptr; - } + napi_callback_info info) { + napi_status ret; + size_t argc = 2; + napi_value args[2] = {nullptr}; + std::string xcomponent_id; + int64_t shell_holder; + ret = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + if (ret != napi_ok) { + FML_DLOG(ERROR) + << "nativeXComponentAttachFlutterEngine napi_get_cb_info error:" << ret; + return nullptr; + } - if (fml::napi::GetString(env, args[0], xcomponent_id) != 0) { - FML_DLOG(ERROR) << "nativeXComponentAttachFlutterEngine xcomponent_id GetString error"; - return nullptr; - } + if (fml::napi::GetString(env, args[0], xcomponent_id) != 0) { + FML_DLOG(ERROR) + << "nativeXComponentAttachFlutterEngine xcomponent_id GetString error"; + return nullptr; + } - ret = napi_get_value_int64(env, args[1], &shell_holder); - if (ret != napi_ok) { - FML_DLOG(ERROR) << "nativeXComponentAttachFlutterEngine shell_holder napi_get_value_int64 error"; - return nullptr; - } - std::string shell_holder_str = std::to_string(shell_holder); + ret = napi_get_value_int64(env, args[1], &shell_holder); + if (ret != napi_ok) { + FML_DLOG(ERROR) << "nativeXComponentAttachFlutterEngine shell_holder " + "napi_get_value_int64 error"; + return nullptr; + } + std::string shell_holder_str = std::to_string(shell_holder); - LOGD("nativeXComponentAttachFlutterEngine xcomponent_id: %{public}s, shell_holder: %{public}ld ", - xcomponent_id.c_str(), shell_holder); + LOGD( + "nativeXComponentAttachFlutterEngine xcomponent_id: %{public}s, " + "shell_holder: %{public}ld ", + xcomponent_id.c_str(), shell_holder); - XComponentAdapter::GetInstance()->AttachFlutterEngine(xcomponent_id, shell_holder_str); - return nullptr; + XComponentAdapter::GetInstance()->AttachFlutterEngine(xcomponent_id, + shell_holder_str); + return nullptr; } /** * @brief xcomponent解除flutter引擎绑定 @@ -1638,31 +1659,34 @@ napi_value PlatformViewOHOSNapi::nativeXComponentAttachFlutterEngine( */ napi_value PlatformViewOHOSNapi::nativeXComponentDetachFlutterEngine( napi_env env, - napi_callback_info info){ - napi_status ret; - size_t argc = 2; - napi_value args[2] = {nullptr}; - std::string xcomponent_id; - int64_t shell_holder; - ret = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); - if (ret != napi_ok) { - FML_DLOG(ERROR) << "nativeXComponentAttachFlutterEngine napi_get_cb_info error:" - << ret; - return nullptr; - } - if (fml::napi::GetString(env, args[0], xcomponent_id) != 0) { - FML_DLOG(ERROR) << "nativeXComponentAttachFlutterEngine xcomponent_id GetString error"; - return nullptr; - } - ret = napi_get_value_int64(env, args[1], &shell_holder); - if (ret != napi_ok) { - FML_DLOG(ERROR) << "nativeXComponentAttachFlutterEngine shell_holder napi_get_value_int64 error"; - return nullptr; - } - - LOGD("nativeXComponentDetachFlutterEngine xcomponent_id: %{public}s", xcomponent_id.c_str()); - XComponentAdapter::GetInstance()->DetachFlutterEngine(xcomponent_id); + napi_callback_info info) { + napi_status ret; + size_t argc = 2; + napi_value args[2] = {nullptr}; + std::string xcomponent_id; + int64_t shell_holder; + ret = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + if (ret != napi_ok) { + FML_DLOG(ERROR) + << "nativeXComponentAttachFlutterEngine napi_get_cb_info error:" << ret; + return nullptr; + } + if (fml::napi::GetString(env, args[0], xcomponent_id) != 0) { + FML_DLOG(ERROR) + << "nativeXComponentAttachFlutterEngine xcomponent_id GetString error"; + return nullptr; + } + ret = napi_get_value_int64(env, args[1], &shell_holder); + if (ret != napi_ok) { + FML_DLOG(ERROR) << "nativeXComponentAttachFlutterEngine shell_holder " + "napi_get_value_int64 error"; return nullptr; + } + + LOGD("nativeXComponentDetachFlutterEngine xcomponent_id: %{public}s", + xcomponent_id.c_str()); + XComponentAdapter::GetInstance()->DetachFlutterEngine(xcomponent_id); + return nullptr; } /** @@ -1678,74 +1702,82 @@ napi_value PlatformViewOHOSNapi::nativeXComponentDetachFlutterEngine( * @param timestamp: number * @return napi_value */ -napi_value PlatformViewOHOSNapi::nativeXComponentDispatchMouseWheel(napi_env env, napi_callback_info info) -{ - napi_status ret; - size_t argc = 8; - napi_value args[8] = {nullptr}; - int64_t shellHolder; - std::string xcomponentId; - std::string eventType; - int64_t fingerId; - double globalX; - double globalY; - double offsetY; - int64_t timestamp; - ret = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); - if (ret != napi_ok) { - FML_DLOG(ERROR) << "nativeXComponentDispatchMouseWheel napi_get_cb_info error:" - << ret; - return nullptr; - } - ret = napi_get_value_int64(env, args[0], &shellHolder); - if (ret != napi_ok) { - LOGE("nativeXComponentDispatchMouseWheel shellHolder napi_get_value_int64 error"); - return nullptr; - } - if (fml::napi::GetString(env, args[1], xcomponentId) != 0) { - FML_DLOG(ERROR) << "nativeXComponentDispatchMouseWheel xcomponentId GetString error"; - return nullptr; - } - if (fml::napi::GetString(env, args[2], eventType) != 0) { - FML_DLOG(ERROR) << "nativeXComponentDispatchMouseWheel eventType GetString error"; - return nullptr; - } - ret = napi_get_value_int64(env, args[3], &fingerId); - if (ret != napi_ok) { - LOGE("nativeXComponentDispatchMouseWheel fingerId napi_get_value_int64 error"); - return nullptr; - } - ret = napi_get_value_double(env, args[4], &globalX); - if (ret != napi_ok) { - LOGE("nativeXComponentDispatchMouseWheel globalX napi_get_value_double error"); - return nullptr; - } - ret = napi_get_value_double(env, args[5], &globalY); - if (ret != napi_ok) { - LOGE("nativeXComponentDispatchMouseWheel globalY napi_get_value_double error"); - return nullptr; - } - ret = napi_get_value_double(env, args[6], &offsetY); - if (ret != napi_ok) { - LOGE("nativeXComponentDispatchMouseWheel offsetY napi_get_value_double error"); - return nullptr; - } - ret = napi_get_value_int64(env, args[7], ×tamp); - if (ret != napi_ok) { - LOGE("nativeXComponentDispatchMouseWheel timestamp napi_get_value_int64 error"); - return nullptr; - } - flutter::mouseWheelEvent event { - eventType, - shellHolder, - fingerId, - globalX, - globalY, - offsetY, - timestamp - }; - XComponentAdapter::GetInstance()->OnMouseWheel(xcomponentId, event); +napi_value PlatformViewOHOSNapi::nativeXComponentDispatchMouseWheel( + napi_env env, + napi_callback_info info) { + napi_status ret; + size_t argc = 8; + napi_value args[8] = {nullptr}; + int64_t shellHolder; + std::string xcomponentId; + std::string eventType; + int64_t fingerId; + double globalX; + double globalY; + double offsetY; + int64_t timestamp; + ret = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + if (ret != napi_ok) { + FML_DLOG(ERROR) + << "nativeXComponentDispatchMouseWheel napi_get_cb_info error:" << ret; + return nullptr; + } + ret = napi_get_value_int64(env, args[0], &shellHolder); + if (ret != napi_ok) { + LOGE( + "nativeXComponentDispatchMouseWheel shellHolder napi_get_value_int64 " + "error"); + return nullptr; + } + if (fml::napi::GetString(env, args[1], xcomponentId) != 0) { + FML_DLOG(ERROR) + << "nativeXComponentDispatchMouseWheel xcomponentId GetString error"; + return nullptr; + } + if (fml::napi::GetString(env, args[2], eventType) != 0) { + FML_DLOG(ERROR) + << "nativeXComponentDispatchMouseWheel eventType GetString error"; + return nullptr; + } + ret = napi_get_value_int64(env, args[3], &fingerId); + if (ret != napi_ok) { + LOGE( + "nativeXComponentDispatchMouseWheel fingerId napi_get_value_int64 " + "error"); + return nullptr; + } + ret = napi_get_value_double(env, args[4], &globalX); + if (ret != napi_ok) { + LOGE( + "nativeXComponentDispatchMouseWheel globalX napi_get_value_double " + "error"); + return nullptr; + } + ret = napi_get_value_double(env, args[5], &globalY); + if (ret != napi_ok) { + LOGE( + "nativeXComponentDispatchMouseWheel globalY napi_get_value_double " + "error"); + return nullptr; + } + ret = napi_get_value_double(env, args[6], &offsetY); + if (ret != napi_ok) { + LOGE( + "nativeXComponentDispatchMouseWheel offsetY napi_get_value_double " + "error"); + return nullptr; + } + ret = napi_get_value_int64(env, args[7], ×tamp); + if (ret != napi_ok) { + LOGE( + "nativeXComponentDispatchMouseWheel timestamp napi_get_value_int64 " + "error"); return nullptr; + } + flutter::mouseWheelEvent event{eventType, shellHolder, fingerId, globalX, + globalY, offsetY, timestamp}; + XComponentAdapter::GetInstance()->OnMouseWheel(xcomponentId, event); + return nullptr; } /** @@ -1754,27 +1786,29 @@ napi_value PlatformViewOHOSNapi::nativeXComponentDispatchMouseWheel(napi_env env * @param str: string * @return napi_value */ -napi_value PlatformViewOHOSNapi::nativeEncodeUtf8(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); +napi_value PlatformViewOHOSNapi::nativeEncodeUtf8(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); + 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); + 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); - void *data; - napi_value arraybuffer; - napi_create_arraybuffer(env, length, &data, &arraybuffer); - std::memcpy(data, char_array.get(), length); + void* data; + napi_value arraybuffer; + napi_create_arraybuffer(env, length, &data, &arraybuffer); + std::memcpy(data, char_array.get(), length); - napi_value uint8_array; - napi_create_typedarray(env, napi_uint8_array, length, arraybuffer, 0, &uint8_array); - return uint8_array; + napi_value uint8_array; + napi_create_typedarray(env, napi_uint8_array, length, arraybuffer, 0, + &uint8_array); + return uint8_array; } /** @@ -1783,32 +1817,130 @@ napi_value PlatformViewOHOSNapi::nativeEncodeUtf8(napi_env env, napi_callback_in * @param array: Uint8Array * @return napi_value */ -napi_value PlatformViewOHOSNapi::nativeDecodeUtf8(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); +napi_value PlatformViewOHOSNapi::nativeDecodeUtf8(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 size = 0; - void *data = nullptr; - napi_get_typedarray_info(env, args[0], nullptr, &size, &data, nullptr, nullptr); + size_t size = 0; + void* data = nullptr; + napi_get_typedarray_info(env, args[0], nullptr, &size, &data, nullptr, + nullptr); - napi_value result; - napi_create_string_utf8(env, static_cast(data), size, &result); - return result; + napi_value result; + napi_create_string_utf8(env, static_cast(data), size, &result); + return result; } -napi_value PlatformViewOHOSNapi::nativeUpdateSemantics( +/** + * 监听获取系统的无障碍服务是否开启 + */ +napi_value PlatformViewOHOSNapi::nativeAccessibilityStateChange( napi_env env, napi_callback_info info) { + napi_status ret; + size_t argc = 2; + napi_value args[2] = {nullptr}; + ret = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + if (ret != napi_ok) { + FML_DLOG(ERROR) << "PlatformViewOHOSNapi::nativeAccessibilityStateChange " + "napi_get_cb_info error:" + << ret; + return nullptr; + } + int64_t shell_holder_id; + ret = napi_get_value_int64(env, args[0], &shell_holder_id); + if (ret != napi_ok) { + FML_DLOG(ERROR) << "PlatformViewOHOSNapi::nativeAccessibilityStateChange " + "napi_get_value_int64 error:" + << ret; + return nullptr; + } + bool state = false; + ret = napi_get_value_bool(env, args[1], &state); + if (ret != napi_ok) { + FML_DLOG(ERROR) << "PlatformViewOHOSNapi::nativeAccessibilityStateChange " + "napi_get_value_bool error:" + << ret; + return nullptr; + } + LOGD( + "PlatformViewOHOSNapi::nativeAccessibilityStateChange state is: " + "%{public}s", + (state ? "true" : "false")); + + //send to accessibility bridge + auto a11y_bridge = OhosAccessibilityBridge::GetInstance(); + a11y_bridge->OnOhosAccessibilityStateChange(shell_holder_id, state); + FML_DLOG(INFO) << "nativeAccessibilityStateChange: state=" << state + << " shell_holder_id=" << shell_holder_id; + return nullptr; +} + +napi_value PlatformViewOHOSNapi::nativeAnnounce( + 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::nativeAnnounce message: %{public}s", char_array.get()); + auto handler = std::make_shared(); + handler->Announce(char_array); return nullptr; } -napi_value PlatformViewOHOSNapi::nativeUpdateCustomAccessibilityActions( - napi_env env, - napi_callback_info info) { +napi_value PlatformViewOHOSNapi::nativeSetSemanticsEnabled(napi_env env, napi_callback_info info) { + napi_status ret; + size_t argc = 2; + napi_value args[2] = {nullptr}; + ret = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + if (ret != napi_ok) { + FML_DLOG(ERROR) << "PlatformViewOHOSNapi::nativeSetSemanticsEnabled " + "napi_get_cb_info error:" + << ret; + return nullptr; + } + int64_t shell_holder; + ret = napi_get_value_int64(env, args[0], &shell_holder); + if (ret != napi_ok) { + FML_DLOG(ERROR) << "PlatformViewOHOSNapi::nativeSetSemanticsEnabled " + "napi_get_value_int64 error:" + << ret; + return nullptr; + } + bool enabled = false; + ret = napi_get_value_bool(env, args[1], &enabled); + if (ret != napi_ok) { + FML_DLOG(ERROR) << "PlatformViewOHOSNapi::nativeSetSemanticsEnabled " + "napi_get_value_bool error:" + << ret; + return nullptr; + } + OHOS_SHELL_HOLDER->GetPlatformView()->SetSemanticsEnabled(enabled); + FML_DLOG(INFO) << "PlatformViewOHOSNapi::nativeSetSemanticsEnabled " + "OHOS_SHELL_HOLDER->GetPlatformView()->SetSemanticsEnabled= "<ClearFlutterSemanticsCaches(); + FML_DLOG(INFO) << "PlatformViewOHOSNapi::nativeSetSemanticsEnabled -> ClearFlutterSemanticsCaches()"; + } + + //给无障碍bridge传递nativeShellHolderId + auto ohosAccessibilityBridge = OhosAccessibilityBridge::GetInstance(); + ohosAccessibilityBridge->native_shell_holder_id_ = shell_holder; + FML_DLOG(INFO) << "PlatformViewOHOSNapi::nativeSetSemanticsEnabled -> shell_holder:"<SetBoldText(fontWeightScale, shell_holder); + auto accessibilityFeatures = std::make_shared(); + accessibilityFeatures->SetBoldText(fontWeightScale, shell_holder); FML_DLOG(INFO) << "PlatformViewOHOSNapi::nativeSetFontWeightScale -> shell_holder: " << shell_holder << " fontWeightScale: "<< fontWeightScale; return nullptr; } +napi_value PlatformViewOHOSNapi::nativeGetShellHolderId(napi_env env, napi_callback_info info) { + napi_status ret; + size_t argc = 1; + napi_value args[1] = {nullptr}; + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + int64_t shell_holder; + ret = napi_get_value_int64(env, args[0], &shell_holder); + if (ret != napi_ok) { + FML_DLOG(ERROR) << "PlatformViewOHOSNapi::nativeSetSemanticsEnabled " + "napi_get_value_int64 error:" + << ret; + return nullptr; + } + napi_shell_holder_id_ = shell_holder; + FML_DLOG(INFO) << "nativeGetShellHolderId -> shell_holder:"<GetPlatformView()->SetSemanticsEnabled(enabled); +} + +void PlatformViewOHOSNapi::DispatchSemanticsAction( + int64_t shell_holder, + int32_t id, + flutter::SemanticsAction action, + fml::MallocMapping args) +{ + OHOS_SHELL_HOLDER->GetPlatformView()->PlatformView::DispatchSemanticsAction(id, action, fml::MallocMapping()); +} + +void PlatformViewOHOSNapi::SetAccessibilityFeatures(int64_t shell_holder, + int32_t flags) +{ + OHOS_SHELL_HOLDER->GetPlatformView()->SetAccessibilityFeatures(flags); +} + +napi_value PlatformViewOHOSNapi::nativeUpdateSemantics( + napi_env env, + napi_callback_info info) { + + return nullptr; +} + +napi_value PlatformViewOHOSNapi::nativeUpdateCustomAccessibilityActions( + napi_env env, + napi_callback_info info) { + + return nullptr; +} + + napi_value PlatformViewOHOSNapi::nativeLookupCallbackInformation(napi_env env, napi_callback_info info) { napi_value result; @@ -1899,6 +2087,27 @@ napi_value PlatformViewOHOSNapi::nativeLookupCallbackInformation(napi_env env, n napi_create_int32(env, 0, &result); return result; } + +napi_value PlatformViewOHOSNapi::nativeGetFlutterNavigationAction(napi_env env, napi_callback_info info) { + napi_status ret; + size_t argc = 1; + napi_value args[1] = {nullptr}; + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + bool isNavigate; + ret = napi_get_value_bool(env, args[0], &isNavigate); + if (ret != napi_ok) { + FML_DLOG(ERROR) << "PlatformViewOHOSNapi::nativeGetFlutterNavigationAction " + "napi_get_value_bool error:" + << ret; + return nullptr; + } + + auto ohosAccessibilityBridge = OhosAccessibilityBridge::GetInstance(); + ohosAccessibilityBridge->IS_FLUTTER_NAVIGATE = isNavigate; + FML_DLOG(INFO) << "PlatformViewOHOSNapi::nativeGetFlutterNavigationAction -> "< touchPacketString, int size); + void FlutterViewOnTouchEvent(std::shared_ptr touchPacketString, + int size); + /** + * accessibility-relevant interfaces + */ + void GetShellHolderId(); + void SetSemanticsEnabled(int64_t shell_hoder, bool enabled); + void SetAccessibilityFeatures(int64_t shell_hoder, int32_t flags); + void DispatchSemanticsAction(int64_t shell_hoder, + int32_t id, + flutter::SemanticsAction action, + fml::MallocMapping args); static napi_value nativeUpdateRefreshRate( napi_env env, @@ -158,29 +168,23 @@ class PlatformViewOHOSNapi { napi_env env, napi_callback_info info); // 应用下发系统语言设置 - static napi_value nativeInitNativeImage( - napi_env env, - napi_callback_info info); + static napi_value nativeInitNativeImage(napi_env env, + napi_callback_info info); - static napi_value nativeUnregisterTexture( - napi_env env, - napi_callback_info info); + static napi_value nativeUnregisterTexture(napi_env env, + napi_callback_info info); - static napi_value nativeMarkTextureFrameAvailable( - napi_env env, - napi_callback_info info); + static napi_value nativeMarkTextureFrameAvailable(napi_env env, + napi_callback_info info); - static napi_value nativeRegisterPixelMap( - napi_env env, - napi_callback_info info); + static napi_value nativeRegisterPixelMap(napi_env env, + napi_callback_info info); - static napi_value nativeSetTextureBackGroundPixelMap( - napi_env env, - napi_callback_info info); + static napi_value nativeSetTextureBackGroundPixelMap(napi_env env, + napi_callback_info info); - static napi_value nativeRegisterTexture( - napi_env env, - napi_callback_info info); + static napi_value nativeRegisterTexture(napi_env env, + napi_callback_info info); static napi_value nativeSetTextureBufferSize( napi_env env, @@ -189,13 +193,12 @@ class PlatformViewOHOSNapi { // Surface相关,XComponent调用 static void SurfaceCreated(int64_t shell_holder, void* window); - static void SurfaceChanged( - int64_t shell_holder, - int32_t width, - int32_t height); + static void SurfaceChanged(int64_t shell_holder, + int32_t width, + int32_t height); static void SurfaceDestroyed(int64_t shell_holder); - static int64_t GetShellHolder(); + static napi_value nativeXComponentAttachFlutterEngine( napi_env env, napi_callback_info info); @@ -204,9 +207,6 @@ class PlatformViewOHOSNapi { napi_callback_info info); static napi_value nativeXComponentDispatchMouseWheel(napi_env env, napi_callback_info info); - static napi_value nativeEncodeUtf8(napi_env env, napi_callback_info info); - static napi_value nativeDecodeUtf8(napi_env env, napi_callback_info info); - /** * ets call c++ */ @@ -215,10 +215,22 @@ class PlatformViewOHOSNapi { static napi_value nativeUpdateCustomAccessibilityActions( napi_env env, napi_callback_info info); + static napi_value nativeAccessibilityStateChange( + napi_env env, + napi_callback_info info); + static napi_value nativeAnnounce( + napi_env env, + napi_callback_info info); + static napi_value nativeSetSemanticsEnabled(napi_env env, napi_callback_info info); + static napi_value nativeEncodeUtf8(napi_env env, napi_callback_info info); + static napi_value nativeDecodeUtf8(napi_env env, napi_callback_info info); static napi_value nativeSetFontWeightScale( napi_env env, napi_callback_info info); + static napi_value nativeGetFlutterNavigationAction( + napi_env env, + napi_callback_info info); static napi_value nativeLookupCallbackInformation( napi_env env, @@ -235,6 +247,9 @@ class PlatformViewOHOSNapi { static napi_value nativeUnicodeIsEmojiModifierBase( napi_env env, napi_callback_info info); + static napi_value nativeGetShellHolderId( + napi_env env, + napi_callback_info info); static napi_value nativeUnicodeIsVariationSelector( napi_env env, @@ -249,6 +264,7 @@ class PlatformViewOHOSNapi { napi_ref ref_napi_obj_; static std::vector system_languages; fml::RefPtr platform_task_runner_; + static int64_t napi_shell_holder_id_; }; } // namespace flutter diff --git a/shell/platform/ohos/ohos_external_texture_gl.cpp b/shell/platform/ohos/ohos_external_texture_gl.cpp index fda7cae8a09d23be4530818ccf48a889a7563cf3..f160e09469ace687db0b6cd5c68f5cf8cd91e85a 100755 --- a/shell/platform/ohos/ohos_external_texture_gl.cpp +++ b/shell/platform/ohos/ohos_external_texture_gl.cpp @@ -26,6 +26,7 @@ #include "third_party/skia/include/core/SkImage.h" #include "third_party/skia/include/gpu/GrBackendSurface.h" #include "third_party/skia/include/gpu/GrDirectContext.h" +#include "types.h" #define EGL_PLATFORM_OHOS_KHR 0x34E0 @@ -40,6 +41,10 @@ constexpr const char *EGL_KHR_PLATFORM_WAYLAND = "EGL_KHR_platform_wayland"; constexpr const char *EGL_GET_PLATFORM_DISPLAY_EXT = "eglGetPlatformDisplayEXT"; constexpr uint32_t WHITE_COLOR = 0xFFFFFFFF; +const SkScalar DEFAULT_MATRIX[] = {1, 0, 0, 0, -1, 1, 0, 0, 1}; + +std::map infoMap; + static int PixelMapToWindowFormat(PIXEL_FORMAT pixel_format) { switch (pixel_format) { @@ -77,23 +82,29 @@ static bool IsPixelMapYUVFormat(PIXEL_FORMAT format) format == PIXEL_FORMAT_YCBCR_P010 || format == PIXEL_FORMAT_YCRCB_P010; } - -OHOSExternalTextureGL::OHOSExternalTextureGL(int64_t id, const std::shared_ptr& ohos_surface) - : Texture(id), ohos_surface_(std::move(ohos_surface)), transform(SkMatrix::I()) +OHOSExternalTextureGL::OHOSExternalTextureGL( + int64_t id, + const std::shared_ptr& ohos_surface, + PlatformView::Delegate& delegate, + const TaskRunners& task_runners) + : Texture(id), + delegate_(delegate), + task_runners_(task_runners), + ohos_surface_(std::move(ohos_surface)), + transform(SkMatrix::I()) { state_ = AttachmentState::uninitialized; nativeImage_ = nullptr; backGroundNativeImage_ = nullptr; nativeWindow_ = nullptr; backGroundNativeWindow_ = nullptr; - eglContext_ = EGL_NO_CONTEXT; + eglContext_ = EGL_NO_CONTEXT; eglDisplay_ = EGL_NO_DISPLAY; - buffer_ = nullptr; - backGroundBuffer_ = nullptr; pixelMap_ = nullptr; backGroundPixelMap_ = nullptr; lastImage_ = nullptr; isEmulator_ = OhosMain::IsEmulator(); + frameData_ = nullptr; } OHOSExternalTextureGL::~OHOSExternalTextureGL() @@ -109,21 +120,52 @@ OHOSExternalTextureGL::~OHOSExternalTextureGL() backGroundNativeWindow_ = nullptr; eglContext_ = EGL_NO_CONTEXT; eglDisplay_ = EGL_NO_DISPLAY; - buffer_ = nullptr; - backGroundBuffer_ = nullptr; pixelMap_ = nullptr; backGroundPixelMap_ = nullptr; lastImage_ = nullptr; } +void OnNativeImageFrameAvailable(void *data) +{ + auto frameData = reinterpret_cast(data); + if (frameData == nullptr) { + FML_LOG(ERROR) << "OnNativeImageFrameAvailable, frameData is null."; + return; + } + frameData->OnPlatformViewMarkTextureFrameAvailable(); +} + +bool RegisterFrameAvailableListener(OH_NativeImage *nativeImage, OhosImageFrameData *frameData) +{ + if (frameData == nullptr) { + FML_LOG(ERROR) << "Error with RegisterFrameAvailableListener, frameData is null"; + return false; + } + OH_OnFrameAvailableListener listener; + listener.context = frameData; + listener.onFrameAvailable = OnNativeImageFrameAvailable; + int64_t ret = OH_NativeImage_SetOnFrameAvailableListener(nativeImage, listener); + if (ret != 0) { + FML_LOG(ERROR) << "Error with OH_NativeImage_SetOnFrameAvailableListener"; + return false; + } + return true; +} + void OHOSExternalTextureGL::Attach() { + FML_DLOG(INFO) << "Attach, texture_name_=" << texture_name_ + << ", Id()=" << Id(); if (state_ != AttachmentState::uninitialized) { FML_LOG(ERROR) << "OHOSExternalTextureGL::Attach, the current status is not uninitialized"; return; } OHOSSurface* ohos_surface_ptr = ohos_surface_.get(); OhosSurfaceGLSkia* ohosSurfaceGLSkia_ = (OhosSurfaceGLSkia*)ohos_surface_ptr; + if (ohosSurfaceGLSkia_->GetOnscreenSurface() == nullptr) { + FML_LOG(WARNING) << "onscreen_surface_ is null, Attach failed"; + return; + } auto result = ohosSurfaceGLSkia_->GLContextMakeCurrent(); if (result->GetResult()) { FML_DLOG(INFO) << "ResourceContextMakeCurrent successed"; @@ -148,38 +190,62 @@ void OHOSExternalTextureGL::Attach() if (ret != 0) { 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; + return; + } state_ = AttachmentState::attached; } else { FML_LOG(ERROR) << "ResourceContextMakeCurrent failed"; } } +GrGLTextureInfo OHOSExternalTextureGL::GetGrGLTextureInfo() +{ + GrGLTextureInfo textureInfo; + if (infoMap.find(backGroundTextureName_) != infoMap.end()) { + textureInfo = infoMap[backGroundTextureName_]; + } else { + textureInfo = {GL_TEXTURE_EXTERNAL_OES, backGroundTextureName_, GL_RGBA8_OES}; + } + infoMap[backGroundTextureName_] = textureInfo; + return textureInfo; +} + void OHOSExternalTextureGL::Paint(PaintContext& context, const SkRect& bounds, bool freeze, const SkSamplingOptions& sampling) { + context_ = eglGetCurrentContext(); + display_ = eglGetCurrentDisplay(); + draw_surface_ = eglGetCurrentSurface(EGL_DRAW); + read_surface_ = eglGetCurrentSurface(EGL_READ); if (state_ == AttachmentState::detached) { - FML_LOG(ERROR) << "OHOSExternalTextureGL::Paint, the current status is detached"; + FML_LOG(ERROR) << "Paint, the current status is detached"; return; } - if (!freeze && texture_update_ && pixelMap_ == nullptr) { - // 多引擎场景(multi_flutters_ohos)需要在这里执行Update - Update(); + if (state_ == AttachmentState::uninitialized) { + delegate_.OnPlatformViewMarkTextureFrameAvailable(Id()); } GrGLTextureInfo textureInfo; - - if (!freeze && !first_update_ && !isEmulator_ && !new_frame_ready_ && pixelMap_ == nullptr) { + if (!freeze && !first_update_ && !isEmulator_ && pixelMap_ == nullptr) { setBackground(bounds.width(), bounds.height()); - textureInfo = {GL_TEXTURE_EXTERNAL_OES, backGroundTextureName_, GL_RGBA8_OES}; + textureInfo = GetGrGLTextureInfo(); } else { textureInfo = {GL_TEXTURE_EXTERNAL_OES, texture_name_, GL_RGBA8_OES}; } GrBackendTexture backendTexture(1, 1, GrMipMapped::kNo, textureInfo); + GrSurfaceOrigin grOrigin = isEmulator_ ? kBottomLeft_GrSurfaceOrigin : kTopLeft_GrSurfaceOrigin; sk_sp image = SkImage::MakeFromTexture( - context.gr_context, backendTexture, kTopLeft_GrSurfaceOrigin, + context.gr_context, backendTexture, grOrigin, kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr); if (image) { SkAutoCanvasRestore autoRestore(context.canvas, true); @@ -188,13 +254,8 @@ void OHOSExternalTextureGL::Paint(PaintContext& context, // back. OpenGL's coordinate system has Positive Y equivalent to up, while // Skia's coordinate system has Negative Y equvalent to up. // 模拟器和真机在外接纹理功能的表现不一致,需要进行适配 - if (isEmulator_) { - context.canvas->translate(bounds.x(), bounds.y()); - context.canvas->scale(bounds.width(), bounds.height()); - } else { - context.canvas->translate(bounds.x(), bounds.y() + bounds.height()); - context.canvas->scale(bounds.width(), -bounds.height()); - } + context.canvas->translate(bounds.x(), bounds.y() + bounds.height()); + context.canvas->scale(bounds.width(), -bounds.height()); if (!transform.isIdentity()) { sk_sp shader = image->makeShader( @@ -217,7 +278,9 @@ void OHOSExternalTextureGL::OnGrContextCreated() FML_DLOG(INFO) << " OHOSExternalTextureGL::OnGrContextCreated" << ", texture_name_=" << texture_name_ << ", Id()=" << Id(); - state_ = AttachmentState::uninitialized; + if (state_ == AttachmentState::attached) { + delegate_.OnPlatformViewMarkTextureFrameAvailable(Id()); + } } void OHOSExternalTextureGL::OnGrContextDestroyed() @@ -225,24 +288,22 @@ void OHOSExternalTextureGL::OnGrContextDestroyed() FML_DLOG(INFO) << " OHOSExternalTextureGL::OnGrContextDestroyed" << ", texture_name_=" << texture_name_ << ", Id()=" << Id(); - if (state_ == AttachmentState::attached) { - Detach(); - state_ = AttachmentState::detached; - } } void OHOSExternalTextureGL::MarkNewFrameAvailable() { FML_DLOG(INFO) << " OHOSExternalTextureGL::MarkNewFrameAvailable"; - new_frame_ready_ = true; - texture_update_ = true; - if (texture_name_ == 0) { - Attach(); + if (state_ == AttachmentState::attached) { + Update(); } - if (pixelMap_ != nullptr) { // 外接纹理图片场景 - ProducePixelMapToNativeImage(); + if (state_ == AttachmentState::uninitialized) { + Attach(); + if (pixelMap_ != nullptr) { + // 外接纹理图片场景 + ProducePixelMapToNativeImage(); + } + Update(); } - Update(); } void OHOSExternalTextureGL::OnTextureUnregistered() @@ -258,15 +319,41 @@ void OHOSExternalTextureGL::OnTextureUnregistered() } } +bool OHOSExternalTextureGL::IsContextCurrent() +{ + EGLContext current_egl_context = eglGetCurrentContext(); + if (context_ != current_egl_context) { + return false; + } + EGLDisplay current_egl_display = eglGetCurrentDisplay(); + if (display_ != current_egl_display) { + return false; + } + EGLSurface draw_surface = eglGetCurrentSurface(EGL_DRAW); + if (draw_surface != draw_surface_) { + return false; + } + EGLSurface read_surface = eglGetCurrentSurface(EGL_READ); + if (read_surface != read_surface_) { + return false; + } + return true; +} + void OHOSExternalTextureGL::Update() { FML_DLOG(INFO) << "OHOSExternalTextureGL::Update, texture_name_=" << texture_name_; + if (!IsContextCurrent() && context_) { + if (eglMakeCurrent(display_, draw_surface_, read_surface_, context_) != EGL_TRUE) { + FML_LOG(WARNING) << "eglMakeCurrent in update failed"; + } + } + if (nativeImage_ == nullptr) { FML_LOG(ERROR) << "Update, nativeImage_ is nullptr, texture_name_=" << texture_name_; return; } int32_t ret = OH_NativeImage_UpdateSurfaceImage(nativeImage_); - texture_update_ = false; if (ret != 0) { FML_LOG(ERROR) << "OHOSExternalTextureGL OH_NativeImage_UpdateSurfaceImage err code:" << ret; return; @@ -282,13 +369,16 @@ void OHOSExternalTextureGL::Detach() FML_LOG(ERROR) << "OHOSExternalTextureGL::Detach, the current status is not attached"; return; } - if (nativeImage_ != nullptr) { 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; @@ -303,14 +393,10 @@ void OHOSExternalTextureGL::Detach() OH_NativeWindow_DestroyNativeWindow(backGroundNativeWindow_); backGroundNativeWindow_ = nullptr; } - - if (texture_name_ != 0) { - glDeleteTextures(1, &texture_name_); - texture_name_ = 0; - } + glDeleteTextures(1, &texture_name_); + glDeleteTextures(1, &backGroundTextureName_); if (backGroundTextureName_ != 0) { - glDeleteTextures(1, &backGroundTextureName_); - backGroundTextureName_ = 0; + infoMap.erase(backGroundTextureName_); } } @@ -330,7 +416,12 @@ void OHOSExternalTextureGL::UpdateTransform(OH_NativeImage *image) transform.set9(matrix3); SkMatrix inverted; if (!transform.invert(&inverted)) { - FML_LOG(ERROR) << "OHOSExternalTextureGL Invalid SurfaceTexture transformation matrix"; + FML_LOG(ERROR) << "OHOSExternalTextureGL UpdateTransform matrix error"; + + transform.set9(DEFAULT_MATRIX); + if (!transform.invert(&inverted)) { + FML_LOG(ERROR) << "UpdateTransform matrix error again"; + } } transform = inverted; } @@ -410,6 +501,12 @@ void OHOSExternalTextureGL::ProduceColorToBackGroundImage(int32_t width, int32_t return; } + uint64_t usage = 0; + OH_NativeWindow_NativeWindowHandleOpt(backGroundNativeWindow_, GET_USAGE, &usage); + usage |= NATIVEBUFFER_USAGE_CPU_READ | (BUFFER_USAGE_HW_COMPOSER); + OH_NativeWindow_NativeWindowHandleOpt(backGroundNativeWindow_, SET_USAGE, usage); + + OHNativeWindowBuffer *backGroundBuffer_; ret = OH_NativeWindow_NativeWindowRequestBuffer(backGroundNativeWindow_, &backGroundBuffer_, &backGroundFenceFd); if (ret != 0) { FML_LOG(ERROR) << "OHOSExternalTextureGL::setBackground OH_NativeWindow_NativeWindowRequestBuffer err:" << ret; @@ -479,13 +576,10 @@ void OHOSExternalTextureGL::ProducePixelMapToBackGroundImage() uint64_t usage = 0; OH_NativeWindow_NativeWindowHandleOpt(backGroundNativeWindow_, GET_USAGE, &usage); - usage |= NATIVEBUFFER_USAGE_CPU_READ; + usage |= NATIVEBUFFER_USAGE_CPU_READ | (BUFFER_USAGE_HW_COMPOSER); OH_NativeWindow_NativeWindowHandleOpt(backGroundNativeWindow_, SET_USAGE, usage); - if (backGroundBuffer_ != nullptr) { - OH_NativeWindow_NativeWindowAbortBuffer(backGroundNativeWindow_, backGroundBuffer_); - backGroundBuffer_ = nullptr; - } + OHNativeWindowBuffer *backGroundBuffer_; ret = OH_NativeWindow_NativeWindowRequestBuffer(backGroundNativeWindow_, &backGroundBuffer_, &backGroundFenceFd); if (ret != 0) { FML_LOG(ERROR) @@ -605,13 +699,10 @@ void OHOSExternalTextureGL::ProducePixelMapToNativeImage() uint64_t usage = 0; OH_NativeWindow_NativeWindowHandleOpt(nativeWindow_, GET_USAGE, &usage); - usage |= NATIVEBUFFER_USAGE_CPU_READ; + usage |= NATIVEBUFFER_USAGE_CPU_READ | (BUFFER_USAGE_HW_COMPOSER); OH_NativeWindow_NativeWindowHandleOpt(nativeWindow_, SET_USAGE, usage); - if (buffer_ != nullptr) { - OH_NativeWindow_NativeWindowAbortBuffer(nativeWindow_, buffer_); - buffer_ = nullptr; - } + OHNativeWindowBuffer *buffer_; ret = OH_NativeWindow_NativeWindowRequestBuffer(nativeWindow_, &buffer_, &fenceFd); if (ret != 0) { FML_LOG(ERROR) << "OHOSExternalTextureGL OH_NativeWindow_NativeWindowRequestBuffer err:" << ret; @@ -679,4 +770,28 @@ 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 26847c228b420b1469c0c58987d487f95befcba2..24beb3279de48788e6d3b945b06c0caa96859db1 100755 --- a/shell/platform/ohos/ohos_external_texture_gl.h +++ b/shell/platform/ohos/ohos_external_texture_gl.h @@ -31,6 +31,7 @@ #include "flutter/shell/platform/ohos/napi/platform_view_ohos_napi.h" #include "flutter/shell/platform/ohos/ohos_surface_gl_skia.h" #include "flutter/shell/platform/ohos/surface/ohos_surface.h" +#include "flutter/shell/common/platform_view.h" // maybe now unused namespace flutter { @@ -38,13 +39,21 @@ namespace flutter { class OHOSExternalTextureGL : public flutter::Texture { public: explicit OHOSExternalTextureGL(int64_t id, const std::shared_ptr& ohos_surface); + explicit OHOSExternalTextureGL(int64_t id, const std::shared_ptr& ohos_surface, + PlatformView::Delegate& delegate, const TaskRunners& task_runners); ~OHOSExternalTextureGL() override; + PlatformView::Delegate& delegate_; + + const TaskRunners& task_runners_; + OH_NativeImage *nativeImage_; OH_NativeImage *backGroundNativeImage_; + void *frameData_; + bool first_update_ = false; void Paint(PaintContext& context, @@ -64,6 +73,8 @@ class OHOSExternalTextureGL : public flutter::Texture { void setBackground(int32_t width, int32_t height); + GrGLTextureInfo GetGrGLTextureInfo(); + void setTextureBufferSize(int32_t width, int32_t height); void DispatchPixelMap(NativePixelMap* pixelMap); @@ -95,10 +106,6 @@ class OHOSExternalTextureGL : public flutter::Texture { AttachmentState state_; - bool new_frame_ready_ = false; - - bool texture_update_ = false; - GLuint texture_name_ = 0; GLuint backGroundTextureName_ = 0; @@ -111,10 +118,6 @@ class OHOSExternalTextureGL : public flutter::Texture { OHNativeWindow *backGroundNativeWindow_; - OHNativeWindowBuffer *buffer_; - - OHNativeWindowBuffer *backGroundBuffer_; - NativePixelMap* backGroundPixelMap_; NativePixelMap* pixelMap_; @@ -133,6 +136,31 @@ class OHOSExternalTextureGL : public flutter::Texture { EGLDisplay eglDisplay_; FML_DISALLOW_COPY_AND_ASSIGN(OHOSExternalTextureGL); + + void* display_; + void* draw_surface_; + void* read_surface_; + void* context_; + + 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_surface_gl_skia.cpp b/shell/platform/ohos/ohos_surface_gl_skia.cpp index dcd4a06481b5af212cecd5aa143bfdd529de6162..6c8d5ea57ee03d74f5e9e83a3ed37020544439d5 100755 --- a/shell/platform/ohos/ohos_surface_gl_skia.cpp +++ b/shell/platform/ohos/ohos_surface_gl_skia.cpp @@ -16,10 +16,12 @@ #include "flutter/shell/platform/ohos/ohos_surface_gl_skia.h" #include +#include #include "flutter/fml/logging.h" #include "flutter/fml/memory/ref_ptr.h" #include "flutter/shell/platform/ohos/ohos_egl_surface.h" +#include "flutter/shell/platform/ohos/ohos_logging.h" #include "flutter/shell/platform/ohos/ohos_shell_holder.h" namespace flutter { @@ -89,17 +91,20 @@ bool OhosSurfaceGLSkia::OnScreenSurfaceResize(const SkISize& size) { return true; } - GLContextPtr()->ClearCurrent(); - - // Ensure the destructor is called since it destroys the `EGLSurface` before - // creating a new onscreen surface. - onscreen_surface_ = nullptr; - onscreen_surface_ = GLContextPtr()->CreateOnscreenSurface(native_window_); - if (!onscreen_surface_->IsValid()) { - FML_LOG(ERROR) << "Unable to create EGL window surface on resize."; + int code = SET_BUFFER_GEOMETRY; + int32_t width = size.fWidth; + int32_t height = size.fHeight; + int32_t ret = OH_NativeWindow_NativeWindowHandleOpt(native_window_->handle(), + code, width, height); + if (ret != 0) { + LOGE( + "OhosSurfaceGLSkia::OnScreenSurfaceResize, window resize failed, " + "ret=%{public}d, " + "width:%{public}d, " + "height:%{public}d", + ret, width, height); return false; } - onscreen_surface_->MakeCurrent(); return true; } diff --git a/shell/platform/ohos/ohos_touch_processor.cpp b/shell/platform/ohos/ohos_touch_processor.cpp index 2e0af9081903b8bdb9c67f2fbe91c2af5647f1e5..32d2ed1ef8d0f420c4c0af25ca01194e299d1923 100644 --- a/shell/platform/ohos/ohos_touch_processor.cpp +++ b/shell/platform/ohos/ohos_touch_processor.cpp @@ -14,8 +14,10 @@ */ #include "flutter/shell/platform/ohos/ohos_touch_processor.h" + #include "flutter/lib/ui/window/pointer_data_packet.h" #include "flutter/shell/platform/ohos/ohos_shell_holder.h" +#include "flutter/fml/trace_event.h" namespace flutter { @@ -151,6 +153,7 @@ void OhosTouchProcessor::HandleTouchEvent( if (touchEvent == nullptr) { return; } + FML_TRACE_EVENT("flutter", "HandleTouchEvent", "timeStamp", touchEvent->timeStamp); const int numTouchPoints = 1; std::unique_ptr packet = std::make_unique(numTouchPoints); PointerData pointerData; @@ -181,7 +184,6 @@ void OhosTouchProcessor::HandleTouchEvent( pointerData.change == PointerData::Change::kMove) { pointerData.buttons = kPointerButtonTouchContact; } - } else if (pointerData.kind == PointerData::DeviceKind::kMouse) { } pointerData.pan_x = 0.0; pointerData.pan_y = 0.0; @@ -197,6 +199,21 @@ void OhosTouchProcessor::HandleTouchEvent( ohos_shell_holder->GetPlatformView()->DispatchPointerDataPacket( std::move(packet)); + // For DFX + fml::closure task = [timeStampDFX = touchEvent->timeStamp](void) { + FML_TRACE_EVENT("flutter", "HandleTouchEventUI", "timeStamp", timeStampDFX); + }; + ohos_shell_holder->GetPlatformView()->RunTask(OHOS_THREAD_TYPE::OHOS_THREAD_TYPE_UI, task); + + PlatformViewOnTouchEvent(shell_holderID, toolType, component, touchEvent); +} + +void OhosTouchProcessor::PlatformViewOnTouchEvent( + int64_t shellHolderID, + OH_NativeXComponent_TouchPointToolType toolType, + OH_NativeXComponent* component, + OH_NativeXComponent_TouchEvent* touchEvent) +{ int numPoints = touchEvent->numPoints; float tiltX = 0.0; float tiltY = 0.0; @@ -211,8 +228,8 @@ void OhosTouchProcessor::HandleTouchEvent( std::shared_ptr touchPacketString = packagePacketData(std::move(touchPacket)); int size = CHANGES_POINTER_MEMBER + PER_POINTER_MEMBER * numPoints + TOUCH_EVENT_ADDITIONAL_ATTRIBUTES; + auto ohos_shell_holder = reinterpret_cast(shellHolderID); ohos_shell_holder->GetPlatformView()->OnTouchEvent(touchPacketString, size); - return; } void OhosTouchProcessor::HandleMouseEvent( diff --git a/shell/platform/ohos/ohos_touch_processor.h b/shell/platform/ohos/ohos_touch_processor.h index 1f59bd16a98b0f171a2ef36c62d774cbc7315e92..892bd672939a038bb718bb7e17b87afb10f9f61a 100644 --- a/shell/platform/ohos/ohos_touch_processor.h +++ b/shell/platform/ohos/ohos_touch_processor.h @@ -24,7 +24,7 @@ namespace flutter { class OhosTouchProcessor { - public: +public: typedef struct { OH_NativeXComponent_TouchEvent* touchEventInput; OH_NativeXComponent_TouchPointToolType toolTypeInput; @@ -32,32 +32,35 @@ class OhosTouchProcessor { float tiltY; } TouchPacket; - public: - void HandleTouchEvent(int64_t shell_holderID, - OH_NativeXComponent* component, - OH_NativeXComponent_TouchEvent* touchEvent); - void HandleMouseEvent(int64_t shell_holderID, - OH_NativeXComponent* component, - OH_NativeXComponent_MouseEvent mouseEvent, - double offsetY); - void HandleVirtualTouchEvent(int64_t shell_holderID, - OH_NativeXComponent* component, - OH_NativeXComponent_TouchEvent* touchEvent); - flutter::PointerData::Change getPointerChangeForAction(int maskedAction); - flutter::PointerData::DeviceKind getPointerDeviceTypeForToolType( - int toolType); - flutter::PointerData::Change getPointerChangeForMouseAction( - OH_NativeXComponent_MouseEventAction mouseAction); - PointerButtonMouse getPointerButtonFromMouse( - OH_NativeXComponent_MouseEventButton mouseButton); +public: + void HandleTouchEvent(int64_t shell_holderID, + OH_NativeXComponent* component, + OH_NativeXComponent_TouchEvent* touchEvent); + void HandleMouseEvent(int64_t shell_holderID, + OH_NativeXComponent* component, + OH_NativeXComponent_MouseEvent mouseEvent, + double offsetY); + void HandleVirtualTouchEvent(int64_t shell_holderID, + OH_NativeXComponent* component, + OH_NativeXComponent_TouchEvent* touchEvent); + flutter::PointerData::Change getPointerChangeForAction(int maskedAction); + flutter::PointerData::DeviceKind getPointerDeviceTypeForToolType( + int toolType); + flutter::PointerData::Change getPointerChangeForMouseAction( + OH_NativeXComponent_MouseEventAction mouseAction); + PointerButtonMouse getPointerButtonFromMouse( + OH_NativeXComponent_MouseEventButton mouseButton); - private: - std::shared_ptr packagePacketData(std::unique_ptr touchPacket); +public: + OH_NativeXComponent_TouchPointToolType touchType_; - public: - OH_NativeXComponent_TouchPointToolType touchType_; +private: + std::shared_ptr packagePacketData(std::unique_ptr touchPacket); - private: + void PlatformViewOnTouchEvent(int64_t shellHolderID, + OH_NativeXComponent_TouchPointToolType toolType, + OH_NativeXComponent* component, + OH_NativeXComponent_TouchEvent* touchEvent); }; } // namespace flutter #endif // XComponent_OhosTouchProcessor_H \ 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 ce9b10f61d4301818eca106aa4f50d0fa9905e5c..e9a0e82d033a8de6ec55b9df7f5a3142f49311ba 100644 --- a/shell/platform/ohos/ohos_xcomponent_adapter.cpp +++ b/shell/platform/ohos/ohos_xcomponent_adapter.cpp @@ -117,51 +117,15 @@ void XComponentAdapter::OnMouseWheel(std::string& id, mouseWheelEvent event) } #include -using OHOS_SurfaceBufferUsage = enum { - BUFFER_USAGE_CPU_READ = (1ULL << 0), /**< CPU read buffer */ - BUFFER_USAGE_CPU_WRITE = (1ULL << 1), /**< CPU write memory */ - BUFFER_USAGE_MEM_MMZ = (1ULL << 2), /**< Media memory zone (MMZ) */ - BUFFER_USAGE_MEM_DMA = (1ULL << 3), /**< Direct memory access (DMA) buffer */ - BUFFER_USAGE_MEM_SHARE = (1ULL << 4), /**< Shared memory buffer*/ - BUFFER_USAGE_MEM_MMZ_CACHE = (1ULL << 5), /**< MMZ with cache*/ - BUFFER_USAGE_MEM_FB = (1ULL << 6), /**< Framebuffer */ - BUFFER_USAGE_ASSIGN_SIZE = (1ULL << 7), /**< Memory assigned */ - BUFFER_USAGE_HW_RENDER = (1ULL << 8), /**< For GPU write case */ - BUFFER_USAGE_HW_TEXTURE = (1ULL << 9), /**< For GPU read case */ - BUFFER_USAGE_HW_COMPOSER = (1ULL << 10), /**< For hardware composer */ - BUFFER_USAGE_PROTECTED = - (1ULL << 11), /**< For safe buffer case, such as DRM */ - BUFFER_USAGE_CAMERA_READ = (1ULL << 12), /**< For camera read case */ - BUFFER_USAGE_CAMERA_WRITE = (1ULL << 13), /**< For camera write case */ - BUFFER_USAGE_VIDEO_ENCODER = (1ULL << 14), /**< For encode case */ - BUFFER_USAGE_VIDEO_DECODER = (1ULL << 15), /**< For decode case */ - BUFFER_USAGE_VENDOR_PRI0 = (1ULL << 44), /**< Reserverd for vendor */ - BUFFER_USAGE_VENDOR_PRI1 = (1ULL << 45), /**< Reserverd for vendor */ - BUFFER_USAGE_VENDOR_PRI2 = (1ULL << 46), /**< Reserverd for vendor */ - BUFFER_USAGE_VENDOR_PRI3 = (1ULL << 47), /**< Reserverd for vendor */ - BUFFER_USAGE_VENDOR_PRI4 = (1ULL << 48), /**< Reserverd for vendor */ - BUFFER_USAGE_VENDOR_PRI5 = (1ULL << 49), /**< Reserverd for vendor */ - BUFFER_USAGE_VENDOR_PRI6 = (1ULL << 50), /**< Reserverd for vendor */ - BUFFER_USAGE_VENDOR_PRI7 = (1ULL << 51), /**< Reserverd for vendor */ - BUFFER_USAGE_VENDOR_PRI8 = (1ULL << 52), /**< Reserverd for vendor */ - BUFFER_USAGE_VENDOR_PRI9 = (1ULL << 53), /**< Reserverd for vendor */ - BUFFER_USAGE_VENDOR_PRI10 = (1ULL << 54), /**< Reserverd for vendor */ - BUFFER_USAGE_VENDOR_PRI11 = (1ULL << 55), /**< Reserverd for vendor */ - BUFFER_USAGE_VENDOR_PRI12 = (1ULL << 56), /**< Reserverd for vendor */ - BUFFER_USAGE_VENDOR_PRI13 = (1ULL << 57), /**< Reserverd for vendor */ - BUFFER_USAGE_VENDOR_PRI14 = (1ULL << 58), /**< Reserverd for vendor */ - BUFFER_USAGE_VENDOR_PRI15 = (1ULL << 59), /**< Reserverd for vendor */ - BUFFER_USAGE_VENDOR_PRI16 = (1ULL << 60), /**< Reserverd for vendor */ - BUFFER_USAGE_VENDOR_PRI17 = (1ULL << 61), /**< Reserverd for vendor */ - BUFFER_USAGE_VENDOR_PRI18 = (1ULL << 62), /**< Reserverd for vendor */ - BUFFER_USAGE_VENDOR_PRI19 = (1ULL << 63), /**< Reserverd for vendor */ -}; + static int32_t SetNativeWindowOpt(OHNativeWindow* nativeWindow, int32_t width, int height) { // Set the read and write scenarios of the native window buffer. - int code = SET_USAGE; - int32_t ret = OH_NativeWindow_NativeWindowHandleOpt(nativeWindow, code, BUFFER_USAGE_MEM_DMA); + uint64_t usage = 0; + int ret = OH_NativeWindow_NativeWindowHandleOpt(nativeWindow, GET_USAGE, &usage); + usage |= BUFFER_USAGE_MEM_DMA | (BUFFER_USAGE_HW_COMPOSER); + ret = OH_NativeWindow_NativeWindowHandleOpt(nativeWindow, SET_USAGE, usage); if (ret) { LOGE( "Set NativeWindow Usage Failed :window:%{public}p ,w:%{public}d x " @@ -169,7 +133,7 @@ static int32_t SetNativeWindowOpt(OHNativeWindow* nativeWindow, nativeWindow, width, height, ret); } // Set the width and height of the native window buffer. - code = SET_BUFFER_GEOMETRY; + int code = SET_BUFFER_GEOMETRY; ret = OH_NativeWindow_NativeWindowHandleOpt(nativeWindow, code, width, height); if (ret) { @@ -214,6 +178,7 @@ void OnSurfaceCreatedCB(OH_NativeXComponent* component, void* window) { for(auto it: XComponentAdapter::GetInstance()->xcomponetMap_) { if(it.second->nativeXComponent_ == component) { + LOGD("OnSurfaceCreatedCB is called"); it.second->OnSurfaceCreated(component, window); } } @@ -274,6 +239,101 @@ void XComponentBase::BindXComponentCallback() { mouseCallback_.DispatchHoverEvent = DispatchHoverEventCB; } + +/** Called when need to get element infos based on a specified node. */ +int32_t FindAccessibilityNodeInfosById( + int64_t elementId, + ArkUI_AccessibilitySearchMode mode, + int32_t requestId, + ArkUI_AccessibilityElementInfoList* elementList) +{ + auto ohosAccessibilityBridge = OhosAccessibilityBridge::GetInstance(); + ohosAccessibilityBridge->FindAccessibilityNodeInfosById(elementId, mode, requestId, elementList); + LOGD("accessibilityProviderCallback_.FindAccessibilityNodeInfosById"); + return 0; +} + +/** Called when need to get element infos based on a specified node and text content. */ +int32_t FindAccessibilityNodeInfosByText( + int64_t elementId, + const char* text, + int32_t requestId, + ArkUI_AccessibilityElementInfoList* elementList) +{ + auto ohosAccessibilityBridge = OhosAccessibilityBridge::GetInstance(); + ohosAccessibilityBridge->FindAccessibilityNodeInfosByText(elementId, text, requestId, elementList); + LOGD("accessibilityProviderCallback_.FindAccessibilityNodeInfosByText"); + return 0; +} + +/** Called when need to get the focused element info based on a specified node. */ +int32_t FindFocusedAccessibilityNode( + int64_t elementId, + ArkUI_AccessibilityFocusType focusType, + int32_t requestId, + ArkUI_AccessibilityElementInfo* elementinfo) +{ + auto ohosAccessibilityBridge = OhosAccessibilityBridge::GetInstance(); + ohosAccessibilityBridge->FindFocusedAccessibilityNode(elementId, focusType, requestId, elementinfo); + LOGD("accessibilityProviderCallback_.FindFocusedAccessibilityNode"); + return 0; +} + +/** Query the node that can be focused based on the reference node. Query the next node that can be focused based on the mode and direction. */ +int32_t FindNextFocusAccessibilityNode( + int64_t elementId, + ArkUI_AccessibilityFocusMoveDirection direction, + int32_t requestId, + ArkUI_AccessibilityElementInfo *elementList) +{ + auto ohosAccessibilityBridge = OhosAccessibilityBridge::GetInstance(); + ohosAccessibilityBridge->FindNextFocusAccessibilityNode(elementId, direction, requestId, elementList); + LOGD("accessibilityProviderCallback_.FindNextFocusAccessibilityNode"); + return 0; +} + +/** Performing the Action operation on a specified node. */ +int32_t ExecuteAccessibilityAction( + int64_t elementId, + ArkUI_Accessibility_ActionType action, + ArkUI_AccessibilityActionArguments* actionArguments, + int32_t requestId) +{ + auto ohosAccessibilityBridge = OhosAccessibilityBridge::GetInstance(); + ohosAccessibilityBridge->ExecuteAccessibilityAction(elementId, action, actionArguments, requestId); + LOGD("accessibilityProviderCallback_.ExecuteAccessibilityAction"); + return 0; +} + +/** Clears the focus status of the currently focused node */ +int32_t ClearFocusedFocusAccessibilityNode() +{ + LOGD("accessibilityProviderCallback_.ClearFocusedFocusAccessibilityNode"); + return 0; +} + +/** Queries the current cursor position of a specified node. */ +int32_t GetAccessibilityNodeCursorPosition( + int64_t elementId, + int32_t requestId, + int32_t* index) +{ + auto ohosAccessibilityBridge = OhosAccessibilityBridge::GetInstance(); + ohosAccessibilityBridge->GetAccessibilityNodeCursorPosition(elementId, requestId, index); + LOGD("accessibilityProviderCallback_.GetAccessibilityNodeCursorPosition"); + return 0; +} + +void XComponentBase::BindAccessibilityProviderCallback() { + accessibilityProviderCallback_.findAccessibilityNodeInfosById = FindAccessibilityNodeInfosById; + accessibilityProviderCallback_.findAccessibilityNodeInfosByText = FindAccessibilityNodeInfosByText; + accessibilityProviderCallback_.findFocusedAccessibilityNode = FindFocusedAccessibilityNode; + accessibilityProviderCallback_.findNextFocusAccessibilityNode = FindNextFocusAccessibilityNode; + accessibilityProviderCallback_.executeAccessibilityAction = ExecuteAccessibilityAction; + accessibilityProviderCallback_.clearFocusedFocusAccessibilityNode = ClearFocusedFocusAccessibilityNode; + accessibilityProviderCallback_.getAccessibilityNodeCursorPosition = GetAccessibilityNodeCursorPosition; +} + XComponentBase::XComponentBase(std::string id){ id_ = id; isEngineAttached_ = false; @@ -315,6 +375,41 @@ void XComponentBase::SetNativeXComponent(OH_NativeXComponent* nativeXComponent){ 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"); + } } } diff --git a/shell/platform/ohos/ohos_xcomponent_adapter.h b/shell/platform/ohos/ohos_xcomponent_adapter.h index aecea89ded2c10ff634eeaa30e292e56bc661730..d2c14146134bffd6d364ddf3e8a57f8326fba305 100644 --- a/shell/platform/ohos/ohos_xcomponent_adapter.h +++ b/shell/platform/ohos/ohos_xcomponent_adapter.h @@ -15,19 +15,24 @@ #ifndef OHOS_XCOMPONENT_ADAPTER_H #define OHOS_XCOMPONENT_ADAPTER_H +#include #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 +#include "flutter/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h" + namespace flutter { class XComponentBase { private: void BindXComponentCallback(); + void BindAccessibilityProviderCallback(); public: XComponentBase(std::string id); @@ -48,6 +53,8 @@ public: OH_NativeXComponent_TouchEvent touchEvent_; OH_NativeXComponent_Callback callback_; OH_NativeXComponent_MouseEvent_Callback mouseCallback_; + ArkUI_AccessibilityProviderCallbacks accessibilityProviderCallback_; + std::string id_; std::string shellholderId_; bool isEngineAttached_; diff --git a/shell/platform/ohos/platform_view_ohos.cpp b/shell/platform/ohos/platform_view_ohos.cpp index bad544f3f89e7b26751c3a892b4ce1b2c1c483f2..b1aca3a69c025b1c28c7870d49ea4e43f4af1521 100644 --- a/shell/platform/ohos/platform_view_ohos.cpp +++ b/shell/platform/ohos/platform_view_ohos.cpp @@ -22,9 +22,9 @@ #include "flutter/shell/platform/ohos/ohos_surface_software.h" #include "flutter/shell/platform/ohos/platform_message_response_ohos.h" #include "napi_common.h" -#include "ohos_logging.h" #include "ohos_external_texture_gl.h" - +#include "ohos_logging.h" +#include "flutter/shell/platform/ohos/platform_view_ohos_delegate.h" #include namespace flutter { @@ -117,15 +117,15 @@ PlatformViewOHOS::PlatformViewOHOS( PlatformViewOHOS::~PlatformViewOHOS() { FML_LOG(INFO) << "PlatformViewOHOS::~PlatformViewOHOS"; - for (std::map::iterator it = contextDatas_.begin(); it != contextDatas_.end(); ++it) { + for (std::map>::iterator it = external_texture_gl_.begin(); + it != external_texture_gl_.end(); ++it) { if (it->second != nullptr) { - OhosImageFrameData* data = reinterpret_cast(it->second); - delete data; - data = nullptr; - it->second = nullptr; + OH_NativeImage_Destroy(&(it->second->nativeImage_)); + it->second->nativeImage_ = nullptr; } } - contextDatas_.clear(); + external_texture_gl_.clear(); + FML_LOG(INFO) << "PlatformViewOHOS::~PlatformViewOHOS finish"; } void PlatformViewOHOS::NotifyCreate( @@ -202,8 +202,7 @@ void PlatformViewOHOS::SetDestroyed(bool isDestroyed) { } // |PlatformView| -void PlatformViewOHOS::NotifyDestroyed() -{ +void PlatformViewOHOS::NotifyDestroyed() { SetDestroyed(true); LOGI("PlatformViewOHOS NotifyDestroyed enter"); PlatformView::NotifyDestroyed(); @@ -225,7 +224,7 @@ void PlatformViewOHOS::DispatchPlatformMessage(std::string name, void* message, int messageLenth, int reponseId) { - FML_DLOG(INFO) << "DispatchSemanticsAction(" << name << ",," << messageLenth + FML_DLOG(INFO) << "DispatchPlatformMessage(" << name << "," << messageLenth << "," << reponseId; fml::MallocMapping mapMessage = fml::MallocMapping::Copy(message, messageLenth); @@ -256,7 +255,7 @@ void PlatformViewOHOS::DispatchSemanticsAction(int id, int action, void* actionData, int actionDataLenth) { - FML_DLOG(INFO) << "DispatchSemanticsAction(" << id << "," << action << "," + FML_DLOG(INFO) << "DispatchSemanticsAction -> id=" << id << ", action=" << action << ", actionDataLenth" << actionDataLenth; auto args_vector = fml::MallocMapping::Copy(actionData, actionDataLenth); @@ -293,11 +292,13 @@ void PlatformViewOHOS::UpdateAssetResolverByType( delegate_.UpdateAssetResolverByType(std::move(updated_asset_resolver), type); } -// todo +// ohos_accessbility_bridge void PlatformViewOHOS::UpdateSemantics( flutter::SemanticsNodeUpdates update, flutter::CustomAccessibilityActionUpdates actions) { - FML_DLOG(INFO) << "UpdateSemantics"; + FML_DLOG(INFO) << "PlatformViewOHOS::UpdateSemantics is called"; + auto nativeAccessibilityChannel_ = std::make_shared(); + nativeAccessibilityChannel_->UpdateSemantics(update, actions); } // |PlatformView| @@ -424,17 +425,15 @@ void PlatformViewOHOS::FireFirstFrameCallback() { napi_facade_->FlutterViewOnFirstFrame(); } -void PlatformViewOHOS::RegisterExternalTextureByImage( - int64_t texture_id, - ImageNative* image) -{ +void PlatformViewOHOS::RegisterExternalTextureByImage(int64_t texture_id, + ImageNative* image) { if (ohos_context_->RenderingApi() == OHOSRenderingAPI::kOpenGLES) { auto iter = external_texture_gl_.find(texture_id); if (iter != external_texture_gl_.end()) { iter->second->DispatchImage(image); } else { std::shared_ptr ohos_external_gl = - std::make_shared(texture_id, ohos_surface_); + std::make_shared(texture_id, ohos_surface_, delegate_, task_runners_); external_texture_gl_[texture_id] = ohos_external_gl; RegisterTexture(ohos_external_gl); ohos_external_gl->DispatchImage(image); @@ -450,27 +449,20 @@ PointerDataDispatcherMaker PlatformViewOHOS::GetDispatcherMaker() { uint64_t PlatformViewOHOS::RegisterExternalTexture(int64_t texture_id) { + FML_DLOG(INFO) << "PlatformViewOHOS::RegisterExternalTexture, texture_id=" << texture_id; uint64_t surface_id = 0; int ret = -1; if (ohos_context_->RenderingApi() == OHOSRenderingAPI::kOpenGLES) { std::shared_ptr ohos_external_gl = - std::make_shared(texture_id, ohos_surface_); - ohos_external_gl->nativeImage_ = OH_NativeImage_Create(texture_id, GL_TEXTURE_EXTERNAL_OES); + std::make_shared(texture_id, ohos_surface_, delegate_, task_runners_); + ohos_external_gl->nativeImage_ = + OH_NativeImage_Create(texture_id, GL_TEXTURE_EXTERNAL_OES); if (ohos_external_gl->nativeImage_ == nullptr) { FML_DLOG(ERROR) << "Error with OH_NativeImage_Create"; return surface_id; } - void* contextData = new OhosImageFrameData(this, texture_id); - contextDatas_.insert(std::pair(texture_id, contextData)); - OH_OnFrameAvailableListener listener; - listener.context = contextData; - listener.onFrameAvailable = &PlatformViewOHOS::OnNativeImageFrameAvailable; - ret = OH_NativeImage_SetOnFrameAvailableListener(ohos_external_gl->nativeImage_, listener); - if (ret != 0) { - FML_DLOG(ERROR) << "Error with OH_NativeImage_SetOnFrameAvailableListener"; - return surface_id; - } - ret = OH_NativeImage_GetSurfaceId(ohos_external_gl->nativeImage_, &surface_id); + ret = OH_NativeImage_GetSurfaceId(ohos_external_gl->nativeImage_, + &surface_id); ohos_external_gl->first_update_ = false; if (ret != 0) { FML_DLOG(ERROR) << "Error with OH_NativeImage_GetSurfaceId"; @@ -478,6 +470,7 @@ uint64_t PlatformViewOHOS::RegisterExternalTexture(int64_t texture_id) } external_texture_gl_[texture_id] = ohos_external_gl; RegisterTexture(ohos_external_gl); + MarkTextureFrameAvailable(texture_id); } return surface_id; } @@ -495,64 +488,23 @@ void PlatformViewOHOS::SetTextureBufferSize( } } -void PlatformViewOHOS::OnNativeImageFrameAvailable(void *data) -{ - auto frameData = reinterpret_cast(data); - if (frameData == nullptr || frameData->context_ == nullptr) { - FML_DLOG(ERROR) << "OnNativeImageFrameAvailable, frameData or context_ is null."; - return; - } - - if (frameData->context_->GetDestroyed()) { - FML_LOG(ERROR) << "OnNativeImageFrameAvailable NotifyDstroyed, will not MarkTextureFrameAvailable"; - return; - } - - std::shared_ptr ohos_surface = frameData->context_->ohos_surface_; - const TaskRunners task_runners = frameData->context_->task_runners_; - if (ohos_surface) { - fml::TaskRunner::RunNowOrPostTask( - task_runners.GetPlatformTaskRunner(), - [frameData]() { - if (frameData->context_->GetDestroyed()) { - FML_LOG(ERROR) << "OnNativeImageFrameAvailable NotifyDstroyed, will not MarkTextureFrameAvailable"; - return; - } - frameData->context_->MarkTextureFrameAvailable(frameData->texture_id_); - }); - } -} - -void PlatformViewOHOS::UnRegisterExternalTexture(int64_t texture_id) -{ - FML_DLOG(INFO) << "PlatformViewOHOS::UnRegisterExternalTexture, texture_id=" << texture_id; +void PlatformViewOHOS::UnRegisterExternalTexture(int64_t texture_id) { + FML_DLOG(INFO) << "PlatformViewOHOS::UnRegisterExternalTexture, texture_id=" + << texture_id; external_texture_gl_.erase(texture_id); UnregisterTexture(texture_id); - std::map::iterator it = contextDatas_.find(texture_id); - if (it != contextDatas_.end()) { - if (it->second != nullptr) { - OhosImageFrameData* data = reinterpret_cast(it->second); - task_runners_.GetPlatformTaskRunner()->PostDelayedTask( - [data_ = data]() { - delete data_; - }, - fml::TimeDelta::FromSeconds(2)); - data = nullptr; - it->second = nullptr; - } - contextDatas_.erase(texture_id); - } } -void PlatformViewOHOS::RegisterExternalTextureByPixelMap(int64_t texture_id, NativePixelMap* pixelMap) -{ +void PlatformViewOHOS::RegisterExternalTextureByPixelMap( + int64_t texture_id, + NativePixelMap* pixelMap) { if (ohos_context_->RenderingApi() == OHOSRenderingAPI::kOpenGLES) { auto iter = external_texture_gl_.find(texture_id); if (iter != external_texture_gl_.end()) { iter->second->DispatchPixelMap(pixelMap); } else { std::shared_ptr ohos_external_gl = - std::make_shared(texture_id, ohos_surface_); + std::make_shared(texture_id, ohos_surface_, delegate_, task_runners_); external_texture_gl_[texture_id] = ohos_external_gl; RegisterTexture(ohos_external_gl); ohos_external_gl->DispatchPixelMap(pixelMap); @@ -561,8 +513,9 @@ void PlatformViewOHOS::RegisterExternalTextureByPixelMap(int64_t texture_id, Nat } } -void PlatformViewOHOS::SetExternalTextureBackGroundPixelMap(int64_t texture_id, NativePixelMap* pixelMap) -{ +void PlatformViewOHOS::SetExternalTextureBackGroundPixelMap( + int64_t texture_id, + NativePixelMap* pixelMap) { if (ohos_context_->RenderingApi() == OHOSRenderingAPI::kOpenGLES) { auto iter = external_texture_gl_.find(texture_id); if (iter != external_texture_gl_.end()) { @@ -571,16 +524,37 @@ void PlatformViewOHOS::SetExternalTextureBackGroundPixelMap(int64_t texture_id, } } -void PlatformViewOHOS::OnTouchEvent(const std::shared_ptr touchPacketString, int size) -{ +void PlatformViewOHOS::OnTouchEvent( + const std::shared_ptr touchPacketString, + int size) { return napi_facade_->FlutterViewOnTouchEvent(touchPacketString, size); } -OhosImageFrameData::OhosImageFrameData( - PlatformViewOHOS* context, - int64_t texture_id) - : context_(context), texture_id_(texture_id) {} +void PlatformViewOHOS::RunTask(OHOS_THREAD_TYPE type, const fml::closure& task) +{ + fml::RefPtr TaskRunnerPtr = nullptr; + switch (type) { + case OHOS_THREAD_TYPE::OHOS_THREAD_TYPE_PLATFORM: + TaskRunnerPtr = task_runners_.GetPlatformTaskRunner(); + break; + case OHOS_THREAD_TYPE::OHOS_THREAD_TYPE_UI: + TaskRunnerPtr = task_runners_.GetUITaskRunner(); + break; + case OHOS_THREAD_TYPE::OHOS_THREAD_TYPE_RASTER: + TaskRunnerPtr = task_runners_.GetRasterTaskRunner(); + break; + case OHOS_THREAD_TYPE::OHOS_THREAD_TYPE_IO: + TaskRunnerPtr = task_runners_.GetIOTaskRunner(); + break; + default: + break; + } + + if (!TaskRunnerPtr) { + return; + } -OhosImageFrameData::~OhosImageFrameData() = default; + fml::TaskRunner::RunNowOrPostTask(TaskRunnerPtr, task); +} } // namespace flutter diff --git a/shell/platform/ohos/platform_view_ohos.h b/shell/platform/ohos/platform_view_ohos.h index 14c60e884c745ece2c2043ecb4d63222d86d153f..c6dd57ccfb4241e6d16a568f0f2c08d3c2e1a81a 100644 --- a/shell/platform/ohos/platform_view_ohos.h +++ b/shell/platform/ohos/platform_view_ohos.h @@ -35,9 +35,18 @@ #include "flutter/shell/platform/ohos/surface/ohos_snapshot_surface_producer.h" #include "flutter/shell/platform/ohos/surface/ohos_surface.h" #include "flutter/shell/platform/ohos/vsync_waiter_ohos.h" +#include "flutter/shell/platform/ohos/platform_view_ohos_delegate.h" +#include "flutter/shell/platform/ohos/accessibility/native_accessibility_channel.h" namespace flutter { +enum class OHOS_THREAD_TYPE { + OHOS_THREAD_TYPE_PLATFORM, + OHOS_THREAD_TYPE_UI, + OHOS_THREAD_TYPE_RASTER, + OHOS_THREAD_TYPE_IO, +}; + class OhosSurfaceFactoryImpl : public OhosSurfaceFactory { public: OhosSurfaceFactoryImpl(const std::shared_ptr& context, @@ -128,18 +137,23 @@ class PlatformViewOHOS final : public PlatformView { const override { return platform_message_handler_; } + void OnTouchEvent(std::shared_ptr touchPacketString, int size); + void RunTask(OHOS_THREAD_TYPE type, const fml::closure& task); + private: const std::shared_ptr napi_facade_; std::shared_ptr ohos_context_; + std::shared_ptr platform_view_ohos_delegate_; + NativeAccessibilityChannel nativeAccessibilityChannel_; + std::shared_ptr ohos_surface_; std::shared_ptr platform_message_handler_; std::shared_ptr surface_factory_; std::map> external_texture_gl_; - std::map contextDatas_; std::atomic isDestroyed_; @@ -193,20 +207,6 @@ class PlatformViewOHOS final : public PlatformView { void FireFirstFrameCallback(); FML_DISALLOW_COPY_AND_ASSIGN(PlatformViewOHOS); - - static void OnNativeImageFrameAvailable(void *data); -}; - -class OhosImageFrameData { - public: - OhosImageFrameData(PlatformViewOHOS* context, - int64_t texture_id); - - ~OhosImageFrameData(); - - PlatformViewOHOS* context_; - - int64_t texture_id_; }; } // namespace flutter diff --git a/shell/platform/ohos/platform_view_ohos_delegate.cpp b/shell/platform/ohos/platform_view_ohos_delegate.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ab423233dc76315ff4bae7de22f59d09053f1250 --- /dev/null +++ b/shell/platform/ohos/platform_view_ohos_delegate.cpp @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2023 Hunan OpenValley Digital Industry Development 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 "flutter/shell/platform/ohos/platform_view_ohos_delegate.h" +#include + +namespace flutter { + +void putStringAttributesIntoBuffer( + const StringAttributes& attributes, + int32_t* buffer_int32, + size_t& position, + std::vector>& string_attribute_args) { + if (attributes.empty()) { + buffer_int32[position++] = -1; + return; + } + buffer_int32[position++] = attributes.size(); + for (const auto& attribute : attributes) { + buffer_int32[position++] = attribute->start; + buffer_int32[position++] = attribute->end; + buffer_int32[position++] = static_cast(attribute->type); + switch (attribute->type) { + case StringAttributeType::kSpellOut: + buffer_int32[position++] = -1; + break; + case StringAttributeType::kLocale: + buffer_int32[position++] = string_attribute_args.size(); + std::shared_ptr locale_attribute = + std::static_pointer_cast(attribute); + string_attribute_args.push_back( + {locale_attribute->locale.begin(), locale_attribute->locale.end()}); + break; + } + } +} +// interaction between java and native, encoding the semantics info to bytebuffer +PlatformViewOHOSDelegate::PlatformViewOHOSDelegate( + std::shared_ptr napi_facade) + : napi_facade_(std::move(napi_facade)) {}; + +void PlatformViewOHOSDelegate::UpdateSemantics( + const flutter::SemanticsNodeUpdates& update, + const flutter::CustomAccessibilityActionUpdates& actions) { + constexpr size_t kBytesPerNode = 47 * sizeof(int32_t); + constexpr size_t kBytesPerChild = sizeof(int32_t); + constexpr size_t kBytesPerCustomAction = sizeof(int32_t); + constexpr size_t kBytesPerAction = 4 * sizeof(int32_t); + constexpr size_t kBytesPerStringAttribute = 4 * sizeof(int32_t); + + { + size_t num_bytes = 0; + for (const auto& value : update) { + num_bytes += kBytesPerNode; + num_bytes += + value.second.childrenInTraversalOrder.size() * kBytesPerChild; + num_bytes += value.second.childrenInHitTestOrder.size() * kBytesPerChild; + num_bytes += value.second.customAccessibilityActions.size() * + kBytesPerCustomAction; + num_bytes += + value.second.labelAttributes.size() * kBytesPerStringAttribute; + num_bytes += + value.second.valueAttributes.size() * kBytesPerStringAttribute; + num_bytes += value.second.increasedValueAttributes.size() * + kBytesPerStringAttribute; + num_bytes += value.second.decreasedValueAttributes.size() * + kBytesPerStringAttribute; + num_bytes += + value.second.hintAttributes.size() * kBytesPerStringAttribute; + } + // encode the updated nodes/actions into bytebuffer/strings + std::vector buffer(num_bytes); + std::vector strings; + std::vector> string_attribute_args; + + int32_t* buffer_int32 = reinterpret_cast(&buffer[0]); + float* buffer_float32 = reinterpret_cast(&buffer[0]); + + size_t position = 0; + for (const auto& value : update) { + // make sure you update kBytesPerNode and/or kBytesPerChild above to + // match the number of values you are sending. + const flutter::SemanticsNode& node = value.second; + buffer_int32[position++] = node.id; + buffer_int32[position++] = node.flags; + buffer_int32[position++] = node.actions; + buffer_int32[position++] = node.maxValueLength; + buffer_int32[position++] = node.currentValueLength; + buffer_int32[position++] = node.textSelectionBase; + buffer_int32[position++] = node.textSelectionExtent; + buffer_int32[position++] = node.platformViewId; + buffer_int32[position++] = node.scrollChildren; + buffer_int32[position++] = node.scrollIndex; + buffer_float32[position++] = static_cast(node.scrollPosition); + buffer_float32[position++] = static_cast(node.scrollExtentMax); + buffer_float32[position++] = static_cast(node.scrollExtentMin); + if (node.label.empty()) { + buffer_int32[position++] = -1; + } else { + buffer_int32[position++] = strings.size(); + strings.push_back(node.label); + } + + putStringAttributesIntoBuffer(node.labelAttributes, buffer_int32, + position, string_attribute_args); + if (node.value.empty()) { + buffer_int32[position++] = -1; + } else { + buffer_int32[position++] = strings.size(); + strings.push_back(node.value); + } + + putStringAttributesIntoBuffer(node.valueAttributes, buffer_int32, + position, string_attribute_args); + if (node.increasedValue.empty()) { + buffer_int32[position++] = -1; + } else { + buffer_int32[position++] = strings.size(); + strings.push_back(node.increasedValue); + } + + putStringAttributesIntoBuffer(node.increasedValueAttributes, buffer_int32, + position, string_attribute_args); + if (node.decreasedValue.empty()) { + buffer_int32[position++] = -1; + } else { + buffer_int32[position++] = strings.size(); + strings.push_back(node.decreasedValue); + } + + putStringAttributesIntoBuffer(node.decreasedValueAttributes, buffer_int32, + position, string_attribute_args); + + if (node.hint.empty()) { + buffer_int32[position++] = -1; + } else { + buffer_int32[position++] = strings.size(); + strings.push_back(node.hint); + } + + putStringAttributesIntoBuffer(node.hintAttributes, buffer_int32, position, + string_attribute_args); + + if (node.tooltip.empty()) { + buffer_int32[position++] = -1; + } else { + buffer_int32[position++] = strings.size(); + strings.push_back(node.tooltip); + } + + buffer_int32[position++] = node.textDirection; + buffer_float32[position++] = node.rect.left(); + buffer_float32[position++] = node.rect.top(); + buffer_float32[position++] = node.rect.right(); + buffer_float32[position++] = node.rect.bottom(); + node.transform.getColMajor(&buffer_float32[position]); + position += 16; + + buffer_int32[position++] = node.childrenInTraversalOrder.size(); + for (int32_t child : node.childrenInTraversalOrder) { + buffer_int32[position++] = child; + } + + for (int32_t child : node.childrenInHitTestOrder) { + buffer_int32[position++] = child; + } + + buffer_int32[position++] = node.customAccessibilityActions.size(); + for (int32_t child : node.customAccessibilityActions) { + buffer_int32[position++] = child; + } + } + + // custom accessibility actions. + size_t num_action_bytes = actions.size() * kBytesPerAction; + std::vector actions_buffer(num_action_bytes); + int32_t* actions_buffer_int32 = + reinterpret_cast(&actions_buffer[0]); + + std::vector action_strings; + size_t actions_position = 0; + for (const auto& value : actions) { + // If you edit this code, make sure you update kBytesPerAction + // to match the number of values you are sending. + const flutter::CustomAccessibilityAction& action = value.second; + actions_buffer_int32[actions_position++] = action.id; + actions_buffer_int32[actions_position++] = action.overrideId; + if (action.label.empty()) { + actions_buffer_int32[actions_position++] = -1; + } else { + actions_buffer_int32[actions_position++] = action_strings.size(); + action_strings.push_back(action.label); + } + if (action.hint.empty()) { + actions_buffer_int32[actions_position++] = -1; + } else { + actions_buffer_int32[actions_position++] = action_strings.size(); + action_strings.push_back(action.hint); + } + } + + if (!actions_buffer.empty()) { + FML_DLOG(INFO) << "PlatformViewOHOSDelegate::" + "updateCustomAccessibilityActions is called"; + } + + if (!buffer.empty()) { + FML_DLOG(INFO) << "PlatformViewOHOSDelegate::UpdateSemantics is called"; + } + } +} + +} // namespace flutter \ No newline at end of file diff --git a/shell/platform/ohos/platform_view_ohos_delegate.h b/shell/platform/ohos/platform_view_ohos_delegate.h new file mode 100644 index 0000000000000000000000000000000000000000..5b5fa634f01a7a025b2e85c5b32e27dbc19d0583 --- /dev/null +++ b/shell/platform/ohos/platform_view_ohos_delegate.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2023 Hunan OpenValley Digital Industry Development 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 SHELL_PLATFORM_OHOS_PLATFORM_VIEW_OHOS_DELEGATE +#define SHELL_PLATFORM_OHOS_PLATFORM_VIEW_OHOS_DELEGATE + +#include +#include +#include + +#include "flutter/shell/common/platform_view.h" +#include "flutter/shell/platform/ohos/napi/platform_view_ohos_napi.h" +#include "flutter/shell/platform/ohos/accessibility/ohos_accessibility_bridge.h" + +namespace flutter { + +class PlatformViewOHOSDelegate { + public: + explicit PlatformViewOHOSDelegate( + std::shared_ptr napi_facade); + + void UpdateSemantics( + const flutter::SemanticsNodeUpdates& update, + const flutter::CustomAccessibilityActionUpdates& actions); + + private: + const std::shared_ptr napi_facade_; + +}; +} // namespace flutter +#endif \ No newline at end of file diff --git a/shell/platform/ohos/testing/ohos_assert_provider_unittests.cpp b/shell/platform/ohos/testing/ohos_assert_provider_unittests.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c9a810e5daa0a3a8f43c6007e51e80020f07d87d --- /dev/null +++ b/shell/platform/ohos/testing/ohos_assert_provider_unittests.cpp @@ -0,0 +1,34 @@ +/* + * 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 +#include +#include +#include +#include + +#include "flutter/shell/platform/ohos/ohos_asset_provider.h" +#include "gtest/gtest.h" + +namespace flutter { +namespace testing { +TEST(OHOSAssetProviderTest, Create001) +{ + std::shared_ptr provider = std::make_shared(nullptr); + EXPECT_TRUE(provider.get() != nullptr); + std::unique_ptr newProvider = provider->Clone(); + EXPECT_TRUE(newProvider.get() != nullptr); +} +} +} \ No newline at end of file diff --git a/shell/platform/ohos/testing/ohos_context_gl_skia_uinttests.cpp b/shell/platform/ohos/testing/ohos_context_gl_skia_uinttests.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c6c129c0a30876387fa038a0c9ca11c7bfe8109a --- /dev/null +++ b/shell/platform/ohos/testing/ohos_context_gl_skia_uinttests.cpp @@ -0,0 +1,105 @@ +/* + * 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 +#include +#include +#include + +#include "flutter/common/task_runners.h" +#include "flutter/shell/common/thread_host.h" +#include "flutter/shell/platform/ohos/ohos_context_gl_skia.h" +#include "flutter/shell/platform/ohos/ohos_egl_surface.h" +#include "flutter/shell/platform/ohos/surface/ohos_native_window.h" +#include "gtest/gtest.h" + +namespace flutter { +namespace testing { +namespace { +TaskRunners MakeTaskRunners(const std::string& threadLabel) +{ + fml::MessageLoop::EnsureInitializedForCurrentThread(); + auto& loop = fml::MessageLoop::GetCurrent(); + return { + threadLabel, + loop.GetTaskRunner(), // platform + loop.GetTaskRunner(), // raster + loop.GetTaskRunner(), // ui + loop.GetTaskRunner() // io + }; +} + +std::unique_ptr CreateOhosContext() +{ + auto environment = fml::MakeRefCounted(); + std::string threadLabel = ::testing::UnitTest::GetInstance()->current_test_info()->name(); + TaskRunners taskRunners = MakeTaskRunners(threadLabel); + return std::make_unique(OHOSRenderingAPI::kOpenGLES, environment, taskRunners, 0); +} +} // namespace +TEST(OHOSContextGlSkiaTest, CreateOnscreenSurface) +{ + std::unique_ptr context = CreateOhosContext(); + EXPECT_TRUE(context.get() != nullptr); + + auto window = fml::MakeRefCounted(nullptr); + std::unique_ptr surface = context->CreateOnscreenSurface(window); + EXPECT_TRUE(surface.get() != nullptr); +} + +TEST(OHOSContextGlSkiaTest, CreateOffscreenSurface) +{ + std::unique_ptr context = CreateOhosContext(); + EXPECT_TRUE(context.get() != nullptr); + + std::unique_ptr surface = context->CreateOffscreenSurface(); + EXPECT_TRUE(surface->IsValid()); +} + +TEST(OHOSContextGlSkiaTest, CreatePbufferSurface) +{ + std::unique_ptr context = CreateOhosContext(); + EXPECT_TRUE(context.get() != nullptr); + + std::unique_ptr surface = context->CreatePbufferSurface(); + EXPECT_TRUE(surface->IsValid()); +} + +TEST(OHOSContextGlSkiaTest, Environment) +{ + std::unique_ptr context = CreateOhosContext(); + EXPECT_TRUE(context.get() != nullptr); + + fml::RefPtr environment = context->Environment(); + EXPECT_TRUE(environment.get() != nullptr); +} + +TEST(OHOSContextGlSkiaTest, ClearCurrent) +{ + std::unique_ptr context = CreateOhosContext(); + EXPECT_TRUE(context.get() != nullptr); + EXPECT_TRUE(context->ClearCurrent()); +} + +TEST(OHOSContextGlSkiaTest, CreateNewContext) +{ + std::unique_ptr context = CreateOhosContext(); + EXPECT_TRUE(context.get() != nullptr); + + EGLContext newContext = context->CreateNewContext(); + EXPECT_TRUE(newContext != EGL_NO_CONTEXT); +} +} +} + diff --git a/shell/platform/ohos/testing/ohos_display_uinttests.cpp b/shell/platform/ohos/testing/ohos_display_uinttests.cpp new file mode 100644 index 0000000000000000000000000000000000000000..78bd056765e2e4b663f167073fa55b80ed15b530 --- /dev/null +++ b/shell/platform/ohos/testing/ohos_display_uinttests.cpp @@ -0,0 +1,34 @@ +/* + * 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 +#include +#include +#include + +#include "flutter/shell/platform/ohos/ohos_display.h" +#include "gtest/gtest.h" + +namespace flutter { +namespace testing { + +const double DEFAULT_FPS = 60; +TEST(OHOSDisplayTest, GetRefreshRate) +{ + std::shared_ptr display = std::make_shared(nullptr); + EXPECT_TRUE(display.get() != nullptr); + EXPECT_EQ(display->GetRefreshRate(), DEFAULT_FPS); +} +} +} \ No newline at end of file diff --git a/shell/platform/ohos/testing/ohos_egl_surface_unittests.cpp b/shell/platform/ohos/testing/ohos_egl_surface_unittests.cpp new file mode 100644 index 0000000000000000000000000000000000000000..62980266b09e6056113db236ed43044032ea8dec --- /dev/null +++ b/shell/platform/ohos/testing/ohos_egl_surface_unittests.cpp @@ -0,0 +1,116 @@ +/* + * 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 +#include +#include +#include + +#include "flutter/common/task_runners.h" +#include "flutter/shell/common/thread_host.h" +#include "flutter/shell/platform/ohos/ohos_context_gl_skia.h" +#include "flutter/shell/platform/ohos/ohos_egl_surface.h" +#include "gtest/gtest.h" + +namespace flutter { +namespace testing { +namespace { +TaskRunners MakeTaskRunners(const std::string& threadLabel) +{ + fml::MessageLoop::EnsureInitializedForCurrentThread(); + auto& loop = fml::MessageLoop::GetCurrent(); + return { + threadLabel, + loop.GetTaskRunner(), // platform + loop.GetTaskRunner(), // raster + loop.GetTaskRunner(), // ui + loop.GetTaskRunner() // io + }; +} + +std::unique_ptr CreateOhosContext() +{ + fml::RefPtr environment = fml::MakeRefCounted(); + std::string threadLabel = ::testing::UnitTest::GetInstance()->current_test_info()->name(); + TaskRunners taskRunners = MakeTaskRunners(threadLabel); + return std::make_unique(OHOSRenderingAPI::kOpenGLES, environment, taskRunners, 0); +} +} // namespace + +TEST(OHOSEGLSurfaceTest, MakeCurrent) +{ + std::unique_ptr context = CreateOhosContext(); + EXPECT_TRUE(context.get() != nullptr); + + std::unique_ptr surface = context->CreateOffscreenSurface(); + EXPECT_TRUE(surface->IsValid()); + + OhosEGLSurfaceMakeCurrentStatus status = surface->MakeCurrent(); + EXPECT_EQ(status, OhosEGLSurfaceMakeCurrentStatus::kSuccessMadeCurrent); +} + +TEST(OHOSEGLSurfaceTest, SupportsPartialRepaint) +{ + std::unique_ptr context = CreateOhosContext(); + EXPECT_TRUE(context.get() != nullptr); + + std::unique_ptr surface = context->CreateOffscreenSurface(); + EXPECT_TRUE(surface->IsValid()); + + bool res = surface->SupportsPartialRepaint(); + EXPECT_EQ(res, false); +} + +TEST(OHOSEGLSurfaceTest, InitialDamage) +{ + std::unique_ptr context = CreateOhosContext(); + EXPECT_TRUE(context.get() != nullptr); + + std::unique_ptr surface = context->CreateOffscreenSurface(); + EXPECT_TRUE(surface->IsValid()); + + std::optional rect = surface->InitialDamage(); + EXPECT_EQ(rect.has_value(), false); +} + +TEST(OHOSEGLSurfaceTest, SetDamageRegion) +{ + std::unique_ptr context = CreateOhosContext(); + EXPECT_TRUE(context.get() != nullptr); + + std::unique_ptr surface = context->CreateOffscreenSurface(); + EXPECT_TRUE(surface->IsValid()); + + std::optional rect(SkIRect::MakeEmpty()); + surface->SetDamageRegion(rect); + EXPECT_EQ(rect.has_value(), true); + SkISize size = surface->GetSize(); + EXPECT_TRUE(size.width() != 0); + EXPECT_TRUE(size.height() != 0); +} + +TEST(OHOSEGLSurfaceTest, SetPresentationTime) +{ + std::unique_ptr context = CreateOhosContext(); + EXPECT_TRUE(context.get() != nullptr); + + std::unique_ptr surface = context->CreateOffscreenSurface(); + EXPECT_TRUE(surface->IsValid()); + + fml::TimePoint timePoint = fml::TimePoint::CurrentWallTime(); + bool res = surface->SetPresentationTime(timePoint); + EXPECT_EQ(res, false); +} +} +} \ No newline at end of file diff --git a/shell/platform/ohos/testing/ohos_environment_gl_unittests.cpp b/shell/platform/ohos/testing/ohos_environment_gl_unittests.cpp new file mode 100644 index 0000000000000000000000000000000000000000..096ae8bfe50b41fc77fc1ae73f495af5582e7f06 --- /dev/null +++ b/shell/platform/ohos/testing/ohos_environment_gl_unittests.cpp @@ -0,0 +1,32 @@ +/* + * 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 +#include +#include +#include + +#include "flutter/shell/platform/ohos/ohos_environment_gl.h" +#include "gtest/gtest.h" + +namespace flutter { +namespace testing { + +TEST(OHOSEnvironmentGLTest, Create) +{ + fml::RefPtr environment = fml::MakeRefCounted(); + EXPECT_TRUE(environment->IsValid()); +} +} +} \ No newline at end of file diff --git a/shell/platform/ohos/testing/ohos_external_texture_gl_unittests.cpp b/shell/platform/ohos/testing/ohos_external_texture_gl_unittests.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5e1cda2737104ea246098ac915609e6150b7fd16 --- /dev/null +++ b/shell/platform/ohos/testing/ohos_external_texture_gl_unittests.cpp @@ -0,0 +1,60 @@ +/* + * 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 +#include +#include +#include + +#include "flutter/shell/platform/ohos/ohos_external_texture_gl.h" +#include "gtest/gtest.h" + +namespace flutter { +namespace testing { + +namespace { +TaskRunners MakeTaskRunners(const std::string& threadLabel) +{ + fml::MessageLoop::EnsureInitializedForCurrentThread(); + auto& loop = fml::MessageLoop::GetCurrent(); + return { + threadLabel, + loop.GetTaskRunner(), // platform + loop.GetTaskRunner(), // raster + loop.GetTaskRunner(), // ui + loop.GetTaskRunner() // io + }; +} + +std::shared_ptr CreateOhosContext() +{ + fml::RefPtr environment = fml::MakeRefCounted(); + std::string threadLabel = ::testing::UnitTest::GetInstance()->current_test_info()->name(); + TaskRunners taskRunners = MakeTaskRunners(threadLabel); + return std::make_shared(OHOSRenderingAPI::kOpenGLES, environment, taskRunners, 0); +} +} // namespace + +TEST(OHOSExternalTextureGLTest, OnTextureUnregistered) +{ + std::shared_ptr context = CreateOhosContext(); + EXPECT_TRUE(context.get() != nullptr); + std::shared_ptr surfaceSkia = std::make_shared(context); + std::shared_ptr extTexture = std::make_shared(0, surfaceSkia); + + extTexture->OnTextureUnregistered(); + EXPECT_TRUE(extTexture->first_update_ == false); +} +} +} \ No newline at end of file diff --git a/shell/platform/ohos/testing/ohos_surface_gl_skia_unittests.cpp b/shell/platform/ohos/testing/ohos_surface_gl_skia_unittests.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f1d98fb76554fe3e2ba102b467da25aa69668ca6 --- /dev/null +++ b/shell/platform/ohos/testing/ohos_surface_gl_skia_unittests.cpp @@ -0,0 +1,102 @@ +/* + * 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 +#include +#include +#include + +#include "flutter/common/task_runners.h" +#include "flutter/fml/message_loop.h" +#include "flutter/shell/common/thread_host.h" +#include "flutter/shell/platform/ohos/ohos_context_gl_skia.h" +#include "flutter/shell/platform/ohos/ohos_surface_gl_skia.h" +#include "gtest/gtest.h" + +namespace flutter { +namespace testing { +namespace { +TaskRunners CreateTaskRunners(const std::string& threadLabel) +{ + fml::MessageLoop::EnsureInitializedForCurrentThread(); + auto& loop = fml::MessageLoop::GetCurrent(); + return { + threadLabel, + loop.GetTaskRunner(), // platform + loop.GetTaskRunner(), // raster + loop.GetTaskRunner(), // ui + loop.GetTaskRunner() // io + }; +} + +std::unique_ptr CreateOhosContext() +{ + auto environment = fml::MakeRefCounted(); + std::string threadLabel = ::testing::UnitTest::GetInstance()->current_test_info()->name(); + TaskRunners task_runners = CreateTaskRunners(threadLabel); + return std::make_unique(OHOSRenderingAPI::kOpenGLES, environment, task_runners, 0); +} +} // namespace + +TEST(OhosSurfaceGLSkiaTest, Create) +{ + std::shared_ptr context = CreateOhosContext(); + EXPECT_TRUE(context != nullptr); + std::unique_ptr surfaceGL = std::make_unique(context); + EXPECT_TRUE(surfaceGL != nullptr); + EXPECT_TRUE(surfaceGL->IsValid()); +} + +TEST(OhosSurfaceGLSkiaTest, ResourceContext) +{ + std::shared_ptr context = CreateOhosContext(); + EXPECT_TRUE(context != nullptr); + + std::unique_ptr surfaceGL = std::make_unique(context); + EXPECT_TRUE(surfaceGL != nullptr); + EXPECT_TRUE(surfaceGL->IsValid()); + + EXPECT_TRUE(surfaceGL->ResourceContextMakeCurrent()); + EXPECT_TRUE(surfaceGL->ResourceContextClearCurrent()); +} + +TEST(OhosSurfaceGLSkiaTest, GetContext) +{ + std::shared_ptr context = CreateOhosContext(); + EXPECT_TRUE(context != nullptr); + std::unique_ptr surfaceGL = std::make_unique(context); + EXPECT_TRUE(surfaceGL != nullptr); + EXPECT_TRUE(surfaceGL->IsValid()); + + EXPECT_TRUE(surfaceGL->CreateSnapshotSurface() != nullptr); + + std::unique_ptr result = surfaceGL->GLContextMakeCurrent(); + EXPECT_TRUE(result != nullptr); + + SurfaceFrame::FramebufferInfo info = surfaceGL->GLContextFramebufferInfo(); + EXPECT_TRUE(info.supports_readback == true); + + std::optional frameDamage(SkIRect::MakeEmpty()); + std::optional bufferDamage(SkIRect::MakeEmpty()); + GLPresentInfo presentInfo = {0, frameDamage, std::nullopt, bufferDamage}; + EXPECT_TRUE(surfaceGL->GLContextPresent(presentInfo)); + + GLFrameInfo frameInfo; + EXPECT_TRUE(surfaceGL->GLContextFBO(frameInfo).fbo_id == 0); + + sk_sp grInterface = surfaceGL->GetGLInterface(); + EXPECT_TRUE(grInterface != nullptr); +} +} +} \ No newline at end of file diff --git a/shell/platform/ohos/testing/ohos_surface_software_unittests.cpp b/shell/platform/ohos/testing/ohos_surface_software_unittests.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c84c1826612bc3ebf16b367f749f20c48f7ec7e5 --- /dev/null +++ b/shell/platform/ohos/testing/ohos_surface_software_unittests.cpp @@ -0,0 +1,65 @@ +/* + * 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 +#include +#include +#include + +#include "flutter/shell/platform/ohos/ohos_surface_software.h" +#include "gtest/gtest.h" + +namespace flutter { +namespace testing { +namespace { +std::shared_ptr CreateOhosContext() +{ + return std::make_shared(OHOSRenderingAPI::kSoftware); +} +} // namespace + +TEST(OHOSSurfaceSoftwareTest, Create) +{ + std::shared_ptr context = CreateOhosContext(); + EXPECT_TRUE(context != nullptr); + std::unique_ptr surfaceSoftWare = std::make_unique(context); + EXPECT_TRUE(surfaceSoftWare != nullptr); + EXPECT_TRUE(surfaceSoftWare->IsValid()); +} + +TEST(OHOSSurfaceSoftwareTest, CreateGPUSurface) +{ + std::shared_ptr context = CreateOhosContext(); + EXPECT_TRUE(context != nullptr); + std::unique_ptr surfaceSoftWare = std::make_unique(context); + EXPECT_TRUE(surfaceSoftWare != nullptr); + + sk_sp grContext = GrDirectContext::MakeMock(nullptr); + std::unique_ptr gpuSurface = surfaceSoftWare->CreateGPUSurface(grContext.get()); + EXPECT_TRUE(gpuSurface != nullptr); +} + +TEST(OHOSSurfaceSoftwareTest, AcquireBackingStore) +{ + std::shared_ptr context = CreateOhosContext(); + EXPECT_TRUE(context != nullptr); + std::unique_ptr surfaceSoftWare = std::make_unique(context); + EXPECT_TRUE(surfaceSoftWare != nullptr); + EXPECT_TRUE(surfaceSoftWare->IsValid()); + + sk_sp skSurface = surfaceSoftWare->AcquireBackingStore({100, 100}); + EXPECT_TRUE(skSurface != nullptr); +} +} +} \ No newline at end of file diff --git a/shell/platform/ohos/testing/ohos_touch_processor_unittests.cpp b/shell/platform/ohos/testing/ohos_touch_processor_unittests.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c9b2a74de2cdf6c10c4b6418f2dc097e7c5c15c1 --- /dev/null +++ b/shell/platform/ohos/testing/ohos_touch_processor_unittests.cpp @@ -0,0 +1,62 @@ +/* + * 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 +#include +#include +#include + +#include "flutter/shell/platform/ohos/ohos_touch_processor.h" +#include "gtest/gtest.h" + +namespace flutter { +namespace testing { + +TEST(OhosTouchProcessorTest, getPointerChangeForAction) +{ + OhosTouchProcessor touchProcessor; + int maskedAction = OH_NATIVEXCOMPONENT_DOWN; + EXPECT_EQ(touchProcessor.getPointerChangeForAction(maskedAction), PointerData::Change::kDown); + maskedAction = OH_NATIVEXCOMPONENT_UP; + EXPECT_EQ(touchProcessor.getPointerChangeForAction(maskedAction), PointerData::Change::kUp); + maskedAction = OH_NATIVEXCOMPONENT_MOVE; + EXPECT_EQ(touchProcessor.getPointerChangeForAction(maskedAction), PointerData::Change::kMove); + maskedAction = OH_NATIVEXCOMPONENT_CANCEL; + EXPECT_EQ(touchProcessor.getPointerChangeForAction(maskedAction), PointerData::Change::kCancel); +} + +TEST(OhosTouchProcessorTest, getPointerDeviceTypeForToolType) +{ + OhosTouchProcessor touchProcessor; + int toolType = OH_NATIVEXCOMPONENT_TOOL_TYPE_FINGER; + EXPECT_EQ(touchProcessor.getPointerDeviceTypeForToolType(toolType), PointerData::DeviceKind::kTouch); + toolType = OH_NATIVEXCOMPONENT_TOOL_TYPE_PEN; + EXPECT_EQ(touchProcessor.getPointerDeviceTypeForToolType(toolType), PointerData::DeviceKind::kStylus); + toolType = OH_NATIVEXCOMPONENT_TOOL_TYPE_RUBBER; + EXPECT_EQ(touchProcessor.getPointerDeviceTypeForToolType(toolType), PointerData::DeviceKind::kInvertedStylus); + toolType = OH_NATIVEXCOMPONENT_TOOL_TYPE_BRUSH; + EXPECT_EQ(touchProcessor.getPointerDeviceTypeForToolType(toolType), PointerData::DeviceKind::kStylus); + toolType = OH_NATIVEXCOMPONENT_TOOL_TYPE_PENCIL; + EXPECT_EQ(touchProcessor.getPointerDeviceTypeForToolType(toolType), PointerData::DeviceKind::kStylus); + toolType = OH_NATIVEXCOMPONENT_TOOL_TYPE_AIRBRUSH; + EXPECT_EQ(touchProcessor.getPointerDeviceTypeForToolType(toolType), PointerData::DeviceKind::kStylus); + toolType = OH_NATIVEXCOMPONENT_TOOL_TYPE_MOUSE; + EXPECT_EQ(touchProcessor.getPointerDeviceTypeForToolType(toolType), PointerData::DeviceKind::kMouse); + toolType = OH_NATIVEXCOMPONENT_TOOL_TYPE_LENS; + EXPECT_EQ(touchProcessor.getPointerDeviceTypeForToolType(toolType), PointerData::DeviceKind::kTouch); + toolType = OH_NATIVEXCOMPONENT_TOOL_TYPE_UNKNOWN; + EXPECT_EQ(touchProcessor.getPointerDeviceTypeForToolType(toolType), PointerData::DeviceKind::kTouch); +} +} +} \ No newline at end of file diff --git a/shell/platform/ohos/testing/ohos_xcomponent_adapter_unittests.cpp b/shell/platform/ohos/testing/ohos_xcomponent_adapter_unittests.cpp new file mode 100644 index 0000000000000000000000000000000000000000..aa1538956c72448ef158f108c89c7c1a5e31d497 --- /dev/null +++ b/shell/platform/ohos/testing/ohos_xcomponent_adapter_unittests.cpp @@ -0,0 +1,35 @@ +/* + * 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 +#include +#include +#include + +#include "flutter/shell/platform/ohos/ohos_xcomponent_adapter.h" +#include "gtest/gtest.h" + +namespace flutter { +namespace testing { +TEST(XComponentAdapterTest, SetNativeXComponent) +{ + XComponentAdapter* xcomponentAdapter = XComponentAdapter::GetInstance(); + std::string id = "test"; + OH_NativeXComponent* nativeXComponent = nullptr; + xcomponentAdapter->SetNativeXComponent(id, nativeXComponent); + + EXPECT_TRUE(xcomponentAdapter->xcomponetMap_.size() > 0); +} +} +} diff --git a/shell/platform/ohos/testing/vsync_waiter_ohos_unittests.cpp b/shell/platform/ohos/testing/vsync_waiter_ohos_unittests.cpp new file mode 100644 index 0000000000000000000000000000000000000000..48245deba360d6b47e17d43339ddd7f79c066180 --- /dev/null +++ b/shell/platform/ohos/testing/vsync_waiter_ohos_unittests.cpp @@ -0,0 +1,48 @@ +/* + * 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 +#include +#include +#include + +#include "flutter/common/task_runners.h" +#include "flutter/shell/platform/ohos/vsync_waiter_ohos.h" +#include "gtest/gtest.h" + +namespace flutter { +namespace testing { +namespace { +TaskRunners CreateTaskRunners(const std::string& threadLabel) +{ + fml::MessageLoop::EnsureInitializedForCurrentThread(); + auto& loop = fml::MessageLoop::GetCurrent(); + return { + threadLabel, + loop.GetTaskRunner(), // platform + loop.GetTaskRunner(), // raster + loop.GetTaskRunner(), // ui + loop.GetTaskRunner() // io + }; +} +} +TEST(VsyncWaiterOHOSTest, Create) +{ + std::string threadLabel = ::testing::UnitTest::GetInstance()->current_test_info()->name(); + TaskRunners runners = CreateTaskRunners(threadLabel); + std::shared_ptr waiter = std::make_shared(runners); + EXPECT_TRUE(waiter != nullptr); +} +} +} \ No newline at end of file diff --git a/shell/platform/ohos/types.h b/shell/platform/ohos/types.h index 9be037096beb0ab63c0aeacae7d04ff0dd1ba6cd..69fa5fd484d54e9d6e878aaaa56ae7c9ee86f0cd 100644 --- a/shell/platform/ohos/types.h +++ b/shell/platform/ohos/types.h @@ -24,5 +24,45 @@ enum Locales { SCRIPT_INDEX, }; +using OHOS_SurfaceBufferUsage = enum { + BUFFER_USAGE_CPU_READ = (1ULL << 0), /**< CPU read buffer */ + BUFFER_USAGE_CPU_WRITE = (1ULL << 1), /**< CPU write memory */ + BUFFER_USAGE_MEM_MMZ = (1ULL << 2), /**< Media memory zone (MMZ) */ + BUFFER_USAGE_MEM_DMA = (1ULL << 3), /**< Direct memory access (DMA) buffer */ + BUFFER_USAGE_MEM_SHARE = (1ULL << 4), /**< Shared memory buffer*/ + BUFFER_USAGE_MEM_MMZ_CACHE = (1ULL << 5), /**< MMZ with cache*/ + BUFFER_USAGE_MEM_FB = (1ULL << 6), /**< Framebuffer */ + BUFFER_USAGE_ASSIGN_SIZE = (1ULL << 7), /**< Memory assigned */ + BUFFER_USAGE_HW_RENDER = (1ULL << 8), /**< For GPU write case */ + BUFFER_USAGE_HW_TEXTURE = (1ULL << 9), /**< For GPU read case */ + BUFFER_USAGE_HW_COMPOSER = (1ULL << 10), /**< For hardware composer */ + BUFFER_USAGE_PROTECTED = + (1ULL << 11), /**< For safe buffer case, such as DRM */ + BUFFER_USAGE_CAMERA_READ = (1ULL << 12), /**< For camera read case */ + BUFFER_USAGE_CAMERA_WRITE = (1ULL << 13), /**< For camera write case */ + BUFFER_USAGE_VIDEO_ENCODER = (1ULL << 14), /**< For encode case */ + BUFFER_USAGE_VIDEO_DECODER = (1ULL << 15), /**< For decode case */ + BUFFER_USAGE_VENDOR_PRI0 = (1ULL << 44), /**< Reserverd for vendor */ + BUFFER_USAGE_VENDOR_PRI1 = (1ULL << 45), /**< Reserverd for vendor */ + BUFFER_USAGE_VENDOR_PRI2 = (1ULL << 46), /**< Reserverd for vendor */ + BUFFER_USAGE_VENDOR_PRI3 = (1ULL << 47), /**< Reserverd for vendor */ + BUFFER_USAGE_VENDOR_PRI4 = (1ULL << 48), /**< Reserverd for vendor */ + BUFFER_USAGE_VENDOR_PRI5 = (1ULL << 49), /**< Reserverd for vendor */ + BUFFER_USAGE_VENDOR_PRI6 = (1ULL << 50), /**< Reserverd for vendor */ + BUFFER_USAGE_VENDOR_PRI7 = (1ULL << 51), /**< Reserverd for vendor */ + BUFFER_USAGE_VENDOR_PRI8 = (1ULL << 52), /**< Reserverd for vendor */ + BUFFER_USAGE_VENDOR_PRI9 = (1ULL << 53), /**< Reserverd for vendor */ + BUFFER_USAGE_VENDOR_PRI10 = (1ULL << 54), /**< Reserverd for vendor */ + BUFFER_USAGE_VENDOR_PRI11 = (1ULL << 55), /**< Reserverd for vendor */ + BUFFER_USAGE_VENDOR_PRI12 = (1ULL << 56), /**< Reserverd for vendor */ + BUFFER_USAGE_VENDOR_PRI13 = (1ULL << 57), /**< Reserverd for vendor */ + BUFFER_USAGE_VENDOR_PRI14 = (1ULL << 58), /**< Reserverd for vendor */ + BUFFER_USAGE_VENDOR_PRI15 = (1ULL << 59), /**< Reserverd for vendor */ + BUFFER_USAGE_VENDOR_PRI16 = (1ULL << 60), /**< Reserverd for vendor */ + BUFFER_USAGE_VENDOR_PRI17 = (1ULL << 61), /**< Reserverd for vendor */ + BUFFER_USAGE_VENDOR_PRI18 = (1ULL << 62), /**< Reserverd for vendor */ + BUFFER_USAGE_VENDOR_PRI19 = (1ULL << 63), /**< Reserverd for vendor */ +}; + } // namespace flutter #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 new file mode 100644 index 0000000000000000000000000000000000000000..5ddbb0e954e9df73b55e955b54b266fa1adca117 --- /dev/null +++ b/shell/platform/ohos/utils/ddl_utils.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef DDL_UTILS_H +#define DDL_UTILS_H + +#include +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) + +#endif // FOUNDATION_ACE_INTERFACE_INNERKITS_ACE_UTILS_H diff --git a/testing/testing.gni b/testing/testing.gni index 3fadcbbc71e16935c24d2c6de108479ad09902e2..e2016e48fc466ca4768f790952b32525f84c8eab 100644 --- a/testing/testing.gni +++ b/testing/testing.gni @@ -331,7 +331,11 @@ template("test_fixtures") { copy_fixtures_target_name = "_cf_$target_name" copy_fixtures(copy_fixtures_target_name) { fixtures = invoker.fixtures - dest = dest + if (is_ohos) { + dest = target_gen_dir + } else { + dest = dest + } forward_variables_from(invoker, [ "deps" ]) } test_public_deps += [ ":$copy_fixtures_target_name" ] diff --git a/tools/gn b/tools/gn index dab248aff26714073cea71e65bf69211f8a47b05..ee44e2512a164fa879863bc5c822adb21cb7632c 100755 --- a/tools/gn +++ b/tools/gn @@ -344,8 +344,6 @@ def to_gn_args(args): gn_args['target_os'] = args.target_os gn_args['target_cpu'] = get_target_cpu(args) gn_args['dart_target_arch'] = gn_args['target_cpu'] - if (args.target_os == 'ohos'): - gn_args['host_cpu'] = get_host_cpu() print("ARGS.target_os:%s-%s" % (args.target_os,gn_args['target_os'] ) ) # We cannot cross-compile for 32 bit arm on a Windows host. We work around @@ -763,7 +761,7 @@ def parse_args(args): '--ohos-cpu', type=str, choices=['x64', 'x86', 'arm64', 'arm'] ) parser.add_argument( - '--ohos-api-int', type=int, choices=[11, 12], default=11 + '--ohos-api-int', type=int, default=13 ) parser.add_argument( '--fuchsia-cpu', type=str, choices=['x64', 'arm64'], default='x64' diff --git a/vulkan/vulkan_window.cc b/vulkan/vulkan_window.cc index a7067fff3f907a68bd8ac570e6fe2328fe79c0bc..25608f54afff6e503044a2deff3293ded7d1d3c5 100644 --- a/vulkan/vulkan_window.cc +++ b/vulkan/vulkan_window.cc @@ -116,6 +116,7 @@ GrDirectContext* VulkanWindow::GetSkiaGrContext() { } bool VulkanWindow::CreateSkiaGrContext() { +#ifdef SK_VULKAN GrVkBackendContext backend_context; if (!CreateSkiaBackendContext(&backend_context)) { @@ -136,6 +137,9 @@ bool VulkanWindow::CreateSkiaGrContext() { skia_gr_context_ = context; return true; +#else + return false; +#endif } bool VulkanWindow::CreateSkiaBackendContext(GrVkBackendContext* context) {