blob: b1adf0e714e117cd8ec1939ac492b0cbc25b09a1 [file] [log] [blame]
// Copyright 2020 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/lib/screen_reader/focus/a11y_focus_manager.h"
#include <fuchsia/ui/views/cpp/fidl.h>
#include <lib/async/default.h>
#include <lib/syslog/cpp/macros.h>
#include <optional>
#include "src/ui/a11y/lib/util/util.h"
namespace a11y {
A11yFocusManager::A11yFocusManager(AccessibilityFocusChainRequester* focus_chain_requester,
AccessibilityFocusChainRegistry* registry,
FocusHighlightManager* focus_highlight_manager)
: focus_chain_requester_(focus_chain_requester),
registry_(registry),
focus_highlight_manager_(focus_highlight_manager),
weak_ptr_factory_(this) {
FX_DCHECK(registry_);
FX_DCHECK(focus_highlight_manager_);
registry_->Register(weak_ptr_factory_.GetWeakPtr());
}
A11yFocusManager::A11yFocusManager() : weak_ptr_factory_(this) {}
A11yFocusManager::~A11yFocusManager() = default;
std::optional<A11yFocusManager::A11yFocusInfo> A11yFocusManager::GetA11yFocus() {
const auto iterator = focused_node_in_view_map_.find(currently_focused_view_);
if (iterator == focused_node_in_view_map_.end()) {
FX_LOGS(INFO) << "No view is currently in a11y-focus.";
return std::nullopt;
}
A11yFocusInfo focus_info;
focus_info.view_ref_koid = currently_focused_view_;
focus_info.node_id = iterator->second;
return focus_info;
}
void A11yFocusManager::SetA11yFocus(zx_koid_t koid, uint32_t node_id,
SetA11yFocusCallback set_focus_callback) {
if (koid == currently_focused_view_) {
// Same view a11y focus change.
focused_node_in_view_map_[koid] = node_id;
UpdateHighlights();
set_focus_callback(true);
return;
}
// Different view, a Focus Chain Update is necessary.
focus_chain_requester_->ChangeFocusToView(
koid, [this, koid, node_id, callback = std::move(set_focus_callback)](bool success) {
if (!success) {
callback(false);
} else {
// Update current a11y focus to the given viewref and node_id.
focused_node_in_view_map_[koid] = node_id;
currently_focused_view_ = koid;
UpdateHighlights();
callback(true);
}
});
}
void A11yFocusManager::OnViewFocus(zx_koid_t view_ref_koid) {
uint32_t newly_focused_node_id = kRootNodeId;
if (focused_node_in_view_map_.find(view_ref_koid) != focused_node_in_view_map_.end()) {
newly_focused_node_id = focused_node_in_view_map_[view_ref_koid];
}
currently_focused_view_ = view_ref_koid;
focused_node_in_view_map_[currently_focused_view_] = newly_focused_node_id;
UpdateHighlights();
}
void A11yFocusManager::UpdateHighlights() {
FocusHighlightManager::SemanticNodeIdentifier newly_focused_node;
newly_focused_node.koid = currently_focused_view_;
newly_focused_node.node_id = focused_node_in_view_map_[currently_focused_view_];
focus_highlight_manager_->UpdateHighlight(newly_focused_node);
}
} // namespace a11y