blob: 31482c237552390dc4bd453ab877a9819c7ae7ad [file] [log] [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_PUBLIC_TEST_ACCESSIBILITY_NOTIFICATION_WAITER_H_
#define CONTENT_PUBLIC_TEST_ACCESSIBILITY_NOTIFICATION_WAITER_H_
#include <memory>
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "content/public/browser/web_contents_observer.h"
#include "ui/accessibility/ax_event_generator.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/accessibility/ax_node_id_forward.h"
#include "ui/accessibility/ax_tree.h"
namespace base {
class RunLoop;
}
namespace ui {
class BrowserAccessibilityManager;
}
namespace content {
class RenderFrameHost;
class RenderFrameHostImpl;
class WebContents;
// Create an instance of this class *before* doing any operation that
// might generate an accessibility event (like a page navigation or
// clicking on a button). Then call WaitForNotification
// afterwards to block until the specified accessibility notification has been
// received.
class AccessibilityNotificationWaiter : public WebContentsObserver {
public:
// Will wait for any event across all ways including scroll or location
// changes as well normal and generated events.
explicit AccessibilityNotificationWaiter(WebContents* web_contents);
// Wait for a specific Blink event.
AccessibilityNotificationWaiter(WebContents* web_contents,
ax::mojom::Event event);
// Wait for a specific AXEventGenerator event.
AccessibilityNotificationWaiter(WebContents* web_contents,
ui::AXEventGenerator::Event event);
AccessibilityNotificationWaiter(const AccessibilityNotificationWaiter&) =
delete;
AccessibilityNotificationWaiter& operator=(
const AccessibilityNotificationWaiter&) = delete;
~AccessibilityNotificationWaiter() override;
// Blocks until the specific accessibility notification registered in
// AccessibilityNotificationWaiter is received. Returns true if an event was
// received, false if waiting ended for some other reason.
// Pass true for |all_frames| to wait for a notification on all frames
// before returning, rather than waiting for only a single notification
// from any frame.
[[nodiscard]] bool WaitForNotification(bool all_frames = false);
// Blocks until the notification is received, or the given timeout passes.
// Returns true if an event was received, false if waiting ended for some
// other reason.
[[nodiscard]] bool WaitForNotificationWithTimeout(base::TimeDelta timeout);
// After WaitForNotification has returned, this will retrieve
// the tree of accessibility nodes received from the renderer process for
// the observed WebContents (not including the trees of inner WebContents).
const ui::AXTree& GetAXTree() const;
// After WaitForNotification returns, use this to retrieve the id of the
// node that was the target of the event.
int event_target_id() const { return event_target_id_; }
bool notification_received() const { return notification_received_; }
// After WaitForNotification returns, use this to retrieve the
// `BrowserAccessibilityManager` that was the target of the event.
ui::BrowserAccessibilityManager* event_browser_accessibility_manager() const {
return event_browser_accessibility_manager_;
}
// WebContentsObserver override:
void RenderFrameHostChanged(RenderFrameHost* old_host,
RenderFrameHost* new_host) override;
// Quits listening and unblocks WaitForNotification* calls.
void Quit();
private:
// Listen to all frames within the frame tree of this WebContents.
void ListenToAllFrames(WebContents* web_contents);
// Bind either the OnAccessibilityEvent or OnGeneratedEvent callback
// for a given frame within the WebContent's frame tree.
void ListenToFrame(RenderFrameHostImpl* frame_host);
// Helper to bind the OnAccessibilityEvent callback.
void BindOnAccessibilityEvent(RenderFrameHostImpl* frame_host);
// Helper to bind the OnGeneratedEvent callback.
void BindOnGeneratedEvent(RenderFrameHostImpl* frame_host);
// Helper to bind the OnLocationsChanged callback.
void BindOnLocationsChanged(RenderFrameHostImpl* frame_host);
// Callback from RenderViewHostImpl.
void OnAccessibilityEvent(RenderFrameHostImpl* rfhi,
ax::mojom::Event event,
int event_target_id);
// Callback from BrowserAccessibilityManager for all generated events.
void OnGeneratedEvent(ui::BrowserAccessibilityManager* manager,
ui::AXEventGenerator::Event event,
ui::AXNodeID event_target_id);
// Callback from BrowserAccessibilityManager when locations / bounding
// boxes change.
void OnLocationsChanged();
// Callback from BrowserAccessibilityManager for the focus changed event.
//
// TODO(crbug.com/41470112): Remove this method once we migrate to using
// AXEventGenerator for focus changed events.
void OnFocusChanged();
// Returns the tree of accessibility nodes received from renderer processes
// for the WebContents that owns `render_frame`. This may not be the observed
// WebContents, but rather an inner WebContents (e.g., for a guest view).
const ui::AXTree& GetAXTreeForFrame(RenderFrameHostImpl* render_frame) const;
std::optional<ax::mojom::Event> event_to_wait_for_;
std::optional<ui::AXEventGenerator::Event> generated_event_to_wait_for_;
std::unique_ptr<base::RunLoop> loop_runner_;
base::RepeatingClosure loop_runner_quit_closure_;
int event_target_id_ = 0;
raw_ptr<ui::BrowserAccessibilityManager, AcrossTasksDanglingUntriaged>
event_browser_accessibility_manager_ = nullptr;
bool notification_received_ = false;
int frame_count_ = 0;
int notification_count_ = 0;
bool wait_for_any_event_ = false;
base::WeakPtrFactory<AccessibilityNotificationWaiter> weak_factory_{this};
};
} // namespace content
#endif // CONTENT_PUBLIC_TEST_ACCESSIBILITY_NOTIFICATION_WAITER_H_