diff --git a/app/src/main/java/org/mozilla/fenix/FenixApplication.kt b/app/src/main/java/org/mozilla/fenix/FenixApplication.kt index 246cf671b..fc5552856 100644 --- a/app/src/main/java/org/mozilla/fenix/FenixApplication.kt +++ b/app/src/main/java/org/mozilla/fenix/FenixApplication.kt @@ -159,15 +159,15 @@ open class FenixApplication : LocaleAwareApplication(), Provider { } private fun initVisualCompletenessQueueAndQueueTasks() { - val taskQueue = components.performance.visualCompletenessQueue + val queue = components.performance.visualCompletenessQueue.queue fun initQueue() { - registerActivityLifecycleCallbacks(PerformanceActivityLifecycleCallbacks(taskQueue)) + registerActivityLifecycleCallbacks(PerformanceActivityLifecycleCallbacks(queue)) } fun queueInitExperiments() { if (settings().isExperimentationEnabled) { - taskQueue.runIfReadyOrQueue { + queue.runIfReadyOrQueue { Experiments.initialize( applicationContext = applicationContext, onExperimentsUpdated = { @@ -188,7 +188,7 @@ open class FenixApplication : LocaleAwareApplication(), Provider { } fun queueInitStorageAndServices() { - components.performance.visualCompletenessQueue.runIfReadyOrQueue { + components.performance.visualCompletenessQueue.queue.runIfReadyOrQueue { GlobalScope.launch(Dispatchers.IO) { logger.info("Running post-visual completeness tasks...") logElapsedTime(logger, "Storage initialization") { @@ -208,7 +208,7 @@ open class FenixApplication : LocaleAwareApplication(), Provider { fun queueMetrics() { if (SDK_INT >= Build.VERSION_CODES.O) { // required by StorageStatsMetrics. - taskQueue.runIfReadyOrQueue { + queue.runIfReadyOrQueue { // Because it may be slow to capture the storage stats, it might be preferred to // create a WorkManager task for this metric, however, I ran out of // implementation time and WorkManager is harder to test. diff --git a/app/src/main/java/org/mozilla/fenix/HomeActivity.kt b/app/src/main/java/org/mozilla/fenix/HomeActivity.kt index 86f26ed9e..c870dd394 100644 --- a/app/src/main/java/org/mozilla/fenix/HomeActivity.kt +++ b/app/src/main/java/org/mozilla/fenix/HomeActivity.kt @@ -21,7 +21,6 @@ import androidx.annotation.VisibleForTesting import androidx.annotation.VisibleForTesting.PROTECTED import androidx.appcompat.app.ActionBar import androidx.appcompat.widget.Toolbar -import androidx.core.view.doOnPreDraw import androidx.lifecycle.lifecycleScope import androidx.navigation.NavDestination import androidx.navigation.NavDirections @@ -56,7 +55,6 @@ import mozilla.components.support.ktx.android.content.share import mozilla.components.support.ktx.kotlin.isUrl import mozilla.components.support.ktx.kotlin.toNormalizedUrl import mozilla.components.support.locale.LocaleAwareAppCompatActivity -import mozilla.components.support.utils.RunWhenReadyQueue import mozilla.components.support.utils.SafeIntent import mozilla.components.support.utils.toSafeIntent import mozilla.components.support.webextensions.WebExtensionPopupFeature @@ -104,6 +102,7 @@ import org.mozilla.fenix.tabtray.TabTrayDialogFragmentDirections import org.mozilla.fenix.theme.DefaultThemeManager import org.mozilla.fenix.theme.ThemeManager import org.mozilla.fenix.utils.BrowsersCache +import java.lang.ref.WeakReference /** * The main activity of the application. The application is primarily a single Activity (this one) @@ -122,7 +121,6 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity { private var isVisuallyComplete = false - private var visualCompletenessQueue: RunWhenReadyQueue? = null private var privateNotificationObserver: PrivateNotificationFeature? = null private var isToolbarInflated = false @@ -164,13 +162,8 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity { // Must be after we set the content view if (isVisuallyComplete) { - rootContainer.doOnPreDraw { - // This delay is temporary. We are delaying 5 seconds until the performance - // team can locate the real point of visual completeness. - it.postDelayed({ - visualCompletenessQueue!!.ready() - }, delay) - } + components.performance.visualCompletenessQueue + .attachViewToRunVisualCompletenessQueueLater(WeakReference(rootContainer)) } sessionObserver = UriOpenedObserver(this) @@ -678,9 +671,8 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity { * The root container is null at this point, so let the HomeActivity know that * we are visually complete. */ - fun postVisualCompletenessQueue(visualCompletenessQueue: RunWhenReadyQueue) { + fun setVisualCompletenessQueueReady() { isVisuallyComplete = true - this.visualCompletenessQueue = visualCompletenessQueue } private fun captureSnapshotTelemetryMetrics() = CoroutineScope(Dispatchers.IO).launch { @@ -717,7 +709,6 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity { const val PRIVATE_BROWSING_MODE = "private_browsing_mode" const val EXTRA_DELETE_PRIVATE_TABS = "notification_delete_and_open" const val EXTRA_OPENED_FROM_NOTIFICATION = "notification_open" - const val delay = 5000L const val START_IN_RECENTS_SCREEN = "start_in_recents_screen" // PWA must have been used within last 30 days to be considered "recently used" for the diff --git a/app/src/main/java/org/mozilla/fenix/components/PerformanceComponent.kt b/app/src/main/java/org/mozilla/fenix/components/PerformanceComponent.kt index 615d348a8..b692d216b 100644 --- a/app/src/main/java/org/mozilla/fenix/components/PerformanceComponent.kt +++ b/app/src/main/java/org/mozilla/fenix/components/PerformanceComponent.kt @@ -5,10 +5,11 @@ package org.mozilla.fenix.components import mozilla.components.support.utils.RunWhenReadyQueue +import org.mozilla.fenix.perf.VisualCompletenessQueue /** * Component group for all functionality related to performance. */ class PerformanceComponent { - val visualCompletenessQueue by lazy { RunWhenReadyQueue() } + val visualCompletenessQueue by lazy { VisualCompletenessQueue(RunWhenReadyQueue()) } } diff --git a/app/src/main/java/org/mozilla/fenix/components/metrics/GleanMetricsService.kt b/app/src/main/java/org/mozilla/fenix/components/metrics/GleanMetricsService.kt index db2e02180..f7ad064c0 100644 --- a/app/src/main/java/org/mozilla/fenix/components/metrics/GleanMetricsService.kt +++ b/app/src/main/java/org/mozilla/fenix/components/metrics/GleanMetricsService.kt @@ -725,7 +725,7 @@ class GleanMetricsService(private val context: Context) : MetricsService { // The code below doesn't need to execute immediately, so we'll add them to the visual // completeness task queue to be run later. - context.components.performance.visualCompletenessQueue.runIfReadyOrQueue { + context.components.performance.visualCompletenessQueue.queue.runIfReadyOrQueue { // We have to initialize Glean *on* the main thread, because it registers lifecycle // observers. However, the activation ping must be sent *off* of the main thread, // because it calls Google ad APIs that must be called *off* of the main thread. diff --git a/app/src/main/java/org/mozilla/fenix/perf/VisualCompletenessQueue.kt b/app/src/main/java/org/mozilla/fenix/perf/VisualCompletenessQueue.kt new file mode 100644 index 000000000..2dd88c289 --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/perf/VisualCompletenessQueue.kt @@ -0,0 +1,33 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.fenix.perf + +import android.view.View +import androidx.core.view.doOnPreDraw +import mozilla.components.support.utils.RunWhenReadyQueue +import java.lang.ref.WeakReference + +/** + * class for all functionality related to Visual completeness queue + */ +class VisualCompletenessQueue(val queue: RunWhenReadyQueue) { + @Suppress("MagicNumber") + val delay = 5000L + + /** + * + * @param containerWeakReference a weak reference to the root view of a view hierarchy. Weak + * reference is to avoid memory leak. + */ + fun attachViewToRunVisualCompletenessQueueLater(containerWeakReference: WeakReference) { + containerWeakReference.get()?.doOnPreDraw { + // This delay is temporary. We are delaying 5 seconds until the performance + // team can locate the real point of visual completeness. + it.postDelayed({ + queue.ready() + }, delay) + } + } +} diff --git a/app/src/main/java/org/mozilla/fenix/session/PerformanceActivityLifecycleCallbacks.kt b/app/src/main/java/org/mozilla/fenix/session/PerformanceActivityLifecycleCallbacks.kt index 2684b0388..6f46fb997 100644 --- a/app/src/main/java/org/mozilla/fenix/session/PerformanceActivityLifecycleCallbacks.kt +++ b/app/src/main/java/org/mozilla/fenix/session/PerformanceActivityLifecycleCallbacks.kt @@ -51,7 +51,7 @@ class PerformanceActivityLifecycleCallbacks( if (activity is HomeActivity) { // We should delay the visualCompletenessQueue when reaching the HomeActivity // to ensure all tasks are delayed until after visual completeness - activity.postVisualCompletenessQueue(visualCompletenessQueue) + activity.setVisualCompletenessQueueReady() } else if (shouldStartVisualCompletenessQueueImmediately()) { // If we do not go through the home activity, we have to start the tasks // immediately to avoid spending time implementing it.