Skip to content

Commit

Permalink
Add picture-in-picture helper classes.
Browse files Browse the repository at this point in the history
  • Loading branch information
Isira-Seneviratne committed Mar 27, 2023
1 parent 9ad095f commit 2c26083
Show file tree
Hide file tree
Showing 5 changed files with 206 additions and 81 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.github.libretube.compat

import android.app.Activity
import android.os.Build

object PictureInPictureCompat {
fun isInPictureInPictureMode(activity: Activity): Boolean {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && activity.isInPictureInPictureMode
}

fun setPictureInPictureParams(activity: Activity, params: PictureInPictureParamsCompat) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
activity.setPictureInPictureParams(params.toPictureInPictureParams())
}
}

fun enterPictureInPictureMode(activity: Activity, params: PictureInPictureParamsCompat) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
activity.enterPictureInPictureMode(params.toPictureInPictureParams())
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package com.github.libretube.compat

import android.app.PictureInPictureParams
import android.graphics.Rect
import android.os.Build
import android.util.Rational
import androidx.annotation.RequiresApi
import androidx.core.app.RemoteActionCompat
import com.google.android.exoplayer2.video.VideoSize

class PictureInPictureParamsCompat private constructor(
private val autoEnterEnabled: Boolean,
private val seamlessResizeEnabled: Boolean,
private val closeAction: RemoteActionCompat?,
private val actions: List<RemoteActionCompat>,
private val sourceRectHint: Rect?,
private val title: CharSequence?,
private val subtitle: CharSequence?,
private val aspectRatio: Rational?,
private val expandedAspectRatio: Rational?,
) {
@RequiresApi(Build.VERSION_CODES.O)
fun toPictureInPictureParams(): PictureInPictureParams {
val pipParams = PictureInPictureParams.Builder()
.setSourceRectHint(sourceRectHint)
.setActions(actions.map { it.toRemoteAction() })
.setAspectRatio(aspectRatio)

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
pipParams.setAutoEnterEnabled(autoEnterEnabled)
.setSeamlessResizeEnabled(seamlessResizeEnabled)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
pipParams.setTitle(title)
.setSubtitle(subtitle)
.setCloseAction(closeAction?.toRemoteAction())
.setExpandedAspectRatio(expandedAspectRatio)
}

return pipParams.build()
}

class Builder {
private var autoEnterEnabled = false
private var seamlessResizeEnabled = true
private var closeAction: RemoteActionCompat? = null
private var actions: List<RemoteActionCompat> = emptyList()
private var sourceRectHint: Rect? = null
private var title: CharSequence? = null
private var subtitle: CharSequence? = null
private var aspectRatio: Rational? = null
private var expandedAspectRatio: Rational? = null

fun setAutoEnterEnabled(autoEnterEnabled: Boolean) = apply {
this.autoEnterEnabled = autoEnterEnabled
}

fun setSeamlessResizeEnabled(seamlessResizeEnabled: Boolean) = apply {
this.seamlessResizeEnabled = seamlessResizeEnabled
}

fun setCloseAction(action: RemoteActionCompat?) = apply {
this.closeAction = action
}

fun setActions(actions: List<RemoteActionCompat>) = apply {
this.actions = actions
}

fun setSourceRectHint(sourceRectHint: Rect?) = apply {
this.sourceRectHint = sourceRectHint
}

fun setTitle(title: CharSequence?) = apply {
this.title = title
}

fun setSubtitle(subtitle: CharSequence?) = apply {
this.subtitle = subtitle
}

fun setAspectRatio(aspectRatio: Rational?) = apply {
this.aspectRatio = aspectRatio
}

// Additional function replacing the project's extension function for the platform builder.
fun setAspectRatio(videoSize: VideoSize): Builder {
val ratio = (videoSize.width.toFloat() / videoSize.height)
val rational = when {
ratio.isNaN() -> Rational(4, 3)
ratio <= 0.418410 -> Rational(41841, 100000)
ratio >= 2.390000 -> Rational(239, 100)
else -> Rational(videoSize.width, videoSize.height)
}
return setAspectRatio(rational)
}

fun setExpandedAspectRatio(expandedAspectRatio: Rational?) = apply {
this.expandedAspectRatio = expandedAspectRatio
}

fun build(): PictureInPictureParamsCompat {
return PictureInPictureParamsCompat(
autoEnterEnabled,
seamlessResizeEnabled,
closeAction,
actions,
sourceRectHint,
title,
subtitle,
aspectRatio,
expandedAspectRatio
)
}
}
}
30 changes: 12 additions & 18 deletions app/src/main/java/com/github/libretube/helpers/PlayerHelper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,18 @@ package com.github.libretube.helpers

import android.app.Activity
import android.app.PendingIntent
import android.app.RemoteAction
import android.content.Context
import android.content.Intent
import android.content.pm.ActivityInfo
import android.graphics.drawable.Icon
import android.os.Build
import android.view.accessibility.CaptioningManager
import android.widget.Toast
import androidx.annotation.RequiresApi
import androidx.annotation.StringRes
import androidx.core.app.RemoteActionCompat
import androidx.core.graphics.drawable.IconCompat
import com.github.libretube.R
import com.github.libretube.api.obj.PipedStream
import com.github.libretube.api.obj.Segment
import com.github.libretube.compat.PendingIntentCompat
import com.github.libretube.constants.PreferenceKeys
import com.github.libretube.enums.AudioQuality
import com.github.libretube.enums.PlayerEvent
Expand Down Expand Up @@ -378,26 +377,24 @@ object PlayerHelper {
return context.packageName + "." + ACTION_MEDIA_CONTROL
}

@RequiresApi(Build.VERSION_CODES.O)
private fun getPendingIntent(activity: Activity, code: Int): PendingIntent {
return PendingIntent.getBroadcast(
return PendingIntentCompat.getBroadcast(
activity,
code,
Intent(getIntentActon(activity)).putExtra(CONTROL_TYPE, code),
PendingIntent.FLAG_IMMUTABLE
0
)
}

@RequiresApi(Build.VERSION_CODES.O)
private fun getRemoteAction(
activity: Activity,
id: Int,
@StringRes title: Int,
event: PlayerEvent
): RemoteAction {
): RemoteActionCompat {
val text = activity.getString(title)
return RemoteAction(
Icon.createWithResource(activity, id),
return RemoteActionCompat(
IconCompat.createWithResource(activity, id),
text,
text,
getPendingIntent(activity, event.value)
Expand All @@ -407,8 +404,7 @@ object PlayerHelper {
/**
* Create controls to use in the PiP window
*/
@RequiresApi(Build.VERSION_CODES.O)
fun getPiPModeActions(activity: Activity, isPlaying: Boolean, isOfflinePlayer: Boolean = false): ArrayList<RemoteAction> {
fun getPiPModeActions(activity: Activity, isPlaying: Boolean): List<RemoteActionCompat> {
val audioModeAction = getRemoteAction(
activity,
R.drawable.ic_headphones,
Expand Down Expand Up @@ -443,12 +439,10 @@ object PlayerHelper {
R.string.forward,
PlayerEvent.Forward
)
return if (
!isOfflinePlayer && alternativePiPControls
) {
arrayListOf(audioModeAction, playPauseAction, skipNextAction)
return if (alternativePiPControls) {
listOf(audioModeAction, playPauseAction, skipNextAction)
} else {
arrayListOf(rewindAction, playPauseAction, forwardAction)
listOf(rewindAction, playPauseAction, forwardAction)
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
package com.github.libretube.ui.activities

import android.app.PictureInPictureParams
import android.content.pm.ActivityInfo
import android.media.session.PlaybackState
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.text.format.DateUtils
import android.view.View
import androidx.activity.viewModels
import androidx.lifecycle.lifecycleScope
import com.github.libretube.compat.PictureInPictureCompat
import com.github.libretube.compat.PictureInPictureParamsCompat
import com.github.libretube.constants.IntentData
import com.github.libretube.databinding.ActivityOfflinePlayerBinding
import com.github.libretube.databinding.ExoStyledPlayerControlViewBinding
Expand All @@ -21,7 +21,6 @@ import com.github.libretube.helpers.PlayerHelper
import com.github.libretube.helpers.PlayerHelper.loadPlaybackParams
import com.github.libretube.helpers.WindowHelper
import com.github.libretube.ui.base.BaseActivity
import com.github.libretube.ui.extensions.setAspectRatio
import com.github.libretube.ui.models.PlayerViewModel
import com.google.android.exoplayer2.C
import com.google.android.exoplayer2.ExoPlayer
Expand Down Expand Up @@ -197,18 +196,14 @@ class OfflinePlayerActivity : BaseActivity() {
}

override fun onUserLeaveHint() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return

if (!PlayerHelper.pipEnabled) return

if (player.playbackState == PlaybackState.STATE_PAUSED) return

enterPictureInPictureMode(
PictureInPictureParams.Builder()
.setActions(emptyList())
.setAspectRatio(player.videoSize.width, player.videoSize.height)
.build()
)
if (PlayerHelper.pipEnabled && player.playbackState != PlaybackState.STATE_PAUSED) {
PictureInPictureCompat.enterPictureInPictureMode(
this,
PictureInPictureParamsCompat.Builder()
.setAspectRatio(player.videoSize)
.build()
)
}

super.onUserLeaveHint()
}
Expand Down
Loading

0 comments on commit 2c26083

Please sign in to comment.