For #6313 - On first load, hides engineView until firstContentfulPaint
This commit is contained in:
parent
495341a945
commit
f663129632
|
@ -44,12 +44,6 @@ import org.mozilla.fenix.helpers.click
|
||||||
import org.mozilla.fenix.helpers.ext.waitNotNull
|
import org.mozilla.fenix.helpers.ext.waitNotNull
|
||||||
|
|
||||||
class BrowserRobot {
|
class BrowserRobot {
|
||||||
|
|
||||||
fun verifyBrowserScreen() {
|
|
||||||
onView(ViewMatchers.withResourceName("browserLayout"))
|
|
||||||
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
|
||||||
}
|
|
||||||
|
|
||||||
fun verifyCurrentPrivateSession(context: Context) {
|
fun verifyCurrentPrivateSession(context: Context) {
|
||||||
val session = context.components.core.sessionManager.selectedSession
|
val session = context.components.core.sessionManager.selectedSession
|
||||||
assertTrue("Current session is private", session?.private!!)
|
assertTrue("Current session is private", session?.private!!)
|
||||||
|
@ -84,6 +78,10 @@ class BrowserRobot {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
fun verifyPageContent(expectedText: String) {
|
fun verifyPageContent(expectedText: String) {
|
||||||
|
mDevice.waitNotNull(
|
||||||
|
Until.findObject(By.res("org.mozilla.fenix.debug:id/engineView")),
|
||||||
|
waitingTime
|
||||||
|
)
|
||||||
assertTrue(mDevice.findObject(UiSelector().text(expectedText)).waitForExists(waitingTime))
|
assertTrue(mDevice.findObject(UiSelector().text(expectedText)).waitForExists(waitingTime))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,7 +143,8 @@ class BrowserRobot {
|
||||||
|
|
||||||
fun verifyEnhancedTrackingProtectionSwitch() = assertEnhancedTrackingProtectionSwitch()
|
fun verifyEnhancedTrackingProtectionSwitch() = assertEnhancedTrackingProtectionSwitch()
|
||||||
|
|
||||||
fun clickEnhancedTrackingProtectionSwitchOffOn() = onView(withResourceName("switch_widget")).click()
|
fun clickEnhancedTrackingProtectionSwitchOffOn() =
|
||||||
|
onView(withResourceName("switch_widget")).click()
|
||||||
|
|
||||||
fun verifyProtectionSettingsButton() = assertProtectionSettingsButton()
|
fun verifyProtectionSettingsButton() = assertProtectionSettingsButton()
|
||||||
|
|
||||||
|
@ -191,7 +190,8 @@ class BrowserRobot {
|
||||||
|
|
||||||
fun clickEnhancedTrackingProtectionPanel() = enhancedTrackingProtectionPanel().click()
|
fun clickEnhancedTrackingProtectionPanel() = enhancedTrackingProtectionPanel().click()
|
||||||
|
|
||||||
fun verifyEnhancedTrackingProtectionPanelNotVisible() = assertEnhancedTrackingProtectionPanelNotVisible()
|
fun verifyEnhancedTrackingProtectionPanelNotVisible() =
|
||||||
|
assertEnhancedTrackingProtectionPanelNotVisible()
|
||||||
|
|
||||||
fun clickContextOpenLinkInNewTab() {
|
fun clickContextOpenLinkInNewTab() {
|
||||||
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
|
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
|
||||||
|
@ -423,7 +423,8 @@ fun navURLBar() = onView(withId(R.id.mozac_browser_toolbar_url_view))
|
||||||
private fun assertNavURLBar() = navURLBar()
|
private fun assertNavURLBar() = navURLBar()
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
|
||||||
fun enhancedTrackingProtectionPanel() = onView(withId(R.id.mozac_browser_toolbar_tracking_protection_indicator))
|
fun enhancedTrackingProtectionPanel() =
|
||||||
|
onView(withId(R.id.mozac_browser_toolbar_tracking_protection_indicator))
|
||||||
|
|
||||||
private fun assertEnhancedTrackingProtectionPanelNotVisible() {
|
private fun assertEnhancedTrackingProtectionPanelNotVisible() {
|
||||||
enhancedTrackingProtectionPanel()
|
enhancedTrackingProtectionPanel()
|
||||||
|
|
|
@ -43,4 +43,9 @@ object FeatureFlags {
|
||||||
* Enables the new search experience
|
* Enables the new search experience
|
||||||
*/
|
*/
|
||||||
val newSearchExperience = Config.channel.isDebug
|
val newSearchExperience = Config.channel.isDebug
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables wait til first contentful paint
|
||||||
|
*/
|
||||||
|
val waitUntilPaintToDraw = Config.channel.isDebug
|
||||||
}
|
}
|
||||||
|
|
|
@ -144,9 +144,11 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session
|
||||||
private val fullScreenFeature = ViewBoundFeatureWrapper<FullScreenFeature>()
|
private val fullScreenFeature = ViewBoundFeatureWrapper<FullScreenFeature>()
|
||||||
private val swipeRefreshFeature = ViewBoundFeatureWrapper<SwipeRefreshFeature>()
|
private val swipeRefreshFeature = ViewBoundFeatureWrapper<SwipeRefreshFeature>()
|
||||||
private val webchannelIntegration = ViewBoundFeatureWrapper<FxaWebChannelFeature>()
|
private val webchannelIntegration = ViewBoundFeatureWrapper<FxaWebChannelFeature>()
|
||||||
private val sitePermissionWifiIntegration = ViewBoundFeatureWrapper<SitePermissionsWifiIntegration>()
|
private val sitePermissionWifiIntegration =
|
||||||
|
ViewBoundFeatureWrapper<SitePermissionsWifiIntegration>()
|
||||||
private val secureWindowFeature = ViewBoundFeatureWrapper<SecureWindowFeature>()
|
private val secureWindowFeature = ViewBoundFeatureWrapper<SecureWindowFeature>()
|
||||||
private var fullScreenMediaFeature = ViewBoundFeatureWrapper<MediaFullscreenOrientationFeature>()
|
private var fullScreenMediaFeature =
|
||||||
|
ViewBoundFeatureWrapper<MediaFullscreenOrientationFeature>()
|
||||||
private var pipFeature: PictureInPictureFeature? = null
|
private var pipFeature: PictureInPictureFeature? = null
|
||||||
|
|
||||||
var customTabSessionId: String? = null
|
var customTabSessionId: String? = null
|
||||||
|
@ -202,7 +204,8 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session
|
||||||
engineView = WeakReference(engineView),
|
engineView = WeakReference(engineView),
|
||||||
swipeRefresh = WeakReference(swipeRefresh),
|
swipeRefresh = WeakReference(swipeRefresh),
|
||||||
viewLifecycleScope = WeakReference(viewLifecycleOwner.lifecycleScope),
|
viewLifecycleScope = WeakReference(viewLifecycleOwner.lifecycleScope),
|
||||||
arguments = requireArguments()
|
arguments = requireArguments(),
|
||||||
|
firstContentfulHappened = ::didFirstContentfulHappen
|
||||||
).apply {
|
).apply {
|
||||||
beginAnimateInIfNecessary()
|
beginAnimateInIfNecessary()
|
||||||
}
|
}
|
||||||
|
@ -412,8 +415,10 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resumeDownloadDialogState(sessionManager.selectedSession?.id,
|
resumeDownloadDialogState(
|
||||||
store, view, context, toolbarHeight)
|
sessionManager.selectedSession?.id,
|
||||||
|
store, view, context, toolbarHeight
|
||||||
|
)
|
||||||
|
|
||||||
downloadsFeature.set(
|
downloadsFeature.set(
|
||||||
downloadFeature,
|
downloadFeature,
|
||||||
|
@ -506,7 +511,11 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session
|
||||||
onNeedToRequestPermissions = { permissions ->
|
onNeedToRequestPermissions = { permissions ->
|
||||||
requestPermissions(permissions, REQUEST_CODE_APP_PERMISSIONS)
|
requestPermissions(permissions, REQUEST_CODE_APP_PERMISSIONS)
|
||||||
},
|
},
|
||||||
onShouldShowRequestPermissionRationale = { shouldShowRequestPermissionRationale(it) }),
|
onShouldShowRequestPermissionRationale = {
|
||||||
|
shouldShowRequestPermissionRationale(
|
||||||
|
it
|
||||||
|
)
|
||||||
|
}),
|
||||||
owner = this,
|
owner = this,
|
||||||
view = view
|
view = view
|
||||||
)
|
)
|
||||||
|
@ -568,6 +577,21 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session
|
||||||
.collect { tab -> pipModeChanged(tab) }
|
.collect { tab -> pipModeChanged(tab) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (context.settings().waitToShowPageUntilFirstPaint) {
|
||||||
|
store.flowScoped(viewLifecycleOwner) { flow ->
|
||||||
|
flow.mapNotNull { state ->
|
||||||
|
state.findTabOrCustomTabOrSelectedTab(
|
||||||
|
customTabSessionId
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.ifChanged { it.content.firstContentfulPaint }
|
||||||
|
.collect {
|
||||||
|
engineView?.asView()?.isVisible =
|
||||||
|
it.content.firstContentfulPaint || it.content.progress == 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Suppress("ConstantConditionIf")
|
@Suppress("ConstantConditionIf")
|
||||||
if (FeatureFlags.pullToRefreshEnabled) {
|
if (FeatureFlags.pullToRefreshEnabled) {
|
||||||
val primaryTextColor =
|
val primaryTextColor =
|
||||||
|
@ -687,7 +711,12 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session
|
||||||
val context = requireContext()
|
val context = requireContext()
|
||||||
val behavior = when (context.settings().toolbarPosition) {
|
val behavior = when (context.settings().toolbarPosition) {
|
||||||
ToolbarPosition.BOTTOM -> EngineViewBottomBehavior(context, null)
|
ToolbarPosition.BOTTOM -> EngineViewBottomBehavior(context, null)
|
||||||
ToolbarPosition.TOP -> SwipeRefreshScrollingViewBehavior(context, null, engineView, browserToolbarView)
|
ToolbarPosition.TOP -> SwipeRefreshScrollingViewBehavior(
|
||||||
|
context,
|
||||||
|
null,
|
||||||
|
engineView,
|
||||||
|
browserToolbarView
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
(swipeRefresh.layoutParams as CoordinatorLayout.LayoutParams).behavior = behavior
|
(swipeRefresh.layoutParams as CoordinatorLayout.LayoutParams).behavior = behavior
|
||||||
|
@ -751,12 +780,13 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session
|
||||||
super.onStop()
|
super.onStop()
|
||||||
initUIJob?.cancel()
|
initUIJob?.cancel()
|
||||||
|
|
||||||
requireComponents.core.store.state.findTabOrCustomTabOrSelectedTab(customTabSessionId)?.let { session ->
|
requireComponents.core.store.state.findTabOrCustomTabOrSelectedTab(customTabSessionId)
|
||||||
// If we didn't enter PiP, exit full screen on stop
|
?.let { session ->
|
||||||
if (!session.content.pictureInPictureEnabled && fullScreenFeature.onBackPressed()) {
|
// If we didn't enter PiP, exit full screen on stop
|
||||||
fullScreenChanged(false)
|
if (!session.content.pictureInPictureEnabled && fullScreenFeature.onBackPressed()) {
|
||||||
|
fullScreenChanged(false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@CallSuper
|
@CallSuper
|
||||||
|
@ -950,7 +980,10 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session
|
||||||
.setAction(getString(R.string.edit_bookmark_snackbar_action)) {
|
.setAction(getString(R.string.edit_bookmark_snackbar_action)) {
|
||||||
nav(
|
nav(
|
||||||
R.id.browserFragment,
|
R.id.browserFragment,
|
||||||
BrowserFragmentDirections.actionGlobalBookmarkEditFragment(guid, true)
|
BrowserFragmentDirections.actionGlobalBookmarkEditFragment(
|
||||||
|
guid,
|
||||||
|
true
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.show()
|
.show()
|
||||||
|
@ -988,10 +1021,10 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session
|
||||||
// Close find in page bar if opened
|
// Close find in page bar if opened
|
||||||
findInPageIntegration.onBackPressed()
|
findInPageIntegration.onBackPressed()
|
||||||
FenixSnackbar.make(
|
FenixSnackbar.make(
|
||||||
view = requireView().browserLayout,
|
view = requireView().browserLayout,
|
||||||
duration = Snackbar.LENGTH_SHORT,
|
duration = Snackbar.LENGTH_SHORT,
|
||||||
isDisplayedWithBrowserToolbar = false
|
isDisplayedWithBrowserToolbar = false
|
||||||
)
|
)
|
||||||
.setText(getString(R.string.full_screen_notification))
|
.setText(getString(R.string.full_screen_notification))
|
||||||
.show()
|
.show()
|
||||||
activity?.enterToImmersiveMode()
|
activity?.enterToImmersiveMode()
|
||||||
|
@ -1014,6 +1047,12 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun didFirstContentfulHappen() =
|
||||||
|
if (!requireContext().settings().waitToShowPageUntilFirstPaint) true else
|
||||||
|
context?.components?.core?.store?.state?.findTabOrCustomTabOrSelectedTab(
|
||||||
|
customTabSessionId
|
||||||
|
)?.content?.firstContentfulPaint ?: false
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Dereference these views when the fragment view is destroyed to prevent memory leaks
|
* Dereference these views when the fragment view is destroyed to prevent memory leaks
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -34,7 +34,8 @@ class BrowserAnimator(
|
||||||
private val engineView: WeakReference<EngineView>,
|
private val engineView: WeakReference<EngineView>,
|
||||||
private val swipeRefresh: WeakReference<View>,
|
private val swipeRefresh: WeakReference<View>,
|
||||||
private val viewLifecycleScope: WeakReference<LifecycleCoroutineScope>,
|
private val viewLifecycleScope: WeakReference<LifecycleCoroutineScope>,
|
||||||
private val arguments: Bundle
|
private val arguments: Bundle,
|
||||||
|
private val firstContentfulHappened: () -> Boolean
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private val unwrappedEngineView: EngineView?
|
private val unwrappedEngineView: EngineView?
|
||||||
|
@ -53,22 +54,9 @@ class BrowserAnimator(
|
||||||
}
|
}
|
||||||
|
|
||||||
doOnEnd {
|
doOnEnd {
|
||||||
unwrappedEngineView?.asView()?.visibility = View.VISIBLE
|
if (firstContentfulHappened()) {
|
||||||
unwrappedSwipeRefresh?.background = null
|
unwrappedEngineView?.asView()?.visibility = View.VISIBLE
|
||||||
arguments.putBoolean(SHOULD_ANIMATE_FLAG, false)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
interpolator = DecelerateInterpolator()
|
|
||||||
duration = ANIMATION_DURATION
|
|
||||||
}
|
|
||||||
|
|
||||||
private val browserFadeInValueAnimator = ValueAnimator.ofFloat(0f, END_ANIMATOR_VALUE).apply {
|
|
||||||
addUpdateListener {
|
|
||||||
unwrappedSwipeRefresh?.alpha = it.animatedFraction
|
|
||||||
}
|
|
||||||
|
|
||||||
doOnEnd {
|
|
||||||
unwrappedEngineView?.asView()?.visibility = View.VISIBLE
|
|
||||||
unwrappedSwipeRefresh?.background = null
|
unwrappedSwipeRefresh?.background = null
|
||||||
arguments.putBoolean(SHOULD_ANIMATE_FLAG, false)
|
arguments.putBoolean(SHOULD_ANIMATE_FLAG, false)
|
||||||
}
|
}
|
||||||
|
@ -93,20 +81,10 @@ class BrowserAnimator(
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
unwrappedSwipeRefresh?.alpha = 1f
|
unwrappedSwipeRefresh?.alpha = 1f
|
||||||
unwrappedEngineView?.asView()?.visibility = View.VISIBLE
|
if (firstContentfulHappened()) {
|
||||||
unwrappedSwipeRefresh?.background = null
|
unwrappedEngineView?.asView()?.visibility = View.VISIBLE
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Triggers the *zoom out* browser animation to run.
|
|
||||||
*/
|
|
||||||
fun beginAnimateOut() {
|
|
||||||
viewLifecycleScope.get()?.launch(Dispatchers.Main) {
|
|
||||||
captureEngineViewAndDrawStatically {
|
|
||||||
unwrappedEngineView?.asView()?.visibility = View.GONE
|
|
||||||
browserZoomInValueAnimator.reverse()
|
|
||||||
}
|
}
|
||||||
|
unwrappedSwipeRefresh?.background = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,5 +30,11 @@ class SecretSettingsFragment : PreferenceFragmentCompat() {
|
||||||
isChecked = context.settings().useNewSearchExperience
|
isChecked = context.settings().useNewSearchExperience
|
||||||
onPreferenceChangeListener = SharedPreferenceUpdater()
|
onPreferenceChangeListener = SharedPreferenceUpdater()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
requirePreference<SwitchPreference>(R.string.pref_key_wait_first_paint).apply {
|
||||||
|
isVisible = FeatureFlags.waitUntilPaintToDraw
|
||||||
|
isChecked = context.settings().waitToShowPageUntilFirstPaint
|
||||||
|
onPreferenceChangeListener = SharedPreferenceUpdater()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,6 +103,12 @@ class Settings(private val appContext: Context) : PreferencesHolder {
|
||||||
featureFlag = FeatureFlags.newSearchExperience
|
featureFlag = FeatureFlags.newSearchExperience
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var waitToShowPageUntilFirstPaint by featureFlagPreference(
|
||||||
|
appContext.getPreferenceKey(R.string.pref_key_wait_first_paint),
|
||||||
|
default = false,
|
||||||
|
featureFlag = FeatureFlags.waitUntilPaintToDraw
|
||||||
|
)
|
||||||
|
|
||||||
var forceEnableZoom by booleanPreference(
|
var forceEnableZoom by booleanPreference(
|
||||||
appContext.getPreferenceKey(R.string.pref_key_accessibility_force_enable_zoom),
|
appContext.getPreferenceKey(R.string.pref_key_accessibility_force_enable_zoom),
|
||||||
default = false
|
default = false
|
||||||
|
|
|
@ -175,6 +175,8 @@
|
||||||
|
|
||||||
<string name="pref_key_use_new_search_experience" translatable="false">pref_key_use_new_search_experience</string>
|
<string name="pref_key_use_new_search_experience" translatable="false">pref_key_use_new_search_experience</string>
|
||||||
|
|
||||||
|
<string name="pref_key_wait_first_paint" translatable="false">pref_key_wait_first_paint</string>
|
||||||
|
|
||||||
<string name="pref_key_debug_settings" translatable="false">pref_key_debug_settings</string>
|
<string name="pref_key_debug_settings" translatable="false">pref_key_debug_settings</string>
|
||||||
|
|
||||||
<string name="pref_key_open_tabs_count" translatable="false">pref_key_open_tabs_count</string>
|
<string name="pref_key_open_tabs_count" translatable="false">pref_key_open_tabs_count</string>
|
||||||
|
|
|
@ -34,6 +34,8 @@
|
||||||
<string name="preferences_debug_settings">Secret Settings</string>
|
<string name="preferences_debug_settings">Secret Settings</string>
|
||||||
<!-- Label for the new search experience preference -->
|
<!-- Label for the new search experience preference -->
|
||||||
<string name="preferences_debug_settings_use_new_search_experience">Use New Search Experience</string>
|
<string name="preferences_debug_settings_use_new_search_experience">Use New Search Experience</string>
|
||||||
|
<!-- Label for the wait until first paint preference -->
|
||||||
|
<string name="preferences_debug_settings_wait_first_paint">Wait Until First Paint To Show Page Content</string>
|
||||||
|
|
||||||
<!-- Content description (not visible, for screen readers etc.) used to announce [LinkTextView]. -->
|
<!-- Content description (not visible, for screen readers etc.) used to announce [LinkTextView]. -->
|
||||||
<string name="link_text_view_type_announcement" translatable="false">link</string>
|
<string name="link_text_view_type_announcement" translatable="false">link</string>
|
||||||
|
|
|
@ -9,4 +9,9 @@
|
||||||
android:key="@string/pref_key_use_new_search_experience"
|
android:key="@string/pref_key_use_new_search_experience"
|
||||||
android:title="@string/preferences_debug_settings_use_new_search_experience"
|
android:title="@string/preferences_debug_settings_use_new_search_experience"
|
||||||
app:iconSpaceReserved="false" />
|
app:iconSpaceReserved="false" />
|
||||||
|
<SwitchPreference
|
||||||
|
android:defaultValue="false"
|
||||||
|
android:key="@string/pref_key_wait_first_paint"
|
||||||
|
android:title="@string/preferences_debug_settings_wait_first_paint"
|
||||||
|
app:iconSpaceReserved="false" />
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user