When using Talkback the replaced view produces a weird result in the top fragment. The button that triggers the transaction of the fragment is still visible(this also happens without the accessibility service on) and it still has the focus. The expected result is to get the accessibility focus in the fragment's TextView after the transaction is commited and not showing the button from replaced root view. I left the commented lines so you can see what I have tried and did not work but might help others. Notice I used both kotlin and java so that the fix can be implemented in any of those.
The code:
FragmentDetail.java
import android.app.Fragment;
import android.app.FragmentManager;
import android.os.Build;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.TextView;
import com.hztlscroll.R;
import com.hztlscroll.ext.FragmentManagerExtensionKt;
public class FragmentDetail extends Fragment {
private FragmentManager fm = null;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup viewGroup, Bundle savedInstanceState) {
fm = getFragmentManager();
// FragmentManagerExtensionKt.setupForAccessibility(fm);
View view = inflater.inflate(R.layout.fr_detail, viewGroup, false);
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
// view.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
// }
TextView tvLbl01 = (TextView) view.findViewById(R.id.tv_detail_title);
tvLbl01.setText(R.string.detail_fr_title);
tvLbl01.requestFocus();
// tvLbl01.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
// tvLbl01.performAccessibilityAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null);
// }
return view;
}
}
fr_detail.xml
<?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:layout_gravity="center"
android:background="@color/colorAccent"
android:orientation="vertical"
android:focusable="true"
android:clickable="true"
android:importantForAccessibility="yes">
<TextView
android:id="@+id/tv_detail_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/landing_fr_msg01_lbl"
android:textColor="#b0b0ff"
android:textSize="20sp" />
</LinearLayout>
MainActivity.kt
import android.app.Fragment
import android.app.FragmentManager
import android.app.FragmentTransaction
import android.os.Build
import android.os.Bundle
import android.view.MotionEvent
import android.view.View
import android.widget.Button
import androidx.appcompat.app.AppCompatActivity
import androidx.constraintlayout.widget.ConstraintLayout
import com.hztlscroll.ext.setupForAccessibility
import com.hztlscroll.ui.FragmentDetail
class MainActivity : AppCompatActivity() {
var fm: FragmentManager? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
fm = fragmentManager
// fm?.setupForAccessibility()
setContentView(R.layout.activity_main)
val landingRootView = findViewById<ConstraintLayout>(R.id.cl_landing)
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
// landingRootView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS)
// }
val landingBtn: Button = findViewById(R.id.btn_landing_01)
landingBtn.setOnClickListener(listener)
}
override fun onTouchEvent(event: MotionEvent?): Boolean {
return super.onTouchEvent(event)
}
val listener: View.OnClickListener = object : View.OnClickListener {
override fun onClick(view: View?) {
var fragment: Fragment? = null
if (view === this@MainActivity.findViewById<Button>(R.id.btn_landing_01)) {
fragment = FragmentDetail()
}
val ft: FragmentTransaction = fm!!.beginTransaction()
ft.replace(R.id.cl_landing, fragment);
ft.commit()
}
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/cl_landing"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/btn_landing_01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toTopOf="@+id/tv_landing_act_focus"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="@+id/tv_landing_act_focus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<FrameLayout
android:id="@+id/fl_landing_focus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/colorPrimary"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/et_landing_act_focus">
<ImageView
android:layout_width="250px"
android:layout_height="250px"
android:scaleType="fitCenter"
android:src="@drawable/ic_launcher_background" />
<TextView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center"
android:text="Frame Demo"
android:textSize="30px"
android:textStyle="bold" />
</FrameLayout>
<EditText
android:id="@+id/et_landing_act_focus"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_landing_act_focus" />
</androidx.constraintlayout.widget.ConstraintLayout>
FragmentManagerExtension.kt
import android.app.FragmentManager
import android.os.Build
import android.view.View
fun FragmentManager.setupForAccessibility() {
addOnBackStackChangedListener {
val lastFragmentWithView = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
fragments.last { it.view != null }
} else {
TODO("VERSION.SDK_INT < O")
}
for (fragment in fragments) {
if (fragment == lastFragmentWithView) {
fragment.view?.importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_YES
} else {
fragment.view?.importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
}
}
}
}
And the consulted sources so far:
Image of the screen after the transaction having focus and the button visible instead of the fragment's title.. fragment's TextView not getting focus