From 1d071eafdb7ead3fd366afc8582992fb300f24cd Mon Sep 17 00:00:00 2001 From: Jannik Date: Sat, 12 Jun 2021 20:57:12 +0200 Subject: [PATCH 1/4] add media session & update exo player to 2.14.0 --- app/build.gradle | 11 ++++--- .../ui/activity/player/PlayerActivity.kt | 26 ++++++---------- .../ui/activity/player/PlayerViewModel.kt | 31 +++++++++++++++++-- 3 files changed, 45 insertions(+), 23 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 9f30c77..b686fa2 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.0' + implementation 'com.google.android.exoplayer:exoplayer-hls:2.14.0' + implementation 'com.google.android.exoplayer:exoplayer-dash:2.14.0' + implementation 'com.google.android.exoplayer:exoplayer-ui:2.14.0' + implementation 'com.google.android.exoplayer:extension-mediasession:2.14.0' 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..15916fa 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 @@ -26,9 +26,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 @@ -187,7 +185,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 +206,7 @@ class PlayerActivity : AppCompatActivity() { } } }) - + // start playing the current episode, after all needed player components have been initialized model.playEpisode(model.currentEpisode, true) } @@ -256,30 +254,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..8d8c565 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,15 @@ package org.mosad.teapod.ui.activity.player import android.app.Application import android.net.Uri +import android.support.v4.media.session.MediaSessionCompat +import android.support.v4.media.session.PlaybackStateCompat 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 @@ -23,6 +26,7 @@ import org.mosad.teapod.util.Media import java.util.* import kotlin.collections.ArrayList + /** * PlayerViewModel handles all stuff related to media/episodes. * When currentEpisode is changed the player will start playing it (not initial media), @@ -31,10 +35,13 @@ 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") + + lateinit var mStateBuilder: PlaybackStateCompat 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 +52,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 +139,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) From 44d1825095112e4cf8b8116429931bcf97789f22 Mon Sep 17 00:00:00 2001 From: Jannik Date: Sat, 12 Jun 2021 21:02:09 +0200 Subject: [PATCH 2/4] minor code clean up --- .../java/org/mosad/teapod/ui/activity/player/PlayerViewModel.kt | 2 -- 1 file changed, 2 deletions(-) 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 8d8c565..93abe76 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 @@ -38,8 +38,6 @@ class PlayerViewModel(application: Application) : AndroidViewModel(application) private val dataSourceFactory = DefaultDataSourceFactory(application, Util.getUserAgent(application, "Teapod")) private val mediaSession = MediaSessionCompat(application, "TEAPOD_PLAYER_SESSION") - lateinit var mStateBuilder: PlaybackStateCompat - val currentEpisodeChangedListener = ArrayList<() -> Unit>() private val preferredLanguage = if (Preferences.preferSecondary) Locale.JAPANESE else Locale.GERMAN From 164db8ebd12c85f427b01f63b7e32a4428e04ea0 Mon Sep 17 00:00:00 2001 From: Jannik Date: Sat, 12 Jun 2021 21:03:19 +0200 Subject: [PATCH 3/4] remove unneeded import --- .../java/org/mosad/teapod/ui/activity/player/PlayerViewModel.kt | 2 -- 1 file changed, 2 deletions(-) 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 93abe76..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 @@ -3,7 +3,6 @@ package org.mosad.teapod.ui.activity.player import android.app.Application import android.net.Uri import android.support.v4.media.session.MediaSessionCompat -import android.support.v4.media.session.PlaybackStateCompat import android.util.Log import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.viewModelScope @@ -26,7 +25,6 @@ import org.mosad.teapod.util.Media import java.util.* import kotlin.collections.ArrayList - /** * PlayerViewModel handles all stuff related to media/episodes. * When currentEpisode is changed the player will start playing it (not initial media), From 8afbae1e1a881c7c06792f1f297aede5c28feacb Mon Sep 17 00:00:00 2001 From: Jannik Date: Thu, 17 Jun 2021 19:36:13 +0200 Subject: [PATCH 4/4] set pip source hint & update exo player * exo player 2.14.0 -> 2.14.1 --- app/build.gradle | 10 +++++----- .../mosad/teapod/ui/activity/player/PlayerActivity.kt | 8 ++++++++ 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index b686fa2..b0b1ebd 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -55,11 +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.14.0' - implementation 'com.google.android.exoplayer:exoplayer-hls:2.14.0' - implementation 'com.google.android.exoplayer:exoplayer-dash:2.14.0' - implementation 'com.google.android.exoplayer:exoplayer-ui:2.14.0' - implementation 'com.google.android.exoplayer:extension-mediasession:2.14.0' + 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 15916fa..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 @@ -145,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) }