blob: ae71ddc140c7054324d33137f5d0c3fcb1fd0476 [file] [log] [blame]
// Copyright 2019 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/semantics/semantic_tree_service.h"
#include <lib/async/default.h>
#include <lib/inspect/cpp/inspect.h>
#include <lib/syslog/cpp/macros.h>
#include <zircon/types.h>
#include <algorithm>
#include "fuchsia/accessibility/semantics/cpp/fidl.h"
#include "src/lib/fsl/handles/object_info.h"
#include "src/lib/fxl/strings/concatenate.h"
#include "zircon/third_party/uapp/dash/src/output.h"
namespace a11y {
namespace {
using fuchsia::accessibility::semantics::Node;
} // namespace
SemanticTreeService::SemanticTreeService(
std::unique_ptr<::a11y::SemanticTree> tree, zx_koid_t(koid),
fuchsia::accessibility::semantics::SemanticListenerPtr semantic_listener,
CloseChannelCallback error_callback)
: tree_(std::move(tree)),
close_channel_callback_(std::move(error_callback)),
koid_(koid),
semantic_listener_(std::move(semantic_listener)),
semantic_tree_factory_(
std::make_unique<fxl::WeakPtrFactory<::a11y::SemanticTree>>(tree_.get())) {
tree_->set_action_handler([this](uint32_t node_id,
fuchsia::accessibility::semantics::Action action,
fuchsia::accessibility::semantics::SemanticListener::
OnAccessibilityActionRequestedCallback callback) {
this->PerformAccessibilityAction(node_id, action, std::move(callback));
});
tree_->set_hit_testing_handler(
[this](fuchsia::math::PointF local_point,
fuchsia::accessibility::semantics::SemanticListener::HitTestCallback callback) {
this->PerformHitTesting(local_point, std::move(callback));
});
}
SemanticTreeService::~SemanticTreeService() { semantic_tree_factory_->InvalidateWeakPtrs(); }
void SemanticTreeService::PerformAccessibilityAction(
uint32_t node_id, fuchsia::accessibility::semantics::Action action,
fuchsia::accessibility::semantics::SemanticListener::OnAccessibilityActionRequestedCallback
callback) {
semantic_listener_->OnAccessibilityActionRequested(node_id, action, std::move(callback));
}
zx_koid_t SemanticTreeService::view_ref_koid() const { return koid_; }
void SemanticTreeService::CommitUpdates(CommitUpdatesCallback callback) {
if (!semantic_updates_enabled_) {
FX_LOGS(INFO) << "Ignoring Commit while semantics are disabled.";
return;
}
if (tree_->Update(std::move(updates_))) {
callback();
updates_.clear();
} else {
// Work around https://fxbug.dev/42150037
std::string tree_str = tree_->ToString();
constexpr size_t kMaxLength = 30000;
if (tree_str.size() > kMaxLength) {
tree_str.resize(kMaxLength);
}
FX_LOGS(ERROR) << "Closing Semantic Tree Channel for View(KOID):" << koid_
<< " because client sent an invalid tree update. Tree before update: "
<< tree_str;
callback();
close_channel_callback_(ZX_ERR_INVALID_ARGS);
}
}
void SemanticTreeService::UpdateSemanticNodes(std::vector<Node> nodes) {
if (!semantic_updates_enabled_) {
FX_LOGS(INFO) << "Ignoring Update while semantics are disabled.";
return;
}
for (auto& node : nodes) {
updates_.emplace_back(std::move(node));
}
}
void SemanticTreeService::DeleteSemanticNodes(std::vector<uint32_t> node_ids) {
if (!semantic_updates_enabled_) {
FX_LOGS(INFO) << "Ignoring Delete while semantics are disabled.";
return;
}
for (const auto& node_id : node_ids) {
updates_.emplace_back(node_id);
}
}
void SemanticTreeService::PerformHitTesting(
::fuchsia::math::PointF local_point,
fuchsia::accessibility::semantics::SemanticListener::HitTestCallback callback) {
semantic_listener_->HitTest(local_point, std::move(callback));
}
void SemanticTreeService::EnableSemanticsUpdates(bool enabled) {
semantic_updates_enabled_ = enabled;
// If Semantics Manager is disabled, then clear current semantic tree.
if (!enabled) {
tree_->Clear();
}
// Notify Semantic Provider about Semantics Manager's enable state.
fuchsia::accessibility::semantics::SemanticListener::OnSemanticsModeChangedCallback callback =
[]() { FX_LOGS(INFO) << "NotifySemanticsEnabled complete."; };
semantic_listener_->OnSemanticsModeChanged(enabled, std::move(callback));
}
const fxl::WeakPtr<::a11y::SemanticTree> SemanticTreeService::Get() const {
FX_DCHECK(semantic_tree_factory_.get());
return semantic_tree_factory_->GetWeakPtr();
}
void SemanticTreeService::SendSemanticEvent(
fuchsia::accessibility::semantics::SemanticEvent semantic_event,
SendSemanticEventCallback callback) {
SemanticsEventInfo event;
event.semantic_event = std::move(semantic_event);
tree_->OnSemanticsEvent(std::move(event));
callback();
}
std::unique_ptr<SemanticTreeService> SemanticTreeServiceFactory::NewService(
zx_koid_t koid, fuchsia::accessibility::semantics::SemanticListenerPtr semantic_listener,
SemanticTreeService::CloseChannelCallback close_channel_callback,
SemanticTree::SemanticsEventCallback semantics_event_callback) {
auto inspect_name = "semantic_tree_" + std::to_string(koid);
auto tree_ptr = std::make_unique<SemanticTree>(inspect_node_.CreateChild(inspect_name));
tree_ptr->set_semantics_event_callback(std::move(semantics_event_callback));
auto semantic_tree = std::make_unique<SemanticTreeService>(
std::move(tree_ptr), koid, std::move(semantic_listener), std::move(close_channel_callback));
return semantic_tree;
}
} // namespace a11y