File: ax_tree_source_android.h

package info (click to toggle)
chromium 145.0.7632.159-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 5,976,224 kB
  • sloc: cpp: 36,198,469; ansic: 7,634,080; javascript: 3,564,060; python: 1,649,622; xml: 838,470; asm: 717,087; pascal: 185,708; sh: 88,786; perl: 88,718; objc: 79,984; sql: 59,811; cs: 42,452; fortran: 24,101; makefile: 21,144; tcl: 15,277; php: 14,022; yacc: 9,066; ruby: 7,553; awk: 3,720; lisp: 3,233; lex: 1,328; ada: 727; jsp: 228; sed: 36
file content (292 lines) | stat: -rw-r--r-- 11,884 bytes parent folder | download | duplicates (9)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#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>;

// This class represents the accessibility tree from the focused ARC window.
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;
    // Populate bounds of a node which can be passed to AXNodeData.location.
    // Bounds are returned in the following coordinates depending on whether
    // it's root or not.
    // - Root node is relative to its container, i.e. focused window.
    // - Non-root node is relative to the root node of this tree.
    virtual void PopulateBounds(const AccessibilityInfoDataWrapper& node,
                                ui::AXNodeData& out_data) const = 0;

   protected:
    raw_ptr<AXTreeSourceAndroid> tree_source_;  // owner of this
   private:
    friend class AXTreeSourceAndroid;
    // Called on construction of tree_source only.
    void BindTree(AXTreeSourceAndroid* tree_source) {
      tree_source_ = tree_source;
    }
  };
  // The interface to hook the event handling and the node serialization.
  class Hook {
   public:
    Hook() = default;
    virtual ~Hook() = default;

    // Called prior to accessibility event dispatch.
    // Hook implementations can update the internal state if necessary so that
    // hooks can update the serialization state in PostSerializeNode().
    // Return true if re-serialization of attaching node is needed.
    virtual bool PreDispatchEvent(
        AXTreeSourceAndroid* tree_source,
        const mojom::AccessibilityEventData& event_data) = 0;

    // Called after the default serialization of the attaching node.
    // Hook implementations can modify the serialization of given |out_data|.
    // Note that serialization is executed only when ui::AXTreeSerializer calls
    // SerializeNode() from AXTreeSerializer.SerializeChanges().
    // To ensure the node re-serialized, the class must return |true| on
    // PreDispatchEvent() if the event is NOT coming from its ancestry.
    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;

  // Notify automation of an accessibility event.
  void NotifyAccessibilityEvent(mojom::AccessibilityEventData* event_data);

  // Notify automation of a result to an action.
  void NotifyActionResult(const ui::AXActionData& data, bool result);

  // Notify automation of result to getTextLocation.
  void NotifyGetTextLocationDataResult(const ui::AXActionData& data,
                                       const std::optional<gfx::Rect>& rect);

  // Invalidates the tree serializer.
  void InvalidateTree();

  // When it is enabled, this class exposes an accessibility tree optimized for
  // screen readers such as ChromeVox and SwitchAccess. This intends to have the
  // navigation order and focusabilities similar to TalkBack.
  // Also, when it is enabled, the accessibility focus in Android is exposed as
  // the focus of this tree.
  bool UseFullFocusMode() const;

  // Returns true if the node id is the root of the node tree (which can have a
  // parent window).
  // virtual for testing.
  virtual bool IsRootOfNodeTree(int32_t id) const;

  // Sets a virtual node, i.e., node that doesn't exist in source Android tree.
  // This set is only effective on the current event serialization.
  // Usually setting a node is always needed by using a Hook.
  // Note that currently panret node should be an instance of
  // AccessibilityWindowInfoDataWrapper.
  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();
  }
  // AXTreeSource:
  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_; }

  // The window id of this tree.
  std::optional<int32_t> window_id() const { return window_id_; }
  // The root id of this tree.
  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;

  // Builds the map that stores relationships between nodes.
  void BuildNodeMap(const mojom::AccessibilityEventData& event_data);

  // Actual implementation of NotifyAccessibilityEvent.
  void NotifyAccessibilityEventInternal(
      const mojom::AccessibilityEventData& event_data);

  // Returns AutomationEventRouter.
  extensions::AutomationEventRouterInterface* GetAutomationEventRouter() const;

  // Computes the smallest rect that encloses all of the descendants of
  // |info_data|.
  gfx::Rect ComputeEnclosingBounds(
      AccessibilityInfoDataWrapper* info_data) const;

  // Helper to recursively compute bounds for |info_data|. Returns true if
  // non-empty bounds were encountered.
  void ComputeEnclosingBoundsInternal(AccessibilityInfoDataWrapper* info_data,
                                      gfx::Rect* computed_bounds) const;

  // Find the most top-left focusable node under the given node in full focus
  // mode.
  AccessibilityInfoDataWrapper* FindFirstFocusableNodeInFullFocusMode(
      AccessibilityInfoDataWrapper* info_data) const;

  // Updates android_focused_id_ from given AccessibilityEventData.
  // Having this method, |android_focused_id_| is one of these:
  // - input focus in Android
  // - accessibility focus in Android
  // - the chrome automation client's internal focus (via set sequential focus
  //   action and replying accessibility focus event from Android).
  // This returns false if we don't want to dispatch the processing
  // event to chrome automation. Otherwise, this returns true.
  bool UpdateAndroidFocusedId(const mojom::AccessibilityEventData& event_data);

  // Processes implementations of Hooks and returns a list node id that needs
  // re-serialization.
  std::vector<int32_t> ProcessHooksOnEvent(
      const mojom::AccessibilityEventData& event_data);

  // Resets tree state.
  void Reset();

  // Returns true if we want to traversal |left| after |right|.
  // Note that this comparison is NOT transitive.
  bool NeedReorder(AccessibilityInfoDataWrapper* left,
                   AccessibilityInfoDataWrapper* right) const;

  // Returns true if we can traversal |left| before |right|.
  bool CompareBounds(const gfx::Rect& left, const gfx::Rect& right) const;

  // AXTreeSource:
  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;

  // AXActionHandlerBase:
  void PerformAction(const ui::AXActionData& data) override;

  std::vector<raw_ptr<AccessibilityInfoDataWrapper, VectorExperimental>>&
  GetChildren(AccessibilityInfoDataWrapper* info_data) const;

  void ComputeAndCacheChildren(AccessibilityInfoDataWrapper* info_data) const;

  // Maps an AccessibilityInfoDataWrapper ID to its tree data.
  std::map<int32_t, std::unique_ptr<AccessibilityInfoDataWrapper>> tree_map_;

  // Maps an AccessibilityInfoDataWrapper ID to its parent.
  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_;

  // Window corresponding this tree.
  raw_ptr<aura::Window, DanglingUntriaged> window_;

  // Cache of mapping from the *Android* window id to the last focused node id.
  std::map<int32_t, int32_t> window_id_to_last_focus_node_id_;

  // Mapping from Chrome node ID to its cached computed bounds.
  // This simplifies bounds calculations.
  std::map<int32_t, gfx::Rect> computed_bounds_;

  // Mapping from Chrome node ID to the attached hook implementations.
  base::flat_map<int32_t, std::unique_ptr<Hook>> hooks_;

  // A delegate that handles accessibility actions on behalf of this tree. The
  // delegate is valid during the lifetime of this tree.
  const raw_ptr<const Delegate> delegate_;
  // A delegate that handles unique serialization logic on behalf of this tree.
  // The delegate is valid during the lifetime of this tree.
  const std::unique_ptr<SerializationDelegate> serialization_delegate_;

  raw_ptr<extensions::AutomationEventRouterInterface>
      automation_event_router_for_test_ = nullptr;
};

}  // namespace ax::android

#endif  // SERVICES_ACCESSIBILITY_ANDROID_AX_TREE_SOURCE_ANDROID_H_