Commit 40d1f8a3 authored by Saho Kobayashi's avatar Saho Kobayashi Committed by Commit Bot

Send kValue changed triggered by state description.

Send kValue changed event when state description change event of range
widget is sent.
CL to set kValue when state description of range widget is sent:
CL:2224487

      AXTreeSourceArcTest.StateDescriptionChangedEvent

Bug: b:154433831
Test: ArcAccessibilityUtilTest.FromContentChangeTypesToAXEvent
Change-Id: Iea60accbc90a6aa04bdb1b9644ab623c9a8acc28
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2251518
Commit-Queue: Saho Kobayashi <sahok@chromium.org>
Reviewed-by: default avatarSara Kato <sarakato@chromium.org>
Reviewed-by: default avatarHiroki Sato <hirokisato@chromium.org>
Cr-Commit-Position: refs/heads/master@{#781239}
parent f3789aa9
......@@ -2873,6 +2873,7 @@ source_set("unit_tests") {
"apps/intent_helper/chromeos_apps_navigation_throttle_unittest.cc",
"apps/metrics/intent_handling_metrics_unittest.cc",
"arc/accessibility/arc_accessibility_helper_bridge_unittest.cc",
"arc/accessibility/arc_accessibility_util_unittest.cc",
"arc/accessibility/ax_tree_source_arc_unittest.cc",
"arc/app_shortcuts/arc_app_shortcuts_menu_builder_unittest.cc",
"arc/app_shortcuts/arc_app_shortcuts_request_unittest.cc",
......
......@@ -5,14 +5,39 @@
#include "chrome/browser/chromeos/arc/accessibility/arc_accessibility_util.h"
#include "chrome/browser/chromeos/arc/accessibility/accessibility_info_data_wrapper.h"
#include "base/optional.h"
#include "components/arc/mojom/accessibility_helper.mojom.h"
#include "ui/accessibility/ax_enums.mojom.h"
namespace arc {
ax::mojom::Event ToAXEvent(mojom::AccessibilityEventType arc_event_type,
AccessibilityInfoDataWrapper* source_node,
AccessibilityInfoDataWrapper* focused_node) {
using AXActionType = mojom::AccessibilityActionType;
using AXBooleanProperty = mojom::AccessibilityBooleanProperty;
using AXIntListProperty = mojom::AccessibilityIntListProperty;
using AXNodeInfoData = mojom::AccessibilityNodeInfoData;
using AXStringProperty = mojom::AccessibilityStringProperty;
base::Optional<ax::mojom::Event> FromContentChangeTypesToAXEvent(
const std::vector<int32_t>& arc_content_change_types,
const AccessibilityInfoDataWrapper& source_node) {
if (!base::Contains(
arc_content_change_types,
static_cast<int32_t>(mojom::ContentChangeType::STATE_DESCRIPTION))) {
return base::nullopt;
}
const AXNodeInfoData* node_ptr = source_node.GetNode();
if (node_ptr && node_ptr->range_info) {
return ax::mojom::Event::kValueChanged;
} else {
return base::nullopt;
}
}
ax::mojom::Event ToAXEvent(
mojom::AccessibilityEventType arc_event_type,
const base::Optional<std::vector<int>>& arc_content_change_types,
AccessibilityInfoDataWrapper* source_node,
AccessibilityInfoDataWrapper* focused_node) {
switch (arc_event_type) {
case mojom::AccessibilityEventType::VIEW_FOCUSED:
case mojom::AccessibilityEventType::VIEW_ACCESSIBILITY_FOCUSED:
......@@ -25,13 +50,35 @@ ax::mojom::Event ToAXEvent(mojom::AccessibilityEventType arc_event_type,
case mojom::AccessibilityEventType::VIEW_TEXT_SELECTION_CHANGED:
return ax::mojom::Event::kTextSelectionChanged;
case mojom::AccessibilityEventType::WINDOW_STATE_CHANGED: {
if (arc_content_change_types.has_value()) {
DCHECK(source_node); // Should be not null because it's dropped in
// Android side.
const base::Optional<ax::mojom::Event> event_or_null =
FromContentChangeTypesToAXEvent(arc_content_change_types.value(),
*source_node);
if (event_or_null.has_value()) {
return event_or_null.value();
}
}
if (focused_node)
return ax::mojom::Event::kFocus;
else
return ax::mojom::Event::kLayoutComplete;
}
case mojom::AccessibilityEventType::NOTIFICATION_STATE_CHANGED:
return ax::mojom::Event::kLayoutComplete;
case mojom::AccessibilityEventType::WINDOW_CONTENT_CHANGED:
if (arc_content_change_types.has_value()) {
DCHECK(source_node); // Should be not null because it's dropped in
// Android side.
const base::Optional<ax::mojom::Event> event_or_null =
FromContentChangeTypesToAXEvent(arc_content_change_types.value(),
*source_node);
if (event_or_null.has_value()) {
return event_or_null.value();
}
}
return ax::mojom::Event::kLayoutComplete;
case mojom::AccessibilityEventType::WINDOWS_CHANGED:
return ax::mojom::Event::kLayoutComplete;
case mojom::AccessibilityEventType::VIEW_HOVER_ENTER:
......
......@@ -9,16 +9,22 @@
#include <string>
#include <vector>
#include "base/containers/flat_map.h"
#include "base/optional.h"
#include "components/arc/mojom/accessibility_helper.mojom-forward.h"
#include "ui/accessibility/ax_enum_util.h"
namespace arc {
class AccessibilityInfoDataWrapper;
base::Optional<ax::mojom::Event> FromContentChangeTypesToAXEvent(
const std::vector<int>& arc_content_change_types,
const AccessibilityInfoDataWrapper& source_node);
ax::mojom::Event ToAXEvent(mojom::AccessibilityEventType arc_event_type,
AccessibilityInfoDataWrapper* source_node,
AccessibilityInfoDataWrapper* focused_node);
ax::mojom::Event ToAXEvent(
mojom::AccessibilityEventType arc_event_type,
const base::Optional<std::vector<int>>& arc_content_change_types,
AccessibilityInfoDataWrapper* source_node,
AccessibilityInfoDataWrapper* focused_node);
base::Optional<mojom::AccessibilityActionType> ConvertToAndroidAction(
ax::mojom::Action action);
......@@ -38,7 +44,7 @@ bool GetBooleanProperty(DataType* node, PropType prop) {
}
template <class PropMTypeMap, class PropType>
bool HasProperty(PropMTypeMap properties, PropType prop) {
bool HasProperty(const PropMTypeMap& properties, const PropType prop) {
if (!properties)
return false;
......@@ -46,7 +52,9 @@ bool HasProperty(PropMTypeMap properties, PropType prop) {
}
template <class PropMTypeMap, class PropType, class OutType>
bool GetProperty(PropMTypeMap properties, PropType prop, OutType* out_value) {
bool GetProperty(const PropMTypeMap& properties,
const PropType prop,
OutType* out_value) {
if (!properties)
return false;
......@@ -58,6 +66,16 @@ bool GetProperty(PropMTypeMap properties, PropType prop, OutType* out_value) {
return true;
}
template <class PropType, class OutType>
base::Optional<OutType> GetPropertyOrNull(
const base::Optional<base::flat_map<PropType, OutType>>& properties,
const PropType prop) {
OutType out_value;
if (GetProperty(properties, prop, &out_value))
return out_value;
return base::nullopt;
}
template <class InfoDataType, class PropType>
bool HasNonEmptyStringProperty(InfoDataType* node, PropType prop) {
if (!node || !node->string_properties)
......
// Copyright 2020 The Chromium 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 <memory>
#include "base/optional.h"
#include "chrome/browser/chromeos/arc/accessibility/accessibility_node_info_data_wrapper.h"
#include "chrome/browser/chromeos/arc/accessibility/arc_accessibility_util.h"
#include "components/arc/mojom/accessibility_helper.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/accessibility/ax_enums.mojom.h"
namespace arc {
using AXEventType = mojom::AccessibilityEventType;
using AXNodeInfoData = mojom::AccessibilityNodeInfoData;
using AXRangeInfoData = mojom::AccessibilityRangeInfoData;
TEST(ArcAccessibilityUtilTest, FromContentChangeTypesToAXEvent) {
auto range_widget = AXNodeInfoData::New();
range_widget->range_info = AXRangeInfoData::New();
AccessibilityNodeInfoDataWrapper source_node_range(nullptr,
range_widget.get());
auto not_range_widget = AXNodeInfoData::New();
AccessibilityNodeInfoDataWrapper source_node_not_range(
nullptr, not_range_widget.get());
std::vector<int32_t> empty_list = {};
EXPECT_EQ(base::nullopt,
FromContentChangeTypesToAXEvent(empty_list, source_node_range));
EXPECT_EQ(base::nullopt,
FromContentChangeTypesToAXEvent(empty_list, source_node_not_range));
std::vector<int32_t> state_description = {
static_cast<int32_t>(mojom::ContentChangeType::STATE_DESCRIPTION)};
// TODO(sahok): add test when source_node is not a range widget.
EXPECT_EQ(
ax::mojom::Event::kValueChanged,
FromContentChangeTypesToAXEvent(state_description, source_node_range));
EXPECT_EQ(ax::mojom::Event::kValueChanged,
ToAXEvent(AXEventType::WINDOW_STATE_CHANGED, state_description,
&source_node_range, &source_node_range));
EXPECT_EQ(ax::mojom::Event::kValueChanged,
ToAXEvent(AXEventType::WINDOW_CONTENT_CHANGED, state_description,
&source_node_range, &source_node_range));
std::vector<int32_t> without_state_description = {
static_cast<int32_t>(mojom::ContentChangeType::TEXT)};
EXPECT_EQ(base::nullopt, FromContentChangeTypesToAXEvent(
without_state_description, source_node_range));
EXPECT_EQ(base::nullopt,
FromContentChangeTypesToAXEvent(without_state_description,
source_node_not_range));
std::vector<int32_t> include_state_description = {
static_cast<int32_t>(mojom::ContentChangeType::TEXT),
static_cast<int32_t>(mojom::ContentChangeType::STATE_DESCRIPTION)};
// TODO(sahok): add test when source_node is not a range widget.
EXPECT_EQ(ax::mojom::Event::kValueChanged,
FromContentChangeTypesToAXEvent(include_state_description,
source_node_range));
EXPECT_EQ(
ax::mojom::Event::kValueChanged,
ToAXEvent(AXEventType::WINDOW_STATE_CHANGED, include_state_description,
&source_node_range, &source_node_range));
EXPECT_EQ(
ax::mojom::Event::kValueChanged,
ToAXEvent(AXEventType::WINDOW_CONTENT_CHANGED, include_state_description,
&source_node_range, &source_node_range));
std::vector<int32_t> not_enum_value = {111};
EXPECT_EQ(base::nullopt,
FromContentChangeTypesToAXEvent(not_enum_value, source_node_range));
EXPECT_EQ(base::nullopt, FromContentChangeTypesToAXEvent(
not_enum_value, source_node_not_range));
}
} // namespace arc
......@@ -23,6 +23,7 @@ namespace arc {
using AXBooleanProperty = mojom::AccessibilityBooleanProperty;
using AXEventData = mojom::AccessibilityEventData;
using AXEventIntListProperty = mojom::AccessibilityEventIntListProperty;
using AXEventIntProperty = mojom::AccessibilityEventIntProperty;
using AXEventType = mojom::AccessibilityEventType;
using AXIntProperty = mojom::AccessibilityIntProperty;
......@@ -136,8 +137,12 @@ void AXTreeSourceArc::NotifyAccessibilityEvent(AXEventData* event_data) {
: nullptr;
event_bundle.events.emplace_back();
ui::AXEvent& event = event_bundle.events.back();
event.event_type = ToAXEvent(event_data->event_type,
GetFromId(event_data->source_id), focused_node);
event.event_type = ToAXEvent(
event_data->event_type,
GetPropertyOrNull(
event_data->int_list_properties,
arc::mojom::AccessibilityEventIntListProperty::CONTENT_CHANGE_TYPES),
GetFromId(event_data->source_id), focused_node);
event.id = event_data->source_id;
if (HasProperty(event_data->int_properties,
......
......@@ -6,9 +6,11 @@
#include <utility>
#include "base/optional.h"
#include "base/stl_util.h"
#include "chrome/browser/chromeos/arc/accessibility/accessibility_node_info_data_wrapper.h"
#include "chrome/browser/chromeos/arc/accessibility/accessibility_window_info_data_wrapper.h"
#include "chrome/browser/chromeos/arc/accessibility/arc_accessibility_util.h"
#include "chrome/grit/generated_resources.h"
#include "components/arc/mojom/accessibility_helper.mojom.h"
#include "extensions/browser/api/automation_internal/automation_event_router.h"
......@@ -27,6 +29,7 @@ using AXBooleanProperty = mojom::AccessibilityBooleanProperty;
using AXCollectionInfoData = mojom::AccessibilityCollectionInfoData;
using AXCollectionItemInfoData = mojom::AccessibilityCollectionItemInfoData;
using AXEventData = mojom::AccessibilityEventData;
using AXEventIntListProperty = mojom::AccessibilityEventIntListProperty;
using AXEventIntProperty = mojom::AccessibilityEventIntProperty;
using AXEventType = mojom::AccessibilityEventType;
using AXIntListProperty = mojom::AccessibilityIntListProperty;
......@@ -113,6 +116,18 @@ void SetProperty(AXEventData* event, AXEventIntProperty prop, int32_t value) {
prop_map.insert(std::make_pair(prop, value));
}
void SetProperty(AXEventData* event,
AXEventIntListProperty prop,
const std::vector<int>& value) {
if (!event->int_list_properties) {
event->int_list_properties =
base::flat_map<AXEventIntListProperty, std::vector<int>>();
}
auto& prop_map = event->int_list_properties.value();
base::EraseIf(prop_map, [prop](auto it) { return it.first == prop; });
prop_map.insert(std::make_pair(prop, value));
}
class MockAutomationEventRouter
: public extensions::AutomationEventRouterInterface {
public:
......@@ -123,8 +138,10 @@ class MockAutomationEventRouter
void DispatchAccessibilityEvents(
const ExtensionMsg_AccessibilityEventBundleParams& events) override {
for (auto&& event : events.events)
for (auto&& event : events.events) {
event_count_[event.event_type]++;
last_event_type_ = event.event_type;
}
for (const auto& update : events.updates)
tree_.Unserialize(update);
......@@ -146,8 +163,13 @@ class MockAutomationEventRouter
const ui::AXActionData& data,
const base::Optional<gfx::Rect>& rect) override {}
ax::mojom::Event last_event_type() const { return last_event_type_; }
std::map<ax::mojom::Event, int> event_count_;
ui::AXTree tree_;
private:
ax::mojom::Event last_event_type_;
};
class AXTreeSourceArcTest : public testing::Test,
......@@ -202,6 +224,10 @@ class AXTreeSourceArcTest : public testing::Test,
return router_->event_count_[type];
}
ax::mojom::Event last_dispatched_event_type() const {
return router_->last_event_type();
}
ui::AXTree* tree() { return router_->tree(); }
void ExpectTree(const std::string& expected) {
......@@ -1712,4 +1738,35 @@ TEST_F(AXTreeSourceArcTest, StateDescriptionWithRange) {
EXPECT_EQ("state description", value);
}
TEST_F(AXTreeSourceArcTest, StateDescriptionChangedEvent) {
auto event = AXEventData::New();
event->source_id = 10;
event->task_id = 1;
event->event_type = AXEventType::WINDOW_STATE_CHANGED;
event->window_data = std::vector<mojom::AccessibilityWindowInfoDataPtr>();
event->window_data->push_back(AXWindowInfoData::New());
AXWindowInfoData* root_window = event->window_data->back().get();
root_window->window_id = 100;
root_window->root_node_id = 10;
event->node_data.push_back(AXNodeInfoData::New());
AXNodeInfoData* range_widget = event->node_data.back().get();
range_widget->range_info = AXRangeInfoData::New();
range_widget->id = 10;
std::vector<int> content_change_types = {
static_cast<int>(mojom::ContentChangeType::TEXT),
static_cast<int>(mojom::ContentChangeType::STATE_DESCRIPTION)};
SetProperty(event.get(), AXEventIntListProperty::CONTENT_CHANGE_TYPES,
content_change_types);
CallNotifyAccessibilityEvent(event.get());
EXPECT_EQ(ax::mojom::Event::kValueChanged, last_dispatched_event_type());
event->event_type = AXEventType::WINDOW_CONTENT_CHANGED;
CallNotifyAccessibilityEvent(event.get());
EXPECT_EQ(ax::mojom::Event::kValueChanged, last_dispatched_event_type());
// TODO(sahok): add test when source_node is not a range widget.
}
} // namespace arc
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment