From c3f5a3900741a5d60b169bea491585662bf8779d Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 2 Apr 2021 15:43:29 +0200 Subject: [PATCH] Added audio file viewer --- .../org/linphone/activities/Navigation.kt | 2 +- .../files/adapters/PdfPagesListAdapter.kt | 8 +- .../files/fragments/AudioViewerFragment.kt | 106 ++++++++++++++++++ .../files/fragments/ImageViewerFragment.kt | 6 +- .../main/files/fragments/PdfViewerFragment.kt | 6 +- .../files/fragments/TextViewerFragment.kt | 6 +- .../files/fragments/VideoViewerFragment.kt | 23 +++- .../files/viewmodels/AudioFileViewModel.kt | 101 +++++++++++++++++ .../res/layout/file_audio_viewer_fragment.xml | 33 ++++++ ...ent.xml => file_image_viewer_fragment.xml} | 0 ...ewer_cell.xml => file_pdf_viewer_cell.xml} | 0 ...gment.xml => file_pdf_viewer_fragment.xml} | 0 ...ment.xml => file_text_viewer_fragment.xml} | 0 ...ent.xml => file_video_viewer_fragment.xml} | 0 .../main/res/navigation/main_nav_graph.xml | 5 + 15 files changed, 276 insertions(+), 20 deletions(-) create mode 100644 app/src/main/java/org/linphone/activities/main/files/fragments/AudioViewerFragment.kt create mode 100644 app/src/main/java/org/linphone/activities/main/files/viewmodels/AudioFileViewModel.kt create mode 100644 app/src/main/res/layout/file_audio_viewer_fragment.xml rename app/src/main/res/layout/{image_viewer_fragment.xml => file_image_viewer_fragment.xml} (100%) rename app/src/main/res/layout/{pdf_viewer_cell.xml => file_pdf_viewer_cell.xml} (100%) rename app/src/main/res/layout/{pdf_viewer_fragment.xml => file_pdf_viewer_fragment.xml} (100%) rename app/src/main/res/layout/{text_viewer_fragment.xml => file_text_viewer_fragment.xml} (100%) rename app/src/main/res/layout/{video_viewer_fragment.xml => file_video_viewer_fragment.xml} (100%) diff --git a/app/src/main/java/org/linphone/activities/Navigation.kt b/app/src/main/java/org/linphone/activities/Navigation.kt index dfea6eceb..74d85ba7a 100644 --- a/app/src/main/java/org/linphone/activities/Navigation.kt +++ b/app/src/main/java/org/linphone/activities/Navigation.kt @@ -387,7 +387,7 @@ internal fun DetailChatRoomFragment.navigateToVideoFileViewer(secure: Boolean) { internal fun DetailChatRoomFragment.navigateToAudioFileViewer(secure: Boolean) { val bundle = bundleOf("Secure" to secure) findMasterNavController().navigate( - R.id.action_global_videoViewerFragment, + R.id.action_global_audioViewerFragment, bundle, getRightToLeftAnimationNavOptions() ) diff --git a/app/src/main/java/org/linphone/activities/main/files/adapters/PdfPagesListAdapter.kt b/app/src/main/java/org/linphone/activities/main/files/adapters/PdfPagesListAdapter.kt index dae37b53a..6271e131f 100644 --- a/app/src/main/java/org/linphone/activities/main/files/adapters/PdfPagesListAdapter.kt +++ b/app/src/main/java/org/linphone/activities/main/files/adapters/PdfPagesListAdapter.kt @@ -25,13 +25,13 @@ import androidx.databinding.DataBindingUtil import androidx.recyclerview.widget.RecyclerView import org.linphone.R import org.linphone.activities.main.files.viewmodels.PdfFileViewModel -import org.linphone.databinding.PdfViewerCellBinding +import org.linphone.databinding.FilePdfViewerCellBinding class PdfPagesListAdapter(private val pdfViewModel: PdfFileViewModel) : RecyclerView.Adapter() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PdfPageViewHolder { - val binding: PdfViewerCellBinding = DataBindingUtil.inflate( + val binding: FilePdfViewerCellBinding = DataBindingUtil.inflate( LayoutInflater.from(parent.context), - R.layout.pdf_viewer_cell, parent, false + R.layout.file_pdf_viewer_cell, parent, false ) return PdfPageViewHolder(binding) } @@ -44,7 +44,7 @@ class PdfPagesListAdapter(private val pdfViewModel: PdfFileViewModel) : Recycler holder.bind(position) } - inner class PdfPageViewHolder(private val binding: PdfViewerCellBinding) : RecyclerView.ViewHolder(binding.root) { + inner class PdfPageViewHolder(private val binding: FilePdfViewerCellBinding) : RecyclerView.ViewHolder(binding.root) { fun bind(index: Int) { with(binding) { pdfViewModel.loadPdfPageInto(index, pdfImage) diff --git a/app/src/main/java/org/linphone/activities/main/files/fragments/AudioViewerFragment.kt b/app/src/main/java/org/linphone/activities/main/files/fragments/AudioViewerFragment.kt new file mode 100644 index 000000000..7ee45d360 --- /dev/null +++ b/app/src/main/java/org/linphone/activities/main/files/fragments/AudioViewerFragment.kt @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2010-2021 Belledonne Communications SARL. + * + * This file is part of linphone-android + * (see https://www.linphone.org). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.linphone.activities.main.files.fragments + +import android.annotation.SuppressLint +import android.os.Bundle +import android.view.KeyEvent +import android.widget.MediaController +import androidx.lifecycle.ViewModelProvider +import androidx.navigation.fragment.findNavController +import org.linphone.R +import org.linphone.activities.main.files.viewmodels.AudioFileViewModel +import org.linphone.activities.main.files.viewmodels.AudioFileViewModelFactory +import org.linphone.activities.main.fragments.SecureFragment +import org.linphone.activities.main.viewmodels.SharedMainViewModel +import org.linphone.databinding.FileAudioViewerFragmentBinding + +class AudioViewerFragment : SecureFragment() { + private lateinit var viewModel: AudioFileViewModel + private lateinit var sharedViewModel: SharedMainViewModel + + private lateinit var mediaController: MediaController + + override fun getLayoutId(): Int = R.layout.file_audio_viewer_fragment + + @SuppressLint("ClickableViewAccessibility") + override fun onActivityCreated(savedInstanceState: Bundle?) { + super.onActivityCreated(savedInstanceState) + + binding.lifecycleOwner = this + + sharedViewModel = requireActivity().run { + ViewModelProvider(this).get(SharedMainViewModel::class.java) + } + + val content = sharedViewModel.contentToOpen.value + content ?: return + val filePath = content.filePath + filePath ?: return + + (childFragmentManager.findFragmentById(R.id.top_bar_fragment) as? TopBarFragment) + ?.setContent(content) + + viewModel = ViewModelProvider( + this, + AudioFileViewModelFactory(filePath) + )[AudioFileViewModel::class.java] + binding.viewModel = viewModel + + isSecure = arguments?.getBoolean("Secure") ?: false + + mediaController = object : MediaController(requireContext()) { + // This hack is even if media controller is showed with timeout=0 + // Once a control is touched, it will disappear 3 seconds later anyway + override fun show(timeout: Int) { + super.show(0) + } + + // This is to prevent the first back key press to only hide to media controls + override fun dispatchKeyEvent(event: KeyEvent?): Boolean { + if (event?.keyCode == KeyEvent.KEYCODE_BACK) { + findNavController().popBackStack() + return true + } + return super.dispatchKeyEvent(event) + } + } + mediaController.setMediaPlayer(viewModel) + + viewModel.mediaPlayer.setOnPreparedListener { + mediaController.setAnchorView(binding.anchor) + // This will make the controls visible forever + mediaController.show(0) + } + } + + override fun onPause() { + mediaController.hide() + viewModel.mediaPlayer.pause() + + super.onPause() + } + + override fun onResume() { + super.onResume() + + mediaController.show(0) + } +} diff --git a/app/src/main/java/org/linphone/activities/main/files/fragments/ImageViewerFragment.kt b/app/src/main/java/org/linphone/activities/main/files/fragments/ImageViewerFragment.kt index b257e8755..0c0630765 100644 --- a/app/src/main/java/org/linphone/activities/main/files/fragments/ImageViewerFragment.kt +++ b/app/src/main/java/org/linphone/activities/main/files/fragments/ImageViewerFragment.kt @@ -27,13 +27,13 @@ import org.linphone.activities.main.files.viewmodels.ImageFileViewModel import org.linphone.activities.main.files.viewmodels.ImageFileViewModelFactory import org.linphone.activities.main.fragments.SecureFragment import org.linphone.activities.main.viewmodels.SharedMainViewModel -import org.linphone.databinding.ImageViewerFragmentBinding +import org.linphone.databinding.FileImageViewerFragmentBinding -class ImageViewerFragment : SecureFragment() { +class ImageViewerFragment : SecureFragment() { private lateinit var viewModel: ImageFileViewModel private lateinit var sharedViewModel: SharedMainViewModel - override fun getLayoutId(): Int = R.layout.image_viewer_fragment + override fun getLayoutId(): Int = R.layout.file_image_viewer_fragment @SuppressLint("ClickableViewAccessibility") override fun onActivityCreated(savedInstanceState: Bundle?) { diff --git a/app/src/main/java/org/linphone/activities/main/files/fragments/PdfViewerFragment.kt b/app/src/main/java/org/linphone/activities/main/files/fragments/PdfViewerFragment.kt index fd8139b89..85a9a0813 100644 --- a/app/src/main/java/org/linphone/activities/main/files/fragments/PdfViewerFragment.kt +++ b/app/src/main/java/org/linphone/activities/main/files/fragments/PdfViewerFragment.kt @@ -27,14 +27,14 @@ import org.linphone.activities.main.files.viewmodels.PdfFileViewModel import org.linphone.activities.main.files.viewmodels.PdfFileViewModelFactory import org.linphone.activities.main.fragments.SecureFragment import org.linphone.activities.main.viewmodels.SharedMainViewModel -import org.linphone.databinding.PdfViewerFragmentBinding +import org.linphone.databinding.FilePdfViewerFragmentBinding -class PdfViewerFragment : SecureFragment() { +class PdfViewerFragment : SecureFragment() { private lateinit var viewModel: PdfFileViewModel private lateinit var sharedViewModel: SharedMainViewModel private lateinit var adapter: PdfPagesListAdapter - override fun getLayoutId(): Int = R.layout.pdf_viewer_fragment + override fun getLayoutId(): Int = R.layout.file_pdf_viewer_fragment override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) diff --git a/app/src/main/java/org/linphone/activities/main/files/fragments/TextViewerFragment.kt b/app/src/main/java/org/linphone/activities/main/files/fragments/TextViewerFragment.kt index 486e54d90..ee710fba7 100644 --- a/app/src/main/java/org/linphone/activities/main/files/fragments/TextViewerFragment.kt +++ b/app/src/main/java/org/linphone/activities/main/files/fragments/TextViewerFragment.kt @@ -26,13 +26,13 @@ import org.linphone.activities.main.files.viewmodels.TextFileViewModel import org.linphone.activities.main.files.viewmodels.TextFileViewModelFactory import org.linphone.activities.main.fragments.SecureFragment import org.linphone.activities.main.viewmodels.SharedMainViewModel -import org.linphone.databinding.TextViewerFragmentBinding +import org.linphone.databinding.FileTextViewerFragmentBinding -class TextViewerFragment : SecureFragment() { +class TextViewerFragment : SecureFragment() { private lateinit var viewModel: TextFileViewModel private lateinit var sharedViewModel: SharedMainViewModel - override fun getLayoutId(): Int = R.layout.text_viewer_fragment + override fun getLayoutId(): Int = R.layout.file_text_viewer_fragment override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) diff --git a/app/src/main/java/org/linphone/activities/main/files/fragments/VideoViewerFragment.kt b/app/src/main/java/org/linphone/activities/main/files/fragments/VideoViewerFragment.kt index 1a29a48ec..cf2540561 100644 --- a/app/src/main/java/org/linphone/activities/main/files/fragments/VideoViewerFragment.kt +++ b/app/src/main/java/org/linphone/activities/main/files/fragments/VideoViewerFragment.kt @@ -20,23 +20,25 @@ package org.linphone.activities.main.files.fragments import android.os.Bundle +import android.view.KeyEvent import android.widget.MediaController import androidx.lifecycle.ViewModelProvider +import androidx.navigation.fragment.findNavController import org.linphone.R import org.linphone.activities.main.files.viewmodels.VideoFileViewModel import org.linphone.activities.main.files.viewmodels.VideoFileViewModelFactory import org.linphone.activities.main.fragments.SecureFragment import org.linphone.activities.main.viewmodels.SharedMainViewModel import org.linphone.core.tools.Log -import org.linphone.databinding.VideoViewerFragmentBinding +import org.linphone.databinding.FileVideoViewerFragmentBinding -class VideoViewerFragment : SecureFragment() { +class VideoViewerFragment : SecureFragment() { private lateinit var viewModel: VideoFileViewModel private lateinit var sharedViewModel: SharedMainViewModel private lateinit var mediaController: MediaController - override fun getLayoutId(): Int = R.layout.video_viewer_fragment + override fun getLayoutId(): Int = R.layout.file_video_viewer_fragment override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) @@ -61,10 +63,19 @@ class VideoViewerFragment : SecureFragment() { )[VideoFileViewModel::class.java] binding.viewModel = viewModel - mediaController = MediaController(requireContext()) - initMediaController() - isSecure = arguments?.getBoolean("Secure") ?: false + + mediaController = object : MediaController(requireContext()) { + // This is to prevent the first back key press to only hide to media controls + override fun dispatchKeyEvent(event: KeyEvent?): Boolean { + if (event?.keyCode == KeyEvent.KEYCODE_BACK) { + findNavController().popBackStack() + return true + } + return super.dispatchKeyEvent(event) + } + } + initMediaController() } override fun onResume() { diff --git a/app/src/main/java/org/linphone/activities/main/files/viewmodels/AudioFileViewModel.kt b/app/src/main/java/org/linphone/activities/main/files/viewmodels/AudioFileViewModel.kt new file mode 100644 index 000000000..e028a638c --- /dev/null +++ b/app/src/main/java/org/linphone/activities/main/files/viewmodels/AudioFileViewModel.kt @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2010-2021 Belledonne Communications SARL. + * + * This file is part of linphone-android + * (see https://www.linphone.org). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.linphone.activities.main.files.viewmodels + +import android.media.AudioAttributes +import android.media.MediaPlayer +import android.widget.MediaController +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import java.lang.IllegalStateException + +class AudioFileViewModelFactory(private val filePath: String) : + ViewModelProvider.NewInstanceFactory() { + + @Suppress("UNCHECKED_CAST") + override fun create(modelClass: Class): T { + return AudioFileViewModel(filePath) as T + } +} + +class AudioFileViewModel(val filePath: String) : ViewModel(), MediaController.MediaPlayerControl { + val mediaPlayer = MediaPlayer() + + init { + mediaPlayer.apply { + setAudioAttributes(AudioAttributes.Builder().setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).setUsage(AudioAttributes.USAGE_MEDIA).build()) + setDataSource(filePath) + prepare() + start() + } + } + + override fun onCleared() { + mediaPlayer.release() + super.onCleared() + } + + override fun start() { + mediaPlayer.start() + } + + override fun pause() { + mediaPlayer.pause() + } + + override fun getDuration(): Int { + return mediaPlayer.duration + } + + override fun getCurrentPosition(): Int { + try { + return mediaPlayer.currentPosition + } catch (ise: IllegalStateException) {} + return 0 + } + + override fun seekTo(pos: Int) { + mediaPlayer.seekTo(pos) + } + + override fun isPlaying(): Boolean { + return mediaPlayer.isPlaying + } + + override fun getBufferPercentage(): Int { + return 0 + } + + override fun canPause(): Boolean { + return true + } + + override fun canSeekBackward(): Boolean { + return true + } + + override fun canSeekForward(): Boolean { + return true + } + + override fun getAudioSessionId(): Int { + return mediaPlayer.audioSessionId + } +} diff --git a/app/src/main/res/layout/file_audio_viewer_fragment.xml b/app/src/main/res/layout/file_audio_viewer_fragment.xml new file mode 100644 index 000000000..addb6c537 --- /dev/null +++ b/app/src/main/res/layout/file_audio_viewer_fragment.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/image_viewer_fragment.xml b/app/src/main/res/layout/file_image_viewer_fragment.xml similarity index 100% rename from app/src/main/res/layout/image_viewer_fragment.xml rename to app/src/main/res/layout/file_image_viewer_fragment.xml diff --git a/app/src/main/res/layout/pdf_viewer_cell.xml b/app/src/main/res/layout/file_pdf_viewer_cell.xml similarity index 100% rename from app/src/main/res/layout/pdf_viewer_cell.xml rename to app/src/main/res/layout/file_pdf_viewer_cell.xml diff --git a/app/src/main/res/layout/pdf_viewer_fragment.xml b/app/src/main/res/layout/file_pdf_viewer_fragment.xml similarity index 100% rename from app/src/main/res/layout/pdf_viewer_fragment.xml rename to app/src/main/res/layout/file_pdf_viewer_fragment.xml diff --git a/app/src/main/res/layout/text_viewer_fragment.xml b/app/src/main/res/layout/file_text_viewer_fragment.xml similarity index 100% rename from app/src/main/res/layout/text_viewer_fragment.xml rename to app/src/main/res/layout/file_text_viewer_fragment.xml diff --git a/app/src/main/res/layout/video_viewer_fragment.xml b/app/src/main/res/layout/file_video_viewer_fragment.xml similarity index 100% rename from app/src/main/res/layout/video_viewer_fragment.xml rename to app/src/main/res/layout/file_video_viewer_fragment.xml diff --git a/app/src/main/res/navigation/main_nav_graph.xml b/app/src/main/res/navigation/main_nav_graph.xml index f5f53da02..08d848039 100644 --- a/app/src/main/res/navigation/main_nav_graph.xml +++ b/app/src/main/res/navigation/main_nav_graph.xml @@ -340,5 +340,10 @@ android:name="org.linphone.activities.main.files.fragments.VideoViewerFragment" android:label="VideoViewerFragment" /> + + \ No newline at end of file