diff --git a/frameworks/core/BUILD.gn b/frameworks/core/BUILD.gn index 48c0dded784758219dfe8d9713b2c8299f3a8200..76e2b635f31efb33e61f0766afdd68f10d988a68 100644 --- a/frameworks/core/BUILD.gn +++ b/frameworks/core/BUILD.gn @@ -1055,6 +1055,7 @@ template("ace_core_ng_source_set") { "ipc:ipc_core", "napi:ace_napi", "webview:libnweb", + "webview:cj_webview_ffi", "window_manager:libwm", ] } else { diff --git a/frameworks/core/components/web/BUILD.gn b/frameworks/core/components/web/BUILD.gn index d63eae943f2e5d5018e88f43ac97be2cab76830b..8c7fee7dcd6bb2784305a001b0b86de7b20853d0 100644 --- a/frameworks/core/components/web/BUILD.gn +++ b/frameworks/core/components/web/BUILD.gn @@ -51,6 +51,7 @@ build_component("web") { "napi:ace_napi", "opengles:libGLES", "webview:libnweb", + "webview:cj_webview_ffi", "window_manager:libwm", ] } diff --git a/frameworks/core/components/web/resource/web_delegate.cpp b/frameworks/core/components/web/resource/web_delegate.cpp index 2b2725534b8aadf9309f4dd672f5b3e08834f99e..d9287c4f2a940a4bb58cd1ea6945f4b4c3ee635f 100644 --- a/frameworks/core/components/web/resource/web_delegate.cpp +++ b/frameworks/core/components/web/resource/web_delegate.cpp @@ -25,6 +25,7 @@ #include "adapter/ohos/entrance/ace_container.h" #include "adapter/ohos/entrance/utils.h" +#include "arkweb_net_error_list.h" #include "base/json/json_util.h" #include "base/log/ace_trace.h" #include "base/log/log.h" @@ -102,6 +103,7 @@ constexpr uint32_t DRAG_DELAY_MILLISECONDS = 300; constexpr uint32_t ACCESSIBILITY_DELAY_MILLISECONDS = 100; constexpr uint32_t DELAY_MILLISECONDS_1000 = 1000; constexpr uint32_t NO_NATIVE_FINGER_TYPE = 100; +constexpr uint32_t ACCESSIBILITY_PAGE_CHANGE_DELAY_MILLISECONDS = 100; const std::string DEFAULT_NATIVE_EMBED_ID = "0"; const std::vector CANONICALENCODINGNAMES = { @@ -4840,6 +4842,7 @@ void WebDelegate::OnPageFinished(const std::string& param) } }, TaskExecutor::TaskType::JS, "ArkUIWebPageFinished"); + AccessibilitySendPageChange(); } void WebDelegate::OnProgressChanged(int param) @@ -5378,6 +5381,96 @@ void WebDelegate::OnErrorReceive(std::shared_ptr(error->ErrorInfo(), error->ErrorCode()))); }, TaskExecutor::TaskType::JS, "ArkUIWebErrorReceive"); + + if (error->ErrorCode() == ArkWeb_NetError::ARKWEB_ERR_INTERNET_DISCONNECTED) { + AccessibilityReleasePageEvent(); + } +} + +void WebDelegate::AccessibilitySendPageChange() +{ + CHECK_NULL_VOID(taskExecutor_); + taskExecutor_->PostDelayedTask( + [weak = WeakClaim(this)]() { + auto delegate = weak.Upgrade(); + CHECK_NULL_VOID(delegate); + auto webPattern = delegate->webPattern_.Upgrade(); + CHECK_NULL_VOID(webPattern); + auto context = AceType::DynamicCast(delegate->context_.Upgrade()); + CHECK_NULL_VOID(context); + auto webNode = webPattern->GetHost(); + CHECK_NULL_VOID(webNode); + auto accessibilityManager = context->GetAccessibilityManager(); + CHECK_NULL_VOID(accessibilityManager); + if (!accessibilityManager->IsScreenReaderEnabled()) { + return; + } + if (webNode->IsOnMainTree()) { + if (!webPattern->CheckVisible()) { + TAG_LOGI(AceLogTag::ACE_WEB, + "WebDelegate::AccessibilitySendPageChange CheckVisible accessibilityId = " + "%{public}" PRId64, + webNode->GetAccessibilityId()); + return; + } + if (accessibilityManager->CheckPageEventCached(webNode, false)) { + TAG_LOGI(AceLogTag::ACE_WEB, + "WebDelegate::AccessibilitySendPageChange CheckPageEventCached accessibilityId = " + "%{public}" PRId64, + webNode->GetAccessibilityId()); + accessibilityManager->ReleasePageEvent(webNode, true, true); + return; + } + auto navigationMgr = context->GetNavigationManager(); + if (navigationMgr && navigationMgr->IsNavigationInAnimation()) { + TAG_LOGI(AceLogTag::ACE_WEB, + "WebDelegate::AccessibilitySendPageChange IsNavigationInAnimation accessibilityId = " + "%{public}" PRId64, + webNode->GetAccessibilityId()); + accessibilityManager->ReleasePageEvent(webNode, true, true); + return; + } + TAG_LOGI(AceLogTag::ACE_WEB, + "WebDelegate::AccessibilitySendPageChange accessibilityId = %{public}" PRId64, + webNode->GetAccessibilityId()); + accessibilityManager->ReleasePageEvent(webNode, true, true); + AccessibilityEvent event; + event.nodeId = webNode->GetAccessibilityId(); + event.type = AccessibilityEventType::PAGE_CHANGE; + accessibilityManager->SendAccessibilityAsyncEvent(event); + } + }, + TaskExecutor::TaskType::UI, ACCESSIBILITY_PAGE_CHANGE_DELAY_MILLISECONDS, + "ArkUIWebAccessibilitySendPageChange"); +} + +void WebDelegate::AccessibilityReleasePageEvent() +{ + CHECK_NULL_VOID(taskExecutor_); + taskExecutor_->PostDelayedTask( + [weak = WeakClaim(this)]() { + auto delegate = weak.Upgrade(); + CHECK_NULL_VOID(delegate); + auto webPattern = delegate->webPattern_.Upgrade(); + CHECK_NULL_VOID(webPattern); + auto context = AceType::DynamicCast(delegate->context_.Upgrade()); + CHECK_NULL_VOID(context); + auto webNode = webPattern->GetHost(); + CHECK_NULL_VOID(webNode); + auto accessibilityManager = context->GetAccessibilityManager(); + CHECK_NULL_VOID(accessibilityManager); + if (!accessibilityManager->IsScreenReaderEnabled()) { + return; + } + if (webNode->IsOnMainTree()) { + TAG_LOGI(AceLogTag::ACE_WEB, + "WebDelegate::AccessibilityReleasePageEvent accessibilityId = %{public}" PRId64, + webNode->GetAccessibilityId()); + accessibilityManager->ReleasePageEvent(webNode, true, true); + } + }, + TaskExecutor::TaskType::UI, ACCESSIBILITY_PAGE_CHANGE_DELAY_MILLISECONDS, + "ArkUIWebAccessibilityReleasePageEvent"); } void WebDelegate::ReportDynamicFrameLossEvent(const std::string& sceneId, bool isStart) diff --git a/frameworks/core/components/web/resource/web_delegate.h b/frameworks/core/components/web/resource/web_delegate.h index 74ea594e7bd692e15064c366383c3107e18e60e9..07610f0dbb13e0c8fb2483f4ab774372c3b66839 100644 --- a/frameworks/core/components/web/resource/web_delegate.h +++ b/frameworks/core/components/web/resource/web_delegate.h @@ -1223,6 +1223,8 @@ private: void TextBlurReportByFocusEvent(int64_t accessibilityId); void WebComponentClickReport(int64_t accessibilityId); void TextBlurReportByBlurEvent(int64_t accessibilityId); + void AccessibilityReleasePageEvent(); + void AccessibilitySendPageChange(); #ifdef OHOS_STANDARD_SYSTEM sptr CreateWindow(); diff --git a/frameworks/core/components_ng/pattern/web/web_pattern.cpp b/frameworks/core/components_ng/pattern/web/web_pattern.cpp index 36f64d5f7b11ebc8155510ddce3971bf3bc3d46a..3d2516ce656537b03c40d9c96a95f2a05c96ecc1 100644 --- a/frameworks/core/components_ng/pattern/web/web_pattern.cpp +++ b/frameworks/core/components_ng/pattern/web/web_pattern.cpp @@ -791,6 +791,16 @@ void WebPattern::OnAttachToMainTree() InitSlideUpdateListener(); // report component is in foreground. delegate_->OnRenderToForeground(); + + auto host = GetHost(); + CHECK_NULL_VOID(host); + auto pipeline = PipelineContext::GetCurrentContext(); + CHECK_NULL_VOID(pipeline); + auto frontend = pipeline->GetFrontend(); + CHECK_NULL_VOID(frontend); + auto accessibilityManager = frontend->GetAccessibilityManager(); + CHECK_NULL_VOID(accessibilityManager); + accessibilityManager->AddToPageEventController(host); } void WebPattern::OnDetachFromMainTree() @@ -799,6 +809,16 @@ void WebPattern::OnDetachFromMainTree() isAttachedToMainTree_ = false; // report component is in background. delegate_->OnRenderToBackground(); + + auto host = GetHost(); + CHECK_NULL_VOID(host); + auto pipeline = PipelineContext::GetCurrentContext(); + CHECK_NULL_VOID(pipeline); + auto frontend = pipeline->GetFrontend(); + CHECK_NULL_VOID(frontend); + auto accessibilityManager = frontend->GetAccessibilityManager(); + CHECK_NULL_VOID(accessibilityManager); + accessibilityManager->ReleasePageEvent(host, true, true); } void WebPattern::OnAttachToFrameNode() @@ -7348,4 +7368,29 @@ void WebPattern::RegisterSurfaceDensityCallback() }); } } + +bool WebPattern::CheckVisible() +{ + auto host = GetHost(); + CHECK_NULL_RETURN(host, false); + + if (!host->IsActive() || !host->IsVisible()) { + TAG_LOGI(AceLogTag::ACE_WEB, "WebPattern::CheckVisible host is inactive or invisible"); + return false; + } + + auto parent = host->GetAncestorNodeOfFrame(true); + while (parent) { + if (parent->IsWindowBoundary()) { + TAG_LOGI(AceLogTag::ACE_WEB, "WebPattern::CheckVisible IsWindowBoundary is true"); + return true; + } + if (!parent->IsActive() || !parent->IsVisible()) { + TAG_LOGI(AceLogTag::ACE_WEB, "WebPattern::CheckVisible parent is inactive or invisible"); + return false; + } + parent = parent->GetAncestorNodeOfFrame(true); + } + return true; +} } // namespace OHOS::Ace::NG diff --git a/frameworks/core/components_ng/pattern/web/web_pattern.h b/frameworks/core/components_ng/pattern/web/web_pattern.h index fa3dfe974587e280cdf3916f88669be7f82b64c3..652b160ca98ef5b941ee7c7f1a9575cffe414d9c 100644 --- a/frameworks/core/components_ng/pattern/web/web_pattern.h +++ b/frameworks/core/components_ng/pattern/web/web_pattern.h @@ -766,6 +766,7 @@ public: void RegisterSurfaceDensityCallback(); void SetSurfaceDensity(double density); + bool CheckVisible(); private: friend class WebContextSelectOverlay; diff --git a/test/unittest/core/pattern/web/web_pattern_part_one_test.cpp b/test/unittest/core/pattern/web/web_pattern_part_one_test.cpp index 7f2f0fc79e911509763bfb5c250eed385c69bd0c..27adecafac178314d4a15d4d3df18bb437f805ac 100644 --- a/test/unittest/core/pattern/web/web_pattern_part_one_test.cpp +++ b/test/unittest/core/pattern/web/web_pattern_part_one_test.cpp @@ -471,7 +471,8 @@ HWTEST_F(WebPatternPartOneTest, OnDetachFromMainTree_001, TestSize.Level1) ASSERT_NE(webPattern, nullptr); webPattern->OnModifyDone(); ASSERT_NE(webPattern->delegate_, nullptr); - + auto host = webPattern->GetHost(); + EXPECT_NE(host, nullptr); webPattern->OnDetachFromMainTree(); ASSERT_NE(webPattern->delegate_, nullptr); #endif diff --git a/test/unittest/core/pattern/web/web_pattern_test_ng.cpp b/test/unittest/core/pattern/web/web_pattern_test_ng.cpp index dcc05ac516373ed2d514e0a0ad1304ac9eedd39b..a297ec0467640f488292b94f5072a73c1813dd88 100755 --- a/test/unittest/core/pattern/web/web_pattern_test_ng.cpp +++ b/test/unittest/core/pattern/web/web_pattern_test_ng.cpp @@ -23,7 +23,7 @@ #undef private #include "test/mock/core/pipeline/mock_pipeline_context.h" - +#include "core/components_ng/pattern/root/root_pattern.h" #include "base/web/webview/ohos_nweb/include/nweb_handler.h" #include "core/components_ng/base/view_stack_processor.h" @@ -1937,4 +1937,115 @@ HWTEST_F(WebPatternTestNg, HandleFocusEvent_002, TestSize.Level1) EXPECT_TRUE(webPattern->needOnFocus_); #endif } + +/** + * @tc.name: CheckVisible_001 + * @tc.desc: CheckVisible. + * @tc.type: FUNC + */ +HWTEST_F(WebPatternTestNg, CheckVisible_001, TestSize.Level1) +{ +#ifdef OHOS_STANDARD_SYSTEM + auto* stack = ViewStackProcessor::GetInstance(); + auto nodeId = stack->ClaimNodeId(); + auto frameNode = + FrameNode::GetOrCreateFrameNode(V2::WEB_ETS_TAG, nodeId, []() { return AceType::MakeRefPtr(); }); + stack->Push(frameNode); + auto webPattern = frameNode->GetPattern(); + ASSERT_NE(webPattern, nullptr); + auto host = webPattern->GetHost(); + ASSERT_NE(host, nullptr); + auto layoutProperty = host->GetLayoutProperty(); + ASSERT_NE(layoutProperty, nullptr); + layoutProperty->UpdateVisibility(VisibleType::INVISIBLE); + EXPECT_EQ(layoutProperty->GetVisibility(), VisibleType::INVISIBLE); + + EXPECT_FALSE(webPattern->CheckVisible()); +#endif +} + +/** + * @tc.name: CheckVisible_002 + * @tc.desc: CheckVisible. + * @tc.type: FUNC + */ +HWTEST_F(WebPatternTestNg, CheckVisible_002, TestSize.Level1) +{ +#ifdef OHOS_STANDARD_SYSTEM + auto* stack = ViewStackProcessor::GetInstance(); + auto nodeId = stack->ClaimNodeId(); + auto frameNode = + FrameNode::GetOrCreateFrameNode(V2::WEB_ETS_TAG, nodeId, []() { return AceType::MakeRefPtr(); }); + stack->Push(frameNode); + auto webPattern = frameNode->GetPattern(); + ASSERT_NE(webPattern, nullptr); + auto host = webPattern->GetHost(); + ASSERT_NE(host, nullptr); + host->isActive_ = false; + EXPECT_FALSE(webPattern->CheckVisible()); +#endif +} + +/** + * @tc.name: CheckVisible_003 + * @tc.desc: CheckVisible. + * @tc.type: FUNC + */ +HWTEST_F(WebPatternTestNg, CheckVisible_003, TestSize.Level1) +{ +#ifdef OHOS_STANDARD_SYSTEM + auto *stack = ViewStackProcessor::GetInstance(); + auto nodeId = stack->ClaimNodeId(); + auto frameNode = + FrameNode::GetOrCreateFrameNode(V2::WEB_ETS_TAG, nodeId, []() { return AceType::MakeRefPtr(); }); + stack->Push(frameNode); + auto webPattern = frameNode->GetPattern(); + ASSERT_NE(webPattern, nullptr); + frameNode->SetParent(nullptr); + auto host = webPattern->GetHost(); + ASSERT_NE(host, nullptr); + auto parent = host->GetParent(); + EXPECT_EQ(parent, nullptr); + auto layoutProperty = host->GetLayoutProperty(); + ASSERT_NE(layoutProperty, nullptr); + layoutProperty->UpdateVisibility(VisibleType::VISIBLE); + EXPECT_EQ(layoutProperty->GetVisibility(), VisibleType::VISIBLE); + host->isActive_ = true; + + EXPECT_TRUE(webPattern->CheckVisible()); +#endif +} + +/** + * @tc.name: CheckVisible_004 + * @tc.desc: CheckVisible. + * @tc.type: FUNC + */ +HWTEST_F(WebPatternTestNg, CheckVisible_004, TestSize.Level1) +{ +#ifdef OHOS_STANDARD_SYSTEM + auto *stack = ViewStackProcessor::GetInstance(); + auto nodeId = stack->ClaimNodeId(); + auto frameNode = + FrameNode::GetOrCreateFrameNode(V2::WEB_ETS_TAG, nodeId, []() { return AceType::MakeRefPtr(); }); + stack->Push(frameNode); + auto webPattern = frameNode->GetPattern(); + ASSERT_NE(webPattern, nullptr); + auto host = webPattern->GetHost(); + ASSERT_NE(host, nullptr); + auto layoutProperty = host->GetLayoutProperty(); + ASSERT_NE(layoutProperty, nullptr); + layoutProperty->UpdateVisibility(VisibleType::VISIBLE); + EXPECT_EQ(layoutProperty->GetVisibility(), VisibleType::VISIBLE); + host->isActive_ = true; + + auto parentNode = FrameNode::CreateFrameNode(V2::ROOT_ETS_TAG, 1, AceType::MakeRefPtr()); + ASSERT_NE(parentNode, nullptr); + stack->Push(parentNode); + frameNode->SetParent(parentNode); + parentNode->SetWindowBoundary(true); + + EXPECT_TRUE(webPattern->CheckVisible()); +#endif +} } // namespace OHOS::Ace::NG