Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(340)

Side by Side Diff: content/browser/accessibility/browser_accessibility_android.cc

Issue 739063002: Fix accessibility of remaining html form controls on Android (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@no_tablet_popup
Patch Set: Better Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/accessibility/browser_accessibility_android.h" 5 #include "content/browser/accessibility/browser_accessibility_android.h"
6 6
7 #include "base/i18n/break_iterator.h" 7 #include "base/i18n/break_iterator.h"
8 #include "base/strings/string_util.h" 8 #include "base/strings/string_util.h"
9 #include "base/strings/stringprintf.h"
9 #include "base/strings/utf_string_conversions.h" 10 #include "base/strings/utf_string_conversions.h"
10 #include "content/browser/accessibility/browser_accessibility_manager_android.h" 11 #include "content/browser/accessibility/browser_accessibility_manager_android.h"
11 #include "content/common/accessibility_messages.h" 12 #include "content/common/accessibility_messages.h"
12 13
13 namespace { 14 namespace {
14 15
15 // These are enums from android.text.InputType in Java: 16 // These are enums from android.text.InputType in Java:
16 enum { 17 enum {
17 ANDROID_TEXT_INPUTTYPE_TYPE_NULL = 0, 18 ANDROID_TEXT_INPUTTYPE_TYPE_NULL = 0,
18 ANDROID_TEXT_INPUTTYPE_TYPE_DATETIME = 0x4, 19 ANDROID_TEXT_INPUTTYPE_TYPE_DATETIME = 0x4,
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
69 if (IsIframe() || 70 if (IsIframe() ||
70 GetRole() == ui::AX_ROLE_ROOT_WEB_AREA || 71 GetRole() == ui::AX_ROLE_ROOT_WEB_AREA ||
71 GetRole() == ui::AX_ROLE_WEB_AREA) { 72 GetRole() == ui::AX_ROLE_WEB_AREA) {
72 return false; 73 return false;
73 } 74 }
74 75
75 // If it has a focusable child, we definitely can't leave out children. 76 // If it has a focusable child, we definitely can't leave out children.
76 if (HasFocusableChild()) 77 if (HasFocusableChild())
77 return false; 78 return false;
78 79
80 // Date and time controls should drop their children.
81 if (GetRole() == ui::AX_ROLE_DATE || GetRole() == ui::AX_ROLE_TIME)
82 return true;
83
79 // Headings with text can drop their children. 84 // Headings with text can drop their children.
80 base::string16 name = GetText(); 85 base::string16 name = GetText();
81 if (GetRole() == ui::AX_ROLE_HEADING && !name.empty()) 86 if (GetRole() == ui::AX_ROLE_HEADING && !name.empty())
82 return true; 87 return true;
83 88
84 // Focusable nodes with text can drop their children. 89 // Focusable nodes with text can drop their children.
85 if (HasState(ui::AX_STATE_FOCUSABLE) && !name.empty()) 90 if (HasState(ui::AX_STATE_FOCUSABLE) && !name.empty())
86 return true; 91 return true;
87 92
88 // Nodes with only static text as children can drop their children. 93 // Nodes with only static text as children can drop their children.
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after
244 switch(GetRole()) { 249 switch(GetRole()) {
245 case ui::AX_ROLE_EDITABLE_TEXT: 250 case ui::AX_ROLE_EDITABLE_TEXT:
246 case ui::AX_ROLE_SPIN_BUTTON: 251 case ui::AX_ROLE_SPIN_BUTTON:
247 case ui::AX_ROLE_TEXT_AREA: 252 case ui::AX_ROLE_TEXT_AREA:
248 case ui::AX_ROLE_TEXT_FIELD: 253 case ui::AX_ROLE_TEXT_FIELD:
249 class_name = "android.widget.EditText"; 254 class_name = "android.widget.EditText";
250 break; 255 break;
251 case ui::AX_ROLE_SLIDER: 256 case ui::AX_ROLE_SLIDER:
252 class_name = "android.widget.SeekBar"; 257 class_name = "android.widget.SeekBar";
253 break; 258 break;
259 case ui::AX_ROLE_COLOR_WELL:
254 case ui::AX_ROLE_COMBO_BOX: 260 case ui::AX_ROLE_COMBO_BOX:
261 case ui::AX_ROLE_DATE:
262 case ui::AX_ROLE_POP_UP_BUTTON:
263 case ui::AX_ROLE_TIME:
255 class_name = "android.widget.Spinner"; 264 class_name = "android.widget.Spinner";
256 break; 265 break;
257 case ui::AX_ROLE_BUTTON: 266 case ui::AX_ROLE_BUTTON:
258 case ui::AX_ROLE_MENU_BUTTON: 267 case ui::AX_ROLE_MENU_BUTTON:
259 case ui::AX_ROLE_POP_UP_BUTTON:
260 class_name = "android.widget.Button"; 268 class_name = "android.widget.Button";
261 break; 269 break;
262 case ui::AX_ROLE_CHECK_BOX: 270 case ui::AX_ROLE_CHECK_BOX:
263 class_name = "android.widget.CheckBox"; 271 class_name = "android.widget.CheckBox";
264 break; 272 break;
265 case ui::AX_ROLE_RADIO_BUTTON: 273 case ui::AX_ROLE_RADIO_BUTTON:
266 class_name = "android.widget.RadioButton"; 274 class_name = "android.widget.RadioButton";
267 break; 275 break;
268 case ui::AX_ROLE_TOGGLE_BUTTON: 276 case ui::AX_ROLE_TOGGLE_BUTTON:
269 class_name = "android.widget.ToggleButton"; 277 class_name = "android.widget.ToggleButton";
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
312 if (IsIframe() || 320 if (IsIframe() ||
313 GetRole() == ui::AX_ROLE_WEB_AREA) { 321 GetRole() == ui::AX_ROLE_WEB_AREA) {
314 return base::string16(); 322 return base::string16();
315 } 323 }
316 324
317 // See comment in browser_accessibility_win.cc for details. 325 // See comment in browser_accessibility_win.cc for details.
318 // The difference here is that we can only expose one accessible 326 // The difference here is that we can only expose one accessible
319 // name on Android, not 2 or 3 like on Windows or Mac. 327 // name on Android, not 2 or 3 like on Windows or Mac.
320 328
321 // First, always return the |value| attribute if this is an 329 // First, always return the |value| attribute if this is an
322 // editable text field. 330 // input field.
323 if (!value().empty() && 331 if (!value().empty()) {
324 (GetRole() == ui::AX_ROLE_EDITABLE_TEXT || 332 if (HasState(ui::AX_STATE_EDITABLE))
325 GetRole() == ui::AX_ROLE_TEXT_AREA || 333 return base::UTF8ToUTF16(value());
326 GetRole() == ui::AX_ROLE_TEXT_FIELD || 334
327 HasState(ui::AX_STATE_EDITABLE))) { 335 switch (GetRole()) {
328 return base::UTF8ToUTF16(value()); 336 case ui::AX_ROLE_COMBO_BOX:
337 case ui::AX_ROLE_EDITABLE_TEXT:
338 case ui::AX_ROLE_POP_UP_BUTTON:
339 case ui::AX_ROLE_TEXT_AREA:
340 case ui::AX_ROLE_TEXT_FIELD:
341 return base::UTF8ToUTF16(value());
342 }
343 }
344
345 // For color wells, the color is stored in separate attributes.
346 // Perhaps we could return color names in the future?
347 if (GetRole() == ui::AX_ROLE_COLOR_WELL) {
348 int red = GetIntAttribute(ui::AX_ATTR_COLOR_VALUE_RED);
349 int green = GetIntAttribute(ui::AX_ATTR_COLOR_VALUE_GREEN);
350 int blue = GetIntAttribute(ui::AX_ATTR_COLOR_VALUE_BLUE);
351 return base::UTF8ToUTF16(
352 base::StringPrintf("#%02X%02X%02X", red, green, blue));
329 } 353 }
330 354
331 // Always prefer visible text if this is a link. Sites sometimes add 355 // Always prefer visible text if this is a link. Sites sometimes add
332 // a "title" attribute to a link with more information, but we can't 356 // a "title" attribute to a link with more information, but we can't
333 // lose the link text. 357 // lose the link text.
334 if (!name().empty() && GetRole() == ui::AX_ROLE_LINK) 358 if (!name().empty() && GetRole() == ui::AX_ROLE_LINK)
335 return base::UTF8ToUTF16(name()); 359 return base::UTF8ToUTF16(name());
336 360
337 // If there's no text value, the basic rule is: prefer description 361 // If there's no text value, the basic rule is: prefer description
338 // (aria-labelledby or aria-label), then help (title), then name 362 // (aria-labelledby or aria-label), then help (title), then name
339 // (inner text), then value (control value). However, if 363 // (inner text), then value (control value). However, if
340 // title_elem_id is set, that means there's a label element 364 // title_elem_id is set, that means there's a label element
341 // supplying the name and then name takes precedence over help. 365 // supplying the name and then name takes precedence over help.
342 // TODO(dmazzoni): clean this up by providing more granular labels in 366 // TODO(dmazzoni): clean this up by providing more granular labels in
343 // Blink, making the platform-specific mapping to accessible text simpler. 367 // Blink, making the platform-specific mapping to accessible text simpler.
344 base::string16 description = GetString16Attribute(ui::AX_ATTR_DESCRIPTION); 368 base::string16 description = GetString16Attribute(ui::AX_ATTR_DESCRIPTION);
345 base::string16 help = GetString16Attribute(ui::AX_ATTR_HELP); 369 base::string16 help = GetString16Attribute(ui::AX_ATTR_HELP);
370
346 base::string16 placeholder; 371 base::string16 placeholder;
347 GetHtmlAttribute("placeholder", &placeholder); 372 switch (GetRole()) {
373 case ui::AX_ROLE_DATE:
374 case ui::AX_ROLE_EDITABLE_TEXT:
375 case ui::AX_ROLE_TEXT_AREA:
376 case ui::AX_ROLE_TEXT_FIELD:
377 case ui::AX_ROLE_TIME:
378 GetHtmlAttribute("placeholder", &placeholder);
379 }
380
348 int title_elem_id = GetIntAttribute( 381 int title_elem_id = GetIntAttribute(
349 ui::AX_ATTR_TITLE_UI_ELEMENT); 382 ui::AX_ATTR_TITLE_UI_ELEMENT);
350 base::string16 text; 383 base::string16 text;
351 if (!description.empty()) 384 if (!description.empty())
352 text = description; 385 text = description;
353 else if (title_elem_id && !name().empty()) 386 else if (title_elem_id && !name().empty())
354 text = base::UTF8ToUTF16(name()); 387 text = base::UTF8ToUTF16(name());
355 else if (!help.empty()) 388 else if (!help.empty())
356 text = help; 389 text = help;
357 else if (!name().empty()) 390 else if (!name().empty())
358 text = base::UTF8ToUTF16(name()); 391 text = base::UTF8ToUTF16(name());
359 else if (GetRole() == ui::AX_ROLE_TEXT_FIELD && !placeholder.empty()) 392 else if (!placeholder.empty())
360 text = placeholder; 393 text = placeholder;
361 else if (!value().empty()) 394 else if (!value().empty())
362 text = base::UTF8ToUTF16(value()); 395 text = base::UTF8ToUTF16(value());
363 396
364 // This is called from PlatformIsLeaf, so don't call PlatformChildCount 397 // This is called from PlatformIsLeaf, so don't call PlatformChildCount
365 // from within this! 398 // from within this!
366 if (text.empty() && 399 if (text.empty() &&
367 (HasOnlyStaticTextChildren() || 400 (HasOnlyStaticTextChildren() ||
368 (IsFocusable() && HasOnlyTextAndImageChildren()))) { 401 (IsFocusable() && HasOnlyTextAndImageChildren()))) {
369 for (uint32 i = 0; i < InternalChildCount(); i++) { 402 for (uint32 i = 0; i < InternalChildCount(); i++) {
(...skipping 459 matching lines...) Expand 10 before | Expand all | Expand 10 after
829 int BrowserAccessibilityAndroid::CountChildrenWithRole(ui::AXRole role) const { 862 int BrowserAccessibilityAndroid::CountChildrenWithRole(ui::AXRole role) const {
830 int count = 0; 863 int count = 0;
831 for (uint32 i = 0; i < PlatformChildCount(); i++) { 864 for (uint32 i = 0; i < PlatformChildCount(); i++) {
832 if (PlatformGetChild(i)->GetRole() == role) 865 if (PlatformGetChild(i)->GetRole() == role)
833 count++; 866 count++;
834 } 867 }
835 return count; 868 return count;
836 } 869 }
837 870
838 } // namespace content 871 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698