#ifndef SERVICES_ACCESSIBILITY_ANDROID_AX_TREE_SOURCE_ANDROID_H_
#define SERVICES_ACCESSIBILITY_ANDROID_AX_TREE_SOURCE_ANDROID_H_
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "base/containers/flat_map.h"
#include "base/memory/raw_ptr.h"
#include "extensions/browser/api/automation_internal/automation_event_router.h"
#include "services/accessibility/android/accessibility_info_data_wrapper.h"
#include "services/accessibility/android/public/mojom/accessibility_helper.mojom-forward.h"
#include "ui/accessibility/ax_action_handler.h"
#include "ui/accessibility/ax_node.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/accessibility/ax_tree_data.h"
#include "ui/accessibility/ax_tree_serializer.h"
#include "ui/accessibility/ax_tree_source.h"
namespace aura {
class Window;
}
namespace ax::android {
class AXTreeSourceAndroidTest;
using AXTreeAndroidSerializer = ui::AXTreeSerializer<
AccessibilityInfoDataWrapper*,
std::vector<raw_ptr<AccessibilityInfoDataWrapper, VectorExperimental>>,
ui::AXTreeUpdate*,
ui::AXTreeData*,
ui::AXNodeData>;
class AXTreeSourceAndroid
: public ui::AXTreeSource<AccessibilityInfoDataWrapper*,
ui::AXTreeData*,
ui::AXNodeData>,
public ui::AXActionHandler {
public:
class Delegate {
public:
virtual void OnAction(const ui::AXActionData& data) const = 0;
virtual bool UseFullFocusMode() const = 0;
};
class SerializationDelegate {
public:
virtual ~SerializationDelegate() = default;
virtual void PopulateBounds(const AccessibilityInfoDataWrapper& node,
ui::AXNodeData& out_data) const = 0;
protected:
raw_ptr<AXTreeSourceAndroid> tree_source_;
private:
friend class AXTreeSourceAndroid;
void BindTree(AXTreeSourceAndroid* tree_source) {
tree_source_ = tree_source;
}
};
class Hook {
public:
Hook() = default;
virtual ~Hook() = default;
virtual bool PreDispatchEvent(
AXTreeSourceAndroid* tree_source,
const mojom::AccessibilityEventData& event_data) = 0;
virtual void PostSerializeNode(ui::AXNodeData* out_data) const = 0;
virtual bool ShouldDestroy(AXTreeSourceAndroid* tree_source) const = 0;
};
AXTreeSourceAndroid(
Delegate* delegate,
std::unique_ptr<SerializationDelegate> serialization_delegate,
aura::Window* window);
AXTreeSourceAndroid(const AXTreeSourceAndroid&) = delete;
AXTreeSourceAndroid& operator=(const AXTreeSourceAndroid&) = delete;
~AXTreeSourceAndroid() override;
void NotifyAccessibilityEvent(mojom::AccessibilityEventData* event_data);
void NotifyActionResult(const ui::AXActionData& data, bool result);
void NotifyGetTextLocationDataResult(const ui::AXActionData& data,
const std::optional<gfx::Rect>& rect);
void InvalidateTree();
bool UseFullFocusMode() const;
virtual bool IsRootOfNodeTree(int32_t id) const;
void SetVirtualNode(int32_t parent_id,
std::unique_ptr<AccessibilityInfoDataWrapper> child);
AccessibilityInfoDataWrapper* GetFirstImportantAncestor(
AccessibilityInfoDataWrapper* info_data) const;
AccessibilityInfoDataWrapper* GetFirstAccessibilityFocusableAncestor(
AccessibilityInfoDataWrapper* info_data) const;
SerializationDelegate& serialization_delegate() const {
return *serialization_delegate_.get();
}
bool GetTreeData(ui::AXTreeData* data) const override;
AccessibilityInfoDataWrapper* GetRoot() const override;
AccessibilityInfoDataWrapper* GetFromId(int32_t id) const override;
AccessibilityInfoDataWrapper* GetParent(
AccessibilityInfoDataWrapper* info_data) const override;
void SerializeNode(AccessibilityInfoDataWrapper* info_data,
ui::AXNodeData* out_data) const override;
aura::Window* window() { return window_; }
void set_window(aura::Window* window) { window_ = window; }
bool is_notification() { return is_notification_; }
bool is_input_method_window() { return is_input_method_window_; }
std::optional<int32_t> window_id() const { return window_id_; }
std::optional<int32_t> root_id() const { return root_id_; }
void set_automation_event_router_for_test(
extensions::AutomationEventRouterInterface* router) {
automation_event_router_for_test_ = router;
}
void set_window_id_for_test(int32_t window_id) { window_id_ = window_id; }
private:
friend class AXTreeSourceAndroidTest;
void BuildNodeMap(const mojom::AccessibilityEventData& event_data);
void NotifyAccessibilityEventInternal(
const mojom::AccessibilityEventData& event_data);
extensions::AutomationEventRouterInterface* GetAutomationEventRouter() const;
gfx::Rect ComputeEnclosingBounds(
AccessibilityInfoDataWrapper* info_data) const;
void ComputeEnclosingBoundsInternal(AccessibilityInfoDataWrapper* info_data,
gfx::Rect* computed_bounds) const;
AccessibilityInfoDataWrapper* FindFirstFocusableNodeInFullFocusMode(
AccessibilityInfoDataWrapper* info_data) const;
bool UpdateAndroidFocusedId(const mojom::AccessibilityEventData& event_data);
std::vector<int32_t> ProcessHooksOnEvent(
const mojom::AccessibilityEventData& event_data);
void Reset();
bool NeedReorder(AccessibilityInfoDataWrapper* left,
AccessibilityInfoDataWrapper* right) const;
bool CompareBounds(const gfx::Rect& left, const gfx::Rect& right) const;
int32_t GetId(AccessibilityInfoDataWrapper* info_data) const override;
void CacheChildrenIfNeeded(AccessibilityInfoDataWrapper*) override;
size_t GetChildCount(AccessibilityInfoDataWrapper*) const override;
AccessibilityInfoDataWrapper* ChildAt(AccessibilityInfoDataWrapper*,
size_t) const override;
void ClearChildCache(AccessibilityInfoDataWrapper*) override;
bool IsIgnored(AccessibilityInfoDataWrapper* info_data) const override;
bool IsEqual(AccessibilityInfoDataWrapper* info_data1,
AccessibilityInfoDataWrapper* info_data2) const override;
AccessibilityInfoDataWrapper* GetNull() const override;
void PerformAction(const ui::AXActionData& data) override;
std::vector<raw_ptr<AccessibilityInfoDataWrapper, VectorExperimental>>&
GetChildren(AccessibilityInfoDataWrapper* info_data) const;
void ComputeAndCacheChildren(AccessibilityInfoDataWrapper* info_data) const;
std::map<int32_t, std::unique_ptr<AccessibilityInfoDataWrapper>> tree_map_;
std::map<int32_t, int32_t> parent_map_;
std::unique_ptr<AXTreeAndroidSerializer> current_tree_serializer_;
std::optional<int32_t> root_id_;
std::optional<int32_t> window_id_;
std::optional<int32_t> android_focused_id_;
bool is_notification_;
bool is_input_method_window_;
std::optional<std::string> notification_key_;
raw_ptr<aura::Window, DanglingUntriaged> window_;
std::map<int32_t, int32_t> window_id_to_last_focus_node_id_;
std::map<int32_t, gfx::Rect> computed_bounds_;
base::flat_map<int32_t, std::unique_ptr<Hook>> hooks_;
const raw_ptr<const Delegate> delegate_;
const std::unique_ptr<SerializationDelegate> serialization_delegate_;
raw_ptr<extensions::AutomationEventRouterInterface>
automation_event_router_for_test_ = nullptr;
};
}
#endif