3030import static com .google .android .material .textfield .TextInputLayout .END_ICON_PASSWORD_TOGGLE ;
3131
3232import android .annotation .SuppressLint ;
33+ import android .content .Context ;
3334import android .content .res .ColorStateList ;
3435import android .graphics .PorterDuff ;
3536import android .graphics .drawable .Drawable ;
4344import android .view .Gravity ;
4445import android .view .LayoutInflater ;
4546import android .view .View ;
47+ import android .view .View .OnAttachStateChangeListener ;
4648import android .view .ViewGroup ;
49+ import android .view .accessibility .AccessibilityManager ;
4750import android .widget .EditText ;
4851import android .widget .FrameLayout ;
4952import android .widget .LinearLayout ;
5760import androidx .core .graphics .drawable .DrawableCompat ;
5861import androidx .core .view .MarginLayoutParamsCompat ;
5962import androidx .core .view .ViewCompat ;
63+ import androidx .core .view .accessibility .AccessibilityManagerCompat ;
64+ import androidx .core .view .accessibility .AccessibilityManagerCompat .TouchExplorationStateChangeListener ;
6065import androidx .core .widget .TextViewCompat ;
6166import com .google .android .material .internal .CheckableImageButton ;
6267import com .google .android .material .internal .TextWatcherAdapter ;
@@ -97,6 +102,8 @@ class EndCompoundLayout extends LinearLayout {
97102 private boolean hintExpanded ;
98103
99104 private EditText editText ;
105+ @ Nullable private final AccessibilityManager accessibilityManager ;
106+ @ Nullable private TouchExplorationStateChangeListener touchExplorationStateChangeListener ;
100107
101108 private final TextWatcher editTextWatcher =
102109 new TextWatcherAdapter () {
@@ -137,6 +144,9 @@ public void onEditTextAttached(@NonNull TextInputLayout textInputLayout) {
137144 EndCompoundLayout (TextInputLayout textInputLayout , TintTypedArray a ) {
138145 super (textInputLayout .getContext ());
139146
147+ accessibilityManager =
148+ (AccessibilityManager ) getContext ().getSystemService (Context .ACCESSIBILITY_SERVICE );
149+
140150 this .textInputLayout = textInputLayout ;
141151
142152 setVisibility (GONE );
@@ -170,6 +180,18 @@ public void onEditTextAttached(@NonNull TextInputLayout textInputLayout) {
170180 addView (errorIconView );
171181
172182 textInputLayout .addOnEditTextAttachedListener (onEditTextAttachedListener );
183+ addOnAttachStateChangeListener (
184+ new OnAttachStateChangeListener () {
185+ @ Override
186+ public void onViewAttachedToWindow (View ignored ) {
187+ addTouchExplorationStateChangeListenerIfNeeded ();
188+ }
189+
190+ @ Override
191+ public void onViewDetachedFromWindow (View ignored ) {
192+ removeTouchExplorationStateChangeListenerIfNeeded ();
193+ }
194+ });
173195 }
174196
175197 private CheckableImageButton createIconView (
@@ -324,7 +346,7 @@ void setEndIconMode(@EndIconMode int endIconMode) {
324346 if (this .endIconMode == endIconMode ) {
325347 return ;
326348 }
327- getEndIconDelegate (). tearDown ( );
349+ tearDownDelegate ( getEndIconDelegate ());
328350 int previousEndIconMode = this .endIconMode ;
329351 this .endIconMode = endIconMode ;
330352 dispatchOnEndIconChanged (previousEndIconMode );
@@ -334,7 +356,7 @@ void setEndIconMode(@EndIconMode int endIconMode) {
334356 setEndIconContentDescription (delegate .getIconContentDescriptionResId ());
335357 setEndIconCheckable (delegate .isIconCheckable ());
336358 if (delegate .isBoxBackgroundModeSupported (textInputLayout .getBoxBackgroundMode ())) {
337- delegate . setUp ( );
359+ setUpDelegate ( delegate );
338360 } else {
339361 throw new IllegalStateException (
340362 "The current box background mode "
@@ -373,6 +395,35 @@ void refreshIconState(boolean force) {
373395 }
374396 }
375397
398+ private void setUpDelegate (@ NonNull EndIconDelegate delegate ) {
399+ delegate .setUp ();
400+
401+ touchExplorationStateChangeListener = delegate .getTouchExplorationStateChangeListener ();
402+ addTouchExplorationStateChangeListenerIfNeeded ();
403+ }
404+
405+ private void tearDownDelegate (@ NonNull EndIconDelegate delegate ) {
406+ removeTouchExplorationStateChangeListenerIfNeeded ();
407+ touchExplorationStateChangeListener = null ;
408+ delegate .tearDown ();
409+ }
410+
411+ private void addTouchExplorationStateChangeListenerIfNeeded () {
412+ if (touchExplorationStateChangeListener != null
413+ && accessibilityManager != null
414+ && ViewCompat .isAttachedToWindow (this )) {
415+ AccessibilityManagerCompat .addTouchExplorationStateChangeListener (
416+ accessibilityManager , touchExplorationStateChangeListener );
417+ }
418+ }
419+
420+ private void removeTouchExplorationStateChangeListenerIfNeeded () {
421+ if (touchExplorationStateChangeListener != null && accessibilityManager != null ) {
422+ AccessibilityManagerCompat .removeTouchExplorationStateChangeListener (
423+ accessibilityManager , touchExplorationStateChangeListener );
424+ }
425+ }
426+
376427 private int getIconResId (EndIconDelegate delegate ) {
377428 int customIconResId = endIconDelegates .customEndIconDrawableId ;
378429 return customIconResId == 0 ? delegate .getIconDrawableResId () : customIconResId ;
0 commit comments