Skip to content

Commit 2864915

Browse files
committed
Use Compiler Metrics to make Composables skippable
1 parent 475fcc0 commit 2864915

File tree

15 files changed

+276
-86
lines changed

15 files changed

+276
-86
lines changed

mobile/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ plugins {
44
}
55

66
android {
7-
compileSdk 32
7+
compileSdk 33
88

99
defaultConfig {
1010
applicationId "com.afzaln.besttvlauncher"
1111
minSdk 29
12-
targetSdk 32
12+
targetSdk 33
1313
versionCode 1
1414
versionName "1.0"
1515

tv/build.gradle

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,19 @@ android {
5454
kotlinOptions {
5555
jvmTarget = "1.8"
5656
freeCompilerArgs += ["-Xjvm-default=enable"]
57+
58+
if (project.findProperty("com.afzaln.besttvlauncher.enableComposeCompilerReports") == "true") {
59+
freeCompilerArgs += [
60+
"-P",
61+
"plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=" +
62+
project.buildDir.absolutePath + "/compose_metrics"
63+
]
64+
freeCompilerArgs += [
65+
"-P",
66+
"plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=" +
67+
project.buildDir.absolutePath + "/compose_metrics"
68+
]
69+
}
5770
}
5871

5972
buildFeatures {
@@ -83,6 +96,7 @@ android {
8396
}
8497

8598
dependencies {
99+
implementation("org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.5")
86100

87101
implementation("androidx.core:core-ktx:1.8.0")
88102
implementation("androidx.leanback:leanback:1.0.0")

tv/src/main/java/com/afzaln/besttvlauncher/data/AppInfoRepository.kt

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ package com.afzaln.besttvlauncher.data
33
import android.content.Context
44
import android.content.Intent
55
import android.content.pm.PackageManager
6+
import com.afzaln.besttvlauncher.data.models.AppInfo
7+
import kotlinx.collections.immutable.ImmutableList
8+
import kotlinx.collections.immutable.persistentListOf
9+
import kotlinx.collections.immutable.toImmutableList
610
import kotlinx.coroutines.Dispatchers
711
import kotlinx.coroutines.flow.Flow
812
import kotlinx.coroutines.flow.flow
@@ -12,8 +16,8 @@ import kotlinx.coroutines.withContext
1216
class AppInfoRepository(private val context: Context) {
1317
private val packageManager: PackageManager = context.packageManager
1418

15-
private var cached: List<AppInfo> = listOf()
16-
val apps: Flow<List<AppInfo>> = flow {
19+
private var cached: ImmutableList<AppInfo> = persistentListOf()
20+
val apps: Flow<ImmutableList<AppInfo>> = flow {
1721
emit(cached)
1822
val newList = loadAppInfo()
1923
if (cached != newList) {
@@ -22,7 +26,7 @@ class AppInfoRepository(private val context: Context) {
2226
}
2327
}.flowOn(Dispatchers.IO)
2428

25-
private suspend fun loadAppInfo(): List<AppInfo> = withContext(Dispatchers.IO) {
29+
private suspend fun loadAppInfo(): ImmutableList<AppInfo> = withContext(Dispatchers.IO) {
2630
val intent = Intent(Intent.ACTION_MAIN, null).apply {
2731
addCategory(Intent.CATEGORY_LEANBACK_LAUNCHER)
2832
}
@@ -34,10 +38,10 @@ class AppInfoRepository(private val context: Context) {
3438
.distinctBy { it.activityInfo.packageName + it.activityInfo.name.split(".").last() }
3539
.map { app ->
3640
AppInfo(
37-
app.loadLabel(packageManager),
41+
app.loadLabel(packageManager).toString(),
3842
app.activityInfo.packageName,
3943
app.activityInfo.loadBanner(packageManager)
4044
)
41-
}
45+
}.toImmutableList()
4246
}
4347
}

tv/src/main/java/com/afzaln/besttvlauncher/data/ChannelRepository.kt

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,14 @@ package com.afzaln.besttvlauncher.data
33
import android.annotation.SuppressLint
44
import android.content.Context
55
import android.content.pm.PackageManager
6-
import androidx.tvprovider.media.tv.*
6+
import androidx.tvprovider.media.tv.PreviewChannelHelper
7+
import androidx.tvprovider.media.tv.PreviewProgram
8+
import androidx.tvprovider.media.tv.PreviewProgramHelper
9+
import androidx.tvprovider.media.tv.TvContractCompat
10+
import com.afzaln.besttvlauncher.data.models.Channel
11+
import com.afzaln.besttvlauncher.data.models.Program
12+
import com.afzaln.besttvlauncher.data.models.toProgram
13+
import kotlinx.collections.immutable.*
714
import kotlinx.coroutines.Dispatchers
815
import kotlinx.coroutines.flow.MutableStateFlow
916
import kotlinx.coroutines.flow.asStateFlow
@@ -16,10 +23,12 @@ class ChannelRepository(context: Context) {
1623
private val previewProgramHelper: PreviewProgramHelper = PreviewProgramHelper(context)
1724
private val packageManager: PackageManager = context.packageManager
1825

19-
private var _cachedMap = MutableStateFlow<Map<PreviewChannel, List<PreviewProgram>>>(mapOf())
26+
private var _cachedMap = MutableStateFlow<ImmutableMap<Channel, ImmutableList<Program>>>(
27+
persistentMapOf()
28+
)
2029
val channelProgramMap = _cachedMap.asStateFlow()
2130

22-
private val _channels = MutableStateFlow<List<PreviewChannelWrapper>>(listOf())
31+
private val _channels = MutableStateFlow<ImmutableList<Channel>>(persistentListOf())
2332
val channels = _channels.asStateFlow()
2433

2534
suspend fun refreshData() {
@@ -32,13 +41,12 @@ class ChannelRepository(context: Context) {
3241

3342
@SuppressLint("RestrictedApi")
3443
private suspend fun loadPrograms(
35-
channelList: List<PreviewChannelWrapper>,
36-
initial: Map<PreviewChannel, List<PreviewProgram>>
37-
): Map<PreviewChannel, List<PreviewProgram>> = withContext(Dispatchers.IO) {
44+
channelList: ImmutableList<Channel>,
45+
initial: ImmutableMap<Channel, ImmutableList<Program>>
46+
): ImmutableMap<Channel, ImmutableList<Program>> = withContext(Dispatchers.IO) {
3847
initial.toMutableMap().apply {
39-
channelList.forEach { wrappedChannel ->
48+
channelList.forEach { channel ->
4049
logcat { "LoadPrograms: ${Thread.currentThread().name}" }
41-
val channel = wrappedChannel.channel
4250
val programs = if (isWrongAspectRatio(channel)) {
4351
previewProgramHelper.getAllProgramsInChannel(channel.id).map { program ->
4452
PreviewProgram.Builder(program)
@@ -49,17 +57,19 @@ class ChannelRepository(context: Context) {
4957
}
5058
} else {
5159
previewProgramHelper.getAllProgramsInChannel(channel.id)
52-
}
60+
}.map { program ->
61+
program.toProgram()
62+
}.toImmutableList()
5363
put(channel, programs)
5464
}
55-
}
65+
}.toImmutableMap()
5666
}
5767

5868
/**
5969
* To compensate for YouTube Recommended, Music,
6070
* and Trending art ratios including black bars.
6171
*/
62-
private fun isWrongAspectRatio(channel: PreviewChannel) =
72+
private fun isWrongAspectRatio(channel: Channel) =
6373
channel.packageName == "com.google.android.youtube.tv" &&
6474
!channel.displayName.contentEquals("Free movies from Youtube", true)
6575

@@ -70,11 +80,13 @@ class ChannelRepository(context: Context) {
7080
return@update previewChannelHelper.allChannels.map { previewChannel ->
7181
logcat { "LoadChannels: ${Thread.currentThread().name}" }
7282
val appInfo = packageManager.getApplicationInfo(previewChannel.packageName, 0)
73-
PreviewChannelWrapper(
74-
previewChannel,
83+
Channel(
84+
previewChannel.id,
85+
previewChannel.displayName.toString(),
86+
previewChannel.packageName,
7587
appInfo.loadLabel(packageManager).toString()
7688
)
77-
}
89+
}.toImmutableList()
7890
}
7991
}
8092
}

tv/src/main/java/com/afzaln/besttvlauncher/data/PreviewChannelWrapper.kt

Lines changed: 0 additions & 8 deletions
This file was deleted.

tv/src/main/java/com/afzaln/besttvlauncher/data/ProgramRepository.kt

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
package com.afzaln.besttvlauncher.data
22

33
import android.content.Context
4-
import androidx.tvprovider.media.tv.WatchNextProgram
54
import androidx.tvprovider.media.tv.WatchNextProgramHelper
5+
import com.afzaln.besttvlauncher.data.models.Program
6+
import com.afzaln.besttvlauncher.data.models.toProgram
7+
import kotlinx.collections.immutable.ImmutableList
8+
import kotlinx.collections.immutable.persistentListOf
9+
import kotlinx.collections.immutable.toImmutableList
610
import kotlinx.coroutines.Dispatchers
711
import kotlinx.coroutines.flow.MutableStateFlow
812
import kotlinx.coroutines.flow.asStateFlow
@@ -12,7 +16,7 @@ import kotlinx.coroutines.withContext
1216
class ProgramRepository(context: Context) {
1317
private val watchNextProgramHelper = WatchNextProgramHelper(context)
1418

15-
private val _watchNextPrograms = MutableStateFlow<List<WatchNextProgram>>(listOf())
19+
private val _watchNextPrograms = MutableStateFlow<ImmutableList<Program>>(persistentListOf())
1620
val watchNextPrograms = _watchNextPrograms.asStateFlow()
1721

1822
suspend fun refreshData() {
@@ -22,7 +26,9 @@ class ProgramRepository(context: Context) {
2226
// TODO observe ContentProvider using ContentResolver.registerContentObserver
2327
private suspend fun loadWatchNextPrograms() = withContext(Dispatchers.IO) {
2428
_watchNextPrograms.update {
25-
watchNextProgramHelper.allWatchNextPrograms
29+
watchNextProgramHelper.allWatchNextPrograms.map { program ->
30+
program.toProgram()
31+
}.toImmutableList()
2632
}
2733
}
2834
}

tv/src/main/java/com/afzaln/besttvlauncher/data/AppInfo.kt renamed to tv/src/main/java/com/afzaln/besttvlauncher/data/models/AppInfo.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
package com.afzaln.besttvlauncher.data
1+
package com.afzaln.besttvlauncher.data.models
22

33
import android.content.Context
44
import android.content.Intent
55
import android.graphics.drawable.Drawable
66

77
data class AppInfo(
8-
val label: CharSequence,
8+
val label: String,
99
val packageName: String,
1010
val banner: Drawable
1111
)
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.afzaln.besttvlauncher.data.models
2+
3+
data class Channel(
4+
val id: Long,
5+
val displayName: String,
6+
val packageName: String,
7+
val appName: String
8+
)

tv/src/main/java/com/afzaln/besttvlauncher/utils/ProgramExt.kt renamed to tv/src/main/java/com/afzaln/besttvlauncher/data/models/Program.kt

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,33 @@
1-
package com.afzaln.besttvlauncher.utils
1+
package com.afzaln.besttvlauncher.data.models
22

33
import android.annotation.SuppressLint
44
import androidx.tvprovider.media.tv.BasePreviewProgram
55
import androidx.tvprovider.media.tv.TvContractCompat
66

7+
data class Program(
8+
val id: Long,
9+
val title: String,
10+
val description: String,
11+
val genre: String?,
12+
val releaseDate: String?,
13+
val durationMillis: Int,
14+
val posterArtAspectRatio: Int,
15+
val posterArtUri: String,
16+
)
17+
18+
fun BasePreviewProgram.toProgram() = Program(
19+
id,
20+
title,
21+
description,
22+
genre,
23+
releaseDate,
24+
durationMillis,
25+
posterArtAspectRatio,
26+
posterArtUri.toString(),
27+
)
28+
729
@SuppressLint("RestrictedApi")
8-
fun BasePreviewProgram.posterAspectRatio(): Float = when (posterArtAspectRatio) {
30+
fun Program.posterAspectRatio(): Float = when (posterArtAspectRatio) {
931
// TODO publish AndroidTvProvider fork 1.0.2
1032
TvContractCompat.PreviewProgramColumns.ASPECT_RATIO_16_9 -> 16f / 9
1133
TvContractCompat.PreviewProgramColumns.ASPECT_RATIO_3_2 -> 3f / 2

tv/src/main/java/com/afzaln/besttvlauncher/ui/apps/AppsScreen.kt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,11 @@ import androidx.compose.ui.unit.dp
2424
import androidx.core.graphics.drawable.toBitmap
2525
import androidx.tv.foundation.lazy.grid.*
2626
import com.afzaln.besttvlauncher.R
27-
import com.afzaln.besttvlauncher.data.AppInfo
28-
import com.afzaln.besttvlauncher.data.getLaunchIntent
27+
import com.afzaln.besttvlauncher.data.models.AppInfo
28+
import com.afzaln.besttvlauncher.data.models.getLaunchIntent
2929
import com.afzaln.besttvlauncher.ui.theme.AppTheme
3030
import com.afzaln.besttvlauncher.utils.dpadFocusable
31+
import kotlinx.collections.immutable.ImmutableList
3132

3233
@Composable
3334
fun AppsScreen(state: HomeViewModel.State) {
@@ -41,7 +42,7 @@ fun AppsScreen(state: HomeViewModel.State) {
4142

4243
@OptIn(ExperimentalFoundationApi::class)
4344
@Composable
44-
fun AppList(appList: List<AppInfo>) {
45+
fun AppList(appList: ImmutableList<AppInfo>) {
4546
val gridState = rememberTvLazyGridState()
4647
val relocationRequester = remember { BringIntoViewRequester() }
4748

0 commit comments

Comments
 (0)