Skip to content

Commit 8cbfd20

Browse files
raajkumarsdsn5ft
authored andcommitted
[M3][SearchBar] Fixed issue that caused the wrong component to be focused on automatically when talkback is active.
PiperOrigin-RevId: 493910945 (cherry picked from commit e2c8cba)
1 parent f707836 commit 8cbfd20

2 files changed

Lines changed: 54 additions & 6 deletions

File tree

lib/java/com/google/android/material/search/SearchBar.java

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import android.view.LayoutInflater;
4242
import android.view.View;
4343
import android.view.ViewGroup;
44+
import android.view.accessibility.AccessibilityManager;
4445
import android.view.accessibility.AccessibilityNodeInfo;
4546
import android.widget.EditText;
4647
import android.widget.ImageButton;
@@ -57,6 +58,8 @@
5758
import androidx.core.graphics.drawable.DrawableCompat;
5859
import androidx.core.view.MarginLayoutParamsCompat;
5960
import androidx.core.view.ViewCompat;
61+
import androidx.core.view.accessibility.AccessibilityManagerCompat;
62+
import androidx.core.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener;
6063
import androidx.core.widget.TextViewCompat;
6164
import androidx.customview.view.AbsSavedState;
6265
import com.google.android.material.appbar.AppBarLayout;
@@ -130,14 +133,17 @@ public class SearchBar extends Toolbar {
130133
private final Drawable defaultNavigationIcon;
131134
private final boolean tintNavigationIcon;
132135
private final boolean forceDefaultNavigationOnClickListener;
133-
134136
@Nullable private View centerView;
135137
@Nullable private Integer navigationIconTint;
136138
@Nullable private Drawable originalNavigationIconBackground;
137139
private int menuResId = -1;
138140
private boolean defaultScrollFlagsEnabled;
139141
private MaterialShapeDrawable backgroundShape;
140142

143+
@Nullable private final AccessibilityManager accessibilityManager;
144+
private final TouchExplorationStateChangeListener touchExplorationStateChangeListener =
145+
(boolean enabled) -> setFocusableInTouchMode(enabled);
146+
141147
public SearchBar(@NonNull Context context) {
142148
this(context, null);
143149
}
@@ -194,6 +200,35 @@ public SearchBar(@NonNull Context context, @Nullable AttributeSet attrs, int def
194200
ViewCompat.setElevation(this, elevation);
195201
initTextView(textAppearanceResId, text, hint);
196202
initBackground(shapeAppearanceModel, elevation, strokeWidth, strokeColor);
203+
204+
accessibilityManager =
205+
(AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
206+
setupTouchExplorationStateChangeListener();
207+
}
208+
209+
private void setupTouchExplorationStateChangeListener() {
210+
if (accessibilityManager != null) {
211+
// Handle the case where touch exploration is already enabled.
212+
if (accessibilityManager.isEnabled() && accessibilityManager.isTouchExplorationEnabled()) {
213+
setFocusableInTouchMode(true);
214+
}
215+
216+
// Handle the case where touch exploration state can change while the view is active.
217+
addOnAttachStateChangeListener(
218+
new OnAttachStateChangeListener() {
219+
@Override
220+
public void onViewAttachedToWindow(View ignored) {
221+
AccessibilityManagerCompat.addTouchExplorationStateChangeListener(
222+
accessibilityManager, touchExplorationStateChangeListener);
223+
}
224+
225+
@Override
226+
public void onViewDetachedFromWindow(View ignored) {
227+
AccessibilityManagerCompat.removeTouchExplorationStateChangeListener(
228+
accessibilityManager, touchExplorationStateChangeListener);
229+
}
230+
});
231+
}
197232
}
198233

199234
private void validateAttributes(@Nullable AttributeSet attributeSet) {

lib/java/com/google/android/material/search/SearchView.java

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import android.view.ViewGroup;
4444
import android.view.Window;
4545
import android.view.WindowManager;
46+
import android.view.accessibility.AccessibilityEvent;
4647
import android.widget.EditText;
4748
import android.widget.FrameLayout;
4849
import android.widget.ImageButton;
@@ -119,6 +120,7 @@
119120
@SuppressWarnings("RestrictTo")
120121
public class SearchView extends FrameLayout implements CoordinatorLayout.AttachedBehavior {
121122

123+
private static final long TALKBACK_FOCUS_CHANGE_DELAY_MS = 100;
122124
private static final int DEF_STYLE_RES = R.style.Widget_Material3_SearchView;
123125

124126
final View scrim;
@@ -791,17 +793,28 @@ void requestFocusAndShowKeyboardIfNeeded() {
791793

792794
/** Requests focus on the main {@link EditText} and shows the soft keyboard. */
793795
public void requestFocusAndShowKeyboard() {
794-
editText.post(
796+
// Without a delay requesting focus on edit text fails when talkback is active.
797+
editText.postDelayed(
795798
() -> {
796-
editText.requestFocus();
799+
if (editText.requestFocus()) {
800+
// Workaround for talkback issue when clear button is clicked
801+
editText.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
802+
}
797803
ViewUtils.showKeyboard(editText, useWindowInsetsController);
798-
});
804+
},
805+
TALKBACK_FOCUS_CHANGE_DELAY_MS);
799806
}
800807

801808
/** Clears focus on the main {@link EditText} and hides the soft keyboard. */
802809
public void clearFocusAndHideKeyboard() {
803-
editText.clearFocus();
804-
ViewUtils.hideKeyboard(editText, useWindowInsetsController);
810+
editText.post(
811+
() -> {
812+
editText.clearFocus();
813+
if (searchBar != null) {
814+
searchBar.requestFocus();
815+
}
816+
ViewUtils.hideKeyboard(editText, useWindowInsetsController);
817+
});
805818
}
806819

807820
boolean isAdjustNothingSoftInputMode() {

0 commit comments

Comments
 (0)