diff --git a/app/src/main/java/org/mozilla/fenix/home/topsites/TopSites.kt b/app/src/main/java/org/mozilla/fenix/home/topsites/TopSites.kt index 46d4fb4305..a701fdfc21 100644 --- a/app/src/main/java/org/mozilla/fenix/home/topsites/TopSites.kt +++ b/app/src/main/java/org/mozilla/fenix/home/topsites/TopSites.kt @@ -104,6 +104,7 @@ fun TopSites( onRemoveTopSiteClicked: (topSite: TopSite) -> Unit, onSettingsClicked: () -> Unit, onSponsorPrivacyClicked: () -> Unit, + onTopSitesItemBound: () -> Unit, ) { val pageCount = ceil((topSites.size.toDouble() / TOP_SITES_PER_PAGE)).toInt() @@ -154,6 +155,7 @@ fun TopSites( topSiteColors = topSiteColors, onTopSiteClick = { item -> onTopSiteClick(item) }, onTopSiteLongClick = onTopSiteLongClick, + onTopSitesItemBound = onTopSitesItemBound, ) } } @@ -251,6 +253,7 @@ private fun TopSiteItem( topSiteColors: TopSiteColors, onTopSiteClick: (TopSite) -> Unit, onTopSiteLongClick: (TopSite) -> Unit, + onTopSitesItemBound: () -> Unit, ) { var menuExpanded by remember { mutableStateOf(false) } @@ -339,6 +342,10 @@ private fun TopSiteItem( } } } + + LaunchedEffect(Unit) { + onTopSitesItemBound() + } } /** @@ -587,6 +594,7 @@ private fun TopSitesPreview() { onRemoveTopSiteClicked = {}, onSettingsClicked = {}, onSponsorPrivacyClicked = {}, + onTopSitesItemBound = {}, ) } } diff --git a/app/src/main/java/org/mozilla/fenix/home/topsites/TopSitesViewHolder.kt b/app/src/main/java/org/mozilla/fenix/home/topsites/TopSitesViewHolder.kt index 74e67ef26b..0e6eb91a14 100644 --- a/app/src/main/java/org/mozilla/fenix/home/topsites/TopSitesViewHolder.kt +++ b/app/src/main/java/org/mozilla/fenix/home/topsites/TopSitesViewHolder.kt @@ -9,9 +9,11 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.platform.ComposeView import androidx.lifecycle.LifecycleOwner import mozilla.components.lib.state.ext.observeAsComposableState +import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.components.components import org.mozilla.fenix.compose.ComposeViewHolder import org.mozilla.fenix.home.sessioncontrol.TopSiteInteractor +import org.mozilla.fenix.perf.StartupTimeline import org.mozilla.fenix.wallpapers.WallpaperState /** @@ -49,6 +51,9 @@ class TopSitesViewHolder( onRemoveTopSiteClicked = interactor::onRemoveTopSiteClicked, onSettingsClicked = interactor::onSettingsClicked, onSponsorPrivacyClicked = interactor::onSponsorPrivacyClicked, + onTopSitesItemBound = { + StartupTimeline.onTopSitesItemBound(activity = composeView.context as HomeActivity) + }, ) } } diff --git a/app/src/main/java/org/mozilla/fenix/perf/StartupReportFullyDrawn.kt b/app/src/main/java/org/mozilla/fenix/perf/StartupReportFullyDrawn.kt index 800272b082..66d31d05c6 100644 --- a/app/src/main/java/org/mozilla/fenix/perf/StartupReportFullyDrawn.kt +++ b/app/src/main/java/org/mozilla/fenix/perf/StartupReportFullyDrawn.kt @@ -61,6 +61,24 @@ class StartupReportFullyDrawn { } } + /** + * Instruments "visually complete" cold startup time to homescreen for use with FNPRMS. + * + * For FNPRMS, we define "visually complete" to be when top sites is loaded with placeholders; + * the animation to display top sites will occur after this point, as will the asynchronous + * loading of the actual top sites icons. Our focus for visually complete is usability. + * There are no tabs available in our FNPRMS tests so they are ignored for this instrumentation. + */ + fun onTopSitesItemBound(state: StartupState, activity: HomeActivity) { + if (!isInstrumented && + state is StartupState.Cold && state.destination == HOMESCREEN + ) { + isInstrumented = true + + attachReportFullyDrawn(activity) + } + } + private fun attachReportFullyDrawn(activity: Activity, view: View) { // For greater accuracy, we could add an onDrawListener instead of a preDrawListener but: // - single use onDrawListeners are not built-in and it's non-trivial to write one @@ -69,4 +87,8 @@ class StartupReportFullyDrawn { // should be comparable view.doOnPreDraw { activity.reportFullyDrawnSafe(Performance.logger) } } + + private fun attachReportFullyDrawn(activity: Activity) { + activity.reportFullyDrawnSafe(Performance.logger) + } } diff --git a/app/src/main/java/org/mozilla/fenix/perf/StartupTimeline.kt b/app/src/main/java/org/mozilla/fenix/perf/StartupTimeline.kt index 0c3cd8bb2c..e87e17af86 100644 --- a/app/src/main/java/org/mozilla/fenix/perf/StartupTimeline.kt +++ b/app/src/main/java/org/mozilla/fenix/perf/StartupTimeline.kt @@ -54,6 +54,13 @@ object StartupTimeline { reportFullyDrawn.onTopSitesItemBound(state, holder) } + /** + * Instruments "visually complete" cold startup time to homescreen for use with FNPRMS. + */ + fun onTopSitesItemBound(activity: HomeActivity) { + reportFullyDrawn.onTopSitesItemBound(state, activity) + } + private fun advanceState(startingActivity: StartupActivity) { state = StartupTimelineStateMachine.getNextState(state, startingActivity) }