[Android] Implement the directional key listeners for the audio players

Nicolas Pomepuy git at videolan.org
Fri Apr 4 10:12:09 UTC 2025


vlc-android | branch: master | Nicolas Pomepuy <nicolas at videolabs.io> | Thu Apr  3 09:04:14 2025 +0200| [2d75fa72131b77f984928fa0d4592c3e79ac80f1] | committer: Duncan McNamara

Implement the directional key listeners for the audio players

Fixes #3187

> https://code.videolan.org/videolan/vlc-android/commit/2d75fa72131b77f984928fa0d4592c3e79ac80f1
---

 .../ui/audioplayer/AudioPlayerActivity.kt          |  4 +--
 .../vlc/gui/AudioPlayerContainerActivity.kt        | 41 +++++++++++++++++----
 .../vlc/gui/helpers/PlayerKeyListenerDelegate.kt   | 42 ++++++++++++++++++++++
 .../videolan/vlc/gui/video/VideoPlayerActivity.kt  |  3 ++
 4 files changed, 82 insertions(+), 8 deletions(-)

diff --git a/application/television/src/main/java/org/videolan/television/ui/audioplayer/AudioPlayerActivity.kt b/application/television/src/main/java/org/videolan/television/ui/audioplayer/AudioPlayerActivity.kt
index ed41741430..12a9bb1025 100644
--- a/application/television/src/main/java/org/videolan/television/ui/audioplayer/AudioPlayerActivity.kt
+++ b/application/television/src/main/java/org/videolan/television/ui/audioplayer/AudioPlayerActivity.kt
@@ -27,7 +27,6 @@ import android.os.Build
 import android.os.Bundle
 import android.support.v4.media.session.PlaybackStateCompat
 import android.text.format.DateFormat
-import android.util.Log
 import android.view.InputDevice
 import android.view.KeyEvent
 import android.view.MotionEvent
@@ -63,7 +62,6 @@ import org.videolan.tools.Settings
 import org.videolan.tools.formatRateString
 import org.videolan.tools.setGone
 import org.videolan.tools.setVisible
-import org.videolan.vlc.BuildConfig
 import org.videolan.vlc.PlaybackService
 import org.videolan.vlc.gui.audio.EqualizerFragment
 import org.videolan.vlc.gui.dialogs.CONFIRM_BOOKMARK_RENAME_DIALOG_RESULT
@@ -287,6 +285,8 @@ class AudioPlayerActivity : BaseTvActivity(),KeycodeListener, PlaybackService.Ca
 
     override fun isReady() = true
 
+    override fun isReadyForDirectional() = true
+
     override fun showAdvancedOptions() {
         showAdvancedOptions(null)
     }
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 f3a93fb394..bfc29e31cf 100644
--- a/application/vlc-android/src/org/videolan/vlc/gui/AudioPlayerContainerActivity.kt
+++ b/application/vlc-android/src/org/videolan/vlc/gui/AudioPlayerContainerActivity.kt
@@ -26,7 +26,12 @@ package org.videolan.vlc.gui
 import android.annotation.SuppressLint
 import android.media.AudioManager
 import android.os.Bundle
-import android.view.*
+import android.view.Gravity
+import android.view.KeyEvent
+import android.view.Menu
+import android.view.MenuItem
+import android.view.View
+import android.view.ViewGroup
 import android.widget.CheckBox
 import android.widget.FrameLayout
 import android.widget.ProgressBar
@@ -39,14 +44,23 @@ import androidx.coordinatorlayout.widget.CoordinatorLayout
 import androidx.core.graphics.Insets
 import androidx.core.net.toUri
 import androidx.core.os.bundleOf
-import androidx.core.view.*
+import androidx.core.view.ViewCompat
+import androidx.core.view.WindowCompat
+import androidx.core.view.WindowInsetsCompat
+import androidx.core.view.WindowInsetsControllerCompat
+import androidx.core.view.isVisible
+import androidx.core.view.updateLayoutParams
 import androidx.fragment.app.Fragment
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.Observer
 import androidx.lifecycle.lifecycleScope
 import com.google.android.material.appbar.AppBarLayout
 import com.google.android.material.bottomnavigation.BottomNavigationView
-import com.google.android.material.bottomsheet.BottomSheetBehavior.*
+import com.google.android.material.bottomsheet.BottomSheetBehavior.BottomSheetCallback
+import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_COLLAPSED
+import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_EXPANDED
+import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_HIDDEN
+import com.google.android.material.bottomsheet.BottomSheetBehavior.from
 import com.google.android.material.navigationrail.NavigationRailView
 import com.google.android.material.snackbar.Snackbar
 import com.google.android.material.tabs.TabLayout
@@ -59,13 +73,26 @@ import org.videolan.medialibrary.interfaces.Medialibrary
 import org.videolan.resources.KEY_CURRENT_AUDIO
 import org.videolan.resources.util.getFromMl
 import org.videolan.resources.util.startMedialibrary
-import org.videolan.tools.*
-import org.videolan.vlc.*
+import org.videolan.tools.AUDIO_RESUME_PLAYBACK
+import org.videolan.tools.PREF_AUDIOPLAYER_TIPS_SHOWN
+import org.videolan.tools.Settings
+import org.videolan.tools.dp
+import org.videolan.tools.setVisibility
+import org.videolan.vlc.BuildConfig
+import org.videolan.vlc.ExternalMonitor
+import org.videolan.vlc.MediaParsingService
+import org.videolan.vlc.PlaybackService
+import org.videolan.vlc.R
+import org.videolan.vlc.VlcMigrationHelper
 import org.videolan.vlc.gui.audio.AudioPlayer
 import org.videolan.vlc.gui.audio.AudioPlaylistTipsDelegate
 import org.videolan.vlc.gui.audio.AudioTipsDelegate
 import org.videolan.vlc.gui.audio.EqualizerFragment
-import org.videolan.vlc.gui.helpers.*
+import org.videolan.vlc.gui.helpers.BottomNavigationBehavior
+import org.videolan.vlc.gui.helpers.KeycodeListener
+import org.videolan.vlc.gui.helpers.PlayerBehavior
+import org.videolan.vlc.gui.helpers.PlayerKeyListenerDelegate
+import org.videolan.vlc.gui.helpers.UiTools
 import org.videolan.vlc.gui.helpers.UiTools.isTablet
 import org.videolan.vlc.interfaces.IRefreshable
 import org.videolan.vlc.media.PlaylistManager
@@ -393,6 +420,8 @@ open class AudioPlayerContainerActivity : BaseActivity(), KeycodeListener, Sched
 
     override fun isReady() = ::audioPlayer.isInitialized
 
+    override fun isReadyForDirectional() = ::audioPlayer.isInitialized && playerBehavior.state == STATE_EXPANDED
+
     override fun showAdvancedOptions() {
         audioPlayer.showAdvancedOptions(null)
     }
diff --git a/application/vlc-android/src/org/videolan/vlc/gui/helpers/PlayerKeyListenerDelegate.kt b/application/vlc-android/src/org/videolan/vlc/gui/helpers/PlayerKeyListenerDelegate.kt
index cc27a6cad6..90494c52a1 100644
--- a/application/vlc-android/src/org/videolan/vlc/gui/helpers/PlayerKeyListenerDelegate.kt
+++ b/application/vlc-android/src/org/videolan/vlc/gui/helpers/PlayerKeyListenerDelegate.kt
@@ -67,6 +67,42 @@ class PlayerKeyListenerDelegate(private val keycodeListener: KeycodeListener) {
                 keycodeListener.seek(60000)
                 true
             }
+            KeyEvent.KEYCODE_DPAD_LEFT -> {
+                val result = if (!keycodeListener.isReadyForDirectional())
+                    false
+                else if (event.isAltPressed && event.isCtrlPressed) {
+                    keycodeListener.seek(-300000)
+                    true
+                } else if (event.isShiftPressed && event.isCtrlPressed) {
+                    keycodeListener.seek(-30000)
+                    true
+                } else if (event.isShiftPressed) {
+                    keycodeListener.seek(-5000)
+                    true
+                } else if (event.isCtrlPressed) {
+                    keycodeListener.seek(-60000)
+                    true
+                } else false
+                result
+            }
+            KeyEvent.KEYCODE_DPAD_RIGHT -> {
+                val result = if (!keycodeListener.isReadyForDirectional())
+                    false
+                else if (event.isAltPressed && event.isCtrlPressed) {
+                    keycodeListener.seek(300000)
+                    true
+                } else if (event.isShiftPressed && event.isCtrlPressed) {
+                    keycodeListener.seek(30000)
+                    true
+                } else if (event.isShiftPressed) {
+                    keycodeListener.seek(5000)
+                    true
+                } else if (event.isCtrlPressed) {
+                    keycodeListener.seek(60000)
+                    true
+                } else false
+                result
+            }
             KeyEvent.KEYCODE_BUTTON_L1 -> {
                 keycodeListener.seek(-60000)
                 true
@@ -119,6 +155,12 @@ interface KeycodeListener {
      */
     fun isReady(): Boolean
 
+    /**
+     * Get the readiness state of the callee for DPAD shortcuts. I ready, the DPAD events will be triggered
+     * @return true if the callee is ready for DPAD events
+     */
+    fun isReadyForDirectional(): Boolean
+
     /**
      * Opens the advanced options menu
      */
diff --git a/application/vlc-android/src/org/videolan/vlc/gui/video/VideoPlayerActivity.kt b/application/vlc-android/src/org/videolan/vlc/gui/video/VideoPlayerActivity.kt
index 10e67405aa..8d80ca6de8 100644
--- a/application/vlc-android/src/org/videolan/vlc/gui/video/VideoPlayerActivity.kt
+++ b/application/vlc-android/src/org/videolan/vlc/gui/video/VideoPlayerActivity.kt
@@ -1489,6 +1489,9 @@ open class VideoPlayerActivity : AppCompatActivity(), PlaybackService.Callback,
 
     override fun isReady() = true
 
+    // Directly managed here
+    override fun isReadyForDirectional() = false
+
     override fun showAdvancedOptions() {
         if (optionsDelegate == null) service?.let {
             optionsDelegate = PlayerOptionsDelegate(this, it)



More information about the Android mailing list