blob: 8446724386f88027d46b08ef9df9e7b0aff3a683 [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 <zircon/types.h>
#include <algorithm>
#include "fuchsia/accessibility/semantics/cpp/fidl.h"
#include "src/lib/fsl/handles/object_info.h"
#include "src/lib/fxl/logging.h"
#include "src/lib/fxl/strings/concatenate.h"
#include "src/lib/syslog/cpp/logger.h"
#include "zircon/third_party/uapp/dash/src/output.h"
namespace a11y {
namespace {
using fuchsia::accessibility::semantics::Node;
// Max file size of semantic tree log file is 1MB.
constexpr size_t kMaxDebugFileSize = 1024 * 1024;
const std::string kNewLine = "\n";
constexpr std::string::size_type kIndentSize = 4;
} // namespace
SemanticTreeService::SemanticTreeService(
std::unique_ptr<::a11y::SemanticTree> tree, zx_koid_t(koid),
fuchsia::accessibility::semantics::SemanticListenerPtr semantic_listener,
vfs::PseudoDir* debug_dir, CloseChannelCallback error_callback)
: tree_(std::move(tree)),
close_channel_callback_(std::move(error_callback)),
koid_(koid),
semantic_listener_(std::move(semantic_listener)),
debug_dir_(debug_dir),
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));
});
debug_file_name_ = std::to_string(koid_);
InitializeDebugEntry();
}
SemanticTreeService::~SemanticTreeService() {
RemoveDebugEntry();
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 (tree_->Update(std::move(updates_))) {
callback();
updates_.clear();
} else {
FX_LOGS(ERROR) << "Closing Semantic Tree Channel for View(KOID):" << koid_
<< " because client sent an invalid tree update. Tree before update: "
<< tree_->ToString();
callback();
close_channel_callback_();
}
}
void SemanticTreeService::UpdateSemanticNodes(std::vector<Node> nodes) {
for (auto& node : nodes) {
updates_.emplace_back(std::move(node));
}
}
void SemanticTreeService::DeleteSemanticNodes(std::vector<uint32_t> node_ids) {
for (const auto& node_id : node_ids) {
updates_.emplace_back(node_id);
}
}
void SemanticTreeService::InitializeDebugEntry() {
if (debug_dir_) {
// Add Semantic Tree log file in Hub-Debug directory.
debug_dir_->AddEntry(
debug_file_name_,
std::make_unique<vfs::PseudoFile>(
kMaxDebugFileSize, [this](std::vector<uint8_t>* output, size_t max_file_size) {
std::string buffer = tree_->ToString();
FX_VLOGS(1) << "Semantic Tree:" << std::endl << buffer;
size_t len = buffer.length();
if (len > max_file_size) {
FX_LOGS(WARNING) << "Semantic Tree log file (" << std::to_string(koid_)
<< ") size is:" << len
<< " which is more than max size:" << kMaxDebugFileSize;
len = kMaxDebugFileSize;
}
output->resize(len);
std::copy(buffer.begin(), buffer.begin() + len, output->begin());
return ZX_OK;
}));
}
}
void SemanticTreeService::RemoveDebugEntry() {
FX_DCHECK(debug_dir_);
if (debug_dir_) {
// Remove Semantic Tree log file in the Hub-Debug directory.
debug_dir_->RemoveEntry(debug_file_name_);
}
} // namespace a11y
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();
}
} // namespace a11y