Merge pull request #4557 from vector-im/feature/adm/voice-keep-screen-on

Keep device screen on during voice message playback and recording
This commit is contained in:
Benoit Marty 2021-11-29 14:29:30 +01:00 committed by GitHub
commit 7beec1c726
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 45 additions and 0 deletions

1
changelog.d/4022.bugfix Normal file
View File

@ -0,0 +1 @@
Keeping device screen on whilst recording and playing back voice messages

View File

@ -19,6 +19,7 @@ package im.vector.app.core.extensions
import android.app.Activity import android.app.Activity
import android.content.Intent import android.content.Intent
import android.os.Parcelable import android.os.Parcelable
import android.view.WindowManager
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.result.ActivityResult import androidx.activity.result.ActivityResult
import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.ActivityResultLauncher
@ -112,3 +113,11 @@ fun Activity.restart() {
startActivity(intent) startActivity(intent)
finish() finish()
} }
fun Activity.keepScreenOn() {
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
}
fun Activity.endKeepScreenOn() {
window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
}

View File

@ -30,12 +30,15 @@ import com.airbnb.mvrx.viewModel
import com.google.android.material.appbar.MaterialToolbar import com.google.android.material.appbar.MaterialToolbar
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R import im.vector.app.R
import im.vector.app.core.extensions.endKeepScreenOn
import im.vector.app.core.extensions.hideKeyboard import im.vector.app.core.extensions.hideKeyboard
import im.vector.app.core.extensions.keepScreenOn
import im.vector.app.core.extensions.replaceFragment import im.vector.app.core.extensions.replaceFragment
import im.vector.app.core.platform.ToolbarConfigurable import im.vector.app.core.platform.ToolbarConfigurable
import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.platform.VectorBaseActivity
import im.vector.app.databinding.ActivityRoomDetailBinding import im.vector.app.databinding.ActivityRoomDetailBinding
import im.vector.app.features.home.room.breadcrumbs.BreadcrumbsFragment import im.vector.app.features.home.room.breadcrumbs.BreadcrumbsFragment
import im.vector.app.features.home.room.detail.timeline.helper.VoiceMessagePlaybackTracker
import im.vector.app.features.matrixto.MatrixToBottomSheet import im.vector.app.features.matrixto.MatrixToBottomSheet
import im.vector.app.features.navigation.Navigator import im.vector.app.features.navigation.Navigator
import im.vector.app.features.room.RequireActiveMembershipAction import im.vector.app.features.room.RequireActiveMembershipAction
@ -43,6 +46,7 @@ import im.vector.app.features.room.RequireActiveMembershipViewEvents
import im.vector.app.features.room.RequireActiveMembershipViewModel import im.vector.app.features.room.RequireActiveMembershipViewModel
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import javax.inject.Inject
@AndroidEntryPoint @AndroidEntryPoint
class RoomDetailActivity : class RoomDetailActivity :
@ -71,8 +75,19 @@ class RoomDetailActivity :
} }
} }
private var lastKnownPlayingOrRecordingState: Boolean? = null
private val playbackActivityListener = VoiceMessagePlaybackTracker.ActivityListener { isPlayingOrRecording ->
if (lastKnownPlayingOrRecordingState == isPlayingOrRecording) return@ActivityListener
when (isPlayingOrRecording) {
true -> keepScreenOn()
false -> endKeepScreenOn()
}
lastKnownPlayingOrRecordingState = isPlayingOrRecording
}
override fun getCoordinatorLayout() = views.coordinatorLayout override fun getCoordinatorLayout() = views.coordinatorLayout
@Inject lateinit var playbackTracker: VoiceMessagePlaybackTracker
private lateinit var sharedActionViewModel: RoomDetailSharedActionViewModel private lateinit var sharedActionViewModel: RoomDetailSharedActionViewModel
private val requireActiveMembershipViewModel: RequireActiveMembershipViewModel by viewModel() private val requireActiveMembershipViewModel: RequireActiveMembershipViewModel by viewModel()
@ -114,6 +129,8 @@ class RoomDetailActivity :
} }
} }
views.drawerLayout.addDrawerListener(drawerListener) views.drawerLayout.addDrawerListener(drawerListener)
playbackTracker.trackActivity(playbackActivityListener)
} }
private fun handleRoomLeft(roomLeft: RequireActiveMembershipViewEvents.RoomLeft) { private fun handleRoomLeft(roomLeft: RequireActiveMembershipViewEvents.RoomLeft) {
@ -136,6 +153,7 @@ class RoomDetailActivity :
override fun onDestroy() { override fun onDestroy() {
supportFragmentManager.unregisterFragmentLifecycleCallbacks(fragmentLifecycleCallbacks) supportFragmentManager.unregisterFragmentLifecycleCallbacks(fragmentLifecycleCallbacks)
views.drawerLayout.removeDrawerListener(drawerListener) views.drawerLayout.removeDrawerListener(drawerListener)
playbackTracker.unTrackActivity(playbackActivityListener)
super.onDestroy() super.onDestroy()
} }

View File

@ -74,6 +74,7 @@ class VoiceMessageHelper @Inject constructor(
voiceRecorder.stopRecord() voiceRecorder.stopRecord()
voiceRecorder.getVoiceMessageFile() voiceRecorder.getVoiceMessageFile()
} }
try { try {
voiceMessageFile?.let { voiceMessageFile?.let {
val outputFileUri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".fileProvider", it, "Voice message.${it.extension}") val outputFileUri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".fileProvider", it, "Voice message.${it.extension}")
@ -153,6 +154,7 @@ class VoiceMessageHelper @Inject constructor(
} }
fun stopPlayback() { fun stopPlayback() {
playbackTracker.stopPlayback(VoiceMessagePlaybackTracker.RECORDING_ID)
mediaPlayer?.stop() mediaPlayer?.stop()
stopPlaybackTicker() stopPlaybackTicker()
} }

View File

@ -26,8 +26,17 @@ class VoiceMessagePlaybackTracker @Inject constructor() {
private val mainHandler = Handler(Looper.getMainLooper()) private val mainHandler = Handler(Looper.getMainLooper())
private val listeners = mutableMapOf<String, Listener>() private val listeners = mutableMapOf<String, Listener>()
private val activityListeners = mutableListOf<ActivityListener>()
private val states = mutableMapOf<String, Listener.State>() private val states = mutableMapOf<String, Listener.State>()
fun trackActivity(listener: ActivityListener) {
activityListeners.add(listener)
}
fun unTrackActivity(listener: ActivityListener) {
activityListeners.remove(listener)
}
fun track(id: String, listener: Listener) { fun track(id: String, listener: Listener) {
listeners[id] = listener listeners[id] = listener
@ -52,8 +61,10 @@ class VoiceMessagePlaybackTracker @Inject constructor() {
*/ */
private fun setState(key: String, state: Listener.State) { private fun setState(key: String, state: Listener.State) {
states[key] = state states[key] = state
val isPlayingOrRecording = states.values.any { it is Listener.State.Playing || it is Listener.State.Recording }
mainHandler.post { mainHandler.post {
listeners[key]?.onUpdate(state) listeners[key]?.onUpdate(state)
activityListeners.forEach { it.onUpdate(isPlayingOrRecording) }
} }
} }
@ -125,4 +136,8 @@ class VoiceMessagePlaybackTracker @Inject constructor() {
data class Recording(val amplitudeList: List<Int>) : State() data class Recording(val amplitudeList: List<Int>) : State()
} }
} }
fun interface ActivityListener {
fun onUpdate(isPlayingOrRecording: Boolean)
}
} }