mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-02 10:00:54 +00:00
Bug 1616466 - Support expand/collapse android accessibility actions. r=Jamie,geckoview-reviewers,snorp
Differential Revision: https://phabricator.services.mozilla.com/D63290 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
1d8103c74a
commit
8e38a4587c
@ -192,7 +192,19 @@ nsresult AccessibleWrap::HandleAccEvent(AccEvent* aEvent) {
|
||||
AccStateChangeEvent* event = downcast_accEvent(aEvent);
|
||||
auto state = event->GetState();
|
||||
if (state & states::CHECKED) {
|
||||
sessionAcc->SendClickedEvent(accessible, event->IsStateEnabled());
|
||||
sessionAcc->SendClickedEvent(
|
||||
accessible, java::SessionAccessibility::FLAG_CHECKABLE |
|
||||
(event->IsStateEnabled()
|
||||
? java::SessionAccessibility::FLAG_CHECKED
|
||||
: 0));
|
||||
}
|
||||
|
||||
if (state & states::EXPANDED) {
|
||||
sessionAcc->SendClickedEvent(
|
||||
accessible, java::SessionAccessibility::FLAG_EXPANDABLE |
|
||||
(event->IsStateEnabled()
|
||||
? java::SessionAccessibility::FLAG_EXPANDED
|
||||
: 0));
|
||||
}
|
||||
|
||||
if (state & states::SELECTED) {
|
||||
@ -500,6 +512,14 @@ uint32_t AccessibleWrap::GetFlags(role aRole, uint64_t aState,
|
||||
flags |= java::SessionAccessibility::FLAG_SELECTED;
|
||||
}
|
||||
|
||||
if (aState & states::EXPANDABLE) {
|
||||
flags |= java::SessionAccessibility::FLAG_EXPANDABLE;
|
||||
}
|
||||
|
||||
if (aState & states::EXPANDED) {
|
||||
flags |= java::SessionAccessibility::FLAG_EXPANDED;
|
||||
}
|
||||
|
||||
if ((aState & (states::INVISIBLE | states::OFFSCREEN)) == 0) {
|
||||
flags |= java::SessionAccessibility::FLAG_VISIBLE_TO_USER;
|
||||
}
|
||||
|
@ -71,7 +71,17 @@ void a11y::ProxyStateChangeEvent(ProxyAccessible* aTarget, uint64_t aState,
|
||||
}
|
||||
|
||||
if (aState & states::CHECKED) {
|
||||
sessionAcc->SendClickedEvent(WrapperFor(aTarget), aEnabled);
|
||||
sessionAcc->SendClickedEvent(
|
||||
WrapperFor(aTarget),
|
||||
java::SessionAccessibility::FLAG_CHECKABLE |
|
||||
(aEnabled ? java::SessionAccessibility::FLAG_CHECKED : 0));
|
||||
}
|
||||
|
||||
if (aState & states::EXPANDED) {
|
||||
sessionAcc->SendClickedEvent(
|
||||
WrapperFor(aTarget),
|
||||
java::SessionAccessibility::FLAG_EXPANDABLE |
|
||||
(aEnabled ? java::SessionAccessibility::FLAG_EXPANDED : 0));
|
||||
}
|
||||
|
||||
if (aState & states::SELECTED) {
|
||||
|
@ -330,11 +330,9 @@ void SessionAccessibility::SendTextTraversedEvent(AccessibleWrap* aAccessible,
|
||||
}
|
||||
|
||||
void SessionAccessibility::SendClickedEvent(AccessibleWrap* aAccessible,
|
||||
bool aChecked) {
|
||||
uint32_t aFlags) {
|
||||
GECKOBUNDLE_START(eventInfo);
|
||||
// Boolean::FALSE/TRUE gets clobbered by a macro, so ugh.
|
||||
GECKOBUNDLE_PUT(eventInfo, "checked",
|
||||
java::sdk::Integer::ValueOf(aChecked ? 1 : 0));
|
||||
GECKOBUNDLE_PUT(eventInfo, "flags", java::sdk::Integer::ValueOf(aFlags));
|
||||
GECKOBUNDLE_FINISH(eventInfo);
|
||||
|
||||
mSessionAccessibility->SendEvent(
|
||||
|
@ -80,7 +80,7 @@ class SessionAccessibility final
|
||||
int32_t aStart, uint32_t aLen, bool aIsInsert,
|
||||
bool aFromUser);
|
||||
void SendSelectedEvent(AccessibleWrap* aAccessible, bool aSelected);
|
||||
void SendClickedEvent(AccessibleWrap* aAccessible, bool aChecked);
|
||||
void SendClickedEvent(AccessibleWrap* aAccessible, uint32_t aFlags);
|
||||
void SendWindowContentChangedEvent();
|
||||
void SendWindowStateChangedEvent(AccessibleWrap* aAccessible);
|
||||
void SendAnnouncementEvent(AccessibleWrap* aAccessible,
|
||||
|
@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
<button onclick="this.setAttribute('aria-expanded', this.getAttribute('aria-expanded') == 'false')" aria-expanded="false">button</button>
|
||||
</body>
|
||||
</html>
|
@ -773,6 +773,50 @@ class AccessibilityTest : BaseSessionTest() {
|
||||
waitUntilClick(false)
|
||||
}
|
||||
|
||||
@Test fun testExpandable() {
|
||||
var nodeId = AccessibilityNodeProvider.HOST_VIEW_ID;
|
||||
loadTestPage("test-expandable")
|
||||
waitForInitialFocus(true)
|
||||
|
||||
sessionRule.waitUntilCalled(object : EventDelegate {
|
||||
@AssertCalled(count = 1)
|
||||
override fun onAccessibilityFocused(event: AccessibilityEvent) {
|
||||
nodeId = getSourceId(event)
|
||||
if (Build.VERSION.SDK_INT >= 21) {
|
||||
val node = createNodeInfo(nodeId)
|
||||
assertThat("button is expandable", node.actionList, hasItem(AccessibilityNodeInfo.AccessibilityAction.ACTION_EXPAND))
|
||||
assertThat("button is not collapsable", node.actionList, not(hasItem(AccessibilityNodeInfo.AccessibilityAction.ACTION_COLLAPSE)))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
provider.performAction(nodeId, AccessibilityNodeInfo.ACTION_EXPAND, null)
|
||||
sessionRule.waitUntilCalled(object : EventDelegate {
|
||||
@AssertCalled(count = 1)
|
||||
override fun onClicked(event: AccessibilityEvent) {
|
||||
assertThat("Clicked event is from same node", getSourceId(event), equalTo(nodeId))
|
||||
if (Build.VERSION.SDK_INT >= 21) {
|
||||
val node = createNodeInfo(nodeId)
|
||||
assertThat("button is collapsable", node.actionList, hasItem(AccessibilityNodeInfo.AccessibilityAction.ACTION_COLLAPSE))
|
||||
assertThat("button is not expandable", node.actionList, not(hasItem(AccessibilityNodeInfo.AccessibilityAction.ACTION_EXPAND)))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
provider.performAction(nodeId, AccessibilityNodeInfo.ACTION_COLLAPSE, null)
|
||||
sessionRule.waitUntilCalled(object : EventDelegate {
|
||||
@AssertCalled(count = 1)
|
||||
override fun onClicked(event: AccessibilityEvent) {
|
||||
assertThat("Clicked event is from same node", getSourceId(event), equalTo(nodeId))
|
||||
if (Build.VERSION.SDK_INT >= 21) {
|
||||
val node = createNodeInfo(nodeId)
|
||||
assertThat("button is expandable", node.actionList, hasItem(AccessibilityNodeInfo.AccessibilityAction.ACTION_EXPAND))
|
||||
assertThat("button is not collapsable", node.actionList, not(hasItem(AccessibilityNodeInfo.AccessibilityAction.ACTION_COLLAPSE)))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@Test fun testSelectable() {
|
||||
var nodeId = View.NO_ID
|
||||
loadTestPage("test-selectable")
|
||||
|
@ -66,6 +66,8 @@ public class SessionAccessibility {
|
||||
@WrapForJNI static final int FLAG_SELECTED = 1 << 14;
|
||||
@WrapForJNI static final int FLAG_VISIBLE_TO_USER = 1 << 15;
|
||||
@WrapForJNI static final int FLAG_SELECTABLE = 1 << 16;
|
||||
@WrapForJNI static final int FLAG_EXPANDABLE = 1 << 17;
|
||||
@WrapForJNI static final int FLAG_EXPANDED = 1 << 18;
|
||||
|
||||
static final int CLASSNAME_UNKNOWN = -1;
|
||||
@WrapForJNI static final int CLASSNAME_VIEW = 0;
|
||||
@ -208,10 +210,12 @@ public class SessionAccessibility {
|
||||
virtualViewId == View.NO_ID ? CLASSNAME_WEBVIEW : CLASSNAME_UNKNOWN, null);
|
||||
return true;
|
||||
case AccessibilityNodeInfo.ACTION_CLICK:
|
||||
case AccessibilityNodeInfo.ACTION_EXPAND:
|
||||
case AccessibilityNodeInfo.ACTION_COLLAPSE:
|
||||
nativeProvider.click(virtualViewId);
|
||||
GeckoBundle nodeInfo = getMostRecentBundle(virtualViewId);
|
||||
if (nodeInfo != null) {
|
||||
if ((nodeInfo.getInt("flags") & (FLAG_SELECTABLE | FLAG_CHECKABLE)) == 0) {
|
||||
if ((nodeInfo.getInt("flags") & (FLAG_SELECTABLE | FLAG_CHECKABLE | FLAG_EXPANDABLE)) == 0) {
|
||||
sendEvent(AccessibilityEvent.TYPE_VIEW_CLICKED, virtualViewId, nodeInfo.getInt("className"), null);
|
||||
}
|
||||
}
|
||||
@ -539,6 +543,19 @@ public class SessionAccessibility {
|
||||
node.setInputType(nodeInfo.getInt("inputType"));
|
||||
}
|
||||
|
||||
// SDK 21 and above
|
||||
if (Build.VERSION.SDK_INT >= 21) {
|
||||
if ((flags & FLAG_EXPANDABLE) != 0) {
|
||||
if ((flags & FLAG_EXPANDED) != 0) {
|
||||
node.removeAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_EXPAND);
|
||||
node.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_COLLAPSE);
|
||||
} else {
|
||||
node.removeAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_COLLAPSE);
|
||||
node.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_EXPAND);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SDK 23 and above
|
||||
if (Build.VERSION.SDK_INT >= 23) {
|
||||
node.setContextClickable((flags & FLAG_CONTEXT_CLICKABLE) != 0);
|
||||
@ -789,19 +806,30 @@ public class SessionAccessibility {
|
||||
event.setScrollY(eventData.getInt("scrollY", -1));
|
||||
event.setMaxScrollX(eventData.getInt("maxScrollX", -1));
|
||||
event.setMaxScrollY(eventData.getInt("maxScrollY", -1));
|
||||
event.setChecked(eventData.getInt("checked") != 0);
|
||||
event.setChecked((eventData.getInt("flags") & FLAG_CHECKED) != 0);
|
||||
}
|
||||
|
||||
// Update cache and stored state from this event.
|
||||
switch (eventType) {
|
||||
case AccessibilityEvent.TYPE_VIEW_CLICKED:
|
||||
if (cachedBundle != null && eventData != null && eventData.containsKey("checked")) {
|
||||
if (eventData.getInt("checked") != 0) {
|
||||
if (cachedBundle != null && eventData != null && eventData.containsKey("flags")) {
|
||||
final int flags = eventData.getInt("flags");
|
||||
if ((flags & FLAG_CHECKABLE) != 0) {
|
||||
if ((flags & FLAG_CHECKED) != 0) {
|
||||
cachedBundle.putInt("flags", cachedBundle.getInt("flags") | FLAG_CHECKED);
|
||||
} else {
|
||||
cachedBundle.putInt("flags", cachedBundle.getInt("flags") & ~FLAG_CHECKED);
|
||||
}
|
||||
}
|
||||
|
||||
if ((flags & FLAG_EXPANDABLE) != 0) {
|
||||
if ((flags & FLAG_EXPANDED) != 0) {
|
||||
cachedBundle.putInt("flags", cachedBundle.getInt("flags") | FLAG_EXPANDED);
|
||||
} else {
|
||||
cachedBundle.putInt("flags", cachedBundle.getInt("flags") & ~FLAG_EXPANDED);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AccessibilityEvent.TYPE_VIEW_SELECTED:
|
||||
if (cachedBundle != null && eventData != null && eventData.containsKey("selected")) {
|
||||
|
Loading…
Reference in New Issue
Block a user