blob: a1fe9fc21d060c22ccfb2f0eb126651c9f2eb329 [file] [log] [blame]
// Copyright 2013 The Flutter 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 "flutter/shell/platform/windows/accessibility_plugin.h"
#include <variant>
#include "flutter/fml/logging.h"
#include "flutter/fml/platform/win/wstring_conversion.h"
#include "flutter/shell/platform/common/client_wrapper/include/flutter/standard_message_codec.h"
#include "flutter/shell/platform/windows/flutter_windows_engine.h"
#include "flutter/shell/platform/windows/flutter_windows_view.h"
namespace flutter {
namespace {
static constexpr char kAccessibilityChannelName[] = "flutter/accessibility";
static constexpr char kTypeKey[] = "type";
static constexpr char kDataKey[] = "data";
static constexpr char kMessageKey[] = "message";
static constexpr char kAnnounceValue[] = "announce";
// Handles messages like:
// {"type": "announce", "data": {"message": "Hello"}}
void HandleMessage(AccessibilityPlugin* plugin, const EncodableValue& message) {
const auto* map = std::get_if<EncodableMap>(&message);
if (!map) {
FML_LOG(ERROR) << "Accessibility message must be a map.";
return;
}
const auto& type_itr = map->find(EncodableValue{kTypeKey});
const auto& data_itr = map->find(EncodableValue{kDataKey});
if (type_itr == map->end()) {
FML_LOG(ERROR) << "Accessibility message must have a 'type' property.";
return;
}
if (data_itr == map->end()) {
FML_LOG(ERROR) << "Accessibility message must have a 'data' property.";
return;
}
const auto* type = std::get_if<std::string>(&type_itr->second);
const auto* data = std::get_if<EncodableMap>(&data_itr->second);
if (!type) {
FML_LOG(ERROR) << "Accessibility message 'type' property must be a string.";
return;
}
if (!data) {
FML_LOG(ERROR) << "Accessibility message 'data' property must be a map.";
return;
}
if (type->compare(kAnnounceValue) == 0) {
const auto& message_itr = data->find(EncodableValue{kMessageKey});
if (message_itr == data->end()) {
return;
}
const auto* message = std::get_if<std::string>(&message_itr->second);
if (!message) {
return;
}
plugin->Announce(*message);
} else {
FML_LOG(WARNING) << "Accessibility message type '" << *type
<< "' is not supported.";
}
}
} // namespace
AccessibilityPlugin::AccessibilityPlugin(FlutterWindowsEngine* engine)
: engine_(engine) {}
void AccessibilityPlugin::SetUp(BinaryMessenger* binary_messenger,
AccessibilityPlugin* plugin) {
BasicMessageChannel<> channel{binary_messenger, kAccessibilityChannelName,
&StandardMessageCodec::GetInstance()};
channel.SetMessageHandler(
[plugin](const EncodableValue& message,
const MessageReply<EncodableValue>& reply) {
HandleMessage(plugin, message);
// The accessibility channel does not support error handling.
// Always return an empty response even on failure.
reply(EncodableValue{std::monostate{}});
});
}
void AccessibilityPlugin::Announce(const std::string_view message) {
if (!engine_->semantics_enabled()) {
return;
}
// TODO(loicsharma): Remove implicit view assumption.
// https://github.com/flutter/flutter/issues/142845
auto view = engine_->view(kImplicitViewId);
if (!view) {
return;
}
std::wstring wide_text = fml::Utf8ToWideString(message);
view->AnnounceAlert(wide_text);
}
} // namespace flutter