| // 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. |
| |
| #include "services/accessibility/assistive_technology_controller_impl.h" |
| |
| #include <memory> |
| #include <utility> |
| |
| #include "base/notreached.h" |
| #include "base/types/cxx23_to_underlying.h" |
| #include "services/accessibility/automation_impl.h" |
| #include "services/accessibility/features/interface_binder.h" |
| #include "services/accessibility/features/v8_manager.h" |
| #include "services/accessibility/public/mojom/accessibility_service.mojom.h" |
| |
| namespace ax { |
| |
| AssistiveTechnologyControllerImpl::AssistiveTechnologyControllerImpl() = |
| default; |
| |
| AssistiveTechnologyControllerImpl::~AssistiveTechnologyControllerImpl() = |
| default; |
| |
| void AssistiveTechnologyControllerImpl::Bind( |
| mojo::PendingReceiver<mojom::AssistiveTechnologyController> |
| at_controller_receiver) { |
| DCHECK(!at_controller_receiver_.is_bound()); |
| at_controller_receiver_.Bind(std::move(at_controller_receiver)); |
| } |
| |
| void AssistiveTechnologyControllerImpl::BindAccessibilityServiceClient( |
| mojo::PendingRemote<mojom::AccessibilityServiceClient> |
| accessibility_client_remote) { |
| DCHECK(!accessibility_service_client_remote_.is_bound()); |
| accessibility_service_client_remote_.Bind( |
| std::move(accessibility_client_remote)); |
| |
| // Once we have access to the AccessibilityServiceClient, initialize file |
| // loading capabilities. |
| accessibility_service_client_remote_->BindAccessibilityFileLoader( |
| file_loader_remote_.BindNewPipeAndPassReceiver()); |
| } |
| |
| void AssistiveTechnologyControllerImpl::BindAutomation( |
| mojo::PendingAssociatedRemote<mojom::Automation> automation) { |
| accessibility_service_client_remote_->BindAutomation(std::move(automation)); |
| } |
| |
| void AssistiveTechnologyControllerImpl::BindAutomationClient( |
| mojo::PendingReceiver<mojom::AutomationClient> automation_client) { |
| accessibility_service_client_remote_->BindAutomationClient( |
| std::move(automation_client)); |
| } |
| |
| void AssistiveTechnologyControllerImpl::BindAutoclickClient( |
| mojo::PendingReceiver<mojom::AutoclickClient> autoclick_client) { |
| accessibility_service_client_remote_->BindAutoclickClient( |
| std::move(autoclick_client)); |
| } |
| |
| void AssistiveTechnologyControllerImpl::BindSpeechRecognition( |
| mojo::PendingReceiver<mojom::SpeechRecognition> sr_receiver) { |
| accessibility_service_client_remote_->BindSpeechRecognition( |
| std::move(sr_receiver)); |
| } |
| |
| void AssistiveTechnologyControllerImpl::BindTts( |
| mojo::PendingReceiver<mojom::Tts> tts_receiver) { |
| accessibility_service_client_remote_->BindTts(std::move(tts_receiver)); |
| } |
| |
| void AssistiveTechnologyControllerImpl::BindUserInput( |
| mojo::PendingReceiver<mojom::UserInput> user_input_receiver) { |
| accessibility_service_client_remote_->BindUserInput( |
| std::move(user_input_receiver)); |
| } |
| |
| void AssistiveTechnologyControllerImpl::BindUserInterface( |
| mojo::PendingReceiver<mojom::UserInterface> user_interface_receiver) { |
| accessibility_service_client_remote_->BindUserInterface( |
| std::move(user_interface_receiver)); |
| } |
| |
| void AssistiveTechnologyControllerImpl::BindAccessibilityFileLoader( |
| mojo::PendingReceiver<ax::mojom::AccessibilityFileLoader> |
| file_loader_receiver) { |
| NOTREACHED(); |
| } |
| |
| void AssistiveTechnologyControllerImpl::EnableAssistiveTechnology( |
| const std::vector<mojom::AssistiveTechnologyType>& enabled_features) { |
| for (auto i = base::to_underlying(mojom::AssistiveTechnologyType::kMinValue); |
| i <= base::to_underlying(mojom::AssistiveTechnologyType::kMaxValue); |
| i++) { |
| mojom::AssistiveTechnologyType type = |
| static_cast<mojom::AssistiveTechnologyType>(i); |
| bool enabled = base::Contains(enabled_features, type); |
| auto it = enabled_ATs_.find(type); |
| if (enabled && it == enabled_ATs_.end()) { |
| // TODO(b/293348920): Re-use an existing V8Manager and install additional |
| // bindings there rather than always making a new one when sharing |
| // V8Managers across different AT types. |
| CreateV8ManagerForTypeIfNoneExists(type); |
| } else if (!enabled && it != enabled_ATs_.end()) { |
| enabled_ATs_.erase(type); |
| } |
| } |
| } |
| |
| bool AssistiveTechnologyControllerImpl::IsFeatureEnabled( |
| mojom::AssistiveTechnologyType type) const { |
| return base::Contains(enabled_ATs_, type); |
| } |
| |
| void AssistiveTechnologyControllerImpl::RunScriptForTest( |
| mojom::AssistiveTechnologyType type, |
| const std::string& script, |
| base::OnceClosure on_complete) { |
| GetOrCreateV8Manager(type).RunScriptForTest( // IN-TEST |
| script, std::move(on_complete)); |
| } |
| |
| void AssistiveTechnologyControllerImpl::AddInterfaceForTest( |
| mojom::AssistiveTechnologyType type, |
| std::unique_ptr<InterfaceBinder> test_interface) { |
| GetOrCreateV8Manager(type).AddInterfaceForTest( // IN-TEST |
| std::move(test_interface)); |
| } |
| |
| V8Manager& AssistiveTechnologyControllerImpl::GetOrCreateV8Manager( |
| mojom::AssistiveTechnologyType type) { |
| CreateV8ManagerForTypeIfNoneExists(type); |
| return enabled_ATs_[type]; |
| } |
| |
| void AssistiveTechnologyControllerImpl::CreateV8ManagerForTypeIfNoneExists( |
| mojom::AssistiveTechnologyType type) { |
| // Do nothing if the manager already exists. |
| if (auto it = enabled_ATs_.find(type); it != enabled_ATs_.end()) { |
| return; |
| } |
| |
| // For the first one we can ask it to initialize v8. |
| if (!v8_initialized_) { |
| BindingsIsolateHolder::InitializeV8(); |
| v8_initialized_ = true; |
| } |
| |
| V8Manager& manager = enabled_ATs_[type]; |
| |
| // Install bindings on the global context depending on the type. |
| // For example, some types may need TTS and some may not. All need Automation |
| // and file loading. |
| // TODO(b/262637071): Create a easy way to map AT types to APIs needed instead |
| // of these large if statements. |
| mojo::PendingAssociatedReceiver<mojom::Automation> automation; |
| BindAutomation(automation.InitWithNewEndpointAndPassRemote()); |
| manager.ConfigureAutomation(this, std::move(automation)); |
| manager.ConfigureFileLoader(&file_loader_remote_); |
| if (type == mojom::AssistiveTechnologyType::kChromeVox || |
| type == mojom::AssistiveTechnologyType::kDictation) { |
| manager.ConfigureOSState(); |
| } |
| if (type == mojom::AssistiveTechnologyType::kChromeVox || |
| type == mojom::AssistiveTechnologyType::kSelectToSpeak) { |
| manager.ConfigureTts(this); |
| } |
| if (type == mojom::AssistiveTechnologyType::kChromeVox || |
| type == mojom::AssistiveTechnologyType::kSelectToSpeak || |
| type == mojom::AssistiveTechnologyType::kAutoClick || |
| type == mojom::AssistiveTechnologyType::kSwitchAccess) { |
| manager.ConfigureUserInterface(this); |
| } |
| if (type == mojom::AssistiveTechnologyType::kDictation) { |
| manager.ConfigureSpeechRecognition(this); |
| } |
| if (type == mojom::AssistiveTechnologyType::kAutoClick) { |
| manager.ConfigureAutoclick(this); |
| } |
| if (type == mojom::AssistiveTechnologyType::kAutoClick || |
| type == mojom::AssistiveTechnologyType::kChromeVox || |
| type == mojom::AssistiveTechnologyType::kDictation || |
| type == mojom::AssistiveTechnologyType::kMagnifier || |
| type == mojom::AssistiveTechnologyType::kSelectToSpeak || |
| type == mojom::AssistiveTechnologyType::kSwitchAccess) { |
| manager.ConfigureUserInput(this); |
| } |
| // TODO(b/262637071): Configure other bindings based on the type |
| // once they are implemented. |
| |
| // After configuring all bindings, initialize. |
| manager.FinishContextSetUp(); |
| } |
| |
| } // namespace ax |