From 0691b100ebf20b6294d14b737d2a43324f55f464 Mon Sep 17 00:00:00 2001
From: Nicolas Pomepuy <nicolas@videolabs.io>
Date: Wed, 1 Jun 2022 09:23:34 +0200
Subject: [PATCH] Accessibility: improve talkback for the audio player

---
 .../resources/src/main/res/values/strings.xml |  9 ++-
 .../res/layout-land/audio_player.xml          | 15 +++-
 .../layout-land/cover_media_switcher_item.xml |  3 +
 .../cover_media_switcher_item.xml             |  2 +
 .../vlc-android/res/layout/audio_player.xml   | 10 ++-
 .../res/layout/cover_media_switcher_item.xml  |  3 +
 .../vlc-android/res/layout/playlist_item.xml  |  4 +
 .../vlc/gui/AudioPlayerContainerActivity.kt   |  8 ++
 .../org/videolan/vlc/gui/audio/AudioPlayer.kt | 77 +++++++++++++------
 9 files changed, 101 insertions(+), 30 deletions(-)

diff --git a/application/resources/src/main/res/values/strings.xml b/application/resources/src/main/res/values/strings.xml
index e29f7236fb..eaea750f07 100644
--- a/application/resources/src/main/res/values/strings.xml
+++ b/application/resources/src/main/res/values/strings.xml
@@ -1014,10 +1014,17 @@
     <string name="talkback_decrease_speed">Decrease speed</string>
     <string name="talkback_subtitle_history">Subtitle history</string>
     <string name="talkback_language_selection">%s selected languages</string>
+    <string name="talkback_audio_player_opened">Audio player opened</string>
+    <string name="talkback_audio_player_collapsed">Audio player collapsed</string>
+    <string name="talkback_audio_player_closed">Audio player closed</string>
+    <string name="talkback_audio_player">Audio player. Currently playing: %s</string>
+    <string name="talkback_out_of">%s out of %s</string>
+    <string name="talkback_track_index">Track %s out of %s</string>
     <string name="downloaded">Downloaded</string>
     <string name="not_downloaded">Not downloaded</string>
     <string name="downloading">Downloading</string>
-    <string name="talkback_out_of">%s out of %s</string>
+    <string name="talkback_action_rewind">Rewind %s seconds</string>
+    <string name="talkback_action_forward">Seek forward %s seconds</string>
 
 
 </resources>
diff --git a/application/vlc-android/res/layout-land/audio_player.xml b/application/vlc-android/res/layout-land/audio_player.xml
index e39fbaed9d..00751a1773 100644
--- a/application/vlc-android/res/layout-land/audio_player.xml
+++ b/application/vlc-android/res/layout-land/audio_player.xml
@@ -31,6 +31,7 @@
             android:background="?attr/background_default_darker"
             android:clickable="true"
             android:focusable="true"
+            android:importantForAccessibility="no"
             android:keyboardNavigationCluster="true"
             tools:targetApi="o">
 
@@ -88,6 +89,7 @@
                 android:layoutDirection="ltr"
                 android:maxHeight="4dp"
                 android:minHeight="4dp"
+                android:importantForAccessibility="no"
                 android:paddingLeft="0px"
                 android:paddingRight="0px"
                 android:progressDrawable="?attr/progress_mini_player"
@@ -433,6 +435,7 @@
                 android:background="?attr/audio_list_background"
                 android:clipToPadding="false"
                 android:paddingBottom="@dimen/listview_bottom_padding"
+                android:importantForAccessibility="no"
                 app:layout_constraintBottom_toBottomOf="@id/timeline"
                 app:layout_constraintEnd_toEndOf="parent"
                 app:layout_constraintTop_toBottomOf="@+id/header"
@@ -462,6 +465,7 @@
                     android:textColor="?attr/font_default"
                     android:ellipsize="marquee"
                     android:marqueeRepeatLimit="1"
+                android:importantForAccessibility="no"
                     android:singleLine="true"
                     android:textSize="24sp"
                     app:layout_constraintVertical_chainStyle="packed"
@@ -482,6 +486,7 @@
                     app:layout_goneMarginBottom="16dp"
                     android:ellipsize="marquee"
                     android:marqueeRepeatLimit="1"
+                android:importantForAccessibility="no"
                     android:singleLine="true"
                     android:maxLines="1"
                     android:textColor="?attr/font_audio_light"
@@ -498,6 +503,7 @@
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
                     android:layout_marginStart="24dp"
+                android:importantForAccessibility="no"
                     android:layout_marginEnd="24dp"
                     android:layout_marginBottom="16dp"
                     android:maxLines="1"
@@ -519,7 +525,6 @@
                     android:layout_marginEnd="8dp"
                     android:background="?attr/actionBarItemBackground"
                     android:clickable="true"
-                    android:contentDescription="@string/air_action_rewind"
                     android:focusable="true"
                     android:padding="8dp"
                     android:onClick="@{fragment::onJumpBack}"
@@ -536,6 +541,7 @@
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
                     android:textColor="?attr/player_icon_color"
+                    android:importantForAccessibility="no"
                     android:textSize="8dp"
                     android:textStyle="bold"
                     app:layout_constraintBottom_toBottomOf="@+id/audio_rewind_10"
@@ -552,7 +558,6 @@
                     android:layout_marginStart="8dp"
                     android:background="?attr/actionBarItemBackground"
                     android:clickable="true"
-                    android:contentDescription="@string/air_action_forward"
                     android:focusable="true"
                     android:padding="8dp"
                     android:onClick="@{fragment::onJumpForward}"
@@ -569,6 +574,7 @@
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
                     android:textColor="?attr/player_icon_color"
+                    android:importantForAccessibility="no"
                     android:textSize="8dp"
                     android:textStyle="bold"
                     app:layout_constraintBottom_toBottomOf="@+id/audio_forward_10"
@@ -590,6 +596,7 @@
                 android:ellipsize="middle"
                 android:maxLines="1"
                 android:paddingStart="16dp"
+                android:accessibilityLiveRegion="none"
                 android:paddingTop="8dp"
                 android:paddingEnd="16dp"
                 android:paddingBottom="8dp"
@@ -628,13 +635,14 @@
                 android:elevation="4dp"
                 android:focusable="true"
                 android:onClick="@{fragment::onTimeLabelClick}"
+                android:importantForAccessibility="no"
                 android:text="@string/time_0"
                 android:textColor="?attr/font_default"
                 android:textSize="12sp"
                 app:layout_constraintBottom_toTopOf="@+id/timeline"
                 app:layout_constraintStart_toStartOf="@+id/timeline" />
 
-        <SeekBar
+        <org.videolan.vlc.gui.view.AccessibleSeekBar
                 android:id="@+id/timeline"
                 android:layout_width="0dp"
                 android:layout_height="wrap_content"
@@ -658,6 +666,7 @@
                 android:layout_gravity="center|end"
                 android:layout_marginEnd="8dp"
                 android:contentDescription="@string/length"
+                android:importantForAccessibility="no"
                 android:elevation="4dp"
                 android:text="@string/time_0"
                 android:textColor="?attr/font_default"
diff --git a/application/vlc-android/res/layout-land/cover_media_switcher_item.xml b/application/vlc-android/res/layout-land/cover_media_switcher_item.xml
index 4e3a9fa24c..ee7729814d 100644
--- a/application/vlc-android/res/layout-land/cover_media_switcher_item.xml
+++ b/application/vlc-android/res/layout-land/cover_media_switcher_item.xml
@@ -69,6 +69,7 @@
                 android:fontFamily="sans-serif-light"
                 android:maxLines="1"
                 android:singleLine="true"
+                android:importantForAccessibility="no"
                 android:textColor="?attr/font_default"
                 android:textSize="24sp"
                 app:layout_constrainedWidth="true"
@@ -85,6 +86,7 @@
                 android:layout_marginStart="24dp"
                 android:layout_marginTop="8dp"
                 android:layout_marginEnd="24dp"
+                android:importantForAccessibility="no"
                 android:maxLines="1"
                 android:singleLine="true"
                 android:textColor="?attr/font_audio_light"
@@ -106,6 +108,7 @@
                 android:layout_marginBottom="32dp"
                 android:maxLines="1"
                 android:textColor="?attr/font_audio_light"
+                android:importantForAccessibility="no"
                 android:textSize="12sp"
                 android:visibility="gone"
                 app:layout_constrainedWidth="true"
diff --git a/application/vlc-android/res/layout-large-land/cover_media_switcher_item.xml b/application/vlc-android/res/layout-large-land/cover_media_switcher_item.xml
index 94988791e5..74c959c307 100644
--- a/application/vlc-android/res/layout-large-land/cover_media_switcher_item.xml
+++ b/application/vlc-android/res/layout-large-land/cover_media_switcher_item.xml
@@ -70,6 +70,7 @@
             android:layout_marginTop="24dp"
             android:layout_marginEnd="24dp"
             android:fontFamily="sans-serif-light"
+                android:importantForAccessibility="no"
             android:maxLines="1"
             android:textColor="?attr/font_default"
             android:textSize="24sp"
@@ -90,6 +91,7 @@
             android:layout_marginEnd="24dp"
             android:maxLines="1"
             android:textColor="?attr/font_audio_light"
+                android:importantForAccessibility="no"
             android:textSize="14sp"
             android:visibility="gone"
             app:layout_constrainedWidth="true"
diff --git a/application/vlc-android/res/layout/audio_player.xml b/application/vlc-android/res/layout/audio_player.xml
index 16ff57e1c7..fe12d64a52 100644
--- a/application/vlc-android/res/layout/audio_player.xml
+++ b/application/vlc-android/res/layout/audio_player.xml
@@ -31,6 +31,7 @@
             android:background="?attr/bottom_navigation_background"
             android:clickable="true"
             android:focusable="true"
+            android:importantForAccessibility="no"
             android:keyboardNavigationCluster="true"
             tools:targetApi="o">
 
@@ -80,6 +81,7 @@
                 android:maxHeight="4dp"
                 android:minHeight="4dp"
                 android:paddingLeft="0px"
+                android:importantForAccessibility="no"
                 android:paddingRight="0px"
                 android:progressDrawable="?attr/progress_mini_player"
                 app:layout_constraintLeft_toLeftOf="parent"
@@ -421,6 +423,7 @@
                 android:clipToPadding="false"
                 android:maxWidth="800dp"
                 android:paddingBottom="68dp"
+                android:importantForAccessibility="no"
                 app:layout_constraintBottom_toTopOf="@+id/songs_list_guide"
                 app:layout_constraintLeft_toLeftOf="parent"
                 app:layout_constraintRight_toRightOf="parent"
@@ -443,6 +446,7 @@
                 android:background="?attr/audio_chip_background"
                 android:elevation="4dp"
                 android:paddingStart="16dp"
+                android:accessibilityLiveRegion="none"
                 android:paddingTop="8dp"
                 android:paddingEnd="16dp"
                 android:paddingBottom="8dp"
@@ -476,7 +480,6 @@
                 android:layout_marginBottom="24dp"
                 android:background="?attr/actionBarItemBackground"
                 android:clickable="true"
-                android:contentDescription="@string/air_action_rewind"
                 android:focusable="true"
                 android:padding="8dp"
                 android:visibility="gone"
@@ -511,7 +514,6 @@
                 android:layout_marginStart="8dp"
                 android:background="?attr/actionBarItemBackground"
                 android:clickable="true"
-                android:contentDescription="@string/air_action_forward"
                 android:focusable="true"
                 android:padding="8dp"
                 android:visibility="gone"
@@ -550,6 +552,7 @@
                 android:clickable="true"
                 android:elevation="4dp"
                 android:focusable="true"
+                android:importantForAccessibility="no"
                 android:onClick="@{fragment::onTimeLabelClick}"
                 android:text="@string/time_0"
                 android:textColor="?attr/font_default"
@@ -567,7 +570,7 @@
                 app:layout_constraintStart_toStartOf="parent"
                 app:layout_constraintTop_toTopOf="@id/timeline" />
 
-        <SeekBar
+        <org.videolan.vlc.gui.view.AccessibleSeekBar
                 android:id="@+id/timeline"
                 android:layout_width="0dp"
                 android:layout_height="wrap_content"
@@ -591,6 +594,7 @@
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_gravity="center|end"
+                android:importantForAccessibility="no"
                 android:layout_marginEnd="@dimen/default_margin"
                 android:background="?attr/selectableItemBackgroundBorderless"
                 android:contentDescription="@string/length"
diff --git a/application/vlc-android/res/layout/cover_media_switcher_item.xml b/application/vlc-android/res/layout/cover_media_switcher_item.xml
index 809f5a562f..cc1c338673 100644
--- a/application/vlc-android/res/layout/cover_media_switcher_item.xml
+++ b/application/vlc-android/res/layout/cover_media_switcher_item.xml
@@ -68,6 +68,7 @@
                 android:layout_marginTop="24dp"
                 android:layout_marginEnd="24dp"
                 android:fontFamily="sans-serif-light"
+                android:importantForAccessibility="no"
                 android:maxLines="1"
                 android:singleLine="true"
                 android:textColor="?attr/font_default"
@@ -87,6 +88,7 @@
                 android:layout_marginTop="8dp"
                 android:layout_marginEnd="24dp"
                 android:maxLines="1"
+                android:importantForAccessibility="no"
                 android:singleLine="true"
                 android:textColor="?attr/font_audio_light"
                 android:textSize="14sp"
@@ -106,6 +108,7 @@
                 android:layout_marginTop="8dp"
                 android:layout_marginEnd="24dp"
                 android:layout_marginBottom="32dp"
+                android:importantForAccessibility="no"
                 android:maxLines="1"
                 android:singleLine="true"
                 android:textColor="?attr/font_audio_light"
diff --git a/application/vlc-android/res/layout/playlist_item.xml b/application/vlc-android/res/layout/playlist_item.xml
index 02ecc91ac1..426dda9fe4 100644
--- a/application/vlc-android/res/layout/playlist_item.xml
+++ b/application/vlc-android/res/layout/playlist_item.xml
@@ -58,6 +58,7 @@
                 android:orientation="vertical"
                 android:paddingTop="4dp"
                 android:paddingBottom="4dp"
+                app:mediaContentDescription="@{media}"
                 app:layout_constraintBottom_toBottomOf="parent"
                 app:layout_constraintEnd_toStartOf="@+id/item_move_up"
                 app:layout_constraintStart_toStartOf="parent"
@@ -108,6 +109,7 @@
                 android:singleLine="true"
                 android:text="@{media.title}"
                 android:textColor="?attr/font_default"
+                android:importantForAccessibility="no"
                 android:textSize="16sp"
                 app:ellipsizeMode="@{true}"
                 app:layout_constraintBottom_toTopOf="@+id/audio_item_subtitle"
@@ -129,6 +131,7 @@
                 android:ellipsize="middle"
                 android:fontFamily="sans-serif"
                 android:paddingLeft="8dp"
+                android:importantForAccessibility="no"
                 android:paddingRight="8dp"
                 android:singleLine="true"
                 android:text="@{subTitle}"
@@ -150,6 +153,7 @@
                 android:layout_centerVertical="true"
                 android:layout_gravity="center"
                 android:layout_marginRight="4dp"
+                android:contentDescription="@string/more_actions"
                 android:padding="8dp"
                 android:background="?attr/selectableItemBackgroundBorderless"
                 android:onClick="@{holder::onMoreClick}"
diff --git a/application/vlc-android/src/org/videolan/vlc/gui/AudioPlayerContainerActivity.kt b/application/vlc-android/src/org/videolan/vlc/gui/AudioPlayerContainerActivity.kt
index 3fa5aa17b0..4c7679b305 100644
--- a/application/vlc-android/src/org/videolan/vlc/gui/AudioPlayerContainerActivity.kt
+++ b/application/vlc-android/src/org/videolan/vlc/gui/AudioPlayerContainerActivity.kt
@@ -62,6 +62,7 @@ import org.videolan.vlc.gui.helpers.*
 import org.videolan.vlc.gui.helpers.UiTools.isTablet
 import org.videolan.vlc.interfaces.IRefreshable
 import org.videolan.vlc.media.PlaylistManager
+import org.videolan.vlc.util.isTalkbackIsEnabled
 import kotlin.math.max
 import kotlin.math.min
 
@@ -246,6 +247,13 @@ open class AudioPlayerContainerActivity : BaseActivity(), KeycodeListener {
                 updateFragmentMargins(newState)
                 applyMarginToProgressBar(playerBehavior.peekHeight)
                 setContentBottomPadding()
+                if (isTalkbackIsEnabled()) {
+                    when (playerBehavior.state) {
+                        STATE_EXPANDED -> audioPlayerContainer.announceForAccessibility(getString(R.string.talkback_audio_player_opened))
+                        STATE_COLLAPSED -> audioPlayerContainer.announceForAccessibility(getString(R.string.talkback_audio_player_collapsed))
+                        STATE_HIDDEN -> audioPlayerContainer.announceForAccessibility(getString(R.string.talkback_audio_player_closed))
+                    }
+                }
             }
         })
         showTipViewIfNeeded(R.id.audio_player_tips, PREF_AUDIOPLAYER_TIPS_SHOWN)
diff --git a/application/vlc-android/src/org/videolan/vlc/gui/audio/AudioPlayer.kt b/application/vlc-android/src/org/videolan/vlc/gui/audio/AudioPlayer.kt
index bfae0de879..314deabd88 100644
--- a/application/vlc-android/src/org/videolan/vlc/gui/audio/AudioPlayer.kt
+++ b/application/vlc-android/src/org/videolan/vlc/gui/audio/AudioPlayer.kt
@@ -66,11 +66,8 @@ import org.videolan.vlc.gui.dialogs.CtxActionReceiver
 import org.videolan.vlc.gui.dialogs.PlaybackSpeedDialog
 import org.videolan.vlc.gui.dialogs.SleepTimerDialog
 import org.videolan.vlc.gui.dialogs.showContext
+import org.videolan.vlc.gui.helpers.*
 import org.videolan.vlc.gui.helpers.AudioUtil.setRingtone
-import org.videolan.vlc.gui.helpers.BookmarkListDelegate
-import org.videolan.vlc.gui.helpers.PlayerOptionsDelegate
-import org.videolan.vlc.gui.helpers.SwipeDragItemTouchHelperCallback
-import org.videolan.vlc.gui.helpers.UiTools
 import org.videolan.vlc.gui.helpers.UiTools.addToPlaylist
 import org.videolan.vlc.gui.helpers.UiTools.isTablet
 import org.videolan.vlc.gui.video.VideoPlayerActivity
@@ -319,6 +316,10 @@ class AudioPlayer : Fragment(), PlaylistAdapter.IPlayer, TextWatcher, IAudioPlay
         updateRepeatMode()
         binding.audioMediaSwitcher.updateMedia(playlistModel.service)
         binding.coverMediaSwitcher.updateMedia(playlistModel.service)
+        playlistModel.service?.currentMediaWrapper?.let {
+            binding.audioMediaSwitcher.contentDescription = getString(R.string.talkback_audio_player,TalkbackUtil.getAudioTrack(requireActivity(), it))
+            binding.trackInfoContainer?.contentDescription = getString(R.string.talkback_audio_player,TalkbackUtil.getAudioTrack(requireActivity(), it))
+        }
 
         val chapter = playlistModel.service?.getCurrentChapter(true)
         binding.songTitle?.text = if (!chapter.isNullOrEmpty()) chapter else  playlistModel.title
@@ -331,6 +332,8 @@ class AudioPlayer : Fragment(), PlaylistAdapter.IPlayer, TextWatcher, IAudioPlay
 
         binding.audioRewindText.text = "${Settings.audioJumpDelay}"
         binding.audioForwardText.text = "${Settings.audioJumpDelay}"
+        binding.audioForward10.contentDescription = getString(R.string.talkback_action_forward, Settings.audioJumpDelay.toString())
+        binding.audioRewind10.contentDescription = getString(R.string.talkback_action_rewind, Settings.audioJumpDelay.toString())
         updateBackground()
     }
 
@@ -398,6 +401,12 @@ class AudioPlayer : Fragment(), PlaylistAdapter.IPlayer, TextWatcher, IAudioPlay
         previousRepeatType = repeatType
     }
 
+    /**
+     * Updates the text views in the player with the current progress
+     * It includes the time, the length and the progress pill text and content description
+     *
+     * @param progress the progress to be displayed
+     */
     private fun updateProgress(progress: PlaybackProgress) {
         if (playlistModel.currentMediaPosition == -1) return
         binding.length.text = progress.lengthText
@@ -413,42 +422,63 @@ class AudioPlayer : Fragment(), PlaylistAdapter.IPlayer, TextWatcher, IAudioPlay
         }
 
         lifecycleScope.launchWhenStarted {
-            val text = withContext(Dispatchers.Default) {
-                val medias = playlistModel.medias ?: return@withContext ""
+            val text:Pair<String, String> = withContext(Dispatchers.Default) {
+                val medias = playlistModel.medias ?: return@withContext Pair("", "")
                 withContext(Dispatchers.Main) { if (!shouldHidePlayProgress()) binding.audioPlayProgress.setVisible() else binding.audioPlayProgress.setGone() }
-                if (playlistModel.currentMediaPosition == -1) return@withContext ""
-                val elapsedTracksTime = playlistModel.previousTotalTime ?: return@withContext ""
+                if (playlistModel.currentMediaPosition == -1) return@withContext Pair("", "")
+                val elapsedTracksTime = playlistModel.previousTotalTime ?: return@withContext Pair("", "")
                 val progressTime = elapsedTracksTime + progress.time
                 val totalTime = playlistModel.getTotalTime()
                 val progressTimeText = Tools.millisToString(
-                    if (showRemainingTime && totalTime > 0) totalTime - progressTime else progressTime,
-                    false,
-                    true,
-                    false
+                        if (showRemainingTime && totalTime > 0) totalTime - progressTime else progressTime,
+                        false,
+                        true,
+                        false
                 )
                 val totalTimeText = Tools.millisToString(totalTime, false, false, false)
+                val totalTimeDescription = TalkbackUtil.millisToString(requireActivity(), totalTime)
+                val progressTimeDescription =  TalkbackUtil.millisToString(requireActivity(), if (showRemainingTime && totalTime > 0) totalTime - progressTime else progressTime)
                 val currentProgressText = if (progressTimeText.isNullOrEmpty()) "0:00" else progressTimeText
 
                 val textTrack = getString(R.string.track_index, "${playlistModel.currentMediaPosition + 1} / ${medias.size}")
+                val textTrackDescription = getString(R.string.talkback_track_index, "${playlistModel.currentMediaPosition + 1}", "${medias.size}")
 
                 val textProgress = if (audioPlayProgressMode) {
                     val endsAt = System.currentTimeMillis() + totalTime - progressTime
                     if ((lastEndsAt - endsAt).absoluteValue > 1) lastEndsAt = endsAt
                     getString(
-                        R.string.audio_queue_progress_finished,
-                        getTimeInstance(java.text.DateFormat.MEDIUM).format(lastEndsAt)
+                            R.string.audio_queue_progress_finished,
+                            getTimeInstance(java.text.DateFormat.MEDIUM).format(lastEndsAt)
                     )
-                } else if (showRemainingTime && totalTime > 0) getString(
-                    R.string.audio_queue_progress_remaining,
-                        currentProgressText
-                )
-                else getString(
-                        R.string.audio_queue_progress,
-                        if (totalTimeText.isNullOrEmpty()) currentProgressText else "$currentProgressText / $totalTimeText"
+                } else
+                    if (showRemainingTime && totalTime > 0) getString(
+                            R.string.audio_queue_progress_remaining,
+                            currentProgressText
+                    )
+                    else getString(
+                            R.string.audio_queue_progress,
+                            if (totalTimeText.isNullOrEmpty()) currentProgressText else "$currentProgressText / $totalTimeText"
+                    )
+                val textDescription = if (audioPlayProgressMode) {
+                    val endsAt = System.currentTimeMillis() + totalTime - progressTime
+                    if ((lastEndsAt - endsAt).absoluteValue > 1) lastEndsAt = endsAt
+                    getString(
+                            R.string.audio_queue_progress_finished,
+                            getTimeInstance(java.text.DateFormat.MEDIUM).format(lastEndsAt)
+                    )
+                } else
+                    if (showRemainingTime && totalTime > 0) getString(
+                            R.string.audio_queue_progress_remaining,
+                            progressTimeDescription
+                    )
+                    else getString(
+                            R.string.audio_queue_progress,
+                            if (totalTimeText.isNullOrEmpty()) progressTimeDescription else getString(R.string.talkback_out_of, progressTimeDescription, totalTimeDescription)
                     )
-                "$textTrack  •  $textProgress"
+                Pair("$textTrack  ${TextUtils.separator}  $textProgress", "$textTrackDescription. $textDescription")
             }
-            binding.audioPlayProgress.text = text
+            binding.audioPlayProgress.text = text.first
+            binding.audioPlayProgress.contentDescription = text.second
         }
     }
 
@@ -743,6 +773,7 @@ class AudioPlayer : Fragment(), PlaylistAdapter.IPlayer, TextWatcher, IAudioPlay
                 playlistModel.setTime(progress.toLong(), true)
                 binding.time.text = Tools.millisToString(if (showRemainingTime) progress - playlistModel.length else progress.toLong())
                 binding.headerTime.text = Tools.millisToString(progress.toLong())
+                binding.timeline.forceAccessibilityUpdate()
             }
         }
     }
-- 
GitLab