add pip support to player activity
This commit is contained in:
parent
a0111d45cf
commit
e5037cf9ac
|
@ -21,16 +21,19 @@
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<activity
|
|
||||||
android:name=".player.PlayerActivity"
|
|
||||||
android:label="@string/app_name"
|
|
||||||
android:theme="@style/PlayerTheme"
|
|
||||||
android:configChanges="orientation|screenSize|layoutDirection" />
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:screenOrientation="portrait">
|
android:screenOrientation="portrait">
|
||||||
</activity>
|
</activity>
|
||||||
|
<activity
|
||||||
|
android:name=".player.PlayerActivity"
|
||||||
|
android:parentActivityName=".MainActivity"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:theme="@style/PlayerTheme"
|
||||||
|
android:supportsPictureInPicture="true"
|
||||||
|
android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|layoutDirection">
|
||||||
|
</activity>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
|
@ -3,11 +3,16 @@ package org.mosad.teapod.player
|
||||||
import android.animation.Animator
|
import android.animation.Animator
|
||||||
import android.animation.AnimatorListenerAdapter
|
import android.animation.AnimatorListenerAdapter
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import android.app.PictureInPictureParams
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.content.res.Configuration
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import android.util.Rational
|
||||||
import android.view.*
|
import android.view.*
|
||||||
import androidx.activity.viewModels
|
import androidx.activity.viewModels
|
||||||
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.view.GestureDetectorCompat
|
import androidx.core.view.GestureDetectorCompat
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
|
@ -73,6 +78,11 @@ class PlayerActivity : AppCompatActivity() {
|
||||||
initActions()
|
initActions()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* once minimum is android 7.0 this can be simplified
|
||||||
|
* only onStart and onStop should be needed then
|
||||||
|
* see: https://developer.android.com/guide/topics/ui/picture-in-picture#continuing_playback
|
||||||
|
*/
|
||||||
override fun onStart() {
|
override fun onStart() {
|
||||||
super.onStart()
|
super.onStart()
|
||||||
if (Util.SDK_INT > 23) {
|
if (Util.SDK_INT > 23) {
|
||||||
|
@ -83,6 +93,8 @@ class PlayerActivity : AppCompatActivity() {
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
|
if (isInPiPMode()) { return }
|
||||||
|
|
||||||
if (Util.SDK_INT <= 23) {
|
if (Util.SDK_INT <= 23) {
|
||||||
initPlayer()
|
initPlayer()
|
||||||
video_view?.onResume()
|
video_view?.onResume()
|
||||||
|
@ -91,6 +103,8 @@ class PlayerActivity : AppCompatActivity() {
|
||||||
|
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
super.onPause()
|
super.onPause()
|
||||||
|
if (isInPiPMode()) { return }
|
||||||
|
|
||||||
if (Util.SDK_INT <= 23) {
|
if (Util.SDK_INT <= 23) {
|
||||||
video_view?.onPause()
|
video_view?.onPause()
|
||||||
releasePlayer()
|
releasePlayer()
|
||||||
|
@ -112,6 +126,38 @@ class PlayerActivity : AppCompatActivity() {
|
||||||
super.onSaveInstanceState(outState)
|
super.onSaveInstanceState(outState)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* previous to android n, don't override
|
||||||
|
*/
|
||||||
|
@RequiresApi(Build.VERSION_CODES.N)
|
||||||
|
override fun onUserLeaveHint() {
|
||||||
|
super.onUserLeaveHint()
|
||||||
|
|
||||||
|
// start pip mode, if supported
|
||||||
|
if (packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE)) {
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
||||||
|
@Suppress("deprecation")
|
||||||
|
enterPictureInPictureMode()
|
||||||
|
} else {
|
||||||
|
val width = model.player.videoFormat?.width ?: 0
|
||||||
|
val height = model.player.videoFormat?.height ?: 0
|
||||||
|
val params = PictureInPictureParams.Builder()
|
||||||
|
.setAspectRatio(Rational(width, height))
|
||||||
|
.build()
|
||||||
|
enterPictureInPictureMode(params)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean, newConfig: Configuration?) {
|
||||||
|
super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig)
|
||||||
|
|
||||||
|
// Hide the full-screen UI (controls, etc.) while in picture-in-picture mode.
|
||||||
|
if (isInPictureInPictureMode) {
|
||||||
|
controller.hideImmediately()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun initPlayer() {
|
private fun initPlayer() {
|
||||||
if (model.media.id < 0) {
|
if (model.media.id < 0) {
|
||||||
Log.e(javaClass.name, "No media was set.")
|
Log.e(javaClass.name, "No media was set.")
|
||||||
|
@ -178,7 +224,9 @@ class PlayerActivity : AppCompatActivity() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initActions() {
|
private fun initActions() {
|
||||||
exo_close_player.setOnClickListener { this.finish() }
|
exo_close_player.setOnClickListener {
|
||||||
|
this.finish()
|
||||||
|
}
|
||||||
rwd_10.setOnButtonClickListener { rewind() }
|
rwd_10.setOnButtonClickListener { rewind() }
|
||||||
ffwd_10.setOnButtonClickListener { fastForward() }
|
ffwd_10.setOnButtonClickListener { fastForward() }
|
||||||
button_next_ep.setOnClickListener { playNextEpisode() }
|
button_next_ep.setOnClickListener { playNextEpisode() }
|
||||||
|
@ -213,8 +261,8 @@ class PlayerActivity : AppCompatActivity() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (remainingTime in 1..20000) {
|
if (remainingTime in 1..20000) {
|
||||||
// if the next ep button is not visible, make it visible
|
// if the next ep button is not visible, make it visible. Don't show in pip mode
|
||||||
if (!btnNextEpIsVisible && model.nextEpisode != null && Preferences.autoplay) {
|
if (!btnNextEpIsVisible && model.nextEpisode != null && Preferences.autoplay && !isInPiPMode()) {
|
||||||
withContext(Dispatchers.Main) { showButtonNextEp() }
|
withContext(Dispatchers.Main) { showButtonNextEp() }
|
||||||
}
|
}
|
||||||
} else if (btnNextEpIsVisible) {
|
} else if (btnNextEpIsVisible) {
|
||||||
|
@ -229,7 +277,7 @@ class PlayerActivity : AppCompatActivity() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun releasePlayer(){
|
private fun releasePlayer() {
|
||||||
playbackPosition = model.player.currentPosition
|
playbackPosition = model.player.currentPosition
|
||||||
currentWindow = model.player.currentWindowIndex
|
currentWindow = model.player.currentWindowIndex
|
||||||
playWhenReady = model.player.playWhenReady
|
playWhenReady = model.player.playWhenReady
|
||||||
|
@ -378,6 +426,14 @@ class PlayerActivity : AppCompatActivity() {
|
||||||
pauseAndHideControls()
|
pauseAndHideControls()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun isInPiPMode(): Boolean {
|
||||||
|
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||||
|
isInPictureInPictureMode
|
||||||
|
} else {
|
||||||
|
false // pip mode not supported
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pause playback and hide controls
|
* pause playback and hide controls
|
||||||
*/
|
*/
|
||||||
|
@ -393,7 +449,10 @@ class PlayerActivity : AppCompatActivity() {
|
||||||
* on single tap hide or show the controls
|
* on single tap hide or show the controls
|
||||||
*/
|
*/
|
||||||
override fun onSingleTapConfirmed(e: MotionEvent?): Boolean {
|
override fun onSingleTapConfirmed(e: MotionEvent?): Boolean {
|
||||||
if (controller.isVisible) controller.hide() else controller.show()
|
if (!isInPiPMode()) {
|
||||||
|
if (controller.isVisible) controller.hide() else controller.show()
|
||||||
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue