Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Merge AccessibilityBridge and AccessibilityBridgeDelegate #36597

Merged
merged 26 commits into from
Nov 4, 2022
Merged
Show file tree
Hide file tree
Changes from 19 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
12 changes: 6 additions & 6 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -2576,9 +2576,9 @@ FILE: ../../../flutter/shell/platform/darwin/macos/framework/Headers/FlutterPlug
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Headers/FlutterPluginRegistrarMacOS.h
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Info.plist
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/AccessibilityBridgeMacDelegate.h
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/AccessibilityBridgeMacDelegate.mm
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/AccessibilityBridgeMacDelegateTest.mm
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/AccessibilityBridgeMac.h
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/AccessibilityBridgeMac.mm
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/AccessibilityBridgeMacTest.mm
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterAppDelegate.mm
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterBackingStore.h
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterBackingStore.mm
Expand Down Expand Up @@ -3075,9 +3075,9 @@ 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_alert.cc
FILE: ../../../flutter/shell/platform/windows/accessibility_alert.h
FILE: ../../../flutter/shell/platform/windows/accessibility_bridge_delegate_windows.cc
FILE: ../../../flutter/shell/platform/windows/accessibility_bridge_delegate_windows.h
FILE: ../../../flutter/shell/platform/windows/accessibility_bridge_delegate_windows_unittests.cc
FILE: ../../../flutter/shell/platform/windows/accessibility_bridge_windows.cc
FILE: ../../../flutter/shell/platform/windows/accessibility_bridge_windows.h
FILE: ../../../flutter/shell/platform/windows/accessibility_bridge_windows_unittests.cc
FILE: ../../../flutter/shell/platform/windows/accessibility_root_node.cc
FILE: ../../../flutter/shell/platform/windows/accessibility_root_node.h
FILE: ../../../flutter/shell/platform/windows/angle_surface_manager.cc
Expand Down
27 changes: 7 additions & 20 deletions shell/platform/common/accessibility_bridge.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,7 @@ constexpr int kHasScrollingAction =
FlutterSemanticsAction::kFlutterSemanticsActionScrollDown;

// AccessibilityBridge
AccessibilityBridge::AccessibilityBridge(
std::unique_ptr<AccessibilityBridgeDelegate> delegate)
: delegate_(std::move(delegate)) {
AccessibilityBridge::AccessibilityBridge() {
event_generator_.SetTree(&tree_);
tree_.AddObserver(static_cast<ui::AXTreeObserver*>(this));
}
Expand Down Expand Up @@ -107,7 +105,7 @@ void AccessibilityBridge::CommitUpdates() {
continue;
}

delegate_->OnAccessibilityEvent(targeted_event);
OnAccessibilityEvent(targeted_event);
}
event_generator_.ClearEvents();
}
Expand All @@ -128,20 +126,16 @@ const ui::AXTreeData& AccessibilityBridge::GetAXTreeData() const {
}

const std::vector<ui::AXEventGenerator::TargetedEvent>
AccessibilityBridge::GetPendingEvents() {
AccessibilityBridge::GetPendingEvents() const {
std::vector<ui::AXEventGenerator::TargetedEvent> result(
event_generator_.begin(), event_generator_.end());
return result;
}

void AccessibilityBridge::UpdateDelegate(
std::unique_ptr<AccessibilityBridgeDelegate> delegate) {
delegate_ = std::move(delegate);
// Recreate FlutterPlatformNodeDelegates since they may contain stale state
// from the previous AccessibilityBridgeDelegate.
void AccessibilityBridge::RecreateNodeDelegates() {
for (const auto& [node_id, old_platform_node_delegate] : id_wrapper_map_) {
std::shared_ptr<FlutterPlatformNodeDelegate> platform_node_delegate =
delegate_->CreateFlutterPlatformNodeDelegate();
CreateFlutterPlatformNodeDelegate();
platform_node_delegate->Init(
std::static_pointer_cast<FlutterPlatformNodeDelegate::OwnerBridge>(
shared_from_this()),
Expand All @@ -166,7 +160,7 @@ void AccessibilityBridge::OnRoleChanged(ui::AXTree* tree,

void AccessibilityBridge::OnNodeCreated(ui::AXTree* tree, ui::AXNode* node) {
BASE_DCHECK(node);
id_wrapper_map_[node->id()] = delegate_->CreateFlutterPlatformNodeDelegate();
id_wrapper_map_[node->id()] = CreateFlutterPlatformNodeDelegate();
id_wrapper_map_[node->id()]->Init(
std::static_pointer_cast<FlutterPlatformNodeDelegate::OwnerBridge>(
shared_from_this()),
Expand Down Expand Up @@ -629,7 +623,7 @@ void AccessibilityBridge::SetLastFocusedId(AccessibilityNodeId node_id) {
auto last_focused_child =
GetFlutterPlatformNodeDelegateFromID(last_focused_id_);
if (!last_focused_child.expired()) {
delegate_->DispatchAccessibilityAction(
DispatchAccessibilityAction(
last_focused_id_,
FlutterSemanticsAction::
kFlutterSemanticsActionDidLoseAccessibilityFocus,
Expand Down Expand Up @@ -659,11 +653,4 @@ gfx::RectF AccessibilityBridge::RelativeToGlobalBounds(const ui::AXNode* node,
clip_bounds);
}

void AccessibilityBridge::DispatchAccessibilityAction(
AccessibilityNodeId target,
FlutterSemanticsAction action,
fml::MallocMapping data) {
delegate_->DispatchAccessibilityAction(target, action, std::move(data));
}

} // namespace flutter
117 changes: 35 additions & 82 deletions shell/platform/common/accessibility_bridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,85 +31,17 @@ namespace flutter {
/// FlutterPlatformNodeDelegate to wrap each AXNode in order to provide
/// an accessibility tree in the native format.
///
/// This class takes in a AccessibilityBridgeDelegate instance and is in charge
/// of its lifecycle. The delegate are used to handle the accessibility events
/// and actions.
///
/// To use this class, you must provide your own implementation of
/// FlutterPlatformNodeDelegate and AccessibilityBridgeDelegate.
/// To use this class, you must implement this class and provide your own
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// To use this class, you must implement this class and provide your own
/// To use this class, one must subclass this class and provide their own

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should it also mention the onaccessibilityevent?

Copy link
Contributor Author

@dkwingsmt dkwingsmt Nov 3, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure. If you think it's worthwhile, can you help me write it?

/// implementation of FlutterPlatformNodeDelegate.
class AccessibilityBridge
: public std::enable_shared_from_this<AccessibilityBridge>,
public FlutterPlatformNodeDelegate::OwnerBridge,
private ui::AXTreeObserver {
public:
//-----------------------------------------------------------------------------
/// Delegate to handle requests from the accessibility bridge. The requests
/// include sending accessibility event to native accessibility system,
/// routing accessibility action to the Flutter framework, and creating
/// platform specific FlutterPlatformNodeDelegate.
///
/// The accessibility events are generated when accessibility tree changes.
/// These events must be sent to the native accessibility system through
/// the native API for the system to pick up the changes
/// (e.g. NSAccessibilityPostNotification in MacOS).
///
/// The accessibility actions are generated by the native accessibility system
/// when users interacted with the assistive technologies. Those actions
/// needed to be sent to the Flutter framework.
///
/// Each platform needs to implement the FlutterPlatformNodeDelegate and
/// returns its platform specific instance of FlutterPlatformNodeDelegate
/// in this delegate.
class AccessibilityBridgeDelegate {
public:
virtual ~AccessibilityBridgeDelegate() = default;
//---------------------------------------------------------------------------
/// @brief Handle accessibility events generated due to accessibility
/// tree changes. These events are generated in accessibility
/// bridge and needed to be sent to native accessibility system.
/// See ui::AXEventGenerator::Event for possible events.
///
/// @param[in] targeted_event The object that contains both the
/// generated event and the event target.
virtual void OnAccessibilityEvent(
ui::AXEventGenerator::TargetedEvent targeted_event) = 0;

//---------------------------------------------------------------------------
/// @brief Dispatch accessibility action back to the Flutter framework.
/// These actions are generated in the native accessibility
/// system when users interact with the assistive technologies.
/// For example, a
/// FlutterSemanticsAction::kFlutterSemanticsActionTap is
/// fired when user click or touch the screen.
///
/// @param[in] target The semantics node id of the action
/// target.
/// @param[in] action The generated flutter semantics action.
/// @param[in] data Additional data associated with the
/// action.
virtual void DispatchAccessibilityAction(AccessibilityNodeId target,
FlutterSemanticsAction action,
fml::MallocMapping data) = 0;

//---------------------------------------------------------------------------
/// @brief Creates a platform specific FlutterPlatformNodeDelegate.
/// Ownership passes to the caller. This method will be called
/// by accessibility bridge whenever a new AXNode is created in
/// AXTree. Each platform needs to implement this method in
/// order to inject its subclass into the accessibility bridge.
virtual std::shared_ptr<FlutterPlatformNodeDelegate>
CreateFlutterPlatformNodeDelegate() = 0;
};

//-----------------------------------------------------------------------------
/// @brief Creates a new instance of a accessibility bridge.
///
/// @param[in] user_data A custom pointer to the data of your
/// choice. This pointer can be retrieve later
/// through GetUserData().
explicit AccessibilityBridge(
std::unique_ptr<AccessibilityBridgeDelegate> delegate);
~AccessibilityBridge();
AccessibilityBridge();
virtual ~AccessibilityBridge();

//-----------------------------------------------------------------------------
/// @brief The ID of the root node in the accessibility tree. In Flutter,
Expand Down Expand Up @@ -168,12 +100,39 @@ class AccessibilityBridge
/// events in AccessibilityBridgeDelegate::OnAccessibilityEvent in
/// case one may decide to handle an event differently based on
/// all pending events.
const std::vector<ui::AXEventGenerator::TargetedEvent> GetPendingEvents();
const std::vector<ui::AXEventGenerator::TargetedEvent> GetPendingEvents()
const;

protected:
//---------------------------------------------------------------------------
/// @brief Handle accessibility events generated due to accessibility
/// tree changes. These events are generated in accessibility
/// bridge and needed to be sent to native accessibility system.
/// See ui::AXEventGenerator::Event for possible events.
///
/// @param[in] targeted_event The object that contains both the
/// generated event and the event target.
virtual void OnAccessibilityEvent(
ui::AXEventGenerator::TargetedEvent targeted_event) = 0;

//---------------------------------------------------------------------------
/// @brief Creates a platform specific FlutterPlatformNodeDelegate.
/// Ownership passes to the caller. This method will be called
/// whenever a new AXNode is created in AXTree. Each platform
/// needs to implement this method in order to inject its
/// subclass into the accessibility bridge.
virtual std::shared_ptr<FlutterPlatformNodeDelegate>
CreateFlutterPlatformNodeDelegate() = 0;

//------------------------------------------------------------------------------
/// @brief Update the AccessibilityBridgeDelegate stored in the
/// accessibility bridge to a new one.
void UpdateDelegate(std::unique_ptr<AccessibilityBridgeDelegate> delegate);
/// @brief Recreate all FlutterPlatformNodeDelegates.
///
/// This can be useful for subclasses when updating some
/// properties that are used by node delegates, such as views.
/// Each node is recreated using
/// CreateFlutterPlatformNodeDelegate, then initialized using
/// AXNodes from their corresponding old one.
void RecreateNodeDelegates();

private:
// See FlutterSemanticsNode in embedder.h
Expand Down Expand Up @@ -220,7 +179,6 @@ class AccessibilityBridge
std::unordered_map<int32_t, SemanticsCustomAction>
pending_semantics_custom_action_updates_;
AccessibilityNodeId last_focused_id_ = ui::AXNode::kInvalidAXID;
std::unique_ptr<AccessibilityBridgeDelegate> delegate_;

void InitAXTree(const ui::AXTreeUpdate& initial_state);

Expand Down Expand Up @@ -295,11 +253,6 @@ class AccessibilityBridge
gfx::NativeViewAccessible GetNativeAccessibleFromId(
AccessibilityNodeId id) override;

// |FlutterPlatformNodeDelegate::OwnerBridge|
void DispatchAccessibilityAction(AccessibilityNodeId target,
FlutterSemanticsAction action,
fml::MallocMapping data) override;

// |FlutterPlatformNodeDelegate::OwnerBridge|
gfx::RectF RelativeToGlobalBounds(const ui::AXNode* node,
bool& offscreen,
Expand Down
Loading