[Android] Accessibility: improve talkback for the video tracks sheet
Nicolas Pomepuy
git at videolan.org
Fri Jun 3 11:30:21 UTC 2022
vlc-android | branch: master | Nicolas Pomepuy <nicolas at videolabs.io> | Tue May 24 08:28:16 2022 +0200| [7627a9e6a1f504fea4d3acc939a74702100ba02f] | committer: Nicolas Pomepuy
Accessibility: improve talkback for the video tracks sheet
Auto expand the track options and improve the content descriptions
> https://code.videolan.org/videolan/vlc-android/commit/7627a9e6a1f504fea4d3acc939a74702100ba02f
---
.../resources/src/main/res/values/strings.xml | 6 +++++-
.../vlc-android/res/layout/video_track_item.xml | 4 ++++
.../videolan/vlc/gui/dialogs/VideoTracksDialog.kt | 21 ++++++++++++++++++---
.../vlc/gui/dialogs/adapters/TrackAdapter.kt | 5 ++++-
.../vlc/gui/view/CollapsibleLinearLayout.kt | 14 ++++++++++++++
5 files changed, 45 insertions(+), 5 deletions(-)
diff --git a/application/resources/src/main/res/values/strings.xml b/application/resources/src/main/res/values/strings.xml
index d4c083288..6503c00ad 100644
--- a/application/resources/src/main/res/values/strings.xml
+++ b/application/resources/src/main/res/values/strings.xml
@@ -1002,7 +1002,11 @@
<string name="talkback_file_size">File size: %s</string>
<string name="talkback_open_in_browser">Open in web browser</string>
<string name="talkback_video_player">Video player. Tap to show controls. Tap the back button to hide them</string>
-
+ <string name="talkback_video_tracks">Video tracks</string>
+ <string name="talkback_audio_tracks">Audio tracks</string>
+ <string name="talkback_subtitle_tracks">Subtitle tracks</string>
+ <string name="talkback_track" translatable="false">%s: %s. %s</string>
+ <string name="selected">Selected</string>
</resources>
diff --git a/application/vlc-android/res/layout/video_track_item.xml b/application/vlc-android/res/layout/video_track_item.xml
index e5331810f..e989d63da 100644
--- a/application/vlc-android/res/layout/video_track_item.xml
+++ b/application/vlc-android/res/layout/video_track_item.xml
@@ -15,6 +15,9 @@
<variable
name="selected"
type="Boolean" />
+ <variable
+ name="contentDescription"
+ type="String" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
@@ -45,6 +48,7 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
+ android:contentDescription="@{contentDescription}"
android:text="@{track.id == -1 ? @string/disable_track : track.name}"
android:textColor="@{selected ? @color/white : @color/white_transparent_50}"
android:maxLines="1"
diff --git a/application/vlc-android/src/org/videolan/vlc/gui/dialogs/VideoTracksDialog.kt b/application/vlc-android/src/org/videolan/vlc/gui/dialogs/VideoTracksDialog.kt
index 08c018429..603df6cbc 100644
--- a/application/vlc-android/src/org/videolan/vlc/gui/dialogs/VideoTracksDialog.kt
+++ b/application/vlc-android/src/org/videolan/vlc/gui/dialogs/VideoTracksDialog.kt
@@ -48,6 +48,7 @@ import org.videolan.vlc.R
import org.videolan.vlc.databinding.PlayerOverlayTracksBinding
import org.videolan.vlc.gui.dialogs.adapters.TrackAdapter
import org.videolan.vlc.gui.helpers.getBitmapFromDrawable
+import org.videolan.vlc.util.isTalkbackIsEnabled
class VideoTracksDialog : VLCBottomSheetDialogFragment() {
override fun getDefaultState(): Int = STATE_EXPANDED
@@ -73,22 +74,24 @@ class VideoTracksDialog : VLCBottomSheetDialogFragment() {
}
playbackService.videoTracks?.let { trackList ->
- val trackAdapter = TrackAdapter(trackList as Array<MediaPlayer.TrackDescription>, trackList.firstOrNull { it.id == playbackService.videoTrack })
+ val trackAdapter = TrackAdapter(trackList as Array<MediaPlayer.TrackDescription>, trackList.firstOrNull { it.id == playbackService.videoTrack }, getString(R.string.track_video))
trackAdapter.setOnTrackSelectedListener { track ->
trackSelectionListener.invoke(track.id, TrackType.VIDEO)
}
binding.videoTracks.trackList.adapter = trackAdapter
+ binding.videoTracks.trackTitle.contentDescription = getString(R.string.talkback_video_tracks)
}
playbackService.audioTracks?.let { trackList ->
- val trackAdapter = TrackAdapter(trackList as Array<MediaPlayer.TrackDescription>, trackList.firstOrNull { it.id == playbackService.audioTrack })
+ val trackAdapter = TrackAdapter(trackList as Array<MediaPlayer.TrackDescription>, trackList.firstOrNull { it.id == playbackService.audioTrack }, getString(R.string.track_audio))
trackAdapter.setOnTrackSelectedListener { track ->
trackSelectionListener.invoke(track.id, TrackType.AUDIO)
}
binding.audioTracks.trackList.adapter = trackAdapter
+ binding.audioTracks.trackTitle.contentDescription = getString(R.string.talkback_audio_tracks)
}
playbackService.spuTracks?.let { trackList ->
if (!playbackService.hasRenderer()) {
- val trackAdapter = TrackAdapter(trackList as Array<MediaPlayer.TrackDescription>, trackList.firstOrNull { it.id == playbackService.spuTrack })
+ val trackAdapter = TrackAdapter(trackList as Array<MediaPlayer.TrackDescription>, trackList.firstOrNull { it.id == playbackService.spuTrack }, getString(R.string.track_text))
trackAdapter.setOnTrackSelectedListener { track ->
trackSelectionListener.invoke(track.id, TrackType.SPU)
}
@@ -99,6 +102,7 @@ class VideoTracksDialog : VLCBottomSheetDialogFragment() {
binding.subtitleTracks.trackMore.setGone()
}
if (trackList.isEmpty()) binding.subtitleTracks.emptyView.setVisible()
+ binding.subtitleTracks.trackTitle.contentDescription = getString(R.string.talkback_subtitle_tracks)
}
if (playbackService.spuTracks == null) binding.subtitleTracks.emptyView.setVisible()
}
@@ -148,6 +152,17 @@ class VideoTracksDialog : VLCBottomSheetDialogFragment() {
binding.subtitleTracks.options.collapse()
}
+ if (requireActivity().isTalkbackIsEnabled()) {
+ binding.subtitleTracks.options.onReady {
+ binding.subtitleTracks.trackMore.setGone()
+ binding.subtitleTracks.options.lock()
+ }
+ binding.audioTracks.options.onReady {
+ binding.audioTracks.trackMore.setGone()
+ binding.audioTracks.options.lock()
+ }
+ }
+
binding.subtitleTracks.trackMore.setOnClickListener {
binding.subtitleTracks.options.toggle()
binding.audioTracks.options.collapse()
diff --git a/application/vlc-android/src/org/videolan/vlc/gui/dialogs/adapters/TrackAdapter.kt b/application/vlc-android/src/org/videolan/vlc/gui/dialogs/adapters/TrackAdapter.kt
index 40b9b6d55..8eeff2182 100644
--- a/application/vlc-android/src/org/videolan/vlc/gui/dialogs/adapters/TrackAdapter.kt
+++ b/application/vlc-android/src/org/videolan/vlc/gui/dialogs/adapters/TrackAdapter.kt
@@ -30,10 +30,11 @@ import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import org.videolan.libvlc.MediaPlayer
import org.videolan.tools.Settings
+import org.videolan.vlc.R
import org.videolan.vlc.databinding.VideoTrackItemBinding
import org.videolan.vlc.gui.helpers.enableMarqueeEffect
-class TrackAdapter(private val tracks: Array<MediaPlayer.TrackDescription>, var selectedTrack: MediaPlayer.TrackDescription?) : RecyclerView.Adapter<TrackAdapter.ViewHolder>() {
+class TrackAdapter(private val tracks: Array<MediaPlayer.TrackDescription>, var selectedTrack: MediaPlayer.TrackDescription?, val trackTypePrefix:String) : RecyclerView.Adapter<TrackAdapter.ViewHolder>() {
lateinit var trackSelectedListener: (MediaPlayer.TrackDescription) -> Unit
private val handler by lazy(LazyThreadSafetyMode.NONE) { Handler() }
@@ -73,6 +74,8 @@ class TrackAdapter(private val tracks: Array<MediaPlayer.TrackDescription>, var
fun bind(trackDescription: MediaPlayer.TrackDescription, selected: Boolean) {
binding.track = trackDescription
+ val context = binding.root.context
+ binding.contentDescription = context.getString(R.string.talkback_track, trackTypePrefix, if (trackDescription.id == -1) context.getString(R.string.disable_track) else trackDescription.name, if (selected) context.getString(R.string.selected) else "")
binding.selected = selected
binding.executePendingBindings()
}
diff --git a/application/vlc-android/src/org/videolan/vlc/gui/view/CollapsibleLinearLayout.kt b/application/vlc-android/src/org/videolan/vlc/gui/view/CollapsibleLinearLayout.kt
index 896fe06aa..6452f281d 100644
--- a/application/vlc-android/src/org/videolan/vlc/gui/view/CollapsibleLinearLayout.kt
+++ b/application/vlc-android/src/org/videolan/vlc/gui/view/CollapsibleLinearLayout.kt
@@ -34,6 +34,8 @@ import androidx.constraintlayout.widget.ConstraintLayout
class CollapsibleLinearLayout : LinearLayout {
+ private var locked: Boolean = false
+ private var onReadyListener: (() -> Unit)? = null
var isCollapsed = true
private var animationUpdateListener: ((Float) -> Unit)? = null
private var maxHeight: Int = -1
@@ -49,6 +51,10 @@ class CollapsibleLinearLayout : LinearLayout {
}
}
+ fun onReady(listener:() -> Unit) {
+ this.onReadyListener = listener
+ }
+
fun setAnimationUpdateListener(listener: (Float) -> Unit) {
this.animationUpdateListener = listener
}
@@ -78,11 +84,13 @@ class CollapsibleLinearLayout : LinearLayout {
viewTreeObserver.removeOnGlobalLayoutListener(this)
layoutParams.height = 0
requestLayout()
+ onReadyListener?.invoke()
}
})
}
fun toggle() {
+ if (locked) return
val fromHeight = if (!isCollapsed) maxHeight else 0
val toHeight = if (!isCollapsed) 0 else maxHeight
isCollapsed = !isCollapsed
@@ -91,8 +99,14 @@ class CollapsibleLinearLayout : LinearLayout {
}
fun collapse() {
+ if (locked) return
if (!isCollapsed) toggle()
}
+ fun lock() {
+ if (isCollapsed) toggle()
+ locked = true
+ }
+
}
\ No newline at end of file
More information about the Android
mailing list