diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 843f5a356..51920b505 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -24,7 +24,7 @@ plugins { id("jacoco") id("dagger.hilt.android.plugin") id("nowinandroid.spotless") - id("com.google.firebase.firebase-perf") version "1.4.1" + id("nowinandroid.firebase-perf") } android { diff --git a/app/src/main/java/com/google/samples/apps/nowinandroid/MainActivity.kt b/app/src/main/java/com/google/samples/apps/nowinandroid/MainActivity.kt index de63dad5d..19ec44ad2 100644 --- a/app/src/main/java/com/google/samples/apps/nowinandroid/MainActivity.kt +++ b/app/src/main/java/com/google/samples/apps/nowinandroid/MainActivity.kt @@ -31,12 +31,12 @@ import javax.inject.Inject @AndroidEntryPoint class MainActivity : ComponentActivity() { + /** + * Lazily inject [JankStats], which is used to track jank throughout the app. + */ @Inject lateinit var lazyStats: dagger.Lazy - @Inject - lateinit var jankFrameListener: JankStats.OnFrameListener - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -51,15 +51,11 @@ class MainActivity : ComponentActivity() { override fun onResume() { super.onResume() - isTrackingEnabled(true) + lazyStats.get().isTrackingEnabled = true } override fun onPause() { super.onPause() - isTrackingEnabled(false) - } - - private fun isTrackingEnabled(enabled: Boolean) { - lazyStats.get().isTrackingEnabled = enabled + lazyStats.get().isTrackingEnabled = false } } diff --git a/app/src/main/java/com/google/samples/apps/nowinandroid/ui/NiaApp.kt b/app/src/main/java/com/google/samples/apps/nowinandroid/ui/NiaApp.kt index c0f5c1b20..d005f2014 100644 --- a/app/src/main/java/com/google/samples/apps/nowinandroid/ui/NiaApp.kt +++ b/app/src/main/java/com/google/samples/apps/nowinandroid/ui/NiaApp.kt @@ -67,7 +67,6 @@ import com.google.samples.apps.nowinandroid.navigation.TopLevelDestination fun NiaApp(windowSizeClass: WindowSizeClass) { NiaTheme { val navController = rememberNavController() - val niaTopLevelNavigation = remember(navController) { NiaTopLevelNavigation(navController) } diff --git a/build-logic/convention/build.gradle.kts b/build-logic/convention/build.gradle.kts index 9a5baaa41..a7841103f 100644 --- a/build-logic/convention/build.gradle.kts +++ b/build-logic/convention/build.gradle.kts @@ -69,5 +69,9 @@ gradlePlugin { id = "nowinandroid.spotless" implementationClass = "SpotlessConventionPlugin" } + register("firebase-perf") { + id = "nowinandroid.firebase-perf" + implementationClass = "FirebasePerfConventionPlugin" + } } } diff --git a/build-logic/convention/src/main/kotlin/FirebasePerfConventionPlugin.kt b/build-logic/convention/src/main/kotlin/FirebasePerfConventionPlugin.kt new file mode 100644 index 000000000..48f750678 --- /dev/null +++ b/build-logic/convention/src/main/kotlin/FirebasePerfConventionPlugin.kt @@ -0,0 +1,29 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * 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 + * + * https://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. + */ + +import org.gradle.api.Plugin +import org.gradle.api.Project + +class FirebasePerfConventionPlugin : Plugin { + override fun apply(target: Project) { + with(target) { + pluginManager.findPlugin("com.google.firebase.firebase-perf").apply { + version = "1.4.1" + } + } + } + +} \ No newline at end of file diff --git a/core-ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/JankStatsExtensions.kt b/core-ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/JankStatsExtensions.kt index 2ae7aa97a..6fdb948c7 100644 --- a/core-ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/JankStatsExtensions.kt +++ b/core-ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/JankStatsExtensions.kt @@ -16,12 +16,14 @@ package com.google.samples.apps.nowinandroid.core.ui +import androidx.compose.foundation.gestures.ScrollableState import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.DisposableEffectResult import androidx.compose.runtime.DisposableEffectScope import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.remember +import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.platform.LocalView import androidx.metrics.performance.PerformanceMetricsState import androidx.metrics.performance.PerformanceMetricsState.MetricsStateHolder @@ -71,3 +73,18 @@ fun JankMetricDisposableEffect( reportMetric(this, metrics) } } + +@Composable +fun TrackScrollJank(scrollableState: ScrollableState, stateName: String) { + JankMetricEffect(scrollableState) { metricsHolder -> + snapshotFlow { scrollableState.isScrollInProgress }.collect { isScrollInProgress -> + metricsHolder.state?.apply { + if (isScrollInProgress) { + addState(stateName, "Scrolling=true") + } else { + removeState(stateName) + } + } + } + } +} diff --git a/feature-foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/AuthorsCarousel.kt b/feature-foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/AuthorsCarousel.kt index 687cdbbd8..fcd400c46 100644 --- a/feature-foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/AuthorsCarousel.kt +++ b/feature-foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/AuthorsCarousel.kt @@ -38,7 +38,6 @@ import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.remember -import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip @@ -57,9 +56,7 @@ import com.google.samples.apps.nowinandroid.core.designsystem.icon.NiaIcons import com.google.samples.apps.nowinandroid.core.designsystem.theme.NiaTheme import com.google.samples.apps.nowinandroid.core.model.data.Author import com.google.samples.apps.nowinandroid.core.model.data.FollowableAuthor -import com.google.samples.apps.nowinandroid.core.ui.JankMetricEffect -import kotlinx.coroutines.flow.collect -import kotlinx.coroutines.flow.combine +import com.google.samples.apps.nowinandroid.core.ui.TrackScrollJank @Composable fun AuthorsCarousel( @@ -69,21 +66,7 @@ fun AuthorsCarousel( ) { val lazyListState = rememberLazyListState() - JankMetricEffect(lazyListState) { metricsHolder -> - combine( - snapshotFlow { lazyListState.isScrollInProgress }, - snapshotFlow { lazyListState.firstVisibleItemIndex } - ) { isScrollInProgress, firstVisibleItemIndex -> - if (isScrollInProgress) { - metricsHolder.state?.addState( - "ForYou:AuthorsCarousel:Scrolling", - "Index=$firstVisibleItemIndex" - ) - } else { - metricsHolder.state?.removeState("ForYou:AuthorsCarousel:Scrolling") - } - }.collect() - } + TrackScrollJank(lazyListState, "ForYou:AuthorsCarousel") LazyRow(modifier, lazyListState) { items(items = authors, key = { item -> item.author.id }) { followableAuthor -> diff --git a/feature-foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt b/feature-foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt index 0a997d894..a6ec3c42e 100644 --- a/feature-foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt +++ b/feature-foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt @@ -63,7 +63,6 @@ import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue -import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @@ -93,11 +92,9 @@ import com.google.samples.apps.nowinandroid.core.model.data.SaveableNewsResource import com.google.samples.apps.nowinandroid.core.model.data.previewAuthors import com.google.samples.apps.nowinandroid.core.model.data.previewNewsResources import com.google.samples.apps.nowinandroid.core.model.data.previewTopics -import com.google.samples.apps.nowinandroid.core.ui.JankMetricEffect import com.google.samples.apps.nowinandroid.core.ui.NewsResourceCardExpanded +import com.google.samples.apps.nowinandroid.core.ui.TrackScrollJank import kotlin.math.floor -import kotlinx.coroutines.flow.collect -import kotlinx.coroutines.flow.combine @Composable fun ForYouRoute( @@ -168,21 +165,7 @@ fun ForYouScreen( } val lazyListState = rememberLazyListState() - JankMetricEffect(lazyListState) { metricsHolder -> - combine( - snapshotFlow { lazyListState.isScrollInProgress }, - snapshotFlow { lazyListState.firstVisibleItemIndex }, - ) { isScrollInProgress, firstVisibleItemIndex -> - if (isScrollInProgress) { - metricsHolder.state?.addState( - "ForYou:Feed:Scrolling", - "index=$firstVisibleItemIndex" - ) - } else { - metricsHolder.state?.removeState("ForYou:Feed:Scrolling") - } - }.collect() - } + TrackScrollJank(lazyListState, "ForYou:Feed") LazyColumn( state = lazyListState, @@ -311,21 +294,8 @@ private fun TopicSelection( modifier: Modifier = Modifier ) { val lazyGridState = rememberLazyGridState() - JankMetricEffect(lazyGridState) { metricsHolder -> - combine( - snapshotFlow { lazyGridState.isScrollInProgress }, - snapshotFlow { lazyGridState.firstVisibleItemIndex }, - ) { isScrollInProgress, firstVisibleItemIndex -> - if (isScrollInProgress) { - metricsHolder.state?.addState( - "ForYou:TopicSelection:Scrolling", - "index=$firstVisibleItemIndex" - ) - } else { - metricsHolder.state?.removeState("ForYou:TopicSelection:Scrolling") - } - }.collect() - } + + TrackScrollJank(scrollableState = lazyGridState, stateName = "ForYou:TopicSelection") LazyHorizontalGrid( state = lazyGridState,