#include "services/accessibility/android/accessibility_window_info_data_wrapper.h"
#include "base/memory/raw_ptr.h"
#include "base/notreached.h"
#include "chrome/grit/generated_resources.h"
#include "services/accessibility/android/android_accessibility_util.h"
#include "services/accessibility/android/ax_tree_source_android.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_node.h"
#include "ui/accessibility/platform/ax_android_constants.h"
#include "ui/base/l10n/l10n_util.h"
namespace ax::android {
AccessibilityWindowInfoDataWrapper::AccessibilityWindowInfoDataWrapper(
AXTreeSourceAndroid* tree_source,
mojom::AccessibilityWindowInfoData* window)
: AccessibilityInfoDataWrapper(tree_source), window_ptr_(window) {}
AccessibilityWindowInfoDataWrapper::~AccessibilityWindowInfoDataWrapper() =
default;
bool AccessibilityWindowInfoDataWrapper::IsNode() const {
return false;
}
mojom::AccessibilityNodeInfoData* AccessibilityWindowInfoDataWrapper::GetNode()
const {
return nullptr;
}
mojom::AccessibilityWindowInfoData*
AccessibilityWindowInfoDataWrapper::GetWindow() const {
return window_ptr_;
}
int32_t AccessibilityWindowInfoDataWrapper::GetId() const {
return window_ptr_->window_id;
}
const gfx::Rect AccessibilityWindowInfoDataWrapper::GetBounds() const {
return window_ptr_->bounds_in_screen;
}
bool AccessibilityWindowInfoDataWrapper::IsVisibleToUser() const {
return true;
}
bool AccessibilityWindowInfoDataWrapper::IsWebNode() const {
return false;
}
bool AccessibilityWindowInfoDataWrapper::IsIgnored() const {
return false;
}
bool AccessibilityWindowInfoDataWrapper::IsImportantInAndroid() const {
return true;
}
bool AccessibilityWindowInfoDataWrapper::IsFocusableInFullFocusMode() const {
return false;
}
bool AccessibilityWindowInfoDataWrapper::IsAccessibilityFocusableContainer()
const {
return tree_source_->GetRoot()->GetId() == GetId();
}
void AccessibilityWindowInfoDataWrapper::PopulateAXRole(
ui::AXNodeData* out_data) const {
if (tree_source_->is_notification()) {
out_data->role = ax::mojom::Role::kGenericContainer;
return;
}
switch (window_ptr_->window_type) {
case mojom::AccessibilityWindowType::TYPE_ACCESSIBILITY_OVERLAY:
out_data->role = ax::mojom::Role::kWindow;
return;
case mojom::AccessibilityWindowType::TYPE_APPLICATION:
if (tree_source_->GetRoot()->GetId() == GetId()) {
out_data->role = ax::mojom::Role::kApplication;
} else {
out_data->role = ax::mojom::Role::kGenericContainer;
}
return;
case mojom::AccessibilityWindowType::TYPE_INPUT_METHOD:
out_data->role = ax::mojom::Role::kKeyboard;
return;
case mojom::AccessibilityWindowType::TYPE_SPLIT_SCREEN_DIVIDER:
out_data->role = ax::mojom::Role::kSplitter;
return;
case mojom::AccessibilityWindowType::TYPE_SYSTEM:
out_data->role = ax::mojom::Role::kWindow;
return;
case mojom::AccessibilityWindowType::INVALID_ENUM_VALUE:
NOTREACHED();
}
}
void AccessibilityWindowInfoDataWrapper::PopulateAXState(
ui::AXNodeData* out_data) const {
}
void AccessibilityWindowInfoDataWrapper::Serialize(
ui::AXNodeData* out_data) const {
AccessibilityInfoDataWrapper* root = tree_source_->GetRoot();
if (!root) {
return;
}
AccessibilityInfoDataWrapper::Serialize(out_data);
const std::string name = ComputeAXName(true);
if (!name.empty()) {
out_data->SetName(name);
out_data->SetNameFrom(ax::mojom::NameFrom::kTitle);
}
if (GetProperty(mojom::AccessibilityWindowBooleanProperty::
IN_PICTURE_IN_PICTURE_MODE)) {
out_data->AddStringAttribute(
ax::mojom::StringAttribute::kDescription,
l10n_util::GetStringUTF8(IDS_ARC_ACCESSIBILITY_WINDOW_TITLE_IN_PIP));
}
if (root->GetId() == GetId()) {
if (!tree_source_->is_notification()) {
out_data->AddBoolAttribute(ax::mojom::BoolAttribute::kModal, true);
}
out_data->AddState(ax::mojom::State::kFocusable);
}
}
std::string AccessibilityWindowInfoDataWrapper::ComputeAXName(
bool do_recursive) const {
std::string title;
GetProperty(mojom::AccessibilityWindowStringProperty::TITLE, &title);
return title;
}
void AccessibilityWindowInfoDataWrapper::GetChildren(
std::vector<raw_ptr<AccessibilityInfoDataWrapper, VectorExperimental>>*
children) const {
if (window_ptr_->int_list_properties) {
const auto& it = window_ptr_->int_list_properties->find(
mojom::AccessibilityWindowIntListProperty::CHILD_WINDOW_IDS);
if (it != window_ptr_->int_list_properties->end()) {
for (const int32_t id : it->second) {
auto* child = tree_source_->GetFromId(id);
if (child != nullptr) {
children->push_back(child);
} else {
LOG(WARNING) << "Unexpected nullptr found while GetChildren";
}
}
}
}
if (window_ptr_->root_node_id) {
auto* child_node = tree_source_->GetFromId(window_ptr_->root_node_id);
if (child_node != nullptr) {
children->push_back(child_node);
} else {
LOG(WARNING) << "Unexpected nullptr found while populating root node for "
"GetChildren";
}
}
for (int32_t vitual_child_id : virtual_child_ids_) {
auto* child_node = tree_source_->GetFromId(vitual_child_id);
if (child_node != nullptr) {
children->push_back(child_node);
} else {
LOG(WARNING)
<< "Unexpected nullptr found while populating virtual child node for "
"GetChildren";
}
}
}
int32_t AccessibilityWindowInfoDataWrapper::GetWindowId() const {
return window_ptr_->window_id;
}
void AccessibilityWindowInfoDataWrapper::AddVirtualChild(int32_t child_id) {
if (std::ranges::find(virtual_child_ids_, child_id) !=
virtual_child_ids_.end()) {
LOG(ERROR) << "Given child id already exists as a virtual child.";
} else {
virtual_child_ids_.push_back(child_id);
}
}
bool AccessibilityWindowInfoDataWrapper::GetProperty(
mojom::AccessibilityWindowBooleanProperty prop) const {
return GetBooleanProperty(window_ptr_.get(), prop);
}
bool AccessibilityWindowInfoDataWrapper::GetProperty(
mojom::AccessibilityWindowIntProperty prop,
int32_t* out_value) const {
return ax::android::GetProperty(window_ptr_->int_properties, prop, out_value);
}
bool AccessibilityWindowInfoDataWrapper::HasProperty(
mojom::AccessibilityWindowStringProperty prop) const {
return ax::android::HasProperty(window_ptr_->string_properties, prop);
}
bool AccessibilityWindowInfoDataWrapper::GetProperty(
mojom::AccessibilityWindowStringProperty prop,
std::string* out_value) const {
return ax::android::GetProperty(window_ptr_->string_properties, prop,
out_value);
}
bool AccessibilityWindowInfoDataWrapper::GetProperty(
mojom::AccessibilityWindowIntListProperty prop,
std::vector<int32_t>* out_value) const {
return ax::android::GetProperty(window_ptr_->int_list_properties, prop,
out_value);
}
}