Backed out changeset ae9049c5ac63 (bug 1473998) for gv-junit failures on test.AccessibilityTest.testTextEntryNode. a=backout

This commit is contained in:
Cosmin Sabou 2018-07-11 02:06:05 +03:00
parent 26e792fe42
commit 1519cc7aac
7 changed files with 78 additions and 121 deletions

View File

@ -9,7 +9,6 @@ const AndroidEvents = {
WINDOW_STATE_CHANGED: 0x20,
VIEW_HOVER_ENTER: 0x80,
VIEW_HOVER_EXIT: 0x100,
WINDOW_CONTENT_CHANGED: 0x800,
VIEW_SCROLLED: 0x1000,
VIEW_TEXT_SELECTION_CHANGED: 0x2000,
ANNOUNCEMENT: 0x4000,

View File

@ -13,17 +13,11 @@ ChromeUtils.defineModuleGetter(this, "UtteranceGenerator", // jshint ignore:line
"resource://gre/modules/accessibility/OutputGenerator.jsm");
ChromeUtils.defineModuleGetter(this, "States", // jshint ignore:line
"resource://gre/modules/accessibility/Constants.jsm");
ChromeUtils.defineModuleGetter(this, "Roles", // jshint ignore:line
"resource://gre/modules/accessibility/Constants.jsm");
ChromeUtils.defineModuleGetter(this, "AndroidEvents", // jshint ignore:line
"resource://gre/modules/accessibility/Constants.jsm");
var EXPORTED_SYMBOLS = ["Presentation"]; // jshint ignore:line
const EDIT_TEXT_ROLES = new Set([
Roles.SPINBUTTON, Roles.PASSWORD_TEXT,
Roles.AUTOCOMPLETE, Roles.ENTRY, Roles.EDITCOMBOBOX]);
class AndroidPresentor {
constructor() {
this.type = "Android";
@ -47,7 +41,11 @@ class AndroidPresentor {
let androidEvents = [];
const isExploreByTouch = aReason == Ci.nsIAccessiblePivot.REASON_POINT;
let isExploreByTouch = (aReason == Ci.nsIAccessiblePivot.REASON_POINT &&
Utils.AndroidSdkVersion >= 14);
let focusEventType = (Utils.AndroidSdkVersion >= 16) ?
AndroidEvents.VIEW_ACCESSIBILITY_FOCUSED :
AndroidEvents.VIEW_FOCUSED;
if (isExploreByTouch) {
// This isn't really used by TalkBack so this is a half-hearted attempt
@ -56,19 +54,20 @@ class AndroidPresentor {
}
if (aReason === Ci.nsIAccessiblePivot.REASON_TEXT) {
const adjustedText = context.textAndAdjustedOffsets;
if (Utils.AndroidSdkVersion >= 16) {
let adjustedText = context.textAndAdjustedOffsets;
androidEvents.push({
eventType: AndroidEvents.VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
text: [adjustedText.text],
fromIndex: adjustedText.startOffset,
toIndex: adjustedText.endOffset
});
androidEvents.push({
eventType: AndroidEvents.VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
text: [adjustedText.text],
fromIndex: adjustedText.startOffset,
toIndex: adjustedText.endOffset
});
}
} else {
let info = this._infoFromContext(context);
let eventType = isExploreByTouch ?
AndroidEvents.VIEW_HOVER_ENTER :
AndroidEvents.VIEW_ACCESSIBILITY_FOCUSED;
AndroidEvents.VIEW_HOVER_ENTER : focusEventType;
androidEvents.push({...info, eventType});
}
@ -144,7 +143,17 @@ class AndroidPresentor {
textSelectionChanged(aText, aStart, aEnd, aOldStart, aOldEnd, aIsFromUserInput) {
let androidEvents = [];
if (aIsFromUserInput) {
if (Utils.AndroidSdkVersion >= 14 && !aIsFromUserInput) {
androidEvents.push({
eventType: AndroidEvents.VIEW_TEXT_SELECTION_CHANGED,
text: [aText],
fromIndex: aStart,
toIndex: aEnd,
itemCount: aText.length
});
}
if (Utils.AndroidSdkVersion >= 16 && aIsFromUserInput) {
let [from, to] = aOldStart < aStart ?
[aOldStart, aStart] : [aStart, aOldStart];
androidEvents.push({
@ -153,14 +162,6 @@ class AndroidPresentor {
fromIndex: from,
toIndex: to
});
} else {
androidEvents.push({
eventType: AndroidEvents.VIEW_TEXT_SELECTION_CHANGED,
text: [aText],
fromIndex: aStart,
toIndex: aEnd,
itemCount: aText.length
});
}
return androidEvents;
@ -224,19 +225,24 @@ class AndroidPresentor {
viewportChanged(aWindow) {
let currentContext = this.displayedAccessibles.get(aWindow);
if (Utils.AndroidSdkVersion < 14) {
return null;
}
let events = [{
eventType: AndroidEvents.VIEW_SCROLLED,
text: [],
scrollX: aWindow.scrollX,
scrollY: aWindow.scrollY,
maxScrollX: aWindow.scrollMaxX,
maxScrollY: aWindow.scrollMaxY,
maxScrollY: aWindow.scrollMaxY
}];
if (currentContext) {
if (Utils.AndroidSdkVersion >= 16 && currentContext) {
let currentAcc = currentContext.accessibleForBounds;
if (Utils.isAliveAndVisible(currentAcc)) {
events.push({
eventType: AndroidEvents.WINDOW_CONTENT_CHANGED,
eventType: AndroidEvents.VIEW_ACCESSIBILITY_FOCUSED,
bounds: Utils.getBounds(currentAcc)
});
}
@ -251,7 +257,9 @@ class AndroidPresentor {
announce(aAnnouncement) {
let localizedAnnouncement = Utils.localize(aAnnouncement).join(" ");
return [{
eventType: AndroidEvents.ANNOUNCEMENT,
eventType: (Utils.AndroidSdkVersion >= 16) ?
AndroidEvents.ANNOUNCEMENT :
AndroidEvents.VIEW_TEXT_CHANGED,
text: [localizedAnnouncement],
addedCount: localizedAnnouncement.length,
removedCount: 0,
@ -287,8 +295,9 @@ class AndroidPresentor {
}
_infoFromContext(aContext) {
const state = Utils.getState(aContext.accessible);
const info = {
let state = Utils.getState(aContext.accessible);
return {
text: Utils.localize(UtteranceGenerator.genForContext(aContext)),
bounds: aContext.bounds,
focusable: state.contains(States.FOCUSABLE),
focused: state.contains(States.FOCUSED),
@ -297,22 +306,6 @@ class AndroidPresentor {
checked: state.contains(States.CHECKED),
editable: state.contains(States.EDITABLE),
};
if (EDIT_TEXT_ROLES.has(aContext.accessible.role)) {
let textAcc = aContext.accessible.QueryInterface(Ci.nsIAccessibleText);
return {
...info,
className: "android.widget.EditText",
hint: aContext.accessible.name,
text: [textAcc.getText(0, -1)]
};
}
return {
...info,
className: "android.view.View",
text: Utils.localize(UtteranceGenerator.genForContext(aContext)),
};
}
}

View File

@ -41,8 +41,9 @@
AndroidEvents.VIEW_TEXT_SELECTION_CHANGED);
is(evt[0].editable, true, "focused item is editable");
runner.eventTextMatches(evt[1],
["Please refrain from Mayoneggs during this salmonella scare."]);
is(evt[1].className, "android.widget.EditText", "editable class");
["Text content test document",
"Please refrain from Mayoneggs during this salmonella scare.",
"text area"]);
is(evt[1].focused, true, "a11y focused item is focused");
is(evt[2].fromIndex, 0, "Correct fromIndex");
is(evt[2].toIndex, 0, "Correct toIndex");

View File

@ -41,7 +41,7 @@
AndroidEvents.VIEW_ACCESSIBILITY_FOCUSED,
AndroidEvents.VIEW_TEXT_SELECTION_CHANGED);
is(evt[0].editable, true, "focused item is editable");
is(evt[1].className, "android.widget.EditText", "editable class");
runner.eventTextMatches(evt[1], ["Text content test document", "entry"]);
is(evt[1].focused, true, "a11y focused item is focused");
is(evt[2].fromIndex, 0, "Caret at start (fromIndex)");
is(evt[2].toIndex, 0, "Caret at start (toIndex)");

View File

@ -32,9 +32,10 @@
AndroidEvents.VIEW_ACCESSIBILITY_FOCUSED);
is(evt[0].editable, true, "focused item is editable");
is(evt[1].focused, true, "a11y focused item is focused");
is(evt[1].className, "android.widget.EditText", "editable class");
runner.eventTextMatches(evt[1],
["Please refrain from Mayoneggs during this salmonella scare."]);
["Text content test document",
"Please refrain from Mayoneggs during this salmonella scare.",
"text area"]);
evt = await runner.moveNext("Simple",
AndroidEvents.VIEW_FOCUSED,
@ -45,7 +46,7 @@
evt = await runner.moveNext("Simple",
AndroidEvents.VIEW_ACCESSIBILITY_FOCUSED);
is(evt.className, "android.widget.EditText", "editable class");
runner.eventTextMatches(evt, ["entry"]);
runner.isFocused("html");
evt = await runner.activateCurrent(0,
@ -65,7 +66,7 @@
evt = await runner.moveNext("Simple",
AndroidEvents.VIEW_ACCESSIBILITY_FOCUSED);
is(evt.className, "android.widget.EditText", "editable class");
runner.eventTextMatches(evt, ["entry"]);
runner.isFocused("html");
// XXX: TEXT_SELECTION_CHANGED should be fired here

View File

@ -33,12 +33,12 @@ import org.junit.runner.RunWith
@WithDevToolsAPI
class AccessibilityTest : BaseSessionTest() {
lateinit var view: View
val provider: AccessibilityNodeProvider get() = view.accessibilityNodeProvider
val provider: AccessibilityNodeProvider get() = view.getAccessibilityNodeProvider()
// Given a child ID, return the virtual descendent ID.
private fun getVirtualDescendantId(childId: Long): Int {
try {
val getVirtualDescendantIdMethod =
var getVirtualDescendantIdMethod =
AccessibilityNodeInfo::class.java.getMethod("getVirtualDescendantId", Long::class.java)
return getVirtualDescendantIdMethod.invoke(null, childId) as Int
} catch (ex: Exception) {
@ -49,7 +49,7 @@ class AccessibilityTest : BaseSessionTest() {
// Retrieve the virtual descendent ID of the event's source.
private fun getSourceId(event: AccessibilityEvent): Int {
try {
val getSourceIdMethod =
var getSourceIdMethod =
AccessibilityRecord::class.java.getMethod("getSourceNodeId")
return getVirtualDescendantId(getSourceIdMethod.invoke(event) as Long)
} catch (ex: Exception) {
@ -60,13 +60,11 @@ class AccessibilityTest : BaseSessionTest() {
private interface EventDelegate {
fun onAccessibilityFocused(event: AccessibilityEvent) { }
fun onFocused(event: AccessibilityEvent) { }
fun onTextSelectionChanged(event: AccessibilityEvent) { }
fun onTextChanged(event: AccessibilityEvent) { }
}
@Before fun setup() {
// We initialize a view with a parent and grandparent so that the
// accessibility events propagate up at least to the parent.
// accessibility events propogate up at least to the parent.
view = FrameLayout(InstrumentationRegistry.getTargetContext())
FrameLayout(InstrumentationRegistry.getTargetContext()).addView(view)
FrameLayout(InstrumentationRegistry.getTargetContext()).addView(view.parent as View)
@ -81,11 +79,9 @@ class AccessibilityTest : BaseSessionTest() {
EventDelegate::class,
{ newDelegate -> (view.parent as View).setAccessibilityDelegate(object : View.AccessibilityDelegate() {
override fun onRequestSendAccessibilityEvent(host: ViewGroup, child: View, event: AccessibilityEvent): Boolean {
when (event.eventType) {
when (event.getEventType()) {
AccessibilityEvent.TYPE_VIEW_FOCUSED -> newDelegate.onFocused(event)
AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED -> newDelegate.onAccessibilityFocused(event)
AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED -> newDelegate.onTextSelectionChanged(event)
AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED -> newDelegate.onTextChanged(event)
else -> {}
}
return false
@ -101,9 +97,9 @@ class AccessibilityTest : BaseSessionTest() {
@Test fun testRootNode() {
assertThat("provider is not null", provider, notNullValue())
val node = provider.createAccessibilityNodeInfo(AccessibilityNodeProvider.HOST_VIEW_ID)
var node = provider.createAccessibilityNodeInfo(AccessibilityNodeProvider.HOST_VIEW_ID)
assertThat("Root node should have WebView class name",
node.className.toString(), equalTo("android.webkit.WebView"))
node.getClassName().toString(), equalTo("android.webkit.WebView"))
}
@Test fun testPageLoad() {
@ -127,8 +123,8 @@ class AccessibilityTest : BaseSessionTest() {
@AssertCalled(count = 1)
override fun onAccessibilityFocused(event: AccessibilityEvent) {
nodeId = getSourceId(event)
val node = provider.createAccessibilityNodeInfo(nodeId)
assertThat("Text node should not be focusable", node.isFocusable, equalTo(false))
var node = provider.createAccessibilityNodeInfo(nodeId)
assertThat("Text node should not be focusable", node.isFocusable(), equalTo(false))
}
})
@ -139,29 +135,9 @@ class AccessibilityTest : BaseSessionTest() {
@AssertCalled(count = 1)
override fun onAccessibilityFocused(event: AccessibilityEvent) {
nodeId = getSourceId(event)
val node = provider.createAccessibilityNodeInfo(nodeId)
assertThat("Entry node should be focusable", node.isFocusable, equalTo(true))
var node = provider.createAccessibilityNodeInfo(nodeId)
assertThat("Entry node should be focusable", node.isFocusable(), equalTo(true))
}
})
}
@Test fun testTextEntryNode() {
sessionRule.session.loadString("<input aria-label='Name' value='Tobias'>", "text/html")
sessionRule.waitForPageStop()
mainSession.evaluateJS("$('input').focus()")
sessionRule.waitUntilCalled(object : EventDelegate {
@AssertCalled(count = 1)
override fun onAccessibilityFocused(event: AccessibilityEvent) {
val nodeId = getSourceId(event)
val node = provider.createAccessibilityNodeInfo(nodeId)
assertThat("Focused EditBox", node.className.toString(),
equalTo("android.widget.EditText"))
assertThat("Hint has field name",
node.extras.getString("AccessibilityNodeInfo.hint"),
equalTo("Name"))
}
})
}
}
}

View File

@ -11,7 +11,9 @@ import org.mozilla.gecko.PrefsHelper;
import org.mozilla.gecko.util.BundleEventListener;
import org.mozilla.gecko.util.EventCallback;
import org.mozilla.gecko.util.GeckoBundle;
import org.mozilla.gecko.util.ThreadUtils;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.Rect;
@ -131,6 +133,7 @@ public class SessionAccessibility {
info.setSource(mView, virtualDescendantId);
info.setVisibleToUser(mView.isShown());
info.setPackageName(GeckoAppShell.getApplicationContext().getPackageName());
info.setClassName(mView.getClass().getName());
info.setEnabled(true);
info.addAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY);
info.addAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY);
@ -321,6 +324,7 @@ public class SessionAccessibility {
private AccessibilityEvent obtainEvent(final int eventType, final int sourceId) {
AccessibilityEvent event = AccessibilityEvent.obtain(eventType);
event.setPackageName(GeckoAppShell.getApplicationContext().getPackageName());
event.setClassName(SessionAccessibility.class.getName());
event.setSource(mView, sourceId);
return event;
@ -333,8 +337,6 @@ public class SessionAccessibility {
event.getText().add(textArray[i] != null ? textArray[i] : "");
}
if (message.containsKey("className"))
event.setClassName(message.getString("className"));
event.setContentDescription(message.getString("description", ""));
event.setEnabled(message.getBoolean("enabled", true));
event.setChecked(message.getBoolean("checked"));
@ -361,11 +363,9 @@ public class SessionAccessibility {
node.setFocusable(message.getBoolean("focusable"));
node.setFocused(message.getBoolean("focused"));
if (Build.VERSION.SDK_INT >= 18) {
node.setEditable(message.getBoolean("editable"));
node.setEditable(message.getBoolean("editable"));
}
node.setClassName(message.getString("className", "android.view.View"));
final String[] textArray = message.getStringArray("text");
StringBuilder sb = new StringBuilder();
if (textArray != null && textArray.length > 0) {
@ -382,29 +382,21 @@ public class SessionAccessibility {
node.addAction(AccessibilityNodeInfo.ACTION_CLICK);
}
if (message.containsKey("hint")) {
Bundle bundle = node.getExtras();
bundle.putCharSequence("AccessibilityNodeInfo.hint", message.getString("hint"));
}
}
private void updateBounds(final AccessibilityNodeInfo node, final GeckoBundle message) {
final GeckoBundle bounds = message.getBundle("bounds");
if (bounds == null) {
return;
if (bounds != null) {
Rect screenBounds = new Rect(bounds.getInt("left"), bounds.getInt("top"),
bounds.getInt("right"), bounds.getInt("bottom"));
node.setBoundsInScreen(screenBounds);
final Matrix matrix = new Matrix();
final float[] origin = new float[2];
mSession.getClientToScreenMatrix(matrix);
matrix.mapPoints(origin);
screenBounds.offset((int) -origin[0], (int) -origin[1]);
node.setBoundsInParent(screenBounds);
}
Rect screenBounds = new Rect(bounds.getInt("left"), bounds.getInt("top"),
bounds.getInt("right"), bounds.getInt("bottom"));
node.setBoundsInScreen(screenBounds);
final Matrix matrix = new Matrix();
final float[] origin = new float[2];
mSession.getClientToScreenMatrix(matrix);
matrix.mapPoints(origin);
screenBounds.offset((int) -origin[0], (int) -origin[1]);
node.setBoundsInParent(screenBounds);
}
private void sendAccessibilityEvent(final GeckoBundle message) {
@ -445,11 +437,6 @@ public class SessionAccessibility {
populateNodeInfoFromJSON(mVirtualContentNode, message);
}
if (mVirtualContentNode != null) {
// Bounds for the virtual content can be updated from any event.
updateBounds(mVirtualContentNode, message);
}
final AccessibilityEvent accessibilityEvent = obtainEvent(eventType, eventSource);
populateEventFromJSON(accessibilityEvent, message);
((ViewParent) mView).requestSendAccessibilityEvent(mView, accessibilityEvent);