blob: b0d00028a3436a5831b8e0c26db63169eb8bbb1d [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/ui/a11y/bin/a11y_manager/app.h"
#include <zircon/status.h>
#include "src/lib/syslog/cpp/logger.h"
#include "src/ui/a11y/lib/screen_reader/focus/a11y_focus_manager.h"
#include "src/ui/a11y/lib/screen_reader/screen_reader_context.h"
namespace a11y_manager {
const float kDefaultMagnificationZoomFactor = 1.0;
App::App(sys::ComponentContext* context, a11y::ViewManager* view_manager,
a11y::TtsManager* tts_manager, a11y::ColorTransformManager* color_transform_manager,
a11y::GestureListenerRegistry* gesture_listener_registry)
: view_manager_(view_manager),
tts_manager_(tts_manager),
color_transform_manager_(color_transform_manager),
gesture_listener_registry_(gesture_listener_registry) {
FX_DCHECK(context);
FX_DCHECK(view_manager);
FX_DCHECK(tts_manager);
FX_DCHECK(color_transform_manager);
FX_DCHECK(gesture_listener_registry_);
context->outgoing()->AddPublicService(semantics_manager_bindings_.GetHandler(view_manager_));
context->outgoing()->AddPublicService(magnifier_bindings_.GetHandler(&magnifier_));
context->outgoing()->AddPublicService(
gesture_listener_registry_bindings_.GetHandler(gesture_listener_registry_));
// Connect to Root presenter service.
pointer_event_registry_ =
context->svc()->Connect<fuchsia::ui::input::accessibility::PointerEventRegistry>();
pointer_event_registry_.set_error_handler([](zx_status_t status) {
FX_LOGS(ERROR) << "Error from fuchsia::ui::input::accessibility::PointerEventRegistry"
<< zx_status_get_string(status);
});
// Inits Focus Chain focuser support / listening Focus Chain updates.
focuser_registry_ = context->svc()->Connect<fuchsia::ui::views::accessibility::FocuserRegistry>();
focuser_registry_.set_error_handler([](zx_status_t status) {
FX_LOGS(ERROR) << "Error from fuchsia::ui::views::accessibility::FocuserRegistry"
<< zx_status_get_string(status);
});
fuchsia::ui::views::FocuserPtr focuser;
focuser_registry_->RegisterFocuser(focuser.NewRequest());
focus_chain_manager_ =
std::make_unique<a11y::FocusChainManager>(std::move(focuser), view_manager_);
// |focus_chain_manager_| listens for Focus Chain updates. Connects to the listener registry and
// start listening.
focus_chain_listener_registry_ =
context->svc()->Connect<fuchsia::ui::focus::FocusChainListenerRegistry>();
focus_chain_listener_registry_.set_error_handler([](zx_status_t status) {
FX_LOGS(ERROR) << "Error from fuchsia::ui::focus::FocusChainListenerRegistry"
<< zx_status_get_string(status);
});
auto focus_chain_listener_handle =
focus_chain_listener_bindings_.AddBinding(focus_chain_manager_.get());
focus_chain_listener_registry_->Register(focus_chain_listener_handle.Bind());
// Connect to setui.
setui_settings_ = context->svc()->Connect<fuchsia::settings::Accessibility>();
setui_settings_.set_error_handler([](zx_status_t status) {
FX_LOGS(ERROR) << "Error from fuchsia::settings::Accessibility" << zx_status_get_string(status);
});
// Start watching setui for current settings
WatchSetui();
}
App::~App() = default;
void App::SetState(A11yManagerState state) {
state_ = state;
UpdateScreenReaderState();
UpdateMagnifierState();
UpdateColorTransformState();
// May rely on screen reader existence.
UpdateGestureManagerState();
}
void App::UpdateScreenReaderState() {
// If this is used elsewhere, it should be moved into its own function.
view_manager_->SetSemanticsEnabled(state_.screen_reader_enabled());
if (state_.screen_reader_enabled()) {
if (!screen_reader_) {
screen_reader_ = InitializeScreenReader();
}
} else {
screen_reader_.reset();
}
}
void App::UpdateMagnifierState() {
if (!state_.magnifier_enabled()) {
magnifier_.ZoomOutIfMagnified();
}
}
void App::UpdateColorTransformState() {
bool color_inversion = state_.color_inversion_enabled();
fuchsia::accessibility::ColorCorrectionMode color_blindness_type = state_.color_correction_mode();
color_transform_manager_->ChangeColorTransform(color_inversion, color_blindness_type);
}
void App::UpdateGestureManagerState() {
GestureState new_state = {.screen_reader_gestures = state_.screen_reader_enabled(),
.magnifier_gestures = state_.magnifier_enabled()};
if (new_state == gesture_state_)
return;
gesture_state_ = new_state;
// For now the easiest way to properly set up all gestures with the right priorities is to rebuild
// the gesture manager when the gestures change.
if (!gesture_state_.has_any()) {
// Shut down and clean up if no users
gesture_manager_.reset();
} else {
gesture_manager_ = std::make_unique<a11y::GestureManager>();
pointer_event_registry_->Register(gesture_manager_->binding().NewBinding());
// The ordering of these recognizers is significant, as it signifies priority.
if (gesture_state_.magnifier_gestures) {
gesture_manager_->arena()->Add(&magnifier_);
}
if (gesture_state_.screen_reader_gestures) {
screen_reader_->BindGestures(gesture_manager_->gesture_handler());
gesture_manager_->gesture_handler()->ConsumeAll();
}
}
}
bool App::GestureState::operator==(GestureState o) const {
return screen_reader_gestures == o.screen_reader_gestures &&
magnifier_gestures == o.magnifier_gestures;
}
void App::SetuiWatchCallback(fuchsia::settings::Accessibility_Watch_Result result) {
if (result.is_err()) {
FX_LOGS(ERROR) << "Error reading setui accessibility settings.";
} else if (result.is_response()) {
SetState(state_.withSettings(result.response().settings));
}
WatchSetui();
}
void App::WatchSetui() { setui_settings_->Watch(fit::bind_member(this, &App::SetuiWatchCallback)); }
// Converts setui color blindess type to the relevant accessibility color correction mode.
fuchsia::accessibility::ColorCorrectionMode ConvertColorCorrection(
fuchsia::settings::ColorBlindnessType color_blindness_type) {
switch (color_blindness_type) {
case fuchsia::settings::ColorBlindnessType::PROTANOMALY:
return fuchsia::accessibility::ColorCorrectionMode::CORRECT_PROTANOMALY;
case fuchsia::settings::ColorBlindnessType::DEUTERANOMALY:
return fuchsia::accessibility::ColorCorrectionMode::CORRECT_DEUTERANOMALY;
case fuchsia::settings::ColorBlindnessType::TRITANOMALY:
return fuchsia::accessibility::ColorCorrectionMode::CORRECT_TRITANOMALY;
case fuchsia::settings::ColorBlindnessType::NONE:
// fall through
default:
return fuchsia::accessibility::ColorCorrectionMode::DISABLED;
}
}
A11yManagerState A11yManagerState::withSettings(
const fuchsia::settings::AccessibilitySettings& systemSettings) {
A11yManagerState state = *this;
if (systemSettings.has_screen_reader()) {
state.screen_reader_enabled_ = systemSettings.screen_reader();
}
if (systemSettings.has_enable_magnification()) {
state.magnifier_enabled_ = systemSettings.enable_magnification();
}
if (systemSettings.has_color_inversion()) {
state.color_inversion_enabled_ = systemSettings.color_inversion();
}
if (systemSettings.has_color_correction()) {
state.color_correction_mode_ = ConvertColorCorrection(systemSettings.color_correction());
}
return state;
}
std::unique_ptr<a11y::ScreenReader> App::InitializeScreenReader() {
auto a11y_focus_manager = std::make_unique<a11y::A11yFocusManager>(
focus_chain_manager_.get(), focus_chain_manager_.get(), view_manager_);
auto screen_reader_context =
std::make_unique<a11y::ScreenReaderContext>(std::move(a11y_focus_manager));
return std::make_unique<a11y::ScreenReader>(std::move(screen_reader_context), view_manager_,
tts_manager_);
}
} // namespace a11y_manager