1
0
Fork 0

For #6313 - On first load, hides engineView until firstContentfulPaint

master
ekager 2020-05-04 23:29:33 -07:00 committed by Emily Kager
parent 495341a945
commit f663129632
9 changed files with 100 additions and 56 deletions

View File

@ -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()

View File

@ -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
} }

View File

@ -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
*/ */

View File

@ -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
} }
} }

View File

@ -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()
}
} }
} }

View File

@ -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

View File

@ -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>

View File

@ -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>

View File

@ -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>