Skip to content

Commit 57f42c8

Browse files
OPTI-1528: address the review feedback
1 parent 03ab98f commit 57f42c8

7 files changed

Lines changed: 277 additions & 148 deletions

File tree

ui/src/main/java/com/theoplayer/android/ui/Helper.kt

Lines changed: 2 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,7 @@ import androidx.compose.runtime.Composable
55
import androidx.compose.runtime.remember
66
import androidx.compose.ui.platform.LocalResources
77
import com.theoplayer.android.api.player.track.Track
8-
import com.theoplayer.android.api.player.track.texttrack.TextTrack
9-
import com.theoplayer.android.api.player.track.texttrack.TextTrackType
10-
import com.theoplayer.android.ui.util.getLabelForChannelNumber
11-
import com.theoplayer.android.ui.util.isLabelCeaFormatted
12-
import com.theoplayer.android.ui.util.localisedLanguage
13-
import com.theoplayer.android.ui.util.runForPlayerWith
8+
import com.theoplayer.android.ui.util.constructLabel
149
import kotlin.math.absoluteValue
1510

1611
/**
@@ -74,37 +69,5 @@ fun rememberTrackLabel(
7469
track: Track,
7570
resources: Resources = LocalResources.current,
7671
): String = remember(key1 = track.id, key2 = track.uid) {
77-
val label: String? = runForPlayerWith(
78-
// With 11 release, the player will no longer
79-
// prefix text tracks with "CC" for CEA-608 and CEA-708,
80-
// if [Track.label] is `null`.
81-
desiredMajorVersion = 11,
82-
actionIfEqualOrAbove = { track.label },
83-
actionIfBelow = {
84-
if ((track is TextTrack) && isLabelCeaFormatted(track.label)) {
85-
// If we are below 11th major release
86-
// and the label is CEA-formatted we
87-
// can safely assume it was the last resort
88-
// option to produce a meaningful label, given
89-
// we cannot localize the language code in the player.
90-
null
91-
} else {
92-
track.label
93-
}
94-
},
95-
)
96-
if (!label.isNullOrBlank()) {
97-
return@remember label
98-
}
99-
val localisedLanguage = track.localisedLanguage
100-
if (localisedLanguage != null) {
101-
return@remember localisedLanguage
102-
}
103-
if ((track is TextTrack) && track.type == TextTrackType.CEA608) {
104-
val channelNumberLabel = getLabelForChannelNumber(track.channelNumber)
105-
if (channelNumberLabel != null) {
106-
return@remember channelNumberLabel
107-
}
108-
}
109-
return@remember resources.getString(R.string.theoplayer_ui_track_unknown)
72+
constructLabel(track) ?: resources.getString(R.string.theoplayer_ui_track_unknown)
11073
}

ui/src/main/java/com/theoplayer/android/ui/util/CeaUtil.kt

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,14 @@ private val CEA_FORMATTING_REGEX = "^CC(\\d+)$".toRegex()
1010
*/
1111
@CheckResult
1212
internal fun isLabelCeaFormatted(label: String?): Boolean {
13-
if (label == null) {
13+
if (label.isNullOrEmpty()) {
1414
return false
1515
}
1616

17-
val matchResult = CEA_FORMATTING_REGEX.find(label)
18-
val groupValues = matchResult?.groupValues
19-
if (matchResult == null ||
20-
groupValues == null ||
21-
// There is one group we want to match with the channel number.
22-
groupValues.size != 2) {
17+
val matchResult = CEA_FORMATTING_REGEX.find(label) ?: return false
18+
val groupValues = matchResult.groupValues
19+
// There is one group we want to match with the channel number.
20+
if (groupValues.size != 2) {
2321
return false
2422
}
2523

@@ -36,7 +34,7 @@ internal fun isLabelCeaFormatted(label: String?): Boolean {
3634
*/
3735
@CheckResult
3836
internal fun getLabelForChannelNumber(
39-
@IntRange(from = 0L, to = 63L) channelNumber: Int?,
37+
@IntRange(from = 0L, to = 63L) channelNumber: Int,
4038
): String? {
4139
// CEA-608 only supports channel numbers in [1, 4],
4240
// while CEA-708 support service numbers in [1, 63].

ui/src/main/java/com/theoplayer/android/ui/util/TrackExts.kt

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
package com.theoplayer.android.ui.util
22

33
import androidx.annotation.CheckResult
4+
import com.theoplayer.android.api.THEOplayerGlobal
45
import com.theoplayer.android.api.player.track.Track
6+
import com.theoplayer.android.api.player.track.texttrack.TextTrack
7+
import com.theoplayer.android.api.player.track.texttrack.TextTrackType
8+
import com.theoplayer.android.ui.R
59
import java.util.Locale
610

711
private const val LANGUAGE_UNDEFINED = "und"
@@ -15,7 +19,7 @@ private const val LANGUAGE_UNDEFINED = "und"
1519
* returns `null`.
1620
*/
1721
@get:CheckResult
18-
internal val Track.localisedLanguage: String?
22+
internal val Track.localizedLanguage: String?
1923
get() {
2024
val languageCode = this.language
2125
if (languageCode.isNullOrBlank() || languageCode == LANGUAGE_UNDEFINED) {
@@ -30,3 +34,73 @@ internal val Track.localisedLanguage: String?
3034

3135
return localisedLanguage
3236
}
37+
38+
/**
39+
* Constructs a label for the given [Track] instance.
40+
* The method works slightly different for different player version.
41+
*
42+
* On version 10 and below the logic checks the following and condition
43+
* and the first not `null` entry from the list:
44+
* 1. Track label if is not a language code
45+
* or a CEA-prefixed string.
46+
* 2. Track language display name
47+
* 3. Track channel number if a text CEA-608 track
48+
* 4. Track label if was either a language code or a CEA-prefixed string
49+
*
50+
* If none of the above is satisfied, returns `null`.
51+
*
52+
* On version 11 and later the logic has slightly changed as
53+
* the player no longer constructs the [Track.getLabel] internally:
54+
* 1. Track label
55+
* 2. Track language display name
56+
* 3. Track channel number
57+
*/
58+
internal fun constructLabel(
59+
track: Track,
60+
): String? {
61+
val playerVersion = getPlayerMajorVersion(THEOplayerGlobal.getVersion())
62+
63+
val label: String? = if(
64+
playerVersion != null &&
65+
playerVersion < 11 &&
66+
(track is TextTrack) &&
67+
(
68+
isLabelCeaFormatted(track.label) ||
69+
(track.label != null && track.language == track.label)
70+
)) {
71+
// If we are below 11th major release
72+
// and the label is CEA-formatted we
73+
// can safely assume it was the last resort
74+
// option to produce a meaningful label, given
75+
// we cannot localize the language code in the player.
76+
null
77+
} else {
78+
// With 11 release, the player will no longer
79+
// prefix text tracks with "CC" for CEA-608 and CEA-708,
80+
// if [Track.label] is `null`.
81+
track.label
82+
}
83+
84+
if (!label.isNullOrBlank()) {
85+
return label
86+
}
87+
88+
val localisedLanguage = track.localizedLanguage
89+
if (localisedLanguage != null) {
90+
return localisedLanguage
91+
}
92+
93+
if ((track is TextTrack) &&
94+
track.channelNumber != null &&
95+
track.type == TextTrackType.CEA608) {
96+
val channelNumberLabel = getLabelForChannelNumber(track.channelNumber)
97+
if (channelNumberLabel != null) {
98+
return channelNumberLabel
99+
}
100+
if (!track.label.isNullOrBlank()) {
101+
return track.label
102+
}
103+
}
104+
105+
return null
106+
}
Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,18 @@
11
package com.theoplayer.android.ui.util
22

3-
import com.theoplayer.android.api.THEOplayerGlobal
4-
5-
private const val VERSION_DELIMITER = "."
3+
private const val DEFAULT_VERSION_DELIMITER = "."
64

75
/**
8-
* Performs a player version check and executes an appropriate action:
9-
* if the major version is equal or above to the [desiredMajorVersion]
10-
* then [actionIfEqualOrAbove] is triggered, otherwise [actionIfBelow].
6+
* Extracts a major version number from
7+
* a formatted version string such as `"major.minor.patch"`.
118
*/
12-
internal inline fun <reified T> runForPlayerWith(
13-
desiredMajorVersion: Int,
14-
actionIfEqualOrAbove: () -> T,
15-
actionIfBelow: () -> T,
16-
): T {
17-
val version: String? = THEOplayerGlobal.getVersion()
18-
val versionSplits = version?.split(VERSION_DELIMITER)
19-
val majorVersionNumber = versionSplits?.getOrNull(0)?.toIntOrNull()
20-
21-
return if (majorVersionNumber == null || majorVersionNumber < desiredMajorVersion) {
22-
actionIfBelow()
23-
} else {
24-
actionIfEqualOrAbove()
9+
internal fun getPlayerMajorVersion(
10+
version: String,
11+
delimiter: String = DEFAULT_VERSION_DELIMITER,
12+
): Int? {
13+
val versionSplits = version.split(delimiter)
14+
if (versionSplits.size != 3) {
15+
return null
2516
}
17+
return versionSplits.getOrNull(0)?.toIntOrNull()
2618
}

ui/src/test/java/com/theoplayer/android/ui/util/CeaUtilTest.kt

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -120,19 +120,15 @@ class CeaUtilTest {
120120
}
121121

122122
data class Args(
123-
val channelNumber: Int?,
123+
val channelNumber: Int,
124124
val expectedLabel: String?,
125125
)
126126

127127
private companion object {
128128
@JvmStatic
129-
@Parameterized.Parameters
129+
@Parameterized.Parameters(name = "{0}")
130130
fun data() = arrayOf(
131131
// Boundary checks.
132-
Args(
133-
channelNumber = null,
134-
expectedLabel = null,
135-
),
136132
Args(
137133
channelNumber = -1,
138134
expectedLabel = null,

0 commit comments

Comments
 (0)