Use CollectionInfo and CollectionItemInfo api in RadioGroup and

RadioButton

Allow RadioGroups to be recognized as groups of
objects by accessibility services. This lays a foundation to better
describe these groups by exposing the number of buttons and the position of
each.

Bug: 144591511
Test: Tested on various app permission fragments in Settings and in the
time picker in Clock. Added cts tests.

Change-Id: Ie0c41d8c9b131ca29bba5387171a85dfdbb8db7e
This commit is contained in:
sallyyuen
2019-11-25 17:05:47 -08:00
parent 700c836e03
commit 69a146ca9c
2 changed files with 73 additions and 7 deletions

View File

@@ -18,6 +18,7 @@ package android.widget;
import android.content.Context;
import android.util.AttributeSet;
import android.view.accessibility.AccessibilityNodeInfo;
/**
@@ -38,19 +39,19 @@ import android.util.AttributeSet;
* guide.</p>
*
* <p><strong>XML attributes</strong></p>
* <p>
* See {@link android.R.styleable#CompoundButton CompoundButton Attributes},
* {@link android.R.styleable#Button Button Attributes},
* {@link android.R.styleable#TextView TextView Attributes},
* <p>
* See {@link android.R.styleable#CompoundButton CompoundButton Attributes},
* {@link android.R.styleable#Button Button Attributes},
* {@link android.R.styleable#TextView TextView Attributes},
* {@link android.R.styleable#View View Attributes}
* </p>
*/
public class RadioButton extends CompoundButton {
public RadioButton(Context context) {
this(context, null);
}
public RadioButton(Context context, AttributeSet attrs) {
this(context, attrs, com.android.internal.R.attr.radioButtonStyle);
}
@@ -81,4 +82,20 @@ public class RadioButton extends CompoundButton {
public CharSequence getAccessibilityClassName() {
return RadioButton.class.getName();
}
@Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
if (getParent() instanceof RadioGroup) {
RadioGroup radioGroup = (RadioGroup) getParent();
if (radioGroup.getOrientation() == LinearLayout.HORIZONTAL) {
info.setCollectionItemInfo(AccessibilityNodeInfo.CollectionItemInfo.obtain(0, 1,
radioGroup.getIndexWithinVisibleButtons(this), 1, false, isChecked()));
} else {
info.setCollectionItemInfo(AccessibilityNodeInfo.CollectionItemInfo.obtain(
radioGroup.getIndexWithinVisibleButtons(this), 1, 0, 1,
false, isChecked()));
}
}
}
}

View File

@@ -18,6 +18,7 @@ package android.widget;
import android.annotation.IdRes;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.TypedArray;
@@ -26,6 +27,7 @@ import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewStructure;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.autofill.AutofillManager;
import android.view.autofill.AutofillValue;
@@ -93,6 +95,7 @@ public class RadioGroup extends LinearLayout {
if (getImportantForAutofill() == IMPORTANT_FOR_AUTOFILL_AUTO) {
setImportantForAutofill(IMPORTANT_FOR_AUTOFILL_YES);
}
setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
// retrieve selected radio button as requested by the user in the
// XML layout file
@@ -475,4 +478,50 @@ public class RadioGroup extends LinearLayout {
}
return null;
}
}
@Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
if (this.getOrientation() == HORIZONTAL) {
info.setCollectionInfo(AccessibilityNodeInfo.CollectionInfo.obtain(1,
getVisibleChildCount(), false,
AccessibilityNodeInfo.CollectionInfo.SELECTION_MODE_SINGLE));
} else {
info.setCollectionInfo(
AccessibilityNodeInfo.CollectionInfo.obtain(getVisibleChildCount(),
1, false,
AccessibilityNodeInfo.CollectionInfo.SELECTION_MODE_SINGLE));
}
}
private int getVisibleChildCount() {
int count = 0;
for (int i = 0; i < getChildCount(); i++) {
if (this.getChildAt(i) instanceof RadioButton) {
if (((RadioButton) this.getChildAt(i)).getVisibility() == VISIBLE) {
count++;
}
}
}
return count;
}
int getIndexWithinVisibleButtons(@Nullable View child) {
if (!(child instanceof RadioButton)) {
return -1;
}
int index = 0;
for (int i = 0; i < getChildCount(); i++) {
if (this.getChildAt(i) instanceof RadioButton) {
RadioButton radioButton = (RadioButton) this.getChildAt(i);
if (radioButton == child) {
return index;
}
if (radioButton.getVisibility() == VISIBLE) {
index++;
}
}
}
return -1;
}
}