From fafd6343d95d35c63fcd6f8ff6c653633a454d59 Mon Sep 17 00:00:00 2001 From: Naveen Singh Date: Fri, 27 Sep 2024 16:27:04 +0530 Subject: [PATCH] Rework the mute button logic See https://github.com/FossifyOrg/Gallery/issues/171#issuecomment-2378649690 - Mute button is now completely unlinked from the system volume. The only way to unmute the player is to use the unmute button. - Mute button state is now persisted. --- .../gallery/activities/VideoPlayerActivity.kt | 31 +++++++--- .../org/fossify/gallery/extensions/Player.kt | 11 ++++ .../gallery/fragments/VideoFragment.kt | 38 +++++++----- .../org/fossify/gallery/helpers/Config.kt | 4 ++ .../org/fossify/gallery/helpers/Constants.kt | 1 + .../gallery/helpers/VolumeController.kt | 58 ------------------- 6 files changed, 62 insertions(+), 81 deletions(-) create mode 100644 app/src/main/kotlin/org/fossify/gallery/extensions/Player.kt delete mode 100644 app/src/main/kotlin/org/fossify/gallery/helpers/VolumeController.kt diff --git a/app/src/main/kotlin/org/fossify/gallery/activities/VideoPlayerActivity.kt b/app/src/main/kotlin/org/fossify/gallery/activities/VideoPlayerActivity.kt index 40332906a..ac6fe8b58 100644 --- a/app/src/main/kotlin/org/fossify/gallery/activities/VideoPlayerActivity.kt +++ b/app/src/main/kotlin/org/fossify/gallery/activities/VideoPlayerActivity.kt @@ -61,7 +61,6 @@ open class VideoPlayerActivity : SimpleActivity(), SeekBar.OnSeekBarChangeListen private var mVideoSize = Point(0, 0) private var mTimerHandler = Handler() private var mPlayWhenReadyHandler = Handler() - private var mVolumeController: VolumeController? = null private var mIgnoreCloseDown = false @@ -119,7 +118,6 @@ open class VideoPlayerActivity : SimpleActivity(), SeekBar.OnSeekBarChangeListen binding.bottomVideoTimeHolder.videoSeekbar.progress = 0 mTimerHandler.removeCallbacksAndMessages(null) mPlayWhenReadyHandler.removeCallbacksAndMessages(null) - mVolumeController?.destroy() } } @@ -189,7 +187,11 @@ open class VideoPlayerActivity : SimpleActivity(), SeekBar.OnSeekBarChangeListen binding.bottomVideoTimeHolder.videoDuration.setOnClickListener { doSkip(true) } binding.bottomVideoTimeHolder.videoTogglePlayPause.setOnClickListener { togglePlayPause() } binding.bottomVideoTimeHolder.videoPlaybackSpeed.setOnClickListener { showPlaybackSpeedPicker() } - binding.bottomVideoTimeHolder.videoToggleMute.setOnClickListener { mVolumeController?.toggleMute() } + binding.bottomVideoTimeHolder.videoToggleMute.setOnClickListener { + config.muteVideos = !config.muteVideos + updatePlayerMuteState() + } + binding.videoSurfaceFrame.setOnClickListener { toggleFullscreen() } binding.videoSurfaceFrame.controller.settings.swallowDoubleTaps = true @@ -239,12 +241,6 @@ open class VideoPlayerActivity : SimpleActivity(), SeekBar.OnSeekBarChangeListen } mDragThreshold = DRAG_THRESHOLD * resources.displayMetrics.density - mVolumeController = VolumeController(this) { isMuted -> - val icon = if (isMuted) R.drawable.ic_vector_speaker_off else R.drawable.ic_vector_speaker_on - binding.bottomVideoTimeHolder.videoToggleMute.setImageDrawable( - AppCompatResources.getDrawable(this, icon) - ) - } } private fun initExoPlayer() { @@ -285,6 +281,8 @@ open class VideoPlayerActivity : SimpleActivity(), SeekBar.OnSeekBarChangeListen prepare() initListeners() } + + updatePlayerMuteState() } private fun ExoPlayer.initListeners() { @@ -397,6 +395,21 @@ open class VideoPlayerActivity : SimpleActivity(), SeekBar.OnSeekBarChangeListen } } + private fun updatePlayerMuteState() { + val isMuted = config.muteVideos + val drawableId = if (isMuted) { + mExoPlayer?.mute() + R.drawable.ic_vector_speaker_off + } else { + mExoPlayer?.unmute() + R.drawable.ic_vector_speaker_on + } + + binding.bottomVideoTimeHolder.videoToggleMute.setImageDrawable( + AppCompatResources.getDrawable(this, drawableId) + ) + } + private fun setPosition(seconds: Int) { mExoPlayer?.seekTo(seconds * 1000L) binding.bottomVideoTimeHolder.videoSeekbar.progress = seconds diff --git a/app/src/main/kotlin/org/fossify/gallery/extensions/Player.kt b/app/src/main/kotlin/org/fossify/gallery/extensions/Player.kt new file mode 100644 index 000000000..05ea56c63 --- /dev/null +++ b/app/src/main/kotlin/org/fossify/gallery/extensions/Player.kt @@ -0,0 +1,11 @@ +package org.fossify.gallery.extensions + +import androidx.media3.common.Player + +fun Player.mute() { + volume = 0f +} + +fun Player.unmute() { + volume = 1f +} diff --git a/app/src/main/kotlin/org/fossify/gallery/fragments/VideoFragment.kt b/app/src/main/kotlin/org/fossify/gallery/fragments/VideoFragment.kt index 797acbdd2..e2045c237 100644 --- a/app/src/main/kotlin/org/fossify/gallery/fragments/VideoFragment.kt +++ b/app/src/main/kotlin/org/fossify/gallery/fragments/VideoFragment.kt @@ -34,9 +34,7 @@ import org.fossify.commons.helpers.ensureBackgroundThread import org.fossify.gallery.R import org.fossify.gallery.activities.VideoActivity import org.fossify.gallery.databinding.PagerVideoItemBinding -import org.fossify.gallery.extensions.config -import org.fossify.gallery.extensions.hasNavBar -import org.fossify.gallery.extensions.parseFileChannel +import org.fossify.gallery.extensions.* import org.fossify.gallery.helpers.* import org.fossify.gallery.interfaces.PlaybackSpeedListener import org.fossify.gallery.models.Medium @@ -87,8 +85,6 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S private lateinit var mPlayPauseButton: ImageView private lateinit var mSeekBar: SeekBar - private var mVolumeController: VolumeController? = null - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { val context = requireContext() val activity = requireActivity() @@ -103,7 +99,11 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S videoHolder.setOnClickListener { toggleFullscreen() } videoPreview.setOnClickListener { toggleFullscreen() } bottomVideoTimeHolder.videoPlaybackSpeed.setOnClickListener { showPlaybackSpeedPicker() } - bottomVideoTimeHolder.videoToggleMute.setOnClickListener { mVolumeController?.toggleMute() } + bottomVideoTimeHolder.videoToggleMute.setOnClickListener { + mConfig.muteVideos = !mConfig.muteVideos + updatePlayerMuteState() + } + videoSurfaceFrame.controller.settings.swallowDoubleTaps = true videoPlayOutline.setOnClickListener { @@ -246,13 +246,6 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S restoreLastVideoSavedPosition() } - mVolumeController = VolumeController(context) { isMuted -> - val icon = if (isMuted) R.drawable.ic_vector_speaker_off else R.drawable.ic_vector_speaker_on - binding.bottomVideoTimeHolder.videoToggleMute.setImageDrawable( - AppCompatResources.getDrawable(context, icon) - ) - } - return mView } @@ -423,6 +416,8 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S initListeners() } + + updatePlayerMuteState() } private fun ExoPlayer.initListeners() { @@ -692,6 +687,22 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S } } + private fun updatePlayerMuteState() { + val context = context ?: return + val isMuted = mConfig.muteVideos + val drawableId = if (isMuted) { + mExoPlayer?.mute() + R.drawable.ic_vector_speaker_off + } else { + mExoPlayer?.unmute() + R.drawable.ic_vector_speaker_on + } + + binding.bottomVideoTimeHolder.videoToggleMute.setImageDrawable( + AppCompatResources.getDrawable(context, drawableId) + ) + } + fun playVideo() { if (mExoPlayer == null) { initExoPlayer() @@ -822,7 +833,6 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S private fun cleanup() { pauseVideo() releaseExoPlayer() - mVolumeController?.destroy() if (mWasFragmentInit) { mCurrTimeView.text = 0.getFormattedDuration() diff --git a/app/src/main/kotlin/org/fossify/gallery/helpers/Config.kt b/app/src/main/kotlin/org/fossify/gallery/helpers/Config.kt index 6c00ede9c..e6609c575 100644 --- a/app/src/main/kotlin/org/fossify/gallery/helpers/Config.kt +++ b/app/src/main/kotlin/org/fossify/gallery/helpers/Config.kt @@ -205,6 +205,10 @@ class Config(context: Context) : BaseConfig(context) { get() = prefs.getBoolean(LOOP_VIDEOS, false) set(loop) = prefs.edit().putBoolean(LOOP_VIDEOS, loop).apply() + var muteVideos: Boolean + get() = prefs.getBoolean(MUTE_VIDEOS, false) + set(muteVideos) = prefs.edit().putBoolean(MUTE_VIDEOS, muteVideos).apply() + var openVideosOnSeparateScreen: Boolean get() = prefs.getBoolean(OPEN_VIDEOS_ON_SEPARATE_SCREEN, false) set(openVideosOnSeparateScreen) = prefs.edit().putBoolean(OPEN_VIDEOS_ON_SEPARATE_SCREEN, openVideosOnSeparateScreen).apply() diff --git a/app/src/main/kotlin/org/fossify/gallery/helpers/Constants.kt b/app/src/main/kotlin/org/fossify/gallery/helpers/Constants.kt index f47f847c0..70c03b259 100644 --- a/app/src/main/kotlin/org/fossify/gallery/helpers/Constants.kt +++ b/app/src/main/kotlin/org/fossify/gallery/helpers/Constants.kt @@ -16,6 +16,7 @@ const val IS_THIRD_PARTY_INTENT = "is_third_party_intent" const val AUTOPLAY_VIDEOS = "autoplay_videos" const val REMEMBER_LAST_VIDEO_POSITION = "remember_last_video_position" const val LOOP_VIDEOS = "loop_videos" +const val MUTE_VIDEOS = "mute_videos" const val OPEN_VIDEOS_ON_SEPARATE_SCREEN = "open_videos_on_separate_screen" const val ANIMATE_GIFS = "animate_gifs" const val MAX_BRIGHTNESS = "max_brightness" diff --git a/app/src/main/kotlin/org/fossify/gallery/helpers/VolumeController.kt b/app/src/main/kotlin/org/fossify/gallery/helpers/VolumeController.kt deleted file mode 100644 index 3066b5fdf..000000000 --- a/app/src/main/kotlin/org/fossify/gallery/helpers/VolumeController.kt +++ /dev/null @@ -1,58 +0,0 @@ -package org.fossify.gallery.helpers - -import android.content.Context -import android.database.ContentObserver -import android.media.AudioManager -import android.os.Handler -import android.os.Looper -import android.provider.Settings -import org.fossify.gallery.extensions.audioManager - -class VolumeController( - private val context: Context, - private val streamType: Int = AudioManager.STREAM_MUSIC, - private val onVolumeChanged: (isMuted: Boolean) -> Unit -) { - private var audioManager = context.audioManager - private var savedVolume = audioManager.getStreamMaxVolume(streamType) - - private val currentVolume: Int - get() = audioManager.getStreamVolume(streamType) - - private val volumeObserver = object : ContentObserver(Handler(Looper.getMainLooper())) { - override fun onChange(selfChange: Boolean) { - super.onChange(selfChange) - onVolumeChanged(isMuted()) - } - } - - init { - context.contentResolver.registerContentObserver(Settings.System.CONTENT_URI, true, volumeObserver) - onVolumeChanged(isMuted()) - } - - private fun isMuted() = currentVolume == 0 - - private fun mute() { - savedVolume = audioManager.getStreamVolume(streamType) - audioManager.setStreamVolume(streamType, 0, 0) - } - - private fun unmute() { - audioManager.setStreamVolume(streamType, savedVolume, 0) - } - - fun toggleMute() { - if (isMuted()) { - unmute() - onVolumeChanged(false) - } else { - mute() - onVolumeChanged(true) - } - } - - fun destroy() { - context.contentResolver.unregisterContentObserver(volumeObserver) - } -}