1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "content/browser/accessibility/accessibility_tree_formatter.h"
6
7#include <string>
8
9#include "base/android/jni_android.h"
10#include "base/android/jni_string.h"
11#include "base/files/file_path.h"
12#include "base/json/json_writer.h"
13#include "base/strings/string_util.h"
14#include "base/strings/stringprintf.h"
15#include "base/strings/utf_string_conversions.h"
16#include "content/browser/accessibility/browser_accessibility_android.h"
17
18using base::StringPrintf;
19
20namespace content {
21
22namespace {
23const char* BOOL_ATTRIBUTES[] = {
24  "checkable",
25  "checked",
26  "clickable",
27  "collection",
28  "collection_item",
29  "content_invalid",
30  "disabled",
31  "dismissable",
32  "editable_text",
33  "focusable",
34  "focused",
35  "heading",
36  "hierarchical",
37  "invisible",
38  "multiline",
39  "password",
40  "range",
41  "scrollable",
42  "selected"
43};
44
45const char* STRING_ATTRIBUTES[] = {
46  "name"
47};
48
49const char* INT_ATTRIBUTES[] = {
50  "item_index",
51  "item_count",
52  "row_count",
53  "column_count",
54  "row_index",
55  "row_span",
56  "column_index",
57  "column_span",
58  "input_type",
59  "live_region_type",
60  "range_min",
61  "range_max",
62  "range_current_value",
63};
64}
65
66void AccessibilityTreeFormatter::Initialize() {
67}
68
69void AccessibilityTreeFormatter::AddProperties(
70    const BrowserAccessibility& node, base::DictionaryValue* dict) {
71  const BrowserAccessibilityAndroid* android_node =
72      static_cast<const BrowserAccessibilityAndroid*>(&node);
73
74  // Class name.
75  dict->SetString("class", android_node->GetClassName());
76
77  // Bool attributes.
78  dict->SetBoolean("checkable", android_node->IsCheckable());
79  dict->SetBoolean("checked", android_node->IsChecked());
80  dict->SetBoolean("clickable", android_node->IsClickable());
81  dict->SetBoolean("collection", android_node->IsCollection());
82  dict->SetBoolean("collection_item", android_node->IsCollectionItem());
83  dict->SetBoolean("disabled", !android_node->IsEnabled());
84  dict->SetBoolean("dismissable", android_node->IsDismissable());
85  dict->SetBoolean("editable_text", android_node->IsEditableText());
86  dict->SetBoolean("focusable", android_node->IsFocusable());
87  dict->SetBoolean("focused", android_node->IsFocused());
88  dict->SetBoolean("heading", android_node->IsHeading());
89  dict->SetBoolean("hierarchical", android_node->IsHierarchical());
90  dict->SetBoolean("invisible", !android_node->IsVisibleToUser());
91  dict->SetBoolean("multiline", android_node->IsMultiLine());
92  dict->SetBoolean("range", android_node->IsRangeType());
93  dict->SetBoolean("password", android_node->IsPassword());
94  dict->SetBoolean("scrollable", android_node->IsScrollable());
95  dict->SetBoolean("selected", android_node->IsSelected());
96
97  // String attributes.
98  dict->SetString("name", android_node->GetText());
99
100  // Int attributes.
101  dict->SetInteger("item_index", android_node->GetItemIndex());
102  dict->SetInteger("item_count", android_node->GetItemCount());
103  dict->SetInteger("row_count", android_node->RowCount());
104  dict->SetInteger("column_count", android_node->ColumnCount());
105  dict->SetInteger("row_index", android_node->RowIndex());
106  dict->SetInteger("row_span", android_node->RowSpan());
107  dict->SetInteger("column_index", android_node->ColumnIndex());
108  dict->SetInteger("column_span", android_node->ColumnSpan());
109  dict->SetInteger("input_type", android_node->AndroidInputType());
110  dict->SetInteger("live_region_type", android_node->AndroidLiveRegionType());
111  dict->SetInteger("range_min", static_cast<int>(android_node->RangeMin()));
112  dict->SetInteger("range_max", static_cast<int>(android_node->RangeMax()));
113  dict->SetInteger("range_current_value",
114                   static_cast<int>(android_node->RangeCurrentValue()));
115}
116
117base::string16 AccessibilityTreeFormatter::ToString(
118    const base::DictionaryValue& dict,
119    const base::string16& indent) {
120  base::string16 line;
121
122  base::string16 class_value;
123  dict.GetString("class", &class_value);
124  WriteAttribute(true, base::UTF16ToUTF8(class_value), &line);
125
126  for (unsigned i = 0; i < arraysize(BOOL_ATTRIBUTES); i++) {
127    const char* attribute_name = BOOL_ATTRIBUTES[i];
128    bool value;
129    if (dict.GetBoolean(attribute_name, &value) && value)
130      WriteAttribute(true, attribute_name, &line);
131  }
132
133  for (unsigned i = 0; i < arraysize(STRING_ATTRIBUTES); i++) {
134    const char* attribute_name = STRING_ATTRIBUTES[i];
135    std::string value;
136    if (!dict.GetString(attribute_name, &value) || value.empty())
137      continue;
138    WriteAttribute(true,
139                   StringPrintf("%s='%s'", attribute_name, value.c_str()),
140                   &line);
141  }
142
143  for (unsigned i = 0; i < arraysize(INT_ATTRIBUTES); i++) {
144    const char* attribute_name = INT_ATTRIBUTES[i];
145    int value;
146    if (!dict.GetInteger(attribute_name, &value) || value == 0)
147      continue;
148    WriteAttribute(true,
149                   StringPrintf("%s=%d", attribute_name, value),
150                   &line);
151  }
152
153  return indent + line + base::ASCIIToUTF16("\n");
154}
155
156// static
157const base::FilePath::StringType
158AccessibilityTreeFormatter::GetActualFileSuffix() {
159  return FILE_PATH_LITERAL("-actual-android.txt");
160}
161
162// static
163const base::FilePath::StringType
164AccessibilityTreeFormatter::GetExpectedFileSuffix() {
165  return FILE_PATH_LITERAL("-expected-android.txt");
166}
167
168// static
169const std::string AccessibilityTreeFormatter::GetAllowEmptyString() {
170  return "@ANDROID-ALLOW-EMPTY:";
171}
172
173// static
174const std::string AccessibilityTreeFormatter::GetAllowString() {
175  return "@ANDROID-ALLOW:";
176}
177
178// static
179const std::string AccessibilityTreeFormatter::GetDenyString() {
180  return "@ANDROID-DENY:";
181}
182
183}  // namespace content
184