diff options
author | dmazzoni <dmazzoni@chromium.org> | 2014-11-04 21:16:29 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-11-05 05:17:50 +0000 |
commit | ab9f8645f966c4d01a8009ac6a67a7c7f082e273 (patch) | |
tree | bd9282e8bb000b5cf5ba0e1cd5382bc1e3d40cc3 | |
parent | fcffcb17a43f6d0ac30cc5b8260028ad6489d6e9 (diff) | |
download | chromium_src-ab9f8645f966c4d01a8009ac6a67a7c7f082e273.zip chromium_src-ab9f8645f966c4d01a8009ac6a67a7c7f082e273.tar.gz chromium_src-ab9f8645f966c4d01a8009ac6a67a7c7f082e273.tar.bz2 |
Add Android AX functions to set the value and selection of a text field.
BUG=414571
Review URL: https://codereview.chromium.org/681503002
Cr-Commit-Position: refs/heads/master@{#302756}
13 files changed, 119 insertions, 16 deletions
diff --git a/content/browser/accessibility/browser_accessibility_android.cc b/content/browser/accessibility/browser_accessibility_android.cc index abc37d8..c57c40e 100644 --- a/content/browser/accessibility/browser_accessibility_android.cc +++ b/content/browser/accessibility/browser_accessibility_android.cc @@ -143,6 +143,12 @@ bool BrowserAccessibilityAndroid::IsDismissable() const { return false; // No concept of "dismissable" on the web currently. } +bool BrowserAccessibilityAndroid::IsEditableText() const { + return (GetRole() == ui::AX_ROLE_EDITABLE_TEXT || + GetRole() == ui::AX_ROLE_TEXT_AREA || + GetRole() == ui::AX_ROLE_TEXT_FIELD); +} + bool BrowserAccessibilityAndroid::IsEnabled() const { return HasState(ui::AX_STATE_ENABLED); } diff --git a/content/browser/accessibility/browser_accessibility_android.h b/content/browser/accessibility/browser_accessibility_android.h index 17c7c46..2f6d1af 100644 --- a/content/browser/accessibility/browser_accessibility_android.h +++ b/content/browser/accessibility/browser_accessibility_android.h @@ -26,6 +26,7 @@ class BrowserAccessibilityAndroid : public BrowserAccessibility { bool IsCollectionItem() const; bool IsContentInvalid() const; bool IsDismissable() const; + bool IsEditableText() const; bool IsEnabled() const; bool IsFocusable() const; bool IsFocused() const; diff --git a/content/browser/accessibility/browser_accessibility_manager.cc b/content/browser/accessibility/browser_accessibility_manager.cc index bd745cd..cb392cb 100644 --- a/content/browser/accessibility/browser_accessibility_manager.cc +++ b/content/browser/accessibility/browser_accessibility_manager.cc @@ -284,8 +284,17 @@ void BrowserAccessibilityManager::ScrollToPoint( } } +void BrowserAccessibilityManager::SetValue( + const BrowserAccessibility& node, + const base::string16& value) { + if (delegate_) + delegate_->AccessibilitySetValue(node.GetId(), value); +} + void BrowserAccessibilityManager::SetTextSelection( - const BrowserAccessibility& node, int start_offset, int end_offset) { + const BrowserAccessibility& node, + int start_offset, + int end_offset) { if (delegate_) { delegate_->AccessibilitySetTextSelection( node.GetId(), start_offset, end_offset); diff --git a/content/browser/accessibility/browser_accessibility_manager.h b/content/browser/accessibility/browser_accessibility_manager.h index 3760141..4b637cd 100644 --- a/content/browser/accessibility/browser_accessibility_manager.h +++ b/content/browser/accessibility/browser_accessibility_manager.h @@ -61,6 +61,8 @@ class CONTENT_EXPORT BrowserAccessibilityDelegate { int acc_obj_id, const gfx::Point& point) = 0; virtual void AccessibilitySetTextSelection( int acc_obj_id, int start_offset, int end_offset) = 0; + virtual void AccessibilitySetValue( + int acc_obj_id, const base::string16& value) = 0; virtual bool AccessibilityViewHasFocus() const = 0; virtual gfx::Rect AccessibilityGetViewBounds() const = 0; virtual gfx::Point AccessibilityOriginInScreen( @@ -146,6 +148,10 @@ class CONTENT_EXPORT BrowserAccessibilityManager : public ui::AXTreeDelegate { void ScrollToPoint( const BrowserAccessibility& node, gfx::Point point); + // Tell the renderer to set the value of an editable text node. + void SetValue( + const BrowserAccessibility& node, const base::string16& value); + // Tell the renderer to set the text selection on a node. void SetTextSelection( const BrowserAccessibility& node, int start_offset, int end_offset); diff --git a/content/browser/accessibility/browser_accessibility_manager_android.cc b/content/browser/accessibility/browser_accessibility_manager_android.cc index 3a31ff7..ce27954 100644 --- a/content/browser/accessibility/browser_accessibility_manager_android.cc +++ b/content/browser/accessibility/browser_accessibility_manager_android.cc @@ -224,6 +224,7 @@ jboolean BrowserAccessibilityManagerAndroid::PopulateAccessibilityNodeInfo( node->IsCheckable(), node->IsChecked(), node->IsClickable(), + node->IsEditableText(), node->IsEnabled(), node->IsFocusable(), node->IsFocused(), @@ -406,6 +407,22 @@ void BrowserAccessibilityManagerAndroid::ScrollToMakeNodeVisible( ScrollToMakeVisible(*node, gfx::Rect(node->GetLocation().size())); } +void BrowserAccessibilityManagerAndroid::SetTextFieldValue( + JNIEnv* env, jobject obj, jint id, jstring value) { + BrowserAccessibility* node = GetFromID(id); + if (node) { + BrowserAccessibilityManager::SetValue( + *node, base::android::ConvertJavaStringToUTF16(env, value)); + } +} + +void BrowserAccessibilityManagerAndroid::SetSelection( + JNIEnv* env, jobject obj, jint id, jint start, jint end) { + BrowserAccessibility* node = GetFromID(id); + if (node) + SetTextSelection(*node, start, end); +} + 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 0946e5e..720f175 100644 --- a/content/browser/accessibility/browser_accessibility_manager_android.h +++ b/content/browser/accessibility/browser_accessibility_manager_android.h @@ -55,7 +55,9 @@ class CONTENT_EXPORT BrowserAccessibilityManagerAndroid void Click(JNIEnv* env, jobject obj, jint id); void Focus(JNIEnv* env, jobject obj, jint id); void Blur(JNIEnv* env, jobject obj); - void ScrollToMakeNodeVisible(JNIEnv* env, jobject obj, int id); + 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); // 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/browser/accessibility/browser_accessibility_manager_unittest.cc b/content/browser/accessibility/browser_accessibility_manager_unittest.cc index a104defa..b71187c 100644 --- a/content/browser/accessibility/browser_accessibility_manager_unittest.cc +++ b/content/browser/accessibility/browser_accessibility_manager_unittest.cc @@ -73,6 +73,8 @@ class TestBrowserAccessibilityDelegate void AccessibilitySetTextSelection(int acc_obj_id, int start_offset, int end_offset) override {} + void AccessibilitySetValue(int acc_obj_id, const base::string16& value) + override {} bool AccessibilityViewHasFocus() const override { return false; } gfx::Rect AccessibilityGetViewBounds() const override { return gfx::Rect(); } gfx::Point AccessibilityOriginInScreen( diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc index 0baac98..fe9b110 100644 --- a/content/browser/frame_host/render_frame_host_impl.cc +++ b/content/browser/frame_host/render_frame_host_impl.cc @@ -434,6 +434,11 @@ void RenderFrameHostImpl::AccessibilitySetTextSelection( routing_id_, object_id, start_offset, end_offset)); } +void RenderFrameHostImpl::AccessibilitySetValue( + int object_id, const base::string16& value) { + Send(new AccessibilityMsg_SetValue(routing_id_, object_id, value)); +} + bool RenderFrameHostImpl::AccessibilityViewHasFocus() const { RenderWidgetHostView* view = render_view_host_->GetView(); if (view) diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h index 0f5d57a..d406a85 100644 --- a/content/browser/frame_host/render_frame_host_impl.h +++ b/content/browser/frame_host/render_frame_host_impl.h @@ -134,6 +134,8 @@ class CONTENT_EXPORT RenderFrameHostImpl void AccessibilitySetTextSelection(int acc_obj_id, int start_offset, int end_offset) override; + void AccessibilitySetValue(int acc_obj_id, const base::string16& value) + override; bool AccessibilityViewHasFocus() const override; gfx::Rect AccessibilityGetViewBounds() const override; gfx::Point AccessibilityOriginInScreen( diff --git a/content/common/accessibility_messages.h b/content/common/accessibility_messages.h index d88d88f..55b8d2b 100644 --- a/content/common/accessibility_messages.h +++ b/content/common/accessibility_messages.h @@ -122,6 +122,12 @@ IPC_MESSAGE_ROUTED3(AccessibilityMsg_SetTextSelection, int /* New start offset */, int /* New end offset */) +// Relay a request from assistive technology to set the value of an +// editable text element. +IPC_MESSAGE_ROUTED2(AccessibilityMsg_SetValue, + int /* object id */, + base::string16 /* Value */) + // Determine the accessibility object under a given point and reply with // a AccessibilityHostMsg_HitTestResult with the same id. IPC_MESSAGE_ROUTED1(AccessibilityMsg_HitTest, 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 3d55f43..5f1ed45 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 @@ -40,6 +40,11 @@ import java.util.Locale; public class BrowserAccessibilityManager { private static final String TAG = "BrowserAccessibilityManager"; + // Constants from AccessibilityNodeInfo defined in the L SDK. + private static final int ACTION_SET_TEXT = 0x200000; + private static final String ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE = + "ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE"; + private ContentViewCore mContentViewCore; private final AccessibilityManager mAccessibilityManager; private final RenderCoordinates mRenderCoordinates; @@ -194,7 +199,6 @@ public class BrowserAccessibilityManager { case AccessibilityNodeInfo.ACTION_CLEAR_FOCUS: nativeBlur(mNativeObj); return true; - case AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT: { if (arguments == null) return false; String elementType = arguments.getString( @@ -211,7 +215,28 @@ public class BrowserAccessibilityManager { elementType = elementType.toUpperCase(Locale.US); return jumpToElementType(elementType, false); } - + case ACTION_SET_TEXT: { + if (arguments == null) return false; + String newText = arguments.getString( + ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE); + if (newText == null) return false; + nativeSetTextFieldValue(mNativeObj, virtualViewId, newText); + // Match Android framework and set the cursor to the end of the text field. + nativeSetSelection(mNativeObj, virtualViewId, newText.length(), newText.length()); + break; + } + case AccessibilityNodeInfo.ACTION_SET_SELECTION: { + int selectionStart = 0; + int selectionEnd = 0; + if (arguments != null) { + selectionStart = arguments.getInt( + AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT); + selectionEnd = arguments.getInt( + AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT); + } + nativeSetSelection(mNativeObj, virtualViewId, selectionStart, selectionEnd); + break; + } default: break; } @@ -388,8 +413,8 @@ public class BrowserAccessibilityManager { * gets initialized first. */ private boolean isFrameInfoInitialized() { - return mRenderCoordinates.getContentWidthCss() != 0.0 || - mRenderCoordinates.getContentHeightCss() != 0.0; + return mRenderCoordinates.getContentWidthCss() != 0.0 + || mRenderCoordinates.getContentHeightCss() != 0.0; } @CalledByNative @@ -480,8 +505,8 @@ public class BrowserAccessibilityManager { @CalledByNative private void setAccessibilityNodeInfoBooleanAttributes(AccessibilityNodeInfo node, int virtualViewId, boolean checkable, boolean checked, boolean clickable, - boolean enabled, boolean focusable, boolean focused, boolean password, - boolean scrollable, boolean selected, boolean visibleToUser) { + 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); @@ -496,6 +521,11 @@ public class BrowserAccessibilityManager { node.addAction(AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT); node.addAction(AccessibilityNodeInfo.ACTION_PREVIOUS_HTML_ELEMENT); + if (editableText && enabled) { + node.addAction(ACTION_SET_TEXT); + node.addAction(AccessibilityNodeInfo.ACTION_SET_SELECTION); + } + if (focusable) { if (focused) { node.addAction(AccessibilityNodeInfo.ACTION_CLEAR_FOCUS); @@ -739,4 +769,8 @@ public class BrowserAccessibilityManager { long nativeBrowserAccessibilityManagerAndroid, int id); private native int nativeFindElementType(long nativeBrowserAccessibilityManagerAndroid, int startId, String elementType, boolean forwards); + private native void nativeSetTextFieldValue(long nativeBrowserAccessibilityManagerAndroid, + int id, String newValue); + private native void nativeSetSelection(long nativeBrowserAccessibilityManagerAndroid, + int id, int start, int end); } diff --git a/content/renderer/accessibility/renderer_accessibility.cc b/content/renderer/accessibility/renderer_accessibility.cc index 18fb07f..e8da448 100644 --- a/content/renderer/accessibility/renderer_accessibility.cc +++ b/content/renderer/accessibility/renderer_accessibility.cc @@ -8,6 +8,7 @@ #include "base/bind.h" #include "base/message_loop/message_loop.h" +#include "base/strings/utf_string_conversions.h" #include "content/renderer/accessibility/blink_ax_enum_conversion.h" #include "content/renderer/render_frame_impl.h" #include "content/renderer/render_view_impl.h" @@ -71,6 +72,7 @@ bool RendererAccessibility::OnMessageReceived(const IPC::Message& message) { OnScrollToMakeVisible) IPC_MESSAGE_HANDLER(AccessibilityMsg_ScrollToPoint, OnScrollToPoint) IPC_MESSAGE_HANDLER(AccessibilityMsg_SetTextSelection, OnSetTextSelection) + IPC_MESSAGE_HANDLER(AccessibilityMsg_SetValue, OnSetValue) IPC_MESSAGE_HANDLER(AccessibilityMsg_HitTest, OnHitTest) IPC_MESSAGE_HANDLER(AccessibilityMsg_Reset, OnReset) IPC_MESSAGE_HANDLER(AccessibilityMsg_FatalError, OnFatalError) @@ -425,15 +427,25 @@ void RendererAccessibility::OnSetTextSelection( return; } - // TODO(dmazzoni): support elements other than <input>. - blink::WebNode node = obj.node(); - if (!node.isNull() && node.isElementNode()) { - blink::WebElement element = node.to<blink::WebElement>(); - blink::WebInputElement* input_element = - blink::toWebInputElement(&element); - if (input_element && input_element->isTextField()) - input_element->setSelectionRange(start_offset, end_offset); + obj.setSelectedTextRange(start_offset, end_offset); +} + +void RendererAccessibility::OnSetValue( + int acc_obj_id, + base::string16 value) { + const WebDocument& document = GetMainDocument(); + if (document.isNull()) + return; + + WebAXObject obj = document.accessibilityObjectFromID(acc_obj_id); + if (obj.isDetached()) { +#ifndef NDEBUG + LOG(WARNING) << "SetTextSelection on invalid object id " << acc_obj_id; +#endif + return; } + + obj.setValue(value); } } // namespace content diff --git a/content/renderer/accessibility/renderer_accessibility.h b/content/renderer/accessibility/renderer_accessibility.h index d757c5a..6bac56e 100644 --- a/content/renderer/accessibility/renderer_accessibility.h +++ b/content/renderer/accessibility/renderer_accessibility.h @@ -92,6 +92,7 @@ class CONTENT_EXPORT RendererAccessibility : public RenderFrameObserver { void OnScrollToPoint(int acc_obj_id, gfx::Point point); void OnSetFocus(int acc_obj_id); void OnSetTextSelection(int acc_obj_id, int start_offset, int end_offset); + void OnSetValue(int acc_obj_id, base::string16 value); // Events from Blink are collected until they are ready to be // sent to the browser. |