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

content / browser / accessibility / browser_accessibility_manager_android.h [blame]

// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_MANAGER_ANDROID_H_
#define CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_MANAGER_ANDROID_H_

#include <unordered_set>
#include <utility>

#include "content/common/content_export.h"
#include "ui/accessibility/platform/browser_accessibility_manager.h"

namespace ui {

class MotionEventAndroid;
class AXPlatformTreeManagerDelegate;

}  // namespace ui

namespace content {

// A Java counterpart will be generated for this enum.
// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.content.browser.accessibility
enum ScrollDirection { FORWARD, BACKWARD, UP, DOWN, LEFT, RIGHT };

// From android.view.accessibility.AccessibilityNodeInfo in Java:
enum AndroidMovementGranularity {
  ANDROID_ACCESSIBILITY_NODE_INFO_MOVEMENT_GRANULARITY_CHARACTER = 1,
  ANDROID_ACCESSIBILITY_NODE_INFO_MOVEMENT_GRANULARITY_WORD = 2,
  ANDROID_ACCESSIBILITY_NODE_INFO_MOVEMENT_GRANULARITY_LINE = 4
};

// From android.view.accessibility.AccessibilityEvent in Java:
enum {
  ANDROID_ACCESSIBILITY_EVENT_TEXT_CHANGED = 16,
  ANDROID_ACCESSIBILITY_EVENT_TEXT_SELECTION_CHANGED = 8192,
  ANDROID_ACCESSIBILITY_EVENT_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY = 131072
};

class BrowserAccessibilityAndroid;
class WebContentsAccessibilityAndroid;

class CONTENT_EXPORT BrowserAccessibilityManagerAndroid
    : public ui::BrowserAccessibilityManager {
 public:
  // Creates the platform-specific BrowserAccessibilityManager.
  static BrowserAccessibilityManager* Create(
      const ui::AXTreeUpdate& initial_tree,
      ui::AXNodeIdDelegate& node_id_delegate,
      ui::AXPlatformTreeManagerDelegate* delegate);

  static BrowserAccessibilityManager* Create(
      ui::AXNodeIdDelegate& node_id_delegate,
      ui::AXPlatformTreeManagerDelegate* delegate);

  BrowserAccessibilityManagerAndroid(
      const ui::AXTreeUpdate& initial_tree,
      base::WeakPtr<WebContentsAccessibilityAndroid> web_contents_accessibility,
      ui::AXNodeIdDelegate& node_id_delegate,
      ui::AXPlatformTreeManagerDelegate* delegate);

  BrowserAccessibilityManagerAndroid(
      const BrowserAccessibilityManagerAndroid&) = delete;
  BrowserAccessibilityManagerAndroid& operator=(
      const BrowserAccessibilityManagerAndroid&) = delete;

  ~BrowserAccessibilityManagerAndroid() override;

  static ui::AXTreeUpdate GetEmptyDocument();

  void set_allow_image_descriptions_for_testing(bool is_allowed) {
    allow_image_descriptions_for_testing_ = is_allowed;
  }

  // By default, the tree is pruned for a better screen reading experience,
  // including:
  //   * If the node has only static text children
  //   * If the node is focusable and has no focusable children
  //   * If the node is a heading
  // This can be turned off to generate a tree that more accurately reflects
  // the DOM and includes style changes within these nodes.
  void set_prune_tree_for_screen_reader(bool prune) {
    prune_tree_for_screen_reader_ = prune;
  }
  bool prune_tree_for_screen_reader() { return prune_tree_for_screen_reader_; }

  void set_web_contents_accessibility(
      base::WeakPtr<WebContentsAccessibilityAndroid> wcax) {
    web_contents_accessibility_ = std::move(wcax);
  }
  void ResetWebContentsAccessibility();

  // State properties defined from Java-side code.
  bool ShouldAllowImageDescriptions();

  // Consume hover event if necessary, and return true if it did.
  bool OnHoverEvent(const ui::MotionEventAndroid& event);

  // AXTreeManager overrides.
  void FireFocusEvent(ui::AXNode* node) override;

  // BrowserAccessibilityManager overrides.
  ui::BrowserAccessibility* GetFocus() const override;
  void SendLocationChangeEvents(
      const std::vector<ui::AXLocationChange>& changes) override;
  ui::AXNode* RetargetForEvents(ui::AXNode* node,
                                RetargetEventType type) const override;
  void FireBlinkEvent(ax::mojom::Event event_type,
                      ui::BrowserAccessibility* node,
                      int action_request_id) override;
  void FireGeneratedEvent(ui::AXEventGenerator::Event event_type,
                          const ui::AXNode* node) override;

  void FireAriaNotificationEvent(
      ui::BrowserAccessibility* node,
      const std::string& announcement,
      const std::string& notification_id,
      ax::mojom::AriaNotificationInterrupt interrupt_property,
      ax::mojom::AriaNotificationPriority priority_property) override;

  void FireLocationChanged(ui::BrowserAccessibility* node);

  // Helper functions to compute the next start and end index when moving
  // forwards or backwards by character, word, or line. This part is
  // unit-tested; the Java interfaces above are just wrappers. Both of these
  // take a single cursor index as input and return the boundaries surrounding
  // the next word or line. If moving by character, the output start and
  // end index will be the same.
  bool NextAtGranularity(int32_t granularity,
                         int cursor_index,
                         BrowserAccessibilityAndroid* node,
                         int32_t* start_index,
                         int32_t* end_index);
  bool PreviousAtGranularity(int32_t granularity,
                             int cursor_index,
                             BrowserAccessibilityAndroid* node,
                             int32_t* start_index,
                             int32_t* end_index);

  // Helper method to clear AccessibilityNodeInfo cache on given node
  void ClearNodeInfoCacheForGivenId(int32_t unique_id);

  std::u16string GenerateAccessibilityNodeInfoString(int32_t unique_id);

  std::vector<std::string> GetMetadataForTree() const;

 protected:
  std::unique_ptr<ui::BrowserAccessibility> CreateBrowserAccessibility(
      ui::AXNode* node) override;

 private:
  // AXTreeObserver overrides.
  void OnAtomicUpdateFinished(
      ui::AXTree* tree,
      bool root_changed,
      const std::vector<ui::AXTreeObserver::Change>& changes) override;

  void OnNodeWillBeDeleted(ui::AXTree* tree, ui::AXNode* node) override;

  WebContentsAccessibilityAndroid* GetWebContentsAXFromRootManager();

  // This gives BrowserAccessibilityManager::Create access to the class
  // constructor.
  friend class ui::BrowserAccessibilityManager;

  // Handle a hover event from the renderer process.
  void HandleHoverEvent(ui::BrowserAccessibility* node);

  // A weak reference to WebContentsAccessibility for reaching Java layer.
  // Only the root manager has the reference. Should be accessed through
  // |GetWebContentsAXFromRootManager| rather than directly.
  base::WeakPtr<WebContentsAccessibilityAndroid> web_contents_accessibility_;

  // See docs for set_prune_tree_for_screen_reader, above.
  bool prune_tree_for_screen_reader_;

  // True if this instance should force enable the image descriptions feature
  // for testing. This allows us to mock generated image descriptions and test
  // tree dumps for nodes without creating web_contents_accessibility_android.
  bool allow_image_descriptions_for_testing_ = false;

  // An unordered_set of |unique_id| values for nodes cleared from the cache
  // with each atomic update to prevent superfluous cache clear calls.
  std::unordered_set<int32_t> nodes_already_cleared_ =
      std::unordered_set<int32_t>();
};

}  // namespace content

#endif  // CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_MANAGER_ANDROID_H_