diff --git a/app/build.gradle b/app/build.gradle index 9f30c77..b0b1ebd 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -11,7 +11,7 @@ android { minSdkVersion 23 targetSdkVersion 30 versionCode 4180 //00.04.100 - versionName "0.4.2-alpha1" + versionName "0.4.2-alpha2" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" resValue "string", "build_time", buildTime() @@ -55,10 +55,11 @@ dependencies { implementation 'com.google.android.material:material:1.3.0' implementation 'com.google.code.gson:gson:2.8.7' - implementation 'com.google.android.exoplayer:exoplayer-core:2.13.3' - implementation 'com.google.android.exoplayer:exoplayer-hls:2.13.3' - implementation 'com.google.android.exoplayer:exoplayer-dash:2.13.3' - implementation 'com.google.android.exoplayer:exoplayer-ui:2.13.3' + implementation 'com.google.android.exoplayer:exoplayer-core:2.14.1' + implementation 'com.google.android.exoplayer:exoplayer-hls:2.14.1' + implementation 'com.google.android.exoplayer:exoplayer-dash:2.14.1' + implementation 'com.google.android.exoplayer:exoplayer-ui:2.14.1' + implementation 'com.google.android.exoplayer:extension-mediasession:2.14.1' implementation 'org.jsoup:jsoup:1.13.1' implementation 'com.github.bumptech.glide:glide:4.12.0' diff --git a/app/src/main/java/org/mosad/teapod/ui/activity/player/PlayerActivity.kt b/app/src/main/java/org/mosad/teapod/ui/activity/player/PlayerActivity.kt index 44e3b55..66728f4 100644 --- a/app/src/main/java/org/mosad/teapod/ui/activity/player/PlayerActivity.kt +++ b/app/src/main/java/org/mosad/teapod/ui/activity/player/PlayerActivity.kt @@ -7,6 +7,7 @@ import android.app.PictureInPictureParams import android.content.Intent import android.content.pm.PackageManager import android.content.res.Configuration +import android.graphics.Rect import android.os.Build import android.os.Bundle import android.util.Log @@ -26,9 +27,7 @@ import com.google.android.exoplayer2.ui.StyledPlayerControlView import com.google.android.exoplayer2.util.Util import kotlinx.android.synthetic.main.activity_player.* import kotlinx.android.synthetic.main.player_controls.* -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext import org.mosad.teapod.R import org.mosad.teapod.preferences.Preferences import org.mosad.teapod.ui.components.EpisodesListPlayer @@ -147,8 +146,15 @@ class PlayerActivity : AppCompatActivity() { } else { val width = model.player.videoFormat?.width ?: 0 val height = model.player.videoFormat?.height ?: 0 + val contentFrame: View = video_view.findViewById(R.id.exo_content_frame) + val contentRect = with(contentFrame) { + val (x, y) = intArrayOf(0, 0).also(::getLocationInWindow) + Rect(x, y, x + width, y + height) + } + val params = PictureInPictureParams.Builder() .setAspectRatio(Rational(width, height)) + .setSourceRectHint(contentRect) .build() enterPictureInPictureMode(params) } @@ -187,7 +193,7 @@ class PlayerActivity : AppCompatActivity() { * set play when ready and listeners */ private fun initExoPlayer() { - model.player.addListener(object : Player.EventListener { + model.player.addListener(object : Player.Listener { override fun onPlaybackStateChanged(state: Int) { super.onPlaybackStateChanged(state) @@ -208,7 +214,7 @@ class PlayerActivity : AppCompatActivity() { } } }) - + // start playing the current episode, after all needed player components have been initialized model.playEpisode(model.currentEpisode, true) } @@ -256,30 +262,26 @@ class PlayerActivity : AppCompatActivity() { timerUpdates = Timer().scheduleAtFixedRate(0, 500) { lifecycleScope.launch { - var btnNextEpIsVisible: Boolean - var controlsVisible: Boolean + val btnNextEpIsVisible = button_next_ep.isVisible + val controlsVisible = controller.isVisible - withContext(Dispatchers.Main) { - if (model.player.duration > 0) { - remainingTime = model.player.duration - model.player.currentPosition - remainingTime = if (remainingTime < 0) 0 else remainingTime - } - btnNextEpIsVisible = button_next_ep.isVisible - controlsVisible = controller.isVisible + if (model.player.duration > 0) { + remainingTime = model.player.duration - model.player.currentPosition + remainingTime = if (remainingTime < 0) 0 else remainingTime } if (remainingTime in 1..20000) { // if the next ep button is not visible, make it visible. Don't show in pip mode if (!btnNextEpIsVisible && model.nextEpisode != null && Preferences.autoplay && !isInPiPMode()) { - withContext(Dispatchers.Main) { showButtonNextEp() } + showButtonNextEp() } } else if (btnNextEpIsVisible) { - withContext(Dispatchers.Main) { hideButtonNextEp() } + hideButtonNextEp() } // if controls are visible, update them if (controlsVisible) { - withContext(Dispatchers.Main) { updateControls() } + updateControls() } } } diff --git a/app/src/main/java/org/mosad/teapod/ui/activity/player/PlayerViewModel.kt b/app/src/main/java/org/mosad/teapod/ui/activity/player/PlayerViewModel.kt index 19a4caf..5dcd69f 100644 --- a/app/src/main/java/org/mosad/teapod/ui/activity/player/PlayerViewModel.kt +++ b/app/src/main/java/org/mosad/teapod/ui/activity/player/PlayerViewModel.kt @@ -2,12 +2,14 @@ package org.mosad.teapod.ui.activity.player import android.app.Application import android.net.Uri +import android.support.v4.media.session.MediaSessionCompat import android.util.Log import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.viewModelScope import com.google.android.exoplayer2.C import com.google.android.exoplayer2.MediaItem import com.google.android.exoplayer2.SimpleExoPlayer +import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector import com.google.android.exoplayer2.source.MediaSource import com.google.android.exoplayer2.source.hls.HlsMediaSource import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory @@ -31,10 +33,11 @@ import kotlin.collections.ArrayList class PlayerViewModel(application: Application) : AndroidViewModel(application) { val player = SimpleExoPlayer.Builder(application).build() - val dataSourceFactory = DefaultDataSourceFactory(application, Util.getUserAgent(application, "Teapod")) + private val dataSourceFactory = DefaultDataSourceFactory(application, Util.getUserAgent(application, "Teapod")) + private val mediaSession = MediaSessionCompat(application, "TEAPOD_PLAYER_SESSION") val currentEpisodeChangedListener = ArrayList<() -> Unit>() - val preferredLanguage = if (Preferences.preferSecondary) Locale.JAPANESE else Locale.GERMAN + private val preferredLanguage = if (Preferences.preferSecondary) Locale.JAPANESE else Locale.GERMAN var media: Media = Media(-1, "", DataTypes.MediaType.OTHER) internal set @@ -45,13 +48,30 @@ class PlayerViewModel(application: Application) : AndroidViewModel(application) var currentLanguage: Locale = Locale.ROOT internal set + init { + initMediaSession() + } + override fun onCleared() { super.onCleared() + + mediaSession.release() player.release() Log.d(javaClass.name, "Released player") } + /** + * set the media session to active + * create a media session connector to set title and description + */ + private fun initMediaSession() { + val mediaSessionConnector = MediaSessionConnector(mediaSession) + mediaSessionConnector.setPlayer(player) + + mediaSession.isActive = true + } + fun loadMedia(mediaId: Int, episodeId: Int) { runBlocking { media = AoDParser.getMediaById(mediaId) @@ -115,6 +135,9 @@ class PlayerViewModel(application: Application) : AndroidViewModel(application) } } + /** + * change the players media source and start playback + */ fun playMedia(source: MediaSource, replace: Boolean = false, seekPosition: Long = 0) { if (replace || player.contentDuration == C.TIME_UNSET) { player.setMediaSource(source)