Ver Fonte

Merge pull request #3704 from Ruggero1912/master

Resumes playback of VoiceMessages on screen rotation and continue playing a voice message if chatActivity in background but still open
Marcel Hibbe há 1 ano atrás
pai
commit
007c407549
1 ficheiros alterados com 113 adições e 10 exclusões
  1. 113 10
      app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt

+ 113 - 10
app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt

@@ -11,6 +11,7 @@
  * Copyright (C) 2021-2022 Marcel Hibbe <dev@mhibbe.de>
  * Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
  * Copyright (C) 2023 Ezhil Shanmugham <ezhil56x.contact@gmail.com>
+ * Copyright (C) 2024 Giacomo Pacini <giacomo@paciosoft.com>
  *
  * 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
@@ -405,6 +406,9 @@ class ChatActivity :
 
     private val onBackPressedCallback = object : OnBackPressedCallback(true) {
         override fun handleOnBackPressed() {
+            if (currentlyPlayedVoiceMessage != null) {
+                stopMediaPlayer(currentlyPlayedVoiceMessage!!)
+            }
             val intent = Intent(this@ChatActivity, ConversationsListActivity::class.java)
             intent.putExtras(Bundle())
             startActivity(intent)
@@ -416,6 +420,9 @@ class ChatActivity :
     val typingParticipants = HashMap<String, TypingParticipant>()
 
     var callStarted = false
+    private var voiceMessageToRestoreId = ""
+    private var voiceMessageToRestoreAudioPosition = 0
+    private var voiceMessageToRestoreWasPlaying = false
 
     private val localParticipantMessageListener = object : SignalingMessageReceiver.LocalParticipantMessageListener {
         override fun onSwitchTo(token: String?) {
@@ -487,6 +494,30 @@ class ChatActivity :
         onBackPressedDispatcher.addCallback(this, onBackPressedCallback)
 
         initObservers()
+
+        if (savedInstanceState != null) {
+            // Restore value of members from saved state
+            var voiceMessageId = savedInstanceState.getString(CURRENT_AUDIO_MESSAGE_KEY, "")
+            var voiceMessagePosition = savedInstanceState.getInt(CURRENT_AUDIO_POSITION_KEY, 0)
+            var wasAudioPLaying = savedInstanceState.getBoolean(CURRENT_AUDIO_WAS_PLAYING_KEY, false)
+            if (!voiceMessageId.equals("")) {
+                Log.d(RESUME_AUDIO_TAG, "restored voice messageID: " + voiceMessageId)
+                Log.d(RESUME_AUDIO_TAG, "audio position: " + voiceMessagePosition)
+                Log.d(RESUME_AUDIO_TAG, "audio was playing: " + wasAudioPLaying.toString())
+                voiceMessageToRestoreId = voiceMessageId
+                voiceMessageToRestoreAudioPosition = voiceMessagePosition
+                voiceMessageToRestoreWasPlaying = wasAudioPLaying
+            } else {
+                Log.d(RESUME_AUDIO_TAG, "stored voice message id is empty, not resuming audio playing")
+                voiceMessageToRestoreId = ""
+                voiceMessageToRestoreAudioPosition = 0
+                voiceMessageToRestoreWasPlaying = false
+            }
+        } else {
+            voiceMessageToRestoreId = ""
+            voiceMessageToRestoreAudioPosition = 0
+            voiceMessageToRestoreWasPlaying = false
+        }
     }
 
     override fun onNewIntent(intent: Intent) {
@@ -548,6 +579,20 @@ class ChatActivity :
         this.lifecycle.addObserver(ChatViewModel.LifeCycleObserver)
     }
 
+    override fun onSaveInstanceState(outState: Bundle) {
+        if (currentlyPlayedVoiceMessage != null) {
+            outState.putString(CURRENT_AUDIO_MESSAGE_KEY, currentlyPlayedVoiceMessage!!.getId())
+            outState.putInt(CURRENT_AUDIO_POSITION_KEY, currentlyPlayedVoiceMessage!!.voiceMessagePlayedSeconds)
+            outState.putBoolean(CURRENT_AUDIO_WAS_PLAYING_KEY, currentlyPlayedVoiceMessage!!.isPlayingVoiceMessage)
+            Log.d(RESUME_AUDIO_TAG, "Stored current audio message ID: " + currentlyPlayedVoiceMessage!!.getId())
+            Log.d(
+                RESUME_AUDIO_TAG, "Audio Position: " + currentlyPlayedVoiceMessage!!.voiceMessagePlayedSeconds
+                    .toString() + " | isPLaying: " + currentlyPlayedVoiceMessage!!.isPlayingVoiceMessage
+            )
+        }
+        super.onSaveInstanceState(outState)
+    }
+
     override fun onStop() {
         super.onStop()
         active = false
@@ -558,9 +603,6 @@ class ChatActivity :
         if (mediaRecorderState == MediaRecorderState.RECORDING) {
             stopAudioRecording()
         }
-        if (currentlyPlayedVoiceMessage != null) {
-            stopMediaPlayer(currentlyPlayedVoiceMessage!!)
-        }
         val text = binding.messageInputView.messageInput.text.toString()
         val cursor = binding.messageInputView.messageInput.selectionStart
         val previous = context.getSharedPreferences(localClassName, MODE_PRIVATE).getString(roomToken, "null")
@@ -1352,7 +1394,7 @@ class ChatActivity :
         }
     }
 
-    private fun setUpWaveform(message: ChatMessage) {
+    private fun setUpWaveform(message: ChatMessage, thenPlay: Boolean = true) {
         val filename = message.selectedIndividualHashMap!!["name"]
         val file = File(context.cacheDir, filename!!)
         if (file.exists() && message.voiceMessageFloatArray == null) {
@@ -1363,11 +1405,11 @@ class ChatActivity :
                 appPreferences.saveWaveFormForFile(filename, r.toTypedArray())
                 message.voiceMessageFloatArray = r
                 withContext(Dispatchers.Main) {
-                    startPlayback(message)
+                    startPlayback(message, thenPlay)
                 }
             }
         } else {
-            startPlayback(message)
+            startPlayback(message, thenPlay)
         }
     }
 
@@ -2321,7 +2363,7 @@ class ChatActivity :
         }
     }
 
-    private fun startPlayback(message: ChatMessage) {
+    private fun startPlayback(message: ChatMessage, doPlay: Boolean = true) {
         if (!active) {
             // don't begin to play voice message if screen is not visible anymore.
             // this situation might happen if file is downloading but user already left the chatview.
@@ -2333,7 +2375,7 @@ class ChatActivity :
         initMediaPlayer(message)
 
         mediaPlayer?.let {
-            if (!it.isPlaying) {
+            if (!it.isPlaying && doPlay) {
                 audioFocusRequest(true) {
                     it.start()
                     handleBecomingNoisyBroadcast(register = true)
@@ -2365,7 +2407,11 @@ class ChatActivity :
             })
 
             message.isDownloadingVoiceMessage = false
-            message.isPlayingVoiceMessage = true
+            message.isPlayingVoiceMessage = doPlay
+            //message.voiceMessagePlayedSeconds = lastRecordMediaPosition / VOICE_MESSAGE_SEEKBAR_BASE
+            //message.voiceMessageSeekbarProgress = lastRecordMediaPosition
+            // the commented instructions objective was to update audio seekbarprogress
+            // in the case in which audio status is paused when the position is resumed
             adapter?.update(message)
         }
     }
@@ -2408,6 +2454,8 @@ class ChatActivity :
                                 lastRecordedSeeked = true
                             }
                         }
+                        // this ensures that audio can be resumed at a given position
+                        this.seekTo(lastRecordMediaPosition)
                     }
                     setOnCompletionListener {
                         stopMediaPlayer(message)
@@ -2426,6 +2474,7 @@ class ChatActivity :
         adapter?.update(message)
 
         currentlyPlayedVoiceMessage = null
+        lastRecordMediaPosition = 0 //this ensures that if audio track is changed, then it is played from the beginning
 
         mediaPlayerHandler.removeCallbacksAndMessages(null)
 
@@ -3750,6 +3799,8 @@ class ChatActivity :
             adapter?.addToEnd(chatMessageList, false)
         }
         scrollToRequestedMessageIfNeeded()
+        //FENOM: add here audio resume policy
+        resumeAudioPlaybackIfNeeded()
     }
 
     private fun scrollToFirstUnreadMessage() {
@@ -3854,6 +3905,54 @@ class ChatActivity :
         }
     }
 
+    /**
+     * this method must be called after that the adatper has finished loading ChatMessages items
+     * it searches by ID the message that was playing,
+     * then, if it finds it, it restores audio position
+     * and eventually resumes audio playback
+     * @author Giacomo Pacini
+     */
+    private fun resumeAudioPlaybackIfNeeded() {
+        if (!voiceMessageToRestoreId.equals("")) {
+            Log.d(RESUME_AUDIO_TAG, "begin method to resume audio playback")
+
+            if (adapter != null) {
+                Log.d(RESUME_AUDIO_TAG, "adapter is not null, proceeding")
+                val voiceMessagePosition = adapter!!.items!!.indexOfFirst {
+                    it.item is ChatMessage && (it.item as ChatMessage).id == voiceMessageToRestoreId
+                }
+                if (voiceMessagePosition >= 0) {
+                    val currentItem = adapter?.items?.get(voiceMessagePosition)?.item
+                    if (currentItem is ChatMessage && currentItem.id == voiceMessageToRestoreId) {
+                        currentlyPlayedVoiceMessage = currentItem
+                        lastRecordMediaPosition = voiceMessageToRestoreAudioPosition * 1000
+                        Log.d(RESUME_AUDIO_TAG, "trying to resume audio")
+                        binding.messagesListView.scrollToPosition(voiceMessagePosition)
+                        // WORKAROUND TO FETCH FILE INFO:
+                        currentlyPlayedVoiceMessage!!.getImageUrl()
+                        // see getImageUrl() source code
+                        setUpWaveform(currentlyPlayedVoiceMessage!!, voiceMessageToRestoreWasPlaying)
+                        Log.d(RESUME_AUDIO_TAG, "resume audio procedure completed")
+                    } else {
+                        Log.d(RESUME_AUDIO_TAG, "currentItem retrieved was not chatmessage or its id was not correct")
+                    }
+                } else {
+                    Log.d(
+                        RESUME_AUDIO_TAG,
+                        "voiceMessagePosition is -1, adapter # of items: " + adapter!!.getItemCount()
+                    )
+                }
+            } else {
+                Log.d(RESUME_AUDIO_TAG, "TalkMessagesListAdapater is null")
+            }
+        } else {
+            Log.d(RESUME_AUDIO_TAG, "No voice message to restore")
+        }
+        voiceMessageToRestoreId = ""
+        voiceMessageToRestoreAudioPosition = 0
+        voiceMessageToRestoreWasPlaying = false
+    }
+
     private fun scrollToRequestedMessageIfNeeded() {
         intent.getStringExtra(BundleKeys.KEY_MESSAGE_ID)?.let {
             scrollToMessageWithId(it)
@@ -4380,7 +4479,7 @@ class ChatActivity :
             val lon = data["longitude"]!!
             metaData =
                 "{\"type\":\"geo-location\",\"id\":\"geo:$lat,$lon\",\"latitude\":\"$lat\"," +
-                "\"longitude\":\"$lon\",\"name\":\"$name\"}"
+                    "\"longitude\":\"$lon\",\"name\":\"$name\"}"
         }
 
         when (type) {
@@ -4861,5 +4960,9 @@ class ChatActivity :
         private const val MILISEC_15: Long = 15
         private const val LINEBREAK = "\n"
         private const val CURSOR_KEY = "_cursor"
+        private const val CURRENT_AUDIO_MESSAGE_KEY = "CURRENT_AUDIO_MESSAGE"
+        private const val CURRENT_AUDIO_POSITION_KEY = "CURRENT_AUDIO_POSITION"
+        private const val CURRENT_AUDIO_WAS_PLAYING_KEY = "CURRENT_AUDIO_PLAYING"
+        private const val RESUME_AUDIO_TAG = "RESUME_AUDIO_TAG"
     }
 }