简体   繁体   中英

View is not selectable after it is made VISIBLE with a delayed transition when Talkback is enabled in Android

When a view is made VISIBLE a certain way, Talkback can no longer select / click / focus on that view, see: https://github.com/kai-vala/DemoForAccessibilityBugs/blob/master/images/animation.gif

(Not enough rep to embed images)

Full example app is here: https://github.com/kai-vala/DemoForAccessibilityBugs

Realized that its caused by the transition, if we remove: TransitionManager.beginDelayedTransition(it) , the view is always selectable.

I'm looking for a way to get the focus / clickable to work consistently even with the delayed transition.


The following should occur consistently with Android 11 on simulator:

  1. Fresh start the app

  2. Tap the button to perform transition

  3. Try to select 'Edit text 2' view, notice it cannot be clicked (swipe navigation with Talkback will also bypass it)


For completenesses sake I'll add a minimal code example below, but I recommend checking out from the repo directly.

EDIT: Modified example code to be simpler after I realized this is caused by the transition.

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>

        <variable
            name="vm"
            type="com.valagroup.demoforaccessibilitybugs.MainViewModel" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginStart="12.5dp"
        android:layout_marginTop="12.5dp"
        android:layout_marginEnd="12.5dp"
        android:layout_marginBottom="12.5dp"
        tools:context=".MainActivity">

        <TextView
            android:id="@+id/title_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:minWidth="44dp"
            android:minHeight="44dp"
            android:text="Remember to enable Talkback"
            android:textAppearance="@style/TextAppearance.AppCompat.Headline"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <!-- See MainActivity.kt where the transition is started -->
        <androidx.appcompat.widget.AppCompatButton
            android:id="@+id/toggleButton"
            style="@style/Widget.AppCompat.Button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="44dp"
            android:text="Transition between text boxes"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/title_text" />

        <androidx.appcompat.widget.AppCompatEditText
            android:id="@+id/editTextByButton1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="12.5dp"
            android:text="Edit text other 1"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toBottomOf="@id/toggleButton"
            app:visible="@{vm.buttonState == true}" />

        <androidx.appcompat.widget.AppCompatEditText
            android:id="@+id/editTextByButton2"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="12.5dp"
            android:text="Edit text other 2"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toBottomOf="@id/editTextByButton1"
            app:visible="@{vm.buttonState == false}" />

        <TextView
            android:id="@+id/bottom_text2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="12.5dp"
            android:text="Above text boxes are not enabled correctly \nWhen transitions are used with Talkback enabled"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toBottomOf="@id/editTextByButton2" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

MainViewModel.kt

class MainViewModel : ViewModel() {
    val buttonState = MutableLiveData<Boolean>().apply { value = true }

    fun toggleButtonState() {
        buttonState.value = !buttonState.value!!
    }

    init {
        Log.d("MainViewModel", "init")
    }
}

MainActivity.kt

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding: ActivityMainBinding =
            DataBindingUtil.setContentView(this, R.layout.activity_main)
        binding.vm = ViewModelProvider(this).get(MainViewModel::class.java)
        binding.lifecycleOwner = this

        binding.toggleButton.setOnClickListener { v ->
            if (v != null) {
                Log.d("OnClick", "toggleButton")
                val viewModel = binding.vm as MainViewModel
                viewModel.toggleButtonState()
                binding.toggleButton.findParent<ConstraintLayout>()?.let {
                    // TODO/FIXME: The issue where edit texts are not enabled is caused by the transition
                    TransitionManager.beginDelayedTransition(it)
                }
            }
        }
    }
}

@BindingAdapter("visible")
fun visible(view: View, visible: Boolean?) {
    Log.d("BindingAdapter", "Changing visibility of view '${view.id}' to: $visible")
    view.visibility = if (visible == true) View.VISIBLE else View.GONE
}

private inline fun <reified T : ViewGroup> View.findParent(): T? {
    var view = this.parent
    while (view != null) {
        if (view is T)
            return view
        view = view.parent
    }
    return null
}

Workaround for this as answered by an AOSP developer: https://issuetracker.google.com/185532478

We fixed a bug in S related to visibility changes that I think has to be the cause of this bug, although there are a few details I can't quite explain.

The issue is that we didn't sent an accessibility event when a view became invisible, because we don't permit invisible views to send events. The fix was to have the parent sent a subtree changed event.

I think if you check if AccessibilityManager#isEnabled, and if so call notifySubtreeAccessibilityStateChanged on the parent, you will force the correct event to be sent and alert services that the old view has disappeared.

parent= view.parent
// null check, etc
parent.notifySubtreeAccessibilityStateChanged(parent, parent, AccessibilityEvent#CONTENT_CHANGE_TYPE_SUBTREE)

In principle, you should only need to do this if the view has become invisible, as the view becoming visible does send an event. But following that reasoning, I don't see why making the second edit text visible doesn't resolve the issue. Either way, I think notifying that the subtree changed should resolve the issue.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM