Close #25919: Move UpdateFirstFrameDrawn to RecyclerView.onLayoutCompleted

As part of a preventitive measure for home page regression loading, we
fixed the UpdateFirstFrameDrawn call to happen after the first layout in
the main RecyclerView is completed. In addition, we also make pocket
aware of this flag so that it renders itself after the first layout.

This helps prioritize current & future features that are visible first
to render before those that are off screen.

Co-authored-by: Arturo Mejia <arturomejiamarmol@gmail.com>
This commit is contained in:
Jonathan Almeida 2022-08-26 11:51:10 -04:00 committed by mergify[bot]
parent ab3f6b5e4b
commit 40cd58132e
3 changed files with 40 additions and 9 deletions

View File

@ -26,7 +26,6 @@ import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
import androidx.constraintlayout.widget.ConstraintSet.TOP
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.content.ContextCompat
import androidx.core.view.doOnPreDraw
import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams
import androidx.fragment.app.Fragment
@ -398,10 +397,6 @@ class HomeFragment : Fragment() {
FxNimbus.features.homescreen.recordExposure()
binding.root.doOnPreDraw {
requireComponents.appStore.dispatch(AppAction.UpdateFirstFrameDrawn(drawn = true))
}
// DO NOT MOVE ANYTHING BELOW THIS addMarker CALL!
requireComponents.core.engine.profiler?.addMarker(
MarkersFragmentLifecycleCallbacks.MARKER_NAME, profilerStartTime, "HomeFragment.onCreateView",

View File

@ -12,6 +12,7 @@ import androidx.recyclerview.widget.RecyclerView
import mozilla.components.feature.tab.collections.TabCollection
import mozilla.components.feature.top.sites.TopSite
import mozilla.components.service.pocket.PocketStory
import org.mozilla.fenix.components.appstate.AppAction
import org.mozilla.fenix.components.appstate.AppState
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.settings
@ -41,7 +42,8 @@ internal fun normalModeAdapterItems(
showRecentTab: Boolean,
showRecentSyncedTab: Boolean,
recentVisits: List<RecentlyVisitedItem>,
pocketStories: List<PocketStory>
pocketStories: List<PocketStory>,
firstFrameDrawn: Boolean = false,
): List<AdapterItem> {
val items = mutableListOf<AdapterItem>()
var shouldShowCustomizeHome = false
@ -86,7 +88,11 @@ internal fun normalModeAdapterItems(
showCollections(collections, expandedCollections, items)
}
if (settings.showPocketRecommendationsFeature && pocketStories.isNotEmpty()) {
// When Pocket is enabled and the initial layout of the app is done, then we can add these items
// to render to the home screen.
// This is only useful while we have a RecyclerView + Compose implementation. We can remove this
// when we switch to a Compose-only home screen.
if (firstFrameDrawn && settings.showPocketRecommendationsFeature && pocketStories.isNotEmpty()) {
shouldShowCustomizeHome = true
items.add(AdapterItem.PocketStoriesItem)
items.add(AdapterItem.PocketCategoriesItem)
@ -166,7 +172,8 @@ private fun AppState.toAdapterList(settings: Settings): List<AdapterItem> = when
shouldShowRecentTabs(settings),
shouldShowRecentSyncedTabs(settings),
recentHistory,
pocketStories
pocketStories,
firstFrameDrawn
)
is Mode.Private -> privateModeAdapterItems()
is Mode.Onboarding -> onboardingAdapterItems(mode.state)
@ -207,6 +214,15 @@ class SessionControlView(
).showSyncCFR()
context.settings().showSyncCFR = false
}
// We want some parts of the home screen UI to be rendered first if they are
// the most prominent parts of the visible part of the screen.
// For this reason, we wait for the home screen recycler view to finish it's
// layout and post an update for when it's best for non-visible parts of the
// home screen to render itself.
containerView.context.components.appStore.dispatch(
AppAction.UpdateFirstFrameDrawn(true)
)
}
}
}

View File

@ -217,7 +217,8 @@ class SessionControlViewTest {
false,
showRecentSyncedTab = false,
historyMetadata,
pocketStories
pocketStories,
true
)
assertTrue(results[0] is AdapterItem.TopPlaceholderItem)
@ -225,6 +226,25 @@ class SessionControlViewTest {
assertTrue(results[2] is AdapterItem.PocketCategoriesItem)
assertTrue(results[3] is AdapterItem.PocketRecommendationsFooterItem)
assertTrue(results[4] is AdapterItem.CustomizeHomeButton)
// When the first frame has not yet drawn don't add pocket.
val results2 = normalModeAdapterItems(
settings,
topSites,
collections,
expandedCollections,
recentBookmarks,
false,
null,
false,
showRecentSyncedTab = false,
historyMetadata,
pocketStories,
false
)
assertTrue(results2[0] is AdapterItem.TopPlaceholderItem)
assertTrue(results2[1] is AdapterItem.BottomSpacer)
}
@Test