diff --git a/.github/workflows/Build.yaml b/.github/workflows/Build.yaml
index fa3a77f55..5f501b6c0 100644
--- a/.github/workflows/Build.yaml
+++ b/.github/workflows/Build.yaml
@@ -109,13 +109,9 @@ jobs:
       - name: Build all build type and flavor permutations
         run: ./gradlew :app:assemble :benchmarks:assemble
           -x pixel6Api33ProdNonMinifiedReleaseAndroidTest
-          -x pixel6Api33ProdNonMinifiedBenchmarkAndroidTest
           -x pixel6Api33DemoNonMinifiedReleaseAndroidTest
-          -x pixel6Api33DemoNonMinifiedBenchmarkAndroidTest
           -x collectDemoNonMinifiedReleaseBaselineProfile
-          -x collectDemoNonMinifiedBenchmarkBaselineProfile
           -x collectProdNonMinifiedReleaseBaselineProfile
-          -x collectProdNonMinifiedBenchmarkBaselineProfile
 
       - name: Upload build outputs (APKs)
         uses: actions/upload-artifact@v4
@@ -151,6 +147,17 @@ jobs:
         api-level: [26, 30]
 
     steps:
+      - name: Delete unnecessary tools 🔧
+        uses: jlumbroso/free-disk-space@v1.3.1
+        with:
+          android: false # Don't remove Android tools
+          tool-cache: true # Remove image tool cache - rm -rf "$AGENT_TOOLSDIRECTORY"
+          dotnet: true # rm -rf /usr/share/dotnet
+          haskell: true # rm -rf /opt/ghc...
+          swap-storage: true # rm -f /mnt/swapfile (4GiB)
+          docker-images: false # Takes 16s, enable if needed in the future
+          large-packages: false # includes google-cloud-sdk and it's slow
+
       - name: Enable KVM group perms
         run: |
           echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
diff --git a/app-nia-catalog/dependencies/releaseRuntimeClasspath.txt b/app-nia-catalog/dependencies/releaseRuntimeClasspath.txt
index 10f2dfa32..c3f83d734 100644
--- a/app-nia-catalog/dependencies/releaseRuntimeClasspath.txt
+++ b/app-nia-catalog/dependencies/releaseRuntimeClasspath.txt
@@ -70,7 +70,8 @@ androidx.profileinstaller:profileinstaller:1.3.1
 androidx.savedstate:savedstate-ktx:1.2.1
 androidx.savedstate:savedstate:1.2.1
 androidx.startup:startup-runtime:1.1.1
-androidx.tracing:tracing:1.0.0
+androidx.tracing:tracing-ktx:1.3.0-alpha02
+androidx.tracing:tracing:1.3.0-alpha02
 androidx.vectordrawable:vectordrawable-animated:1.1.0
 androidx.vectordrawable:vectordrawable:1.1.0
 androidx.versionedparcelable:versionedparcelable:1.1.1
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 38166f7ff..520baa134 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -57,17 +57,6 @@ android {
             // Ensure Baseline Profile is fresh for release builds.
             baselineProfile.automaticGenerationDuringBuild = true
         }
-        create("benchmark") {
-            // Enable all the optimizations from release build through initWith(release).
-            initWith(release)
-            matchingFallbacks.add("release")
-            // Debug key signing is available to everyone.
-            signingConfig = signingConfigs.getByName("debug")
-            // Only use benchmark proguard rules
-            proguardFiles("benchmark-rules.pro")
-            isMinifyEnabled = true
-            applicationIdSuffix = NiaBuildType.BENCHMARK.applicationIdSuffix
-        }
     }
 
     packaging {
diff --git a/app/dependencies/prodReleaseRuntimeClasspath.txt b/app/dependencies/prodReleaseRuntimeClasspath.txt
index e9e3ebf8e..eaeff771a 100644
--- a/app/dependencies/prodReleaseRuntimeClasspath.txt
+++ b/app/dependencies/prodReleaseRuntimeClasspath.txt
@@ -71,19 +71,20 @@ androidx.hilt:hilt-navigation:1.0.0
 androidx.hilt:hilt-work:1.1.0
 androidx.interpolator:interpolator:1.0.0
 androidx.legacy:legacy-support-core-utils:1.0.0
-androidx.lifecycle:lifecycle-common-java8:2.6.2
-androidx.lifecycle:lifecycle-common:2.6.2
-androidx.lifecycle:lifecycle-livedata-core:2.6.2
-androidx.lifecycle:lifecycle-livedata:2.6.2
-androidx.lifecycle:lifecycle-process:2.6.2
-androidx.lifecycle:lifecycle-runtime-compose:2.6.2
-androidx.lifecycle:lifecycle-runtime-ktx:2.6.2
-androidx.lifecycle:lifecycle-runtime:2.6.2
-androidx.lifecycle:lifecycle-service:2.6.2
-androidx.lifecycle:lifecycle-viewmodel-compose:2.6.2
-androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2
-androidx.lifecycle:lifecycle-viewmodel-savedstate:2.6.2
-androidx.lifecycle:lifecycle-viewmodel:2.6.2
+androidx.lifecycle:lifecycle-common-java8:2.7.0
+androidx.lifecycle:lifecycle-common:2.7.0
+androidx.lifecycle:lifecycle-livedata-core-ktx:2.7.0
+androidx.lifecycle:lifecycle-livedata-core:2.7.0
+androidx.lifecycle:lifecycle-livedata:2.7.0
+androidx.lifecycle:lifecycle-process:2.7.0
+androidx.lifecycle:lifecycle-runtime-compose:2.7.0
+androidx.lifecycle:lifecycle-runtime-ktx:2.7.0
+androidx.lifecycle:lifecycle-runtime:2.7.0
+androidx.lifecycle:lifecycle-service:2.7.0
+androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0
+androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0
+androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0
+androidx.lifecycle:lifecycle-viewmodel:2.7.0
 androidx.loader:loader:1.0.0
 androidx.localbroadcastmanager:localbroadcastmanager:1.0.0
 androidx.metrics:metrics-performance:1.0.0-alpha04
@@ -105,8 +106,8 @@ androidx.savedstate:savedstate:1.2.1
 androidx.sqlite:sqlite-framework:2.4.0
 androidx.sqlite:sqlite:2.4.0
 androidx.startup:startup-runtime:1.1.1
-androidx.tracing:tracing-ktx:1.1.0
-androidx.tracing:tracing:1.1.0
+androidx.tracing:tracing-ktx:1.3.0-alpha02
+androidx.tracing:tracing:1.3.0-alpha02
 androidx.vectordrawable:vectordrawable-animated:1.1.0
 androidx.vectordrawable:vectordrawable:1.1.0
 androidx.versionedparcelable:versionedparcelable:1.1.1
@@ -168,8 +169,8 @@ com.google.guava:failureaccess:1.0.1
 com.google.guava:guava:31.1-android
 com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
 com.google.j2objc:j2objc-annotations:1.3
-com.google.protobuf:protobuf-javalite:3.24.4
-com.google.protobuf:protobuf-kotlin-lite:3.24.4
+com.google.protobuf:protobuf-javalite:3.25.2
+com.google.protobuf:protobuf-kotlin-lite:3.25.2
 com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:1.0.0
 com.squareup.okhttp3:logging-interceptor:4.12.0
 com.squareup.okhttp3:okhttp:4.12.0
diff --git a/app/src/main/kotlin/com/google/samples/apps/nowinandroid/NiaApplication.kt b/app/src/main/kotlin/com/google/samples/apps/nowinandroid/NiaApplication.kt
index 9f0bb2ef7..8e3ad814a 100644
--- a/app/src/main/kotlin/com/google/samples/apps/nowinandroid/NiaApplication.kt
+++ b/app/src/main/kotlin/com/google/samples/apps/nowinandroid/NiaApplication.kt
@@ -23,7 +23,6 @@ import com.google.samples.apps.nowinandroid.sync.initializers.Sync
 import com.google.samples.apps.nowinandroid.util.ProfileVerifierLogger
 import dagger.hilt.android.HiltAndroidApp
 import javax.inject.Inject
-import javax.inject.Provider
 
 /**
  * [Application] class for NiA
@@ -31,7 +30,7 @@ import javax.inject.Provider
 @HiltAndroidApp
 class NiaApplication : Application(), ImageLoaderFactory {
     @Inject
-    lateinit var imageLoader: Provider<ImageLoader>
+    lateinit var imageLoader: dagger.Lazy<ImageLoader>
 
     @Inject
     lateinit var profileVerifierLogger: ProfileVerifierLogger
diff --git a/app/src/testDemo/kotlin/com/google/samples/apps/nowinandroid/ui/NiaAppScreenSizesScreenshotTests.kt b/app/src/testDemo/kotlin/com/google/samples/apps/nowinandroid/ui/NiaAppScreenSizesScreenshotTests.kt
index dcbc1e5c0..f7345f04f 100644
--- a/app/src/testDemo/kotlin/com/google/samples/apps/nowinandroid/ui/NiaAppScreenSizesScreenshotTests.kt
+++ b/app/src/testDemo/kotlin/com/google/samples/apps/nowinandroid/ui/NiaAppScreenSizesScreenshotTests.kt
@@ -37,6 +37,7 @@ import com.google.samples.apps.nowinandroid.core.data.repository.TopicsRepositor
 import com.google.samples.apps.nowinandroid.core.data.repository.UserDataRepository
 import com.google.samples.apps.nowinandroid.core.data.repository.UserNewsResourceRepository
 import com.google.samples.apps.nowinandroid.core.data.util.NetworkMonitor
+import com.google.samples.apps.nowinandroid.core.designsystem.theme.NiaTheme
 import com.google.samples.apps.nowinandroid.core.testing.util.DefaultRoborazziOptions
 import com.google.samples.apps.nowinandroid.uitesthiltmanifest.HiltComponentActivity
 import dagger.hilt.android.testing.BindValue
@@ -140,13 +141,15 @@ class NiaAppScreenSizesScreenshotTests {
             ) {
                 TestHarness(size = DpSize(width, height)) {
                     BoxWithConstraints {
-                        NiaApp(
-                            windowSizeClass = WindowSizeClass.calculateFromSize(
-                                DpSize(maxWidth, maxHeight),
-                            ),
-                            networkMonitor = networkMonitor,
-                            userNewsResourceRepository = userNewsResourceRepository,
-                        )
+                        NiaTheme {
+                            NiaApp(
+                                windowSizeClass = WindowSizeClass.calculateFromSize(
+                                    DpSize(maxWidth, maxHeight),
+                                ),
+                                networkMonitor = networkMonitor,
+                                userNewsResourceRepository = userNewsResourceRepository,
+                            )
+                        }
                     }
                 }
             }
diff --git a/app/src/testDemo/screenshots/compactWidth_compactHeight_showsNavigationBar.png b/app/src/testDemo/screenshots/compactWidth_compactHeight_showsNavigationBar.png
index 04ccb8424..06db1c65b 100644
Binary files a/app/src/testDemo/screenshots/compactWidth_compactHeight_showsNavigationBar.png and b/app/src/testDemo/screenshots/compactWidth_compactHeight_showsNavigationBar.png differ
diff --git a/app/src/testDemo/screenshots/compactWidth_expandedHeight_showsNavigationBar.png b/app/src/testDemo/screenshots/compactWidth_expandedHeight_showsNavigationBar.png
index 833ecdf07..fe9cd884a 100644
Binary files a/app/src/testDemo/screenshots/compactWidth_expandedHeight_showsNavigationBar.png and b/app/src/testDemo/screenshots/compactWidth_expandedHeight_showsNavigationBar.png differ
diff --git a/app/src/testDemo/screenshots/compactWidth_mediumHeight_showsNavigationBar.png b/app/src/testDemo/screenshots/compactWidth_mediumHeight_showsNavigationBar.png
index e9e0c76cf..5d75a44a7 100644
Binary files a/app/src/testDemo/screenshots/compactWidth_mediumHeight_showsNavigationBar.png and b/app/src/testDemo/screenshots/compactWidth_mediumHeight_showsNavigationBar.png differ
diff --git a/app/src/testDemo/screenshots/expandedWidth_compactHeight_showsNavigationRail.png b/app/src/testDemo/screenshots/expandedWidth_compactHeight_showsNavigationRail.png
index bcaf32ebe..8568d174c 100644
Binary files a/app/src/testDemo/screenshots/expandedWidth_compactHeight_showsNavigationRail.png and b/app/src/testDemo/screenshots/expandedWidth_compactHeight_showsNavigationRail.png differ
diff --git a/app/src/testDemo/screenshots/expandedWidth_expandedHeight_showsNavigationRail.png b/app/src/testDemo/screenshots/expandedWidth_expandedHeight_showsNavigationRail.png
index d40d06be0..ab95819dd 100644
Binary files a/app/src/testDemo/screenshots/expandedWidth_expandedHeight_showsNavigationRail.png and b/app/src/testDemo/screenshots/expandedWidth_expandedHeight_showsNavigationRail.png differ
diff --git a/app/src/testDemo/screenshots/expandedWidth_mediumHeight_showsNavigationRail.png b/app/src/testDemo/screenshots/expandedWidth_mediumHeight_showsNavigationRail.png
index ce2c055ef..befeac749 100644
Binary files a/app/src/testDemo/screenshots/expandedWidth_mediumHeight_showsNavigationRail.png and b/app/src/testDemo/screenshots/expandedWidth_mediumHeight_showsNavigationRail.png differ
diff --git a/app/src/testDemo/screenshots/mediumWidth_compactHeight_showsNavigationRail.png b/app/src/testDemo/screenshots/mediumWidth_compactHeight_showsNavigationRail.png
index bbde94375..57d5585da 100644
Binary files a/app/src/testDemo/screenshots/mediumWidth_compactHeight_showsNavigationRail.png and b/app/src/testDemo/screenshots/mediumWidth_compactHeight_showsNavigationRail.png differ
diff --git a/app/src/testDemo/screenshots/mediumWidth_expandedHeight_showsNavigationRail.png b/app/src/testDemo/screenshots/mediumWidth_expandedHeight_showsNavigationRail.png
index 7591fb871..e80a26617 100644
Binary files a/app/src/testDemo/screenshots/mediumWidth_expandedHeight_showsNavigationRail.png and b/app/src/testDemo/screenshots/mediumWidth_expandedHeight_showsNavigationRail.png differ
diff --git a/app/src/testDemo/screenshots/mediumWidth_mediumHeight_showsNavigationRail.png b/app/src/testDemo/screenshots/mediumWidth_mediumHeight_showsNavigationRail.png
index e2961bddf..0db65e2fb 100644
Binary files a/app/src/testDemo/screenshots/mediumWidth_mediumHeight_showsNavigationRail.png and b/app/src/testDemo/screenshots/mediumWidth_mediumHeight_showsNavigationRail.png differ
diff --git a/benchmarks/build.gradle.kts b/benchmarks/build.gradle.kts
index 67fccb979..279c4b226 100644
--- a/benchmarks/build.gradle.kts
+++ b/benchmarks/build.gradle.kts
@@ -13,7 +13,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import com.google.samples.apps.nowinandroid.NiaBuildType
 import com.google.samples.apps.nowinandroid.configureFlavors
 
 plugins {
@@ -35,23 +34,6 @@ android {
         buildConfig = true
     }
 
-    buildTypes {
-        // This benchmark buildType is used for benchmarking, and should function like your
-        // release build (for example, with minification on). It's signed with a debug key
-        // for easy local/CI testing.
-        create("benchmark") {
-            // Keep the build type debuggable so we can attach a debugger if needed.
-            isDebuggable = true
-            signingConfig = signingConfigs.getByName("debug")
-            matchingFallbacks.add("release")
-            buildConfigField(
-                "String",
-                "APP_BUILD_TYPE_SUFFIX",
-                "\"${NiaBuildType.BENCHMARK.applicationIdSuffix ?: ""}\""
-            )
-        }
-    }
-
     // Use the same flavor dimensions as the application to allow generating Baseline Profiles on prod,
     // which is more close to what will be shipped to users (no fake data), but has ability to run the
     // benchmarks on demo, so we benchmark on stable data. 
diff --git a/benchmarks/src/main/kotlin/com/google/samples/apps/nowinandroid/Utils.kt b/benchmarks/src/main/kotlin/com/google/samples/apps/nowinandroid/Utils.kt
index 9ece991c4..e8fb53c4f 100644
--- a/benchmarks/src/main/kotlin/com/google/samples/apps/nowinandroid/Utils.kt
+++ b/benchmarks/src/main/kotlin/com/google/samples/apps/nowinandroid/Utils.kt
@@ -30,7 +30,6 @@ import java.io.ByteArrayOutputStream
 val PACKAGE_NAME = buildString {
     append("com.google.samples.apps.nowinandroid")
     append(BuildConfig.APP_FLAVOR_SUFFIX)
-    append(BuildConfig.APP_BUILD_TYPE_SUFFIX)
 }
 
 fun UiDevice.flingElementDownUp(element: UiObject2) {
diff --git a/build-logic/convention/src/main/kotlin/AndroidFeatureConventionPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidFeatureConventionPlugin.kt
index 7a334beb3..b8699a05d 100644
--- a/build-logic/convention/src/main/kotlin/AndroidFeatureConventionPlugin.kt
+++ b/build-logic/convention/src/main/kotlin/AndroidFeatureConventionPlugin.kt
@@ -44,6 +44,9 @@ class AndroidFeatureConventionPlugin : Plugin<Project> {
                 add("implementation", libs.findLibrary("androidx.hilt.navigation.compose").get())
                 add("implementation", libs.findLibrary("androidx.lifecycle.runtimeCompose").get())
                 add("implementation", libs.findLibrary("androidx.lifecycle.viewModelCompose").get())
+                add("implementation", libs.findLibrary("androidx.tracing.ktx").get())
+
+                add("androidTestImplementation", libs.findLibrary("androidx.lifecycle.runtimeTesting").get())
             }
         }
     }
diff --git a/build-logic/convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt
index 8eb329f58..d442d94ef 100644
--- a/build-logic/convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt
+++ b/build-logic/convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt
@@ -21,6 +21,7 @@ import com.google.samples.apps.nowinandroid.configureGradleManagedDevices
 import com.google.samples.apps.nowinandroid.configureKotlinAndroid
 import com.google.samples.apps.nowinandroid.configurePrintApksTask
 import com.google.samples.apps.nowinandroid.disableUnnecessaryAndroidTests
+import com.google.samples.apps.nowinandroid.libs
 import org.gradle.api.Plugin
 import org.gradle.api.Project
 import org.gradle.kotlin.dsl.configure
@@ -51,6 +52,8 @@ class AndroidLibraryConventionPlugin : Plugin<Project> {
             }
             dependencies {
                 add("testImplementation", kotlin("test"))
+
+                add("implementation", libs.findLibrary("androidx.tracing.ktx").get())
             }
         }
     }
diff --git a/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/NiaBuildType.kt b/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/NiaBuildType.kt
index 653506f51..e4f40840d 100644
--- a/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/NiaBuildType.kt
+++ b/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/NiaBuildType.kt
@@ -22,5 +22,4 @@ package com.google.samples.apps.nowinandroid
 enum class NiaBuildType(val applicationIdSuffix: String? = null) {
     DEBUG(".debug"),
     RELEASE,
-    BENCHMARK(".benchmark")
 }
diff --git a/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/di/NetworkModule.kt b/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/di/NetworkModule.kt
index 21d93c0e4..a68683c7c 100644
--- a/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/di/NetworkModule.kt
+++ b/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/di/NetworkModule.kt
@@ -17,6 +17,7 @@
 package com.google.samples.apps.nowinandroid.core.network.di
 
 import android.content.Context
+import androidx.tracing.trace
 import coil.ImageLoader
 import coil.decode.SvgDecoder
 import coil.util.DebugLogger
@@ -51,16 +52,18 @@ internal object NetworkModule {
 
     @Provides
     @Singleton
-    fun okHttpCallFactory(): Call.Factory = OkHttpClient.Builder()
-        .addInterceptor(
-            HttpLoggingInterceptor()
-                .apply {
-                    if (BuildConfig.DEBUG) {
-                        setLevel(HttpLoggingInterceptor.Level.BODY)
-                    }
-                },
-        )
-        .build()
+    fun okHttpCallFactory(): Call.Factory = trace("NiaOkHttpClient") {
+        OkHttpClient.Builder()
+            .addInterceptor(
+                HttpLoggingInterceptor()
+                    .apply {
+                        if (BuildConfig.DEBUG) {
+                            setLevel(HttpLoggingInterceptor.Level.BODY)
+                        }
+                    },
+            )
+            .build()
+    }
 
     /**
      * Since we're displaying SVGs in the app, Coil needs an ImageLoader which supports this
@@ -72,20 +75,21 @@ internal object NetworkModule {
     @Provides
     @Singleton
     fun imageLoader(
-        okHttpCallFactory: Call.Factory,
+        // We specifically request dagger.Lazy here, so that it's not instantiated from Dagger.
+        okHttpCallFactory: dagger.Lazy<Call.Factory>,
         @ApplicationContext application: Context,
-    ): ImageLoader = ImageLoader.Builder(application)
-        .callFactory(okHttpCallFactory)
-        .components {
-            add(SvgDecoder.Factory())
-        }
-        // Assume most content images are versioned urls
-        // but some problematic images are fetching each time
-        .respectCacheHeaders(false)
-        .apply {
-            if (BuildConfig.DEBUG) {
-                logger(DebugLogger())
+    ): ImageLoader = trace("NiaImageLoader") {
+        ImageLoader.Builder(application)
+            .callFactory { okHttpCallFactory.get() }
+            .components { add(SvgDecoder.Factory()) }
+            // Assume most content images are versioned urls
+            // but some problematic images are fetching each time
+            .respectCacheHeaders(false)
+            .apply {
+                if (BuildConfig.DEBUG) {
+                    logger(DebugLogger())
+                }
             }
-        }
-        .build()
+            .build()
+    }
 }
diff --git a/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/retrofit/RetrofitNiaNetwork.kt b/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/retrofit/RetrofitNiaNetwork.kt
index 321e856fe..e9fe99d9e 100644
--- a/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/retrofit/RetrofitNiaNetwork.kt
+++ b/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/retrofit/RetrofitNiaNetwork.kt
@@ -16,6 +16,7 @@
 
 package com.google.samples.apps.nowinandroid.core.network.retrofit
 
+import androidx.tracing.trace
 import com.google.samples.apps.nowinandroid.core.network.BuildConfig
 import com.google.samples.apps.nowinandroid.core.network.NiaNetworkDataSource
 import com.google.samples.apps.nowinandroid.core.network.model.NetworkChangeList
@@ -73,17 +74,21 @@ private data class NetworkResponse<T>(
 @Singleton
 internal class RetrofitNiaNetwork @Inject constructor(
     networkJson: Json,
-    okhttpCallFactory: Call.Factory,
+    okhttpCallFactory: dagger.Lazy<Call.Factory>,
 ) : NiaNetworkDataSource {
 
-    private val networkApi = Retrofit.Builder()
-        .baseUrl(NIA_BASE_URL)
-        .callFactory(okhttpCallFactory)
-        .addConverterFactory(
-            networkJson.asConverterFactory("application/json".toMediaType()),
-        )
-        .build()
-        .create(RetrofitNiaNetworkApi::class.java)
+    private val networkApi = trace("RetrofitNiaNetwork") {
+        Retrofit.Builder()
+            .baseUrl(NIA_BASE_URL)
+            // We use callFactory lambda here with dagger.Lazy<Call.Factory>
+            // to prevent initializing OkHttp on the main thread.
+            .callFactory { okhttpCallFactory.get().newCall(it) }
+            .addConverterFactory(
+                networkJson.asConverterFactory("application/json".toMediaType()),
+            )
+            .build()
+            .create(RetrofitNiaNetworkApi::class.java)
+    }
 
     override suspend fun getTopics(ids: List<String>?): List<NetworkTopic> =
         networkApi.getTopics(ids = ids).data
diff --git a/core/testing/src/main/kotlin/com/google/samples/apps/nowinandroid/core/testing/repository/TestSearchContentsRepository.kt b/core/testing/src/main/kotlin/com/google/samples/apps/nowinandroid/core/testing/repository/TestSearchContentsRepository.kt
index 9b6151449..5436cd10f 100644
--- a/core/testing/src/main/kotlin/com/google/samples/apps/nowinandroid/core/testing/repository/TestSearchContentsRepository.kt
+++ b/core/testing/src/main/kotlin/com/google/samples/apps/nowinandroid/core/testing/repository/TestSearchContentsRepository.kt
@@ -21,42 +21,36 @@ import com.google.samples.apps.nowinandroid.core.model.data.NewsResource
 import com.google.samples.apps.nowinandroid.core.model.data.SearchResult
 import com.google.samples.apps.nowinandroid.core.model.data.Topic
 import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.flow
-import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.update
+import org.jetbrains.annotations.TestOnly
 
 class TestSearchContentsRepository : SearchContentsRepository {
 
-    private val cachedTopics: MutableList<Topic> = mutableListOf()
-    private val cachedNewsResources: MutableList<NewsResource> = mutableListOf()
+    private val cachedTopics = MutableStateFlow(emptyList<Topic>())
+    private val cachedNewsResources = MutableStateFlow(emptyList<NewsResource>())
 
     override suspend fun populateFtsData() = Unit
 
-    override fun searchContents(searchQuery: String): Flow<SearchResult> = flowOf(
-        SearchResult(
-            topics = cachedTopics.filter {
-                searchQuery in it.name || searchQuery in it.shortDescription || searchQuery in it.longDescription
-            },
-            newsResources = cachedNewsResources.filter {
-                searchQuery in it.content || searchQuery in it.title
-            },
-        ),
-    )
-
-    override fun getSearchContentsCount(): Flow<Int> = flow {
-        emit(cachedTopics.size + cachedNewsResources.size)
-    }
-
-    /**
-     * Test only method to add the topics to the stored list in memory
-     */
-    fun addTopics(topics: List<Topic>) {
-        cachedTopics.addAll(topics)
-    }
-
-    /**
-     * Test only method to add the news resources to the stored list in memory
-     */
-    fun addNewsResources(newsResources: List<NewsResource>) {
-        cachedNewsResources.addAll(newsResources)
-    }
+    override fun searchContents(searchQuery: String): Flow<SearchResult> =
+        combine(cachedTopics, cachedNewsResources) { topics, news ->
+            SearchResult(
+                topics = topics.filter {
+                    searchQuery in it.name || searchQuery in it.shortDescription || searchQuery in it.longDescription
+                },
+                newsResources = news.filter {
+                    searchQuery in it.content || searchQuery in it.title
+                },
+            )
+        }
+
+    override fun getSearchContentsCount(): Flow<Int> = combine(cachedTopics, cachedNewsResources) { topics, news -> topics.size + news.size }
+
+    @TestOnly
+    fun addTopics(topics: List<Topic>) = cachedTopics.update { it + topics }
+
+    @TestOnly
+    fun addNewsResources(newsResources: List<NewsResource>) =
+        cachedNewsResources.update { it + newsResources }
 }
diff --git a/feature/bookmarks/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/BookmarksScreenTest.kt b/feature/bookmarks/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/BookmarksScreenTest.kt
index 3d684f9d1..40f54e4a7 100644
--- a/feature/bookmarks/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/BookmarksScreenTest.kt
+++ b/feature/bookmarks/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/BookmarksScreenTest.kt
@@ -17,6 +17,8 @@
 package com.google.samples.apps.nowinandroid.feature.bookmarks
 
 import androidx.activity.ComponentActivity
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.ui.platform.LocalLifecycleOwner
 import androidx.compose.ui.test.assertCountEquals
 import androidx.compose.ui.test.assertHasClickAction
 import androidx.compose.ui.test.filter
@@ -30,8 +32,11 @@ import androidx.compose.ui.test.onNodeWithContentDescription
 import androidx.compose.ui.test.onNodeWithText
 import androidx.compose.ui.test.performClick
 import androidx.compose.ui.test.performScrollToNode
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.testing.TestLifecycleOwner
 import com.google.samples.apps.nowinandroid.core.testing.data.userNewsResourcesTestData
 import com.google.samples.apps.nowinandroid.core.ui.NewsFeedUiState
+import kotlinx.coroutines.test.runTest
 import org.junit.Rule
 import org.junit.Test
 import kotlin.test.assertEquals
@@ -166,4 +171,29 @@ class BookmarksScreenTest {
             )
             .assertExists()
     }
+
+    @Test
+    fun feed_whenLifecycleStops_undoBookmarkedStateIsCleared() = runTest {
+        var undoStateCleared = false
+        val testLifecycleOwner = TestLifecycleOwner(initialState = Lifecycle.State.STARTED)
+
+        composeTestRule.setContent {
+            CompositionLocalProvider(LocalLifecycleOwner provides testLifecycleOwner) {
+                BookmarksScreen(
+                    feedState = NewsFeedUiState.Success(emptyList()),
+                    onShowSnackbar = { _, _ -> false },
+                    removeFromBookmarks = {},
+                    onTopicClick = {},
+                    onNewsResourceViewed = {},
+                    clearUndoState = {
+                        undoStateCleared = true
+                    },
+                )
+            }
+        }
+
+        assertEquals(false, undoStateCleared)
+        testLifecycleOwner.handleLifecycleEvent(event = Lifecycle.Event.ON_STOP)
+        assertEquals(true, undoStateCleared)
+    }
 }
diff --git a/feature/bookmarks/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/BookmarksScreen.kt b/feature/bookmarks/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/BookmarksScreen.kt
index 5b54db7cd..7c229c5ea 100644
--- a/feature/bookmarks/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/BookmarksScreen.kt
+++ b/feature/bookmarks/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/BookmarksScreen.kt
@@ -42,14 +42,12 @@ import androidx.compose.foundation.lazy.staggeredgrid.rememberLazyStaggeredGridS
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.getValue
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.ColorFilter
-import androidx.compose.ui.platform.LocalLifecycleOwner
 import androidx.compose.ui.platform.testTag
 import androidx.compose.ui.res.painterResource
 import androidx.compose.ui.res.stringResource
@@ -60,7 +58,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
 import androidx.compose.ui.unit.dp
 import androidx.hilt.navigation.compose.hiltViewModel
 import androidx.lifecycle.Lifecycle
-import androidx.lifecycle.LifecycleEventObserver
+import androidx.lifecycle.compose.LifecycleEventEffect
 import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaLoadingWheel
 import com.google.samples.apps.nowinandroid.core.designsystem.component.scrollbar.DraggableScrollbar
@@ -128,15 +126,8 @@ internal fun BookmarksScreen(
         }
     }
 
-    val lifecycleOwner = LocalLifecycleOwner.current
-    DisposableEffect(lifecycleOwner) {
-        val observer = LifecycleEventObserver { _, event ->
-            if (event == Lifecycle.Event.ON_STOP) {
-                clearUndoState()
-            }
-        }
-        lifecycleOwner.lifecycle.addObserver(observer)
-        onDispose { lifecycleOwner.lifecycle.removeObserver(observer) }
+    LifecycleEventEffect(Lifecycle.Event.ON_STOP) {
+        clearUndoState()
     }
 
     when (feedState) {
diff --git a/feature/foryou/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt b/feature/foryou/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt
index 30134715b..e1418d747 100644
--- a/feature/foryou/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt
+++ b/feature/foryou/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt
@@ -81,9 +81,9 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.max
 import androidx.compose.ui.unit.sp
-import androidx.compose.ui.util.trace
 import androidx.hilt.navigation.compose.hiltViewModel
 import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import androidx.tracing.trace
 import com.google.accompanist.permissions.ExperimentalPermissionsApi
 import com.google.accompanist.permissions.PermissionStatus.Denied
 import com.google.accompanist.permissions.rememberPermissionState
diff --git a/feature/search/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/search/SearchViewModelTest.kt b/feature/search/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/search/SearchViewModelTest.kt
index fc9c20549..da0d5654e 100644
--- a/feature/search/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/search/SearchViewModelTest.kt
+++ b/feature/search/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/search/SearchViewModelTest.kt
@@ -26,6 +26,7 @@ import com.google.samples.apps.nowinandroid.core.testing.data.topicsTestData
 import com.google.samples.apps.nowinandroid.core.testing.repository.TestRecentSearchRepository
 import com.google.samples.apps.nowinandroid.core.testing.repository.TestSearchContentsRepository
 import com.google.samples.apps.nowinandroid.core.testing.repository.TestUserDataRepository
+import com.google.samples.apps.nowinandroid.core.testing.repository.emptyUserData
 import com.google.samples.apps.nowinandroid.core.testing.util.MainDispatcherRule
 import com.google.samples.apps.nowinandroid.feature.search.RecentSearchQueriesUiState.Success
 import com.google.samples.apps.nowinandroid.feature.search.SearchResultUiState.EmptyQuery
@@ -71,6 +72,7 @@ class SearchViewModelTest {
             recentSearchRepository = recentSearchRepository,
             analyticsHelper = NoOpAnalyticsHelper(),
         )
+        userDataRepository.setUserData(emptyUserData)
     }
 
     @Test
@@ -100,8 +102,7 @@ class SearchViewModelTest {
         searchContentsRepository.addTopics(topicsTestData)
 
         val result = viewModel.searchResultUiState.value
-        // TODO: Figure out to get the latest emitted ui State? The result is emitted as EmptyQuery
-        // assertIs<Success>(result)
+        assertIs<SearchResultUiState.Success>(result)
 
         collectJob.cancel()
     }
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 1a8d82dce..bba66a858 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -15,7 +15,7 @@ androidxCoreSplashscreen = "1.0.1"
 androidxDataStore = "1.0.0"
 androidxEspresso = "3.5.1"
 androidxHiltNavigationCompose = "1.0.0"
-androidxLifecycle = "2.6.2"
+androidxLifecycle = "2.7.0"
 androidxMacroBenchmark = "1.2.2"
 androidxMetrics = "1.0.0-alpha04"
 androidxNavigation = "2.7.4"
@@ -24,7 +24,7 @@ androidxTestCore = "1.5.0"
 androidxTestExt = "1.1.5"
 androidxTestRules = "1.5.0"
 androidxTestRunner = "1.5.2"
-androidxTracing = "1.1.0"
+androidxTracing = "1.3.0-alpha02"
 androidxUiAutomator = "2.2.0"
 androidxWindowManager = "1.2.0"
 androidxWork = "2.9.0"
@@ -46,7 +46,7 @@ kotlinxDatetime = "0.5.0"
 kotlinxSerializationJson = "1.6.0"
 ksp = "1.9.21-1.0.16"
 okhttp = "4.12.0"
-protobuf = "3.24.4"
+protobuf = "3.25.2"
 protobufPlugin = "0.9.4"
 retrofit = "2.9.0"
 retrofitKotlinxSerializationJson = "1.0.0"
@@ -83,6 +83,7 @@ androidx-dataStore = { group = "androidx.datastore", name = "datastore", version
 androidx-dataStore-core = { group = "androidx.datastore", name = "datastore-core", version.ref = "androidxDataStore" }
 androidx-hilt-navigation-compose = { group = "androidx.hilt", name = "hilt-navigation-compose", version.ref = "androidxHiltNavigationCompose" }
 androidx-lifecycle-runtimeCompose = { group = "androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "androidxLifecycle" }
+androidx-lifecycle-runtimeTesting = { group = "androidx.lifecycle", name = "lifecycle-runtime-testing", version.ref = "androidxLifecycle" }
 androidx-lifecycle-viewModelCompose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "androidxLifecycle" }
 androidx-metrics = { group = "androidx.metrics", name = "metrics-performance", version.ref = "androidxMetrics" }
 androidx-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "androidxNavigation" }