Skip to content

Commit d3ab6d7

Browse files
drchenleticiarossi
authored andcommitted
[CleanUp][TextField] Centralize accessibility event dispatching logic for drop-downs
This also fixes the bug that clients cannot use custom AccessibilityDelegate with drop-down mode. PiperOrigin-RevId: 447748501
1 parent 72228f4 commit d3ab6d7

File tree

3 files changed

+51
-34
lines changed

3 files changed

+51
-34
lines changed

lib/java/com/google/android/material/textfield/DropdownMenuEndIconDelegate.java

Lines changed: 26 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@
4747
import androidx.core.view.ViewCompat;
4848
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
4949
import com.google.android.material.animation.AnimationUtils;
50-
import com.google.android.material.textfield.TextInputLayout.AccessibilityDelegate;
5150
import com.google.android.material.textfield.TextInputLayout.BoxBackgroundMode;
5251

5352
/** Default initialization of the exposed dropdown menu {@link TextInputLayout.EndIconMode}. */
@@ -62,37 +61,6 @@ class DropdownMenuEndIconDelegate extends EndIconDelegate {
6261
@Nullable
6362
private AutoCompleteTextView autoCompleteTextView;
6463

65-
private final TextInputLayout.AccessibilityDelegate accessibilityDelegate =
66-
new AccessibilityDelegate(textInputLayout) {
67-
@Override
68-
public void onInitializeAccessibilityNodeInfo(
69-
View host, @NonNull AccessibilityNodeInfoCompat info) {
70-
super.onInitializeAccessibilityNodeInfo(host, info);
71-
// The non-editable exposed dropdown menu behaves like a Spinner.
72-
if (!isEditable(autoCompleteTextView)) {
73-
info.setClassName(Spinner.class.getName());
74-
}
75-
if (info.isShowingHintText()) {
76-
// Set hint text to null so TalkBack doesn't announce the label twice when there is no
77-
// item selected.
78-
info.setHintText(null);
79-
}
80-
}
81-
82-
@Override
83-
public void onPopulateAccessibilityEvent(View host, @NonNull AccessibilityEvent event) {
84-
super.onPopulateAccessibilityEvent(host, event);
85-
// If dropdown is non editable, layout click is what triggers showing/hiding the popup
86-
// list. Otherwise, arrow icon alone is what triggers it.
87-
if (event.getEventType() == TYPE_VIEW_CLICKED
88-
&& accessibilityManager.isEnabled()
89-
&& !isEditable(autoCompleteTextView)) {
90-
showHideDropdown();
91-
updateDropdownPopupDirty();
92-
}
93-
}
94-
};
95-
9664
private final OnClickListener onIconClickListener = view -> showHideDropdown();
9765

9866
private final OnFocusChangeListener onEditTextFocusChangeListener = (view, hasFocus) -> {
@@ -177,8 +145,6 @@ public void onEditTextAttached(@Nullable EditText editText) {
177145
if (!isEditable(editText) && accessibilityManager.isTouchExplorationEnabled()) {
178146
ViewCompat.setImportantForAccessibility(endIconView, IMPORTANT_FOR_ACCESSIBILITY_NO);
179147
}
180-
textInputLayout.setTextInputAccessibilityDelegate(accessibilityDelegate);
181-
182148
textInputLayout.setEndIconVisible(true);
183149
}
184150

@@ -202,6 +168,32 @@ OnFocusChangeListener getOnEditTextFocusChangeListener() {
202168
return onEditTextFocusChangeListener;
203169
}
204170

171+
@Override
172+
public void onInitializeAccessibilityNodeInfo(
173+
View host, @NonNull AccessibilityNodeInfoCompat info) {
174+
// The non-editable exposed dropdown menu behaves like a Spinner.
175+
if (!isEditable(autoCompleteTextView)) {
176+
info.setClassName(Spinner.class.getName());
177+
}
178+
if (info.isShowingHintText()) {
179+
// Set hint text to null so TalkBack doesn't announce the label twice when there is no
180+
// item selected.
181+
info.setHintText(null);
182+
}
183+
}
184+
185+
@Override
186+
public void onPopulateAccessibilityEvent(View host, @NonNull AccessibilityEvent event) {
187+
// If dropdown is non editable, layout click is what triggers showing/hiding the popup
188+
// list. Otherwise, arrow icon alone is what triggers it.
189+
if (event.getEventType() == TYPE_VIEW_CLICKED
190+
&& accessibilityManager.isEnabled()
191+
&& !isEditable(autoCompleteTextView)) {
192+
showHideDropdown();
193+
updateDropdownPopupDirty();
194+
}
195+
}
196+
205197
private void showHideDropdown() {
206198
if (autoCompleteTextView == null) {
207199
return;

lib/java/com/google/android/material/textfield/EndIconDelegate.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,15 @@
1818

1919
import android.content.Context;
2020
import android.text.Editable;
21+
import android.view.View;
2122
import android.view.View.OnClickListener;
2223
import android.view.View.OnFocusChangeListener;
24+
import android.view.accessibility.AccessibilityEvent;
2325
import android.widget.EditText;
2426
import androidx.annotation.DrawableRes;
2527
import androidx.annotation.NonNull;
2628
import androidx.annotation.Nullable;
29+
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
2730
import com.google.android.material.internal.CheckableImageButton;
2831
import com.google.android.material.textfield.TextInputLayout.BoxBackgroundMode;
2932

@@ -122,4 +125,17 @@ void beforeEditTextChanged(CharSequence s, int start, int count, int after) {}
122125
* @see android.text.TextWatcher#afterTextChanged(Editable)
123126
*/
124127
void afterEditTextChanged(Editable s) {}
128+
129+
/**
130+
* This method will be called when the associated {@link TextInputLayout} is initializing the
131+
* accessibility node info.
132+
*/
133+
void onInitializeAccessibilityNodeInfo(View host, @NonNull AccessibilityNodeInfoCompat info) {}
134+
135+
/**
136+
* This method will be called when the associated {@link TextInputLayout} is populating a
137+
* accessibility event.
138+
*/
139+
void onPopulateAccessibilityEvent(View host, @NonNull AccessibilityEvent event) {}
125140
}
141+

lib/java/com/google/android/material/textfield/TextInputLayout.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4239,6 +4239,15 @@ public void onInitializeAccessibilityNodeInfo(
42394239
info.setLabelFor(helperTextView);
42404240
}
42414241
}
4242+
4243+
layout.endLayout.getEndIconDelegate().onInitializeAccessibilityNodeInfo(host, info);
4244+
}
4245+
4246+
@Override
4247+
public void onPopulateAccessibilityEvent(
4248+
@NonNull View host, @NonNull AccessibilityEvent event) {
4249+
super.onPopulateAccessibilityEvent(host, event);
4250+
layout.endLayout.getEndIconDelegate().onPopulateAccessibilityEvent(host, event);
42424251
}
42434252
}
42444253
}

0 commit comments

Comments
 (0)