diff options
author | dmazzoni <dmazzoni@chromium.org> | 2014-11-19 11:19:22 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-11-19 19:19:48 +0000 |
commit | e22626b3944038b075b37f135c32bdbabe16fd28 (patch) | |
tree | c10bcdc2f24237a581e1487f072400b793fe5d16 | |
parent | 91d93479d107ce77f761f78a085135b19d3e3294 (diff) | |
download | chromium_src-e22626b3944038b075b37f135c32bdbabe16fd28.zip chromium_src-e22626b3944038b075b37f135c32bdbabe16fd28.tar.gz chromium_src-e22626b3944038b075b37f135c32bdbabe16fd28.tar.bz2 |
Support accessibility actions to increment / decrement sliders.
BUG=378799
Review URL: https://codereview.chromium.org/734933002
Cr-Commit-Position: refs/heads/master@{#304858}
10 files changed, 110 insertions, 25 deletions
diff --git a/content/browser/accessibility/browser_accessibility_android.cc b/content/browser/accessibility/browser_accessibility_android.cc index 4ab0e6e..b80334f 100644 --- a/content/browser/accessibility/browser_accessibility_android.cc +++ b/content/browser/accessibility/browser_accessibility_android.cc @@ -92,6 +92,24 @@ bool BrowserAccessibilityAndroid::PlatformIsLeaf() const { return BrowserAccessibility::PlatformIsLeaf(); } +bool BrowserAccessibilityAndroid::CanScrollForward() const { + if (!IsSlider()) + return false; + + float value = GetFloatAttribute(ui::AX_ATTR_VALUE_FOR_RANGE); + float max = GetFloatAttribute(ui::AX_ATTR_MAX_VALUE_FOR_RANGE); + return value < max; +} + +bool BrowserAccessibilityAndroid::CanScrollBackward() const { + if (!IsSlider()) + return false; + + float value = GetFloatAttribute(ui::AX_ATTR_VALUE_FOR_RANGE); + float min = GetFloatAttribute(ui::AX_ATTR_MIN_VALUE_FOR_RANGE); + return value > min; +} + bool BrowserAccessibilityAndroid::IsCheckable() const { bool checkable = false; bool is_aria_pressed_defined; @@ -208,6 +226,10 @@ bool BrowserAccessibilityAndroid::IsSelected() const { return HasState(ui::AX_STATE_SELECTED); } +bool BrowserAccessibilityAndroid::IsSlider() const { + return GetRole() == ui::AX_ROLE_SLIDER; +} + bool BrowserAccessibilityAndroid::IsVisibleToUser() const { return !HasState(ui::AX_STATE_INVISIBLE); } @@ -383,11 +405,13 @@ int BrowserAccessibilityAndroid::GetItemIndex() const { break; case ui::AX_ROLE_SLIDER: case ui::AX_ROLE_PROGRESS_INDICATOR: { - float value_for_range; - if (GetFloatAttribute( - ui::AX_ATTR_VALUE_FOR_RANGE, &value_for_range)) { - index = static_cast<int>(value_for_range); - } + // Return a percentage here for live feedback in an AccessibilityEvent. + // The exact value is returned in RangeCurrentValue. + float min = GetFloatAttribute(ui::AX_ATTR_MIN_VALUE_FOR_RANGE); + float max = GetFloatAttribute(ui::AX_ATTR_MAX_VALUE_FOR_RANGE); + float value = GetFloatAttribute(ui::AX_ATTR_VALUE_FOR_RANGE); + if (max > min && value >= min && value <= max) + index = static_cast<int>(((value - min)) * 100 / (max - min)); break; } } @@ -403,14 +427,12 @@ int BrowserAccessibilityAndroid::GetItemCount() const { count = PlatformChildCount(); break; case ui::AX_ROLE_SLIDER: - case ui::AX_ROLE_PROGRESS_INDICATOR: { - float max_value_for_range; - if (GetFloatAttribute(ui::AX_ATTR_MAX_VALUE_FOR_RANGE, - &max_value_for_range)) { - count = static_cast<int>(max_value_for_range); - } + case ui::AX_ROLE_PROGRESS_INDICATOR: + // An AccessibilityEvent can only return integer information about a + // seek control, so we return a percentage. The real range is returned + // in RangeMin and RangeMax. + count = 100; break; - } } return count; } diff --git a/content/browser/accessibility/browser_accessibility_android.h b/content/browser/accessibility/browser_accessibility_android.h index 8dc2126..70579ab 100644 --- a/content/browser/accessibility/browser_accessibility_android.h +++ b/content/browser/accessibility/browser_accessibility_android.h @@ -19,6 +19,8 @@ class CONTENT_EXPORT BrowserAccessibilityAndroid : public BrowserAccessibility { virtual bool PlatformIsLeaf() const override; + bool CanScrollForward() const; + bool CanScrollBackward() const; bool IsCheckable() const; bool IsChecked() const; bool IsClickable() const; @@ -38,6 +40,7 @@ class CONTENT_EXPORT BrowserAccessibilityAndroid : public BrowserAccessibility { bool IsRangeType() const; bool IsScrollable() const; bool IsSelected() const; + bool IsSlider() const; bool IsVisibleToUser() const; bool CanOpenPopup() const; diff --git a/content/browser/accessibility/browser_accessibility_manager_android.cc b/content/browser/accessibility/browser_accessibility_manager_android.cc index 7dbc149..8bc13c8 100644 --- a/content/browser/accessibility/browser_accessibility_manager_android.cc +++ b/content/browser/accessibility/browser_accessibility_manager_android.cc @@ -116,6 +116,9 @@ void BrowserAccessibilityManagerAndroid::NotifyAccessibilityEvent( if (obj.is_null()) return; + BrowserAccessibilityAndroid* android_node = + static_cast<BrowserAccessibilityAndroid*>(node); + if (event_type == ui::AX_EVENT_HIDE) return; @@ -157,8 +160,6 @@ void BrowserAccessibilityManagerAndroid::NotifyAccessibilityEvent( case ui::AX_EVENT_SHOW: { // This event is fired when an object appears in a live region. // Speak its text. - BrowserAccessibilityAndroid* android_node = - static_cast<BrowserAccessibilityAndroid*>(node); Java_BrowserAccessibilityManager_announceLiveRegionText( env, obj.obj(), base::android::ConvertUTF16ToJavaString( @@ -175,6 +176,9 @@ void BrowserAccessibilityManagerAndroid::NotifyAccessibilityEvent( if (node->IsEditableText()) { Java_BrowserAccessibilityManager_handleEditableTextChanged( env, obj.obj(), node->GetId()); + } else if (android_node->IsSlider()) { + Java_BrowserAccessibilityManager_handleSliderChanged( + env, obj.obj(), node->GetId()); } break; default: @@ -247,6 +251,8 @@ jboolean BrowserAccessibilityManagerAndroid::PopulateAccessibilityNodeInfo( Java_BrowserAccessibilityManager_setAccessibilityNodeInfoBooleanAttributes( env, obj, info, id, + node->CanScrollForward(), + node->CanScrollBackward(), node->IsCheckable(), node->IsChecked(), node->IsClickable(), @@ -465,6 +471,38 @@ void BrowserAccessibilityManagerAndroid::SetSelection( SetTextSelection(*node, start, end); } +jboolean BrowserAccessibilityManagerAndroid::AdjustSlider( + JNIEnv* env, jobject obj, jint id, jboolean increment) { + BrowserAccessibility* node = GetFromID(id); + if (!node) + return false; + + BrowserAccessibilityAndroid* android_node = + static_cast<BrowserAccessibilityAndroid*>(node); + + if (!android_node->IsSlider() || !android_node->IsEnabled()) + return false; + + float value = node->GetFloatAttribute(ui::AX_ATTR_VALUE_FOR_RANGE); + float min = node->GetFloatAttribute(ui::AX_ATTR_MIN_VALUE_FOR_RANGE); + float max = node->GetFloatAttribute(ui::AX_ATTR_MAX_VALUE_FOR_RANGE); + if (max <= min) + return false; + + // To behave similarly to an Android SeekBar, move by an increment of + // approximately 20%. + float original_value = value; + float delta = (max - min) / 5.0f; + value += (increment ? delta : -delta); + value = std::max(std::min(value, max), min); + if (value != original_value) { + BrowserAccessibilityManager::SetValue( + *node, base::UTF8ToUTF16(base::DoubleToString(value))); + return true; + } + return false; +} + void BrowserAccessibilityManagerAndroid::HandleHoverEvent( BrowserAccessibility* node) { JNIEnv* env = AttachCurrentThread(); diff --git a/content/browser/accessibility/browser_accessibility_manager_android.h b/content/browser/accessibility/browser_accessibility_manager_android.h index 63d3268..eb860d4 100644 --- a/content/browser/accessibility/browser_accessibility_manager_android.h +++ b/content/browser/accessibility/browser_accessibility_manager_android.h @@ -79,6 +79,7 @@ class CONTENT_EXPORT BrowserAccessibilityManagerAndroid void ScrollToMakeNodeVisible(JNIEnv* env, jobject obj, jint id); void SetTextFieldValue(JNIEnv* env, jobject obj, jint id, jstring value); void SetSelection(JNIEnv* env, jobject obj, jint id, jint start, jint end); + jboolean AdjustSlider(JNIEnv* env, jobject obj, jint id, jboolean increment); // Return the id of the next node in tree order in the direction given by // |forwards|, starting with |start_id|, that matches |element_type|, diff --git a/content/public/android/java/src/org/chromium/content/browser/accessibility/BrowserAccessibilityManager.java b/content/public/android/java/src/org/chromium/content/browser/accessibility/BrowserAccessibilityManager.java index 0888376..593c2e5 100644 --- a/content/public/android/java/src/org/chromium/content/browser/accessibility/BrowserAccessibilityManager.java +++ b/content/public/android/java/src/org/chromium/content/browser/accessibility/BrowserAccessibilityManager.java @@ -291,6 +291,10 @@ public class BrowserAccessibilityManager { } return previousAtGranularity(granularity, extend); } + case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: + return nativeAdjustSlider(mNativeObj, virtualViewId, true); + case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: + return nativeAdjustSlider(mNativeObj, virtualViewId, false); default: break; } @@ -593,6 +597,11 @@ public class BrowserAccessibilityManager { } @CalledByNative + private void handleSliderChanged(int id) { + sendAccessibilityEvent(id, AccessibilityEvent.TYPE_VIEW_SCROLLED); + } + + @CalledByNative private void handleContentChanged(int id) { int rootId = nativeGetRootId(mNativeObj); if (rootId != mCurrentRootId) { @@ -649,9 +658,10 @@ public class BrowserAccessibilityManager { @CalledByNative private void setAccessibilityNodeInfoBooleanAttributes(AccessibilityNodeInfo node, - int virtualViewId, boolean checkable, boolean checked, boolean clickable, - boolean editableText, boolean enabled, boolean focusable, boolean focused, - boolean password, boolean scrollable, boolean selected, boolean visibleToUser) { + int virtualViewId, boolean canScrollForward, boolean canScrollBackward, + boolean checkable, boolean checked, boolean clickable, boolean editableText, + boolean enabled, boolean focusable, boolean focused, boolean password, + boolean scrollable, boolean selected, boolean visibleToUser) { node.setCheckable(checkable); node.setChecked(checked); node.setClickable(clickable); @@ -677,6 +687,14 @@ public class BrowserAccessibilityManager { node.addAction(AccessibilityNodeInfo.ACTION_SET_SELECTION); } + if (canScrollForward) { + node.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD); + } + + if (canScrollBackward) { + node.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD); + } + if (focusable) { if (focused) { node.addAction(AccessibilityNodeInfo.ACTION_CLEAR_FOCUS); @@ -942,4 +960,6 @@ public class BrowserAccessibilityManager { private native boolean nativePreviousAtGranularity( long nativeBrowserAccessibilityManagerAndroid, int selectionGranularity, boolean extendSelection, int id, int cursorIndex); + private native boolean nativeAdjustSlider( + long nativeBrowserAccessibilityManagerAndroid, int id, boolean increment); } diff --git a/content/renderer/accessibility/renderer_accessibility.cc b/content/renderer/accessibility/renderer_accessibility.cc index 44bc64d..17bc571 100644 --- a/content/renderer/accessibility/renderer_accessibility.cc +++ b/content/renderer/accessibility/renderer_accessibility.cc @@ -464,6 +464,7 @@ void RendererAccessibility::OnSetValue( } obj.setValue(value); + HandleAXEvent(obj, ui::AX_EVENT_VALUE_CHANGED); } } // namespace content diff --git a/content/test/data/accessibility/aria-valuemax-expected-android.txt b/content/test/data/accessibility/aria-valuemax-expected-android.txt index 0c5f2444..20bfb69 100644 --- a/content/test/data/accessibility/aria-valuemax-expected-android.txt +++ b/content/test/data/accessibility/aria-valuemax-expected-android.txt @@ -1,5 +1,5 @@ android.webkit.WebView focusable focused scrollable - android.widget.ProgressBar range item_index=51 item_count=101 range_min=1 range_max=101 range_current_value=51 + android.widget.ProgressBar range item_index=50 item_count=100 range_min=1 range_max=101 range_current_value=51 android.view.View range range_min=2 range_max=102 range_current_value=52 - android.widget.SeekBar range item_index=53 item_count=103 range_min=3 range_max=103 range_current_value=53 - android.widget.EditText range_min=4 range_max=104 range_current_value=54 + android.widget.SeekBar range item_index=50 item_count=100 range_min=3 range_max=103 range_current_value=53 + android.widget.EditText range_min=4 range_max=104 range_current_value=54
\ No newline at end of file diff --git a/content/test/data/accessibility/aria-valuemin-expected-android.txt b/content/test/data/accessibility/aria-valuemin-expected-android.txt index 0c5f2444..20bfb69 100644 --- a/content/test/data/accessibility/aria-valuemin-expected-android.txt +++ b/content/test/data/accessibility/aria-valuemin-expected-android.txt @@ -1,5 +1,5 @@ android.webkit.WebView focusable focused scrollable - android.widget.ProgressBar range item_index=51 item_count=101 range_min=1 range_max=101 range_current_value=51 + android.widget.ProgressBar range item_index=50 item_count=100 range_min=1 range_max=101 range_current_value=51 android.view.View range range_min=2 range_max=102 range_current_value=52 - android.widget.SeekBar range item_index=53 item_count=103 range_min=3 range_max=103 range_current_value=53 - android.widget.EditText range_min=4 range_max=104 range_current_value=54 + android.widget.SeekBar range item_index=50 item_count=100 range_min=3 range_max=103 range_current_value=53 + android.widget.EditText range_min=4 range_max=104 range_current_value=54
\ No newline at end of file diff --git a/content/test/data/accessibility/aria-valuenow-expected-android.txt b/content/test/data/accessibility/aria-valuenow-expected-android.txt index 9d59be2..9bc7f1d 100644 --- a/content/test/data/accessibility/aria-valuenow-expected-android.txt +++ b/content/test/data/accessibility/aria-valuenow-expected-android.txt @@ -1,2 +1,2 @@ android.webkit.WebView focusable focused scrollable - android.widget.ProgressBar range item_index=3 range_current_value=3 + android.widget.ProgressBar range item_count=100 range_current_value=3
\ No newline at end of file diff --git a/content/test/data/accessibility/input-range-expected-android.txt b/content/test/data/accessibility/input-range-expected-android.txt index 8e8d7f4..db1b0c6 100644 --- a/content/test/data/accessibility/input-range-expected-android.txt +++ b/content/test/data/accessibility/input-range-expected-android.txt @@ -1,3 +1,3 @@ android.webkit.WebView focusable focused scrollable android.view.View - android.widget.SeekBar focusable range item_index=5 item_count=10 range_min=1 range_max=10 range_current_value=5 + android.widget.SeekBar focusable range item_index=44 item_count=100 range_min=1 range_max=10 range_current_value=5
\ No newline at end of file |