| // Copyright 2022 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CHROME_BROWSER_ASH_ACCESSIBILITY_SERVICE_FAKE_ACCESSIBILITY_SERVICE_H_ |
| #define CHROME_BROWSER_ASH_ACCESSIBILITY_SERVICE_FAKE_ACCESSIBILITY_SERVICE_H_ |
| |
| #include "base/files/file_path.h" |
| #include "base/functional/callback.h" |
| #include "base/unguessable_token.h" |
| #include "chrome/browser/accessibility/service/accessibility_service_router.h" |
| #include "components/keyed_service/core/keyed_service.h" |
| #include "mojo/public/cpp/bindings/associated_receiver_set.h" |
| #include "mojo/public/cpp/bindings/pending_receiver.h" |
| #include "mojo/public/cpp/bindings/receiver_set.h" |
| #include "mojo/public/cpp/bindings/remote_set.h" |
| #include "services/accessibility/public/mojom/accessibility_service.mojom.h" |
| #include "services/accessibility/public/mojom/autoclick.mojom.h" |
| #include "services/accessibility/public/mojom/automation.mojom.h" |
| #include "services/accessibility/public/mojom/automation_client.mojom.h" |
| #include "services/accessibility/public/mojom/file_loader.mojom.h" |
| #include "services/accessibility/public/mojom/speech_recognition.mojom.h" |
| #include "services/accessibility/public/mojom/tts.mojom.h" |
| #include "services/accessibility/public/mojom/user_input.mojom.h" |
| #include "services/accessibility/public/mojom/user_interface.mojom.h" |
| #include "ui/accessibility/ax_action_data.h" |
| #include "ui/accessibility/ax_event.h" |
| #include "ui/accessibility/ax_tree_update.h" |
| |
| namespace ash { |
| |
| // A fake Chrome OS Accessibility service to use for Chrome testing. |
| // This class acts as an AccessibilityServiceRouter in the browser process |
| // and then implements service mojom to act as a mock service. |
| class FakeAccessibilityService |
| : public ax::AccessibilityServiceRouter, |
| public ax::mojom::Automation, |
| public ax::mojom::AssistiveTechnologyController, |
| public ax::mojom::Autoclick { |
| public: |
| FakeAccessibilityService(); |
| FakeAccessibilityService(const FakeAccessibilityService&) = delete; |
| FakeAccessibilityService& operator=(const FakeAccessibilityService&) = delete; |
| ~FakeAccessibilityService() override; |
| |
| // AccessibilityServiceRouter: |
| void BindAccessibilityServiceClient( |
| mojo::PendingRemote<ax::mojom::AccessibilityServiceClient> |
| accessibility_service_client) override; |
| void BindAssistiveTechnologyController( |
| mojo::PendingReceiver<ax::mojom::AssistiveTechnologyController> |
| at_controller_receiver, |
| const std::vector<ax::mojom::AssistiveTechnologyType>& enabled_features) |
| override; |
| void ConnectDevToolsAgent( |
| mojo::PendingAssociatedReceiver<blink::mojom::DevToolsAgent> agent, |
| ax::mojom::AssistiveTechnologyType type) override; |
| |
| // ax::mojom::Automation: |
| void DispatchTreeDestroyedEvent(const ui::AXTreeID& tree_id) override; |
| void DispatchActionResult(const ui::AXActionData& data, bool result) override; |
| void DispatchAccessibilityEvents( |
| const ui::AXTreeID& tree_id, |
| const std::vector<ui::AXTreeUpdate>& updates, |
| const gfx::Point& mouse_location, |
| const std::vector<ui::AXEvent>& events) override; |
| void DispatchAccessibilityLocationChange( |
| const ui::AXTreeID& tree_id, |
| int node_id, |
| const ui::AXRelativeBounds& bounds) override; |
| void DispatchAccessibilityScrollChange(const ui::AXTreeID& tree_id, |
| int node_id, |
| int scroll_x, |
| int scroll_y) override; |
| void DispatchGetTextLocationResult( |
| const ui::AXActionData& data, |
| const std::optional<gfx::Rect>& rect) override; |
| |
| // ax::mojom::AssistiveTechnologyController: |
| void EnableAssistiveTechnology( |
| const std::vector<ax::mojom::AssistiveTechnologyType>& enabled_features) |
| override; |
| |
| // In the service, V8 JS implements autoclick. |
| // ax::mojom::Autoclick: |
| void RequestScrollableBoundsForPoint(const gfx::Point& point) override; |
| |
| // |
| // Methods for testing. |
| // |
| |
| // Whether the service client remote is bound. |
| bool IsBound() const; |
| |
| // Waits for EnableAssistiveTechnology to be called |count| times. |
| void WaitForATChangeCount(int count); |
| |
| // Gets the currently enabled assistive technology types. |
| const std::set<ax::mojom::AssistiveTechnologyType>& GetEnabledATs() const { |
| return enabled_ATs_; |
| } |
| |
| int GetDevtoolsConnectionCount(ax::mojom::AssistiveTechnologyType type) const; |
| |
| // Allows tests to bind APIs multiple times, mimicking multiple |
| // V8 instances in the service. |
| void BindAnotherAutomation(); |
| void BindAnotherAutomationClient(); |
| void BindAnotherAutoclickClient(); |
| void BindAnotherSpeechRecognition(); |
| void BindAnotherTts(); |
| void BindAnotherUserInput(); |
| void BindAnotherUserInterface(); |
| |
| // |
| // Methods to pretend an AutomationClient request came from the service. |
| // |
| |
| // Calls ax::mojom::AutomationClient::Enable or ::Disable. |
| void AutomationClientEnable(bool enabled); |
| |
| // Waits for Automation events to come in. |
| void WaitForAutomationEvents(); |
| |
| // |
| // Methods to pretend a SpeechRecognition request came from the service. |
| // |
| |
| void RequestSpeechRecognitionStart( |
| ax::mojom::StartOptionsPtr options, |
| base::OnceCallback<void(ax::mojom::SpeechRecognitionStartInfoPtr)> |
| callback); |
| void RequestSpeechRecognitionStop( |
| ax::mojom::StopOptionsPtr options, |
| base::OnceCallback<void(const std::optional<std::string>&)> callback); |
| |
| // |
| // Methods to pretend a TTS request came from the service. |
| // |
| |
| // Sends a request for speech using the default options, but with on_event |
| // set to true. |
| void RequestSpeak( |
| const std::string& utterance, |
| base::OnceCallback<void(ax::mojom::TtsSpeakResultPtr)> callback); |
| |
| // Sends a request for speech using the given options. |
| void RequestSpeak( |
| const std::string& utterance, |
| ax::mojom::TtsOptionsPtr options, |
| base::OnceCallback<void(ax::mojom::TtsSpeakResultPtr)> callback); |
| |
| // Sends a request to stop speech. |
| void RequestStop(); |
| |
| // Sends a request to pause speech. |
| void RequestPause(); |
| |
| // Sends a request to resume speech. |
| void RequestResume(); |
| |
| // Asks if speech is in progress. |
| void IsTtsSpeaking(base::OnceCallback<void(bool)> callback); |
| |
| // Sends a request from the service for the TTS voices list. |
| void RequestTtsVoices(ax::mojom::Tts::GetVoicesCallback callback); |
| |
| // |
| // Methods to pretend a UserInput request came from the service. |
| // |
| |
| // Sends a request to send a synthetic key event. |
| void RequestSendSyntheticKeyEventForShortcutOrNavigation( |
| ax::mojom::SyntheticKeyEventPtr key_event); |
| |
| // Sends a request to send a synthetic mouse event. |
| void RequestSendSyntheticMouseEvent( |
| ax::mojom::SyntheticMouseEventPtr mouse_event); |
| |
| // |
| // Methods to pretend a UserInterface request came from the service. |
| // |
| |
| void RequestDarkenScreen(bool darken); |
| |
| void RequestOpenSettingsSubpage(const std::string& subpage); |
| |
| void RequestShowConfirmationDialog( |
| const std::string& title, |
| const std::string& description, |
| const std::optional<std::string>& cancel_name, |
| ax::mojom::UserInterface::ShowConfirmationDialogCallback callback); |
| |
| void RequestSetFocusRings( |
| std::vector<ax::mojom::FocusRingInfoPtr> focus_rings, |
| ax::mojom::AssistiveTechnologyType at_type); |
| |
| void RequestSetHighlights(const std::vector<gfx::Rect>& rects, SkColor color); |
| |
| void RequestSetVirtualKeyboardVisible(bool is_visible); |
| |
| // Getters for automation events. |
| std::vector<ui::AXTreeID> tree_destroyed_events() const { |
| return tree_destroyed_events_; |
| } |
| std::vector<std::tuple<ui::AXActionData, bool>> action_results() const { |
| return action_results_; |
| } |
| std::vector<ui::AXTreeID> accessibility_events() const { |
| return accessibility_events_; |
| } |
| std::vector<ui::AXTreeID> location_changes() const { |
| return location_changes_; |
| } |
| |
| // Loads a file indicated by |relative_path|, which must be a relative path. |
| // The base path used to load paths from is the base accessibility resources |
| // directory in ChromeOS. |callback| runs when the operation is completed. |
| void RequestLoadFile( |
| base::FilePath relative_path, |
| ax::mojom::AccessibilityFileLoader::LoadCallback callback); |
| |
| void set_autoclick_scrollable_bounds(const gfx::Rect& bounds) { |
| autoclick_scrollable_bounds_ = bounds; |
| } |
| |
| private: |
| // Emulates V8 getting the autoclick receiver in the service process. |
| void OnAutoclickBoundCallback( |
| mojo::PendingReceiver<ax::mojom::Autoclick> autoclick_receiver); |
| |
| base::OnceClosure change_ATs_closure_; |
| std::set<ax::mojom::AssistiveTechnologyType> enabled_ATs_; |
| base::OnceClosure automation_events_closure_; |
| |
| std::vector<ui::AXTreeID> tree_destroyed_events_; |
| std::vector<std::tuple<ui::AXActionData, bool>> action_results_; |
| std::vector<ui::AXTreeID> accessibility_events_; |
| std::vector<ui::AXTreeID> location_changes_; |
| std::vector<ui::AXTreeID> scroll_changes_; |
| |
| gfx::Rect autoclick_scrollable_bounds_; |
| |
| std::map<ax::mojom::AssistiveTechnologyType, int> connect_devtools_counts; |
| |
| // Number of times ATs changed state. |
| int at_change_count_ = 0; |
| int expected_count_ = 0; |
| |
| mojo::AssociatedReceiverSet<ax::mojom::Automation> automation_receivers_; |
| mojo::RemoteSet<ax::mojom::AutomationClient> automation_client_remotes_; |
| |
| mojo::RemoteSet<ax::mojom::SpeechRecognition> sr_remotes_; |
| mojo::RemoteSet<ax::mojom::AutoclickClient> autoclick_client_remotes_; |
| mojo::ReceiverSet<ax::mojom::Autoclick> autoclick_receivers_; |
| mojo::RemoteSet<ax::mojom::Tts> tts_remotes_; |
| mojo::RemoteSet<ax::mojom::UserInput> ui_remotes_; |
| mojo::RemoteSet<ax::mojom::UserInterface> ux_remotes_; |
| |
| mojo::ReceiverSet<ax::mojom::AssistiveTechnologyController> |
| at_controller_receivers_; |
| mojo::Remote<ax::mojom::AccessibilityServiceClient> |
| accessibility_service_client_remote_; |
| mojo::Remote<ax::mojom::AccessibilityFileLoader> file_loader_remote_; |
| }; |
| |
| } // namespace ash |
| |
| #endif // CHROME_BROWSER_ASH_ACCESSIBILITY_SERVICE_FAKE_ACCESSIBILITY_SERVICE_H_ |