Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions buildSrc/src/main/java/kohii/Dependencies.kt
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ object Libs {
val liveData = "androidx.lifecycle:lifecycle-livedata-ktx:$version"
val viewModel = "androidx.lifecycle:lifecycle-viewmodel-ktx:$version"
val service = "androidx.lifecycle:lifecycle-service:$version"
val process = "androidx.lifecycle:lifecycle-process:$version"
}

object Room {
Expand Down
1 change: 1 addition & 0 deletions kohii-core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ dependencies {
implementation Libs.AndroidX.coordinatorLayout
implementation Libs.AndroidX.Lifecycle.extensions
implementation Libs.AndroidX.Lifecycle.service
implementation Libs.AndroidX.Lifecycle.process
api Libs.AndroidX.Lifecycle.java8

testImplementation(Libs.Common.junit)
Expand Down
76 changes: 45 additions & 31 deletions kohii-core/src/main/java/kohii/v1/core/AbstractPlayable.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import kohii.v1.core.MemoryMode.HIGH
import kohii.v1.core.MemoryMode.INFINITE
import kohii.v1.core.MemoryMode.LOW
import kohii.v1.core.MemoryMode.NORMAL
import kohii.v1.debugOnly
import kohii.v1.internal.PlayerParametersChangeListener
import kohii.v1.logInfo
import kohii.v1.logWarn
Expand All @@ -41,7 +42,7 @@ abstract class AbstractPlayable<RENDERER : Any>(
private var playRequested: Boolean = false

override fun toString(): String {
return "Playable([t=$tag][b=$bridge][h=${super.hashCode()}])"
return "Playable([t=$tag][b=$bridge][h=${hashCode()}])"
}

// Ensure the preparation for the playback
Expand Down Expand Up @@ -89,6 +90,7 @@ abstract class AbstractPlayable<RENDERER : Any>(
}

override fun isPlaying(): Boolean {
"Playable#isPlaying $this".logInfo()
return bridge.isPlaying()
}

Expand All @@ -102,12 +104,12 @@ abstract class AbstractPlayable<RENDERER : Any>(
val newManager = field
if (oldManager === newManager) return
"Playable#manager $oldManager --> $newManager, $this".logInfo()
oldManager?.removePlayable(this)
newManager?.addPlayable(this)
// Setting Manager to null.
if (newManager == null) {
master.trySavePlaybackInfo(this)
master.tearDown(
playable = this,
clearState = if (oldManager is Manager) !oldManager.isChangingConfigurations() else true
)
master.tearDown(playable = this)
} else if (oldManager === null) {
master.tryRestorePlaybackInfo(this)
}
Expand All @@ -120,15 +122,7 @@ abstract class AbstractPlayable<RENDERER : Any>(
val newPlayback = field
if (oldPlayback === newPlayback) return
"Playable#playback $oldPlayback --> $newPlayback, $this".logInfo()
if (oldPlayback != null) {
bridge.removeErrorListener(oldPlayback)
bridge.removeEventListener(oldPlayback)
oldPlayback.removeCallback(this)
if (oldPlayback.playable === this) oldPlayback.playable = null
if (oldPlayback.playerParametersChangeListener === this) {
oldPlayback.playerParametersChangeListener = null
}
}
oldPlayback?.let(::detachFromPlayback)

this.manager = if (newPlayback != null) {
newPlayback.manager
Expand All @@ -150,30 +144,50 @@ abstract class AbstractPlayable<RENDERER : Any>(
}
}

if (newPlayback != null) {
newPlayback.playable = this
newPlayback.playerParametersChangeListener = this
newPlayback.addCallback(this)
newPlayback.config.callbacks.forEach { callback -> newPlayback.addCallback(callback) }

bridge.addEventListener(newPlayback)
bridge.addErrorListener(newPlayback)

if (newPlayback.tag != Master.NO_TAG) {
if (newPlayback.config.controller != null) {
master.plannedManualPlayables.add(newPlayback.tag)
} else {
master.plannedManualPlayables.remove(newPlayback.tag)
}
}
}
newPlayback?.let(::attachToPlayback)

master.notifyPlaybackChanged(this, oldPlayback, newPlayback)
}

override val playerState: Int
get() = bridge.playerState

private fun attachToPlayback(playback: Playback) {
playback.playable = this
playback.playerParametersChangeListener = this
playback.addCallback(this)
playback.config.callbacks.forEach { callback -> playback.addCallback(callback) }

bridge.addEventListener(playback)
bridge.addErrorListener(playback)

if (playback.tag != Master.NO_TAG) {
if (playback.config.controller != null) {
master.plannedManualPlayables.add(playback.tag)
} else {
master.plannedManualPlayables.remove(playback.tag)
}
}
}

private fun detachFromPlayback(playback: Playback) {
bridge.removeErrorListener(playback)
bridge.removeEventListener(playback)
playback.removeCallback(this)
debugOnly {
check(playback.playable === this) {
"""
Old playback of this playable ($this) is
bound to a different playable: ${playback.playable}
""".trimIndent()
}
}
if (playback.playable === this) playback.playable = null
if (playback.playerParametersChangeListener === this) {
playback.playerParametersChangeListener = null
}
}

// Playback.Callback

override fun onActive(playback: Playback) {
Expand Down
2 changes: 1 addition & 1 deletion kohii-core/src/main/java/kohii/v1/core/Binder.kt
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ class Binder(
if (cache.config != config /* equals */) {
// Scenario: client bind a Video of same tag/media but different Renderer type or Config.
cache.playback = null // will also set Manager to null
engine.master.tearDown(cache, true)
engine.master.tearDown(cache)
cache = null
}
}
Expand Down
6 changes: 5 additions & 1 deletion kohii-core/src/main/java/kohii/v1/core/Bridge.kt
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,11 @@ interface Bridge<RENDERER : Any> {
*/
fun prepare(loadSource: Boolean)

// Ensure resource is ready to play. PlaybackDispatcher will require this for manual playback.
/**
* Ensure the resources is ready to play.
*
* Note: PlaybackDispatcher will require this for manual playback.
*/
fun ready()

fun play()
Expand Down
39 changes: 39 additions & 0 deletions kohii-core/src/main/java/kohii/v1/core/CompatHelper.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright (c) 2021 Nam Nguyen, [email protected]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package kohii.v1.core

import androidx.annotation.MainThread

object CompatHelper {

private val defaultConfig: CompatConfig = CompatConfig()
private var customConfig: CompatConfig? = null

val compatConfig: CompatConfig get() = customConfig ?: defaultConfig

@MainThread
fun setCompatConfig(compatConfig: CompatConfig) {
check(customConfig == null || customConfig == compatConfig) {
"Another CompatConfig is already set."
}
customConfig = compatConfig
}
}

data class CompatConfig(
val useLegacyPlaybackInfoStore: Boolean = false
)
8 changes: 5 additions & 3 deletions kohii-core/src/main/java/kohii/v1/core/Engine.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,14 @@ import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.Lifecycle.State
import androidx.lifecycle.Lifecycle.State.STARTED
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.ViewModelProvider
import kohii.v1.core.Binder.Options
import kohii.v1.core.MemoryMode.LOW
import kohii.v1.core.Scope.BUCKET
import kohii.v1.core.Scope.GROUP
import kohii.v1.core.Scope.MANAGER
import kohii.v1.core.Scope.PLAYBACK
import kohii.v1.internal.ManagerViewModel
import kohii.v1.media.Media
import kohii.v1.media.MediaItem
import kohii.v1.media.VolumeInfo
Expand All @@ -47,9 +49,7 @@ abstract class Engine<RENDERER : Any> constructor(
playableCreator: PlayableCreator<RENDERER>
) : this(Master[context], playableCreator)

internal fun inject(group: Group) {
group.managers.forEach { prepare(it) }
}
internal fun inject(group: Group) = group.managers.forEach(::prepare)

abstract fun prepare(manager: Manager)

Expand Down Expand Up @@ -103,6 +103,7 @@ abstract class Engine<RENDERER : Any> constructor(
activity = activity,
host = fragment,
managerLifecycleOwner = lifecycleOwner,
viewModel = ViewModelProvider(fragment).get(ManagerViewModel::class.java),
memoryMode = memoryMode,
activeLifecycleState = activeLifecycleState
)
Expand All @@ -117,6 +118,7 @@ abstract class Engine<RENDERER : Any> constructor(
activity = activity,
host = activity,
managerLifecycleOwner = activity,
viewModel = ViewModelProvider(activity).get(ManagerViewModel::class.java),
memoryMode = memoryMode,
activeLifecycleState = activeLifecycleState
)
Expand Down
28 changes: 15 additions & 13 deletions kohii-core/src/main/java/kohii/v1/core/Group.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package kohii.v1.core

import android.graphics.Rect
import android.os.Handler
import android.os.Looper
import android.os.Message
import android.view.ViewGroup
import androidx.collection.arraySetOf
Expand Down Expand Up @@ -51,20 +52,21 @@ class Group(

private var stickyManager: Manager? = null
set(value) {
val from = field
val prevStickyManager = field
field = value
val to = field
if (from === to) return
if (to != null) { // a Manager is promoted
to.sticky = true
managers.push(to)
val nextStickyManager = field
if (prevStickyManager === nextStickyManager) return
if (nextStickyManager != null) { // a Manager is promoted
nextStickyManager.sticky = true
managers.push(nextStickyManager)
} else {
require(from != null && from.sticky)
if (managers.peek() === from) {
from.sticky = false
require(prevStickyManager != null && prevStickyManager.sticky)
if (managers.peek() === prevStickyManager) {
prevStickyManager.sticky = false
managers.pop()
}
}
onRefresh()
}

internal var groupVolumeInfo: VolumeInfo = VolumeInfo.DEFAULT_ACTIVE
Expand All @@ -83,7 +85,7 @@ class Group(
managers.forEach { it.lock = value }
}

private val handler = Handler(this)
private val handler = Handler(/* looper */ Looper.getMainLooper(), /* callback */ this)
private val dispatcher = PlayableDispatcher(master)

private val playbacks: Collection<Playback>
Expand Down Expand Up @@ -157,8 +159,8 @@ class Group(
toPlay.addAll(canPlay)
toPause.addAll(canPause)
} else {
managers.forEach {
val (canPlay, canPause) = it.splitPlaybacks()
for (manager in managers) {
val (canPlay, canPause) = manager.splitPlaybacks()
toPlay.addAll(canPlay)
toPause.addAll(canPause)
}
Expand Down Expand Up @@ -190,6 +192,7 @@ class Group(
if (it.host is OnSelectionListener) {
it.host to (grouped[it] ?: emptyList())
} else {
@Suppress("USELESS_CAST")
null as Pair<OnSelectionListener, List<Playback>>?
}
}
Expand Down Expand Up @@ -231,7 +234,6 @@ class Group(
internal fun onManagerDestroyed(manager: Manager) {
if (stickyManager === manager) stickyManager = null
if (managers.remove(manager)) master.onGroupUpdated(this)
if (managers.size == 0) master.onLastManagerDestroyed(this)
}

// This operation should:
Expand Down
2 changes: 0 additions & 2 deletions kohii-core/src/main/java/kohii/v1/core/Interfaces.kt
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,4 @@ interface DefaultTrackSelectorHolder {
val trackSelector: DefaultTrackSelector
}

interface PlayableManager

interface PlayableContainer
Loading