Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -1698,6 +1698,7 @@ FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_view.h
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/flutter_linux.h
FILE: ../../../flutter/shell/platform/windows/accessibility_bridge_delegate_win32.cc
FILE: ../../../flutter/shell/platform/windows/accessibility_bridge_delegate_win32.h
FILE: ../../../flutter/shell/platform/windows/accessibility_bridge_delegate_win32_unittests.cc
FILE: ../../../flutter/shell/platform/windows/accessibility_bridge_delegate_winuwp.cc
FILE: ../../../flutter/shell/platform/windows/accessibility_bridge_delegate_winuwp.h
FILE: ../../../flutter/shell/platform/windows/angle_surface_manager.cc
Expand Down
1 change: 1 addition & 0 deletions shell/platform/windows/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ executable("flutter_windows_unittests") {
} else {
sources += [
# TODO move first two tests to common once above TODO's unblocked.
"accessibility_bridge_delegate_win32_unittests.cc",
"dpi_utils_win32_unittests.cc",
"flutter_project_bundle_unittests.cc",
"flutter_window_win32_unittests.cc",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ void AccessibilityBridgeDelegateWin32::DispatchAccessibilityAction(
AccessibilityNodeId target,
FlutterSemanticsAction action,
fml::MallocMapping data) {
// TODO(cbracken): https://github.com/flutter/flutter/issues/77838
engine_->DispatchSemanticsAction(target, action, std::move(data));
}

std::shared_ptr<FlutterPlatformNodeDelegate>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "flutter/shell/platform/windows/accessibility_bridge_delegate_win32.h"

#include <comdef.h>
#include <comutil.h>
#include <oleacc.h>

#include <vector>

#include "flutter/shell/platform/embedder/embedder.h"
#include "flutter/shell/platform/embedder/test_utils/proc_table_replacement.h"
#include "flutter/shell/platform/windows/flutter_platform_node_delegate_win32.h"
#include "flutter/shell/platform/windows/flutter_windows_engine.h"
#include "flutter/shell/platform/windows/flutter_windows_view.h"
#include "flutter/shell/platform/windows/testing/engine_modifier.h"
#include "flutter/shell/platform/windows/testing/mock_window_binding_handler.h"
#include "flutter/shell/platform/windows/testing/test_keyboard.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"

namespace flutter {
namespace testing {

namespace {

// Returns an engine instance configured with dummy project path values, and
// overridden methods for sending platform messages, so that the engine can
// respond as if the framework were connected.
std::unique_ptr<FlutterWindowsEngine> GetTestEngine() {
FlutterDesktopEngineProperties properties = {};
properties.assets_path = L"C:\\foo\\flutter_assets";
properties.icu_data_path = L"C:\\foo\\icudtl.dat";
properties.aot_library_path = L"C:\\foo\\aot.so";
FlutterProjectBundle project(properties);
auto engine = std::make_unique<FlutterWindowsEngine>(project);

EngineModifier modifier(engine.get());
modifier.embedder_api().UpdateSemanticsEnabled =
[](FLUTTER_API_SYMBOL(FlutterEngine) engine, bool enabled) {
return kSuccess;
};
MockEmbedderApiForKeyboard(
modifier, [] { return false; },
[](const FlutterKeyEvent* event) { return false; });

engine->RunWithEntrypoint(nullptr);
return engine;
}

// Populates the AXTree associated with the specified bridge with test data.
//
// node0
// / \
// node1 node2
// / \
// node3 node4
//
// node0 and node2 are grouping nodes. node1 and node2 are static text nodes.
// node4 is a static text node with no text, and hence has the "ignored" state.
void PopulateAXTree(std::shared_ptr<AccessibilityBridge> bridge) {
// Add node 0: root.
FlutterSemanticsNode node0{sizeof(FlutterSemanticsNode), 0};
std::vector<int32_t> node0_children{1, 2};
node0.child_count = node0_children.size();
node0.children_in_traversal_order = node0_children.data();
node0.children_in_hit_test_order = node0_children.data();

// Add node 1: text child of node 0.
FlutterSemanticsNode node1{sizeof(FlutterSemanticsNode), 1};
node1.label = "prefecture";
node1.value = "Kyoto";

// Add node 2: subtree child of node 0.
FlutterSemanticsNode node2{sizeof(FlutterSemanticsNode), 2};
std::vector<int32_t> node2_children{3, 4};
node2.child_count = node2_children.size();
node2.children_in_traversal_order = node2_children.data();
node2.children_in_hit_test_order = node2_children.data();

// Add node 3: text child of node 2.
FlutterSemanticsNode node3{sizeof(FlutterSemanticsNode), 3};
node3.label = "city";
node3.value = "Uji";

// Add node 4: text child (with no text) of node 2.
FlutterSemanticsNode node4{sizeof(FlutterSemanticsNode), 4};

bridge->AddFlutterSemanticsNodeUpdate(&node0);
bridge->AddFlutterSemanticsNodeUpdate(&node1);
bridge->AddFlutterSemanticsNodeUpdate(&node2);
bridge->AddFlutterSemanticsNodeUpdate(&node3);
bridge->AddFlutterSemanticsNodeUpdate(&node4);
bridge->CommitUpdates();
}

} // namespace

TEST(AccessibilityBridgeDelegateWin32, DispatchAccessibilityAction) {
auto window_binding_handler =
std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
FlutterWindowsView view(std::move(window_binding_handler));
view.SetEngine(GetTestEngine());
view.OnUpdateSemanticsEnabled(true);

auto bridge = view.GetEngine()->accessibility_bridge().lock();
PopulateAXTree(bridge);

FlutterSemanticsAction actual_action = kFlutterSemanticsActionTap;
EngineModifier modifier(view.GetEngine());
modifier.embedder_api().DispatchSemanticsAction = MOCK_ENGINE_PROC(
DispatchSemanticsAction,
([&actual_action](FLUTTER_API_SYMBOL(FlutterEngine) engine, uint64_t id,
FlutterSemanticsAction action, const uint8_t* data,
size_t data_length) {
actual_action = action;
return kSuccess;
}));

AccessibilityBridgeDelegateWin32 delegate(view.GetEngine());
delegate.DispatchAccessibilityAction(1, kFlutterSemanticsActionCopy, {});
EXPECT_EQ(actual_action, kFlutterSemanticsActionCopy);
}

} // namespace testing
} // namespace flutter