I have the following xml file.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:id="@+id/linear_layout1"
android:layout_width="match_parent"
android:layout_height="200dp"
android:focusable="true"
android:layout_margin="10dp"
android:orientation="vertical">
<TextView
android:id="@+id/text1"
android:layout_width="match_parent"
android:layout_height="100dp"
android:text="first text"
android:layout_margin="10dp"/>
<TextView
android:id="@+id/text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="second text"
android:layout_margin="10dp"/>
</LinearLayout>
</LinearLayout>
I have set a click listener for LinearLayout and TextView.
TextView textView1 = (TextView) findViewById(R.id.text1);
LinearLayout linearLayout = findViewById(R.id.linear_layout1);
linearLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(v.getContext(), "Linear layout clicked", Toast.LENGTH_SHORT).show();
}
});
textView1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(v.getContext(), "text view clicked", Toast.LENGTH_SHORT).show();
}
});
I have made the LinearLayout focusable so that in talkback mode, it can get the accessibility focus. Now when I double tap on it, click event of text view is called instead of linear layout.
How can I make it call the click listener of linear layout instead?
I had the same problem and I solved it by creating new View, which was extending LinearLayout and in this View I have overriden onInterceptTouchEvent()
method. In this method is checked whether Accessibility is turned on and if the ViewGroup (LinearLayout) is selected. If so, return true and intercept this event.
public class AccessibleLinearLayout extends LinearLayout {
public AccessibleLinearLayout(Context context) {
super(context);
}
public AccessibleLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public AccessibleLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (((AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE)).isEnabled() && isAccessibilityFocused()) {
return true;
}
return super.onInterceptTouchEvent(ev);
}
}
I'm not sure if you need to check ((AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE)).isEnabled()
when you check if isAccessibilityFocused()
There are a couple of interesting things at play here. And that is two different approaches to TalkBack* click event handling.
Old TalkBack passes events different from normal touch events. Instead of sending a physical touch event, it sends a request to call "click actions". So, no, the click doesn't end up propagating like a normal "click".
TalkBack now relies on the gesture APIs to send actual physical events. These artificial physical click events are sent to the center of the view that has had the activation action sent to it by TalkBack (the double click action).
The problem that your having, is that these two behaviors are going to break ONE of the two obvious solutions. You have utilized one obvious solution (just utilizing multiple click listeners, and assuming the events are passed to the focused node), and it has not worked, because the technology combination you happen to be using is V2 (sending an artificial hardware click). However, if you were to install your app on a Samsung device, you may well get the behavior you want... but that doesn't mean it works! :)
Because of these two different behaviors, the only way to get this to work universally (all versions of TalkBack and Android), is to override one of the views AccessibilityDelegates (actually potentially both views), and intercept those events. Don't allow them through to the default handler, which would be one of the two methods described above. Instead, call the logic you wish to call, and pass the vent around yourself.
- Note: It's actually probably more dependant on Android OS version/manufacturer, but I'm not on my dev machine right now, and believe it or not, but browsing around the AOSP code in a web browser just isn't going to happen at 10 PM on a Sunday night. I may update this answer with more details at a later date.
Height and Width of TextView
is problem
Change from
<TextView
android:id="@+id/text1"
android:layout_width="match_parent"
android:layout_height="100dp"
android:text="first text"
android:layout_margin="10dp"/>
to
<TextView
android:id="@+id/text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="first text"
android:layout_margin="10dp"/>