blob: ce2bcc694c90bc05e4888ad0adebb26b640cdea7 [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/change_range_value_action.h"
#include <lib/syslog/cpp/macros.h>
#include "fuchsia/accessibility/semantics/cpp/fidl.h"
#include "src/ui/a11y/lib/screen_reader/default_action.h"
#include "src/ui/a11y/lib/screen_reader/util/util.h"
namespace a11y {
namespace {
using fuchsia::accessibility::semantics::Action;
} // namespace
ChangeRangeValueAction::ChangeRangeValueAction(ActionContext* action_context,
ScreenReaderContext* screen_reader_context,
ChangeRangeValueActionType action)
: ScreenReaderAction(action_context, screen_reader_context), range_value_action_(action) {}
ChangeRangeValueAction::~ChangeRangeValueAction() = default;
void ChangeRangeValueAction::Run(a11y::gesture_util_v2::GestureContext gesture_context) {
auto a11y_focus = screen_reader_context_->GetA11yFocusManager()->GetA11yFocus();
if (!a11y_focus) {
FX_LOGS(INFO) << "Change Range Value Action: No view is in focus.";
return;
}
FX_DCHECK(action_context_->semantics_source);
// Get the node in focus.
const zx_koid_t focused_koid = a11y_focus->view_ref_koid;
const uint32_t focused_node_id = a11y_focus->node_id;
const fuchsia::accessibility::semantics::Node* focused_node;
focused_node = action_context_->semantics_source->GetSemanticNode(focused_koid, focused_node_id);
if (!focused_node || !focused_node->has_node_id()) {
return;
}
Action semantic_action;
switch (range_value_action_) {
case ChangeRangeValueActionType::kDecrementAction:
semantic_action = Action::DECREMENT;
break;
case ChangeRangeValueActionType::kIncrementAction:
semantic_action = Action::INCREMENT;
break;
default:
break;
}
auto old_value = GetSliderValue(*focused_node);
auto promise =
ExecuteAccessibilityActionPromise(a11y_focus->view_ref_koid, a11y_focus->node_id,
semantic_action)
.and_then([this, focused_koid, focused_node_id, old_value]() {
// Ask the screen reader to read the next value of the slider.
screen_reader_context_->set_on_node_update_callback([this, focused_koid,
focused_node_id, old_value]() {
// Get current focus.
auto a11y_focus = screen_reader_context_->GetA11yFocusManager()->GetA11yFocus();
if (!a11y_focus) {
return;
}
// If the focused node has changed, then we shouldn't
// try to read the new slider value.
if (a11y_focus->view_ref_koid != focused_koid ||
a11y_focus->node_id != focused_node_id) {
return;
}
auto new_focused_node = action_context_->semantics_source->GetSemanticNode(
a11y_focus->view_ref_koid, a11y_focus->node_id);
// If the focused node no longer exists, then we
// shouldn't try to read the new slider value.
if (!new_focused_node) {
return;
}
// If the slider value hasn't changed, or is no longer
// valid, then we shouldn't try to read it.
auto new_value = GetSliderValue(*new_focused_node);
if (new_value == old_value || new_value.empty()) {
return;
}
// Read the new slider value.
auto* speaker = screen_reader_context_->speaker();
FX_DCHECK(speaker);
fuchsia::accessibility::tts::Utterance utterance;
utterance.set_message(new_value);
auto promise = speaker->SpeakMessagePromise(std::move(utterance), {.interrupt = true})
.wrap_with(scope_);
auto* executor = screen_reader_context_->executor();
executor->schedule_task(std::move(promise));
});
return fpromise::make_ok_promise();
})
// Cancel any promises if this class goes out of scope.
.wrap_with(scope_);
auto* executor = screen_reader_context_->executor();
executor->schedule_task(std::move(promise));
}
} // namespace a11y