12/Update assertion classes

Introduce flicker test object for flicker service assertions to avoid missing forAllEntries

Test: atest FlickerLibTest
Bug: 262241371
Change-Id: I79c8fb4a2dc0bb28aa18d482c627a93a0f72e2f0
diff --git a/libraries/flicker/Android.bp b/libraries/flicker/Android.bp
index 0882559..63ca9b4 100644
--- a/libraries/flicker/Android.bp
+++ b/libraries/flicker/Android.bp
@@ -29,6 +29,7 @@
         enabled: false
     },
     srcs: [
+        "src/android/tools/device/AndroidLogger.kt",
         "src/android/tools/device/flicker/**/*.kt",
         "src/android/tools/device/flicker/**/*.eventlog"
     ],
diff --git a/libraries/flicker/src/android/tools/common/ConsoleLogger.kt b/libraries/flicker/src/android/tools/common/ConsoleLogger.kt
new file mode 100644
index 0000000..fd9501d
--- /dev/null
+++ b/libraries/flicker/src/android/tools/common/ConsoleLogger.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.tools.common
+
+class ConsoleLogger : ILogger {
+    override fun v(tag: String, msg: String) = println("(V) $tag $msg")
+
+    override fun d(tag: String, msg: String) = println("(D) $tag $msg")
+
+    override fun i(tag: String, msg: String) = println("(I) $tag $msg")
+
+    override fun w(tag: String, msg: String) = println("(W) $tag $msg")
+
+    override fun e(tag: String, msg: String, error: Throwable?) {
+        println("(e) $tag $msg $error")
+        error?.printStackTrace()
+    }
+
+    override fun <T> withTracing(name: String, predicate: () -> T): T =
+        try {
+            println("(withTracing#start) $name")
+            predicate()
+        } finally {
+            println("(withTracing#end) $name")
+        }
+}
diff --git a/libraries/flicker/src/android/tools/common/Consts.kt b/libraries/flicker/src/android/tools/common/Consts.kt
index 54b0987..309993a 100644
--- a/libraries/flicker/src/android/tools/common/Consts.kt
+++ b/libraries/flicker/src/android/tools/common/Consts.kt
@@ -22,3 +22,9 @@
 const val MINUTE_AS_NANOSECONDS: Long = 60000000000
 const val HOUR_AS_NANOSECONDS: Long = 3600000000000
 const val DAY_AS_NANOSECONDS: Long = 86400000000000
+
+var Logger: ILogger = ConsoleLogger()
+    internal set
+
+var Timestamps: TimestampFactory = TimestampFactory()
+    internal set
diff --git a/libraries/flicker/src/android/tools/common/CrossPlatform.kt b/libraries/flicker/src/android/tools/common/CrossPlatform.kt
index 53d4332..d468ad2 100644
--- a/libraries/flicker/src/android/tools/common/CrossPlatform.kt
+++ b/libraries/flicker/src/android/tools/common/CrossPlatform.kt
@@ -21,13 +21,11 @@
 
 @JsExport
 object CrossPlatform {
-    var log: ILogger = LoggerBuilder().build()
-        private set
-    var timestamp: TimestampFactory = TimestampFactory()
-        private set
+    val timestamp: TimestampFactory
+        get() = Timestamps
 
-    @JsName("setLogger") fun setLogger(logger: ILogger) = apply { log = logger }
+    @JsName("setLogger") fun setLogger(logger: ILogger) = apply { Logger = logger }
 
     @JsName("setTimestampFactory")
-    fun setTimestampFactory(factory: TimestampFactory) = apply { timestamp = factory }
+    fun setTimestampFactory(factory: TimestampFactory) = apply { Timestamps = factory }
 }
diff --git a/libraries/flicker/src/android/tools/common/ScenarioImpl.kt b/libraries/flicker/src/android/tools/common/ScenarioImpl.kt
index 0c48bf1..a9fe6c8 100644
--- a/libraries/flicker/src/android/tools/common/ScenarioImpl.kt
+++ b/libraries/flicker/src/android/tools/common/ScenarioImpl.kt
@@ -36,7 +36,10 @@
     config: Map<String, Any?>,
     override val description: String
 ) : Scenario {
-    internal val extraConfig = config.toMutableMap()
+    private val _extraConfig = config.toMutableMap()
+
+    val extraConfig: Map<String, Any?>
+        get() = _extraConfig
 
     override val isEmpty = testClass.isEmpty()
 
@@ -54,7 +57,7 @@
                 ?: error("$IS_TABLET property not initialized. Use [setIsTablet] to initialize ")
 
     fun setIsTablet(isTablet: Boolean) {
-        extraConfig[IS_TABLET] = isTablet
+        _extraConfig[IS_TABLET] = isTablet
     }
 
     override fun <T> getConfigValue(key: String): T? = extraConfig[key] as T?
diff --git a/libraries/flicker/src/android/tools/common/flicker/TagIdGenerator.kt b/libraries/flicker/src/android/tools/common/flicker/Factories.kt
similarity index 65%
rename from libraries/flicker/src/android/tools/common/flicker/TagIdGenerator.kt
rename to libraries/flicker/src/android/tools/common/flicker/Factories.kt
index a4d90b4..249c1ca 100644
--- a/libraries/flicker/src/android/tools/common/flicker/TagIdGenerator.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/Factories.kt
@@ -16,7 +16,11 @@
 
 package android.tools.common.flicker
 
-object TagIdGenerator {
-    fun getNext() = ++latestId
-    private var latestId = 0
-}
+import android.tools.common.flicker.extractors.ScenarioExtractor
+import kotlin.js.JsName
+
+@JsName("FlickerServiceFactory") fun FlickerService(): FlickerService = FlickerServiceImpl()
+
+@JsName("FlickerServiceFactoryWithScenario")
+fun FlickerService(scenarioExtractor: ScenarioExtractor): FlickerService =
+    FlickerServiceImpl(scenarioExtractor)
diff --git a/libraries/flicker/src/android/tools/common/flicker/FlickerServiceImpl.kt b/libraries/flicker/src/android/tools/common/flicker/FlickerServiceImpl.kt
new file mode 100644
index 0000000..1e5b553
--- /dev/null
+++ b/libraries/flicker/src/android/tools/common/flicker/FlickerServiceImpl.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.tools.common.flicker
+
+import android.tools.common.Logger
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.common.flicker.extractors.CombinedScenarioExtractor
+import android.tools.common.flicker.extractors.ScenarioExtractor
+import android.tools.common.io.Reader
+
+/** Contains the logic for Flicker as a Service. */
+internal class FlickerServiceImpl(
+    private val scenarioExtractor: ScenarioExtractor =
+        CombinedScenarioExtractor(FlickerServiceConfig.getExtractors())
+) : FlickerService {
+    override fun detectScenarios(reader: Reader): Collection<ScenarioInstance> {
+        return Logger.withTracing("FlickerService#detectScenarios") {
+            scenarioExtractor.extract(reader)
+        }
+    }
+}
diff --git a/libraries/flicker/src/android/tools/common/flicker/ScenarioInstance.kt b/libraries/flicker/src/android/tools/common/flicker/ScenarioInstance.kt
index 3efb99b..5235a08 100644
--- a/libraries/flicker/src/android/tools/common/flicker/ScenarioInstance.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/ScenarioInstance.kt
@@ -16,10 +16,8 @@
 
 package android.tools.common.flicker
 
-import android.tools.common.CrossPlatform
 import android.tools.common.Scenario
 import android.tools.common.flicker.assertions.ScenarioAssertion
-import android.tools.common.flicker.assertions.ScenarioAssertionImpl
 import android.tools.common.flicker.config.FaasScenarioType
 import android.tools.common.flicker.config.ScenarioConfig
 import android.tools.common.io.Reader
@@ -35,14 +33,5 @@
     val type: FaasScenarioType
         get() = config.type
 
-    fun generateAssertions(): Collection<ScenarioAssertion> =
-        CrossPlatform.log.withTracing("generateAssertions") {
-            config.assertionTemplates.map { template ->
-                ScenarioAssertionImpl(
-                    reader,
-                    template.createAssertion(this),
-                    template.stabilityGroup
-                )
-            }
-        }
+    fun generateAssertions(): Collection<ScenarioAssertion>
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/ScenarioInstanceImpl.kt b/libraries/flicker/src/android/tools/common/flicker/ScenarioInstanceImpl.kt
index a0024d7..6f7096b 100644
--- a/libraries/flicker/src/android/tools/common/flicker/ScenarioInstanceImpl.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/ScenarioInstanceImpl.kt
@@ -16,14 +16,17 @@
 
 package android.tools.common.flicker
 
+import android.tools.common.Logger
 import android.tools.common.Rotation
 import android.tools.common.Timestamp
+import android.tools.common.flicker.assertions.ScenarioAssertion
+import android.tools.common.flicker.assertions.ScenarioAssertionImpl
 import android.tools.common.flicker.config.ScenarioConfig
 import android.tools.common.io.Reader
 import android.tools.common.traces.events.CujType
 import android.tools.common.traces.wm.Transition
 
-data class ScenarioInstanceImpl(
+internal data class ScenarioInstanceImpl(
     override val config: ScenarioConfig,
     override val startRotation: Rotation,
     override val endRotation: Rotation,
@@ -45,5 +48,14 @@
 
     override fun <T> getConfigValue(key: String): T? = null
 
+    override fun generateAssertions(): Collection<ScenarioAssertion> =
+        Logger.withTracing("generateAssertions") {
+            config.assertionTemplates.flatMap { template ->
+                template.createAssertions(this).map { assertion ->
+                    ScenarioAssertionImpl(reader, assertion, template.stabilityGroup)
+                }
+            }
+        }
+
     override fun toString() = key
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertions/AssertionDataFactory.kt b/libraries/flicker/src/android/tools/common/flicker/assertions/AssertionDataFactory.kt
index c7b64c7..6160c28 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertions/AssertionDataFactory.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertions/AssertionDataFactory.kt
@@ -38,6 +38,7 @@
      * @param assertion Assertion predicate
      */
     fun createTraceAssertion(
+        name: String = "",
         assertion: (FlickerTraceSubject<FlickerSubject>) -> Unit
     ): AssertionData {
         val closedAssertion: FlickerTraceSubject<FlickerSubject>.() -> Unit = {
@@ -46,7 +47,7 @@
             forAllEntries()
         }
         return AssertionDataImpl(
-            name = "",
+            name,
             tag = Tag.ALL,
             expectedSubjectClass = traceSubject,
             assertion = closedAssertion as FlickerSubject.() -> Unit
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertions/AssertionFactory.kt b/libraries/flicker/src/android/tools/common/flicker/assertions/AssertionFactory.kt
index d76b375..99e7e06 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertions/AssertionFactory.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertions/AssertionFactory.kt
@@ -16,7 +16,7 @@
 
 package android.tools.common.flicker.assertions
 
-import android.tools.common.CrossPlatform
+import android.tools.common.Logger
 import android.tools.common.Tag
 import android.tools.common.flicker.subject.FlickerSubject
 import android.tools.common.flicker.subject.FlickerTraceSubject
@@ -40,9 +40,15 @@
      *
      * @param assertion Assertion predicate
      */
-    fun createWmStartAssertion(assertion: WindowManagerStateSubject.() -> Unit): AssertionData =
-        CrossPlatform.log.withTracing("createWmStartAssertion") {
-            wmAssertionFactory.createStartStateAssertion(assertion as FlickerSubject.() -> Unit)
+    fun createWmStartAssertion(
+        name: String,
+        assertion: WindowManagerStateSubject.() -> Unit
+    ): AssertionData =
+        Logger.withTracing("createWmStartAssertion") {
+            wmAssertionFactory.createStartStateAssertion(
+                name,
+                assertion as FlickerSubject.() -> Unit
+            )
         }
 
     /**
@@ -50,9 +56,12 @@
      *
      * @param assertion Assertion predicate
      */
-    fun createWmEndAssertion(assertion: WindowManagerStateSubject.() -> Unit): AssertionData =
-        CrossPlatform.log.withTracing("createWmEndAssertion") {
-            wmAssertionFactory.createEndStateAssertion(assertion as FlickerSubject.() -> Unit)
+    fun createWmEndAssertion(
+        name: String,
+        assertion: WindowManagerStateSubject.() -> Unit
+    ): AssertionData =
+        Logger.withTracing("createWmEndAssertion") {
+            wmAssertionFactory.createEndStateAssertion(name, assertion as FlickerSubject.() -> Unit)
         }
 
     /**
@@ -60,9 +69,13 @@
      *
      * @param assertion Assertion predicate
      */
-    fun createWmAssertion(assertion: WindowManagerTraceSubject.() -> Unit): AssertionData =
-        CrossPlatform.log.withTracing("createWmAssertion") {
+    fun createWmAssertion(
+        name: String,
+        assertion: WindowManagerTraceSubject.() -> Unit
+    ): AssertionData =
+        Logger.withTracing("createWmAssertion") {
             wmAssertionFactory.createTraceAssertion(
+                name,
                 assertion as (FlickerTraceSubject<FlickerSubject>) -> Unit
             )
         }
@@ -74,10 +87,11 @@
      */
     fun createWmTagAssertion(
         tag: String,
+        name: String,
         assertion: WindowManagerStateSubject.() -> Unit
     ): AssertionData =
-        CrossPlatform.log.withTracing("createWmTagAssertion") {
-            wmAssertionFactory.createTagAssertion(tag, assertion as FlickerSubject.() -> Unit)
+        Logger.withTracing("createWmTagAssertion") {
+            wmAssertionFactory.createTagAssertion(name, tag, assertion as FlickerSubject.() -> Unit)
         }
 
     /**
@@ -88,9 +102,10 @@
      */
     fun createWmVisibleRegionAssertion(
         componentMatcher: IComponentMatcher,
+        name: String,
         assertion: RegionTraceSubject.() -> Unit
     ): AssertionData =
-        CrossPlatform.log.withTracing("createWmVisibleRegionAssertion") {
+        Logger.withTracing("createWmVisibleRegionAssertion") {
             val closedAssertion: WindowManagerTraceSubject.() -> Unit = {
                 require(!hasAssertions()) { "Subject was already used to execute assertions" }
                 // convert WindowManagerTraceSubject to RegionTraceSubject
@@ -102,6 +117,7 @@
             }
 
             wmAssertionFactory.createTraceAssertion(
+                name,
                 closedAssertion as (FlickerTraceSubject<FlickerSubject>) -> Unit
             )
         }
@@ -111,9 +127,15 @@
      *
      * @param assertion Assertion predicate
      */
-    fun createLayersStartAssertion(assertion: LayerTraceEntrySubject.() -> Unit): AssertionData =
-        CrossPlatform.log.withTracing("createLayersStartAssertion") {
-            layersAssertionFactory.createStartStateAssertion(assertion as FlickerSubject.() -> Unit)
+    fun createLayersStartAssertion(
+        name: String,
+        assertion: LayerTraceEntrySubject.() -> Unit
+    ): AssertionData =
+        Logger.withTracing("createLayersStartAssertion") {
+            layersAssertionFactory.createStartStateAssertion(
+                name,
+                assertion as FlickerSubject.() -> Unit
+            )
         }
 
     /**
@@ -121,9 +143,15 @@
      *
      * @param assertion Assertion predicate
      */
-    fun createLayersEndAssertion(assertion: LayerTraceEntrySubject.() -> Unit): AssertionData =
-        CrossPlatform.log.withTracing("createLayersEndAssertion") {
-            layersAssertionFactory.createEndStateAssertion(assertion as FlickerSubject.() -> Unit)
+    fun createLayersEndAssertion(
+        name: String,
+        assertion: LayerTraceEntrySubject.() -> Unit
+    ): AssertionData =
+        Logger.withTracing("createLayersEndAssertion") {
+            layersAssertionFactory.createEndStateAssertion(
+                name,
+                assertion as FlickerSubject.() -> Unit
+            )
         }
 
     /**
@@ -131,9 +159,13 @@
      *
      * @param assertion Assertion predicate
      */
-    fun createLayersAssertion(assertion: LayersTraceSubject.() -> Unit): AssertionData =
-        CrossPlatform.log.withTracing("createLayersAssertion") {
+    fun createLayersAssertion(
+        name: String,
+        assertion: LayersTraceSubject.() -> Unit
+    ): AssertionData =
+        Logger.withTracing("createLayersAssertion") {
             layersAssertionFactory.createTraceAssertion(
+                name,
                 assertion as (FlickerTraceSubject<FlickerSubject>) -> Unit
             )
         }
@@ -145,10 +177,15 @@
      */
     fun createLayersTagAssertion(
         tag: String,
+        name: String,
         assertion: LayerTraceEntrySubject.() -> Unit
     ): AssertionData =
-        CrossPlatform.log.withTracing("createLayersTagAssertion") {
-            layersAssertionFactory.createTagAssertion(tag, assertion as FlickerSubject.() -> Unit)
+        Logger.withTracing("createLayersTagAssertion") {
+            layersAssertionFactory.createTagAssertion(
+                name,
+                tag,
+                assertion as FlickerSubject.() -> Unit
+            )
         }
 
     /**
@@ -163,10 +200,11 @@
      */
     fun createLayersVisibleRegionAssertion(
         componentMatcher: IComponentMatcher,
+        name: String,
         useCompositionEngineRegionOnly: Boolean = true,
         assertion: RegionTraceSubject.() -> Unit
     ): AssertionData =
-        CrossPlatform.log.withTracing("createLayersVisibleRegionAssertion") {
+        Logger.withTracing("createLayersVisibleRegionAssertion") {
             val closedAssertion: LayersTraceSubject.() -> Unit = {
                 require(!hasAssertions()) { "Subject was already used to execute assertions" }
                 // convert LayersTraceSubject to RegionTraceSubject
@@ -180,6 +218,7 @@
             }
 
             layersAssertionFactory.createTraceAssertion(
+                name,
                 closedAssertion as (FlickerTraceSubject<*>) -> Unit
             )
         }
@@ -189,9 +228,13 @@
      *
      * @param assertion Assertion predicate
      */
-    fun createEventLogAssertion(assertion: EventLogSubject.() -> Unit): AssertionData =
-        CrossPlatform.log.withTracing("createEventLogAssertion") {
+    fun createEventLogAssertion(
+        name: String,
+        assertion: EventLogSubject.() -> Unit
+    ): AssertionData =
+        Logger.withTracing("createEventLogAssertion") {
             eventLogAssertionFactory.createTagAssertion(
+                name,
                 Tag.ALL,
                 assertion as FlickerSubject.() -> Unit
             )
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/AssertionResult.kt b/libraries/flicker/src/android/tools/common/flicker/assertions/AssertionResult.kt
similarity index 89%
rename from libraries/flicker/src/android/tools/common/flicker/assertors/AssertionResult.kt
rename to libraries/flicker/src/android/tools/common/flicker/assertions/AssertionResult.kt
index 90b7ced..6ac89ec 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/AssertionResult.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertions/AssertionResult.kt
@@ -14,16 +14,16 @@
  * limitations under the License.
  */
 
-package android.tools.common.flicker.assertors
+package android.tools.common.flicker.assertions
 
 import android.tools.common.flicker.AssertionInvocationGroup
-import android.tools.common.flicker.assertions.AssertionData
 
 interface AssertionResult {
     val assertion: AssertionData
     val assertionError: Throwable?
     val stabilityGroup: AssertionInvocationGroup
     val passed: Boolean
+        get() = assertionError == null
     val failed: Boolean
         get() = !passed
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/runners/IAssertionRunner.kt b/libraries/flicker/src/android/tools/common/flicker/assertions/AssertionResultImpl.kt
similarity index 79%
rename from libraries/flicker/src/android/tools/common/flicker/assertors/runners/IAssertionRunner.kt
rename to libraries/flicker/src/android/tools/common/flicker/assertions/AssertionResultImpl.kt
index 96e404f..0e3d550 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/runners/IAssertionRunner.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertions/AssertionResultImpl.kt
@@ -14,16 +14,13 @@
  * limitations under the License.
  */
 
-package android.tools.common.flicker.assertors
+package android.tools.common.flicker.assertions
 
 import android.tools.common.flicker.AssertionInvocationGroup
-import android.tools.common.flicker.assertions.AssertionData
 
 /** Base class for a FaaS assertion */
-data class AssertionResultImpl(
+internal data class AssertionResultImpl(
     override val assertion: AssertionData,
     override val assertionError: Throwable?,
     override val stabilityGroup: AssertionInvocationGroup
-) : AssertionResult {
-    override val passed = assertionError == null
-}
+) : AssertionResult
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertions/AssertionStateDataFactory.kt b/libraries/flicker/src/android/tools/common/flicker/assertions/AssertionStateDataFactory.kt
index 649e337..e9b3b4e 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertions/AssertionStateDataFactory.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertions/AssertionStateDataFactory.kt
@@ -31,9 +31,9 @@
      *
      * @param assertion Assertion predicate
      */
-    fun createStartStateAssertion(assertion: FlickerSubject.() -> Unit) =
+    fun createStartStateAssertion(name: String, assertion: FlickerSubject.() -> Unit) =
         AssertionDataImpl(
-            name = "",
+            name,
             tag = Tag.START,
             expectedSubjectClass = stateSubject,
             assertion = assertion
@@ -44,9 +44,9 @@
      *
      * @param assertion Assertion predicate
      */
-    fun createEndStateAssertion(assertion: FlickerSubject.() -> Unit) =
+    fun createEndStateAssertion(name: String, assertion: FlickerSubject.() -> Unit) =
         AssertionDataImpl(
-            name = "",
+            name,
             tag = Tag.END,
             expectedSubjectClass = stateSubject,
             assertion = assertion
@@ -57,9 +57,9 @@
      *
      * @param assertion Assertion predicate
      */
-    fun createTagAssertion(tag: String, assertion: FlickerSubject.() -> Unit) =
+    fun createTagAssertion(name: String, tag: String, assertion: FlickerSubject.() -> Unit) =
         AssertionDataImpl(
-            name = "",
+            name,
             tag = tag,
             expectedSubjectClass = stateSubject,
             assertion = assertion
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertions/BaseFlickerTest.kt b/libraries/flicker/src/android/tools/common/flicker/assertions/BaseFlickerTest.kt
new file mode 100644
index 0000000..68c6324
--- /dev/null
+++ b/libraries/flicker/src/android/tools/common/flicker/assertions/BaseFlickerTest.kt
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.tools.common.flicker.assertions
+
+import android.tools.common.Logger
+import android.tools.common.flicker.subject.events.EventLogSubject
+import android.tools.common.flicker.subject.layers.LayerTraceEntrySubject
+import android.tools.common.flicker.subject.layers.LayersTraceSubject
+import android.tools.common.flicker.subject.region.RegionTraceSubject
+import android.tools.common.flicker.subject.wm.WindowManagerStateSubject
+import android.tools.common.flicker.subject.wm.WindowManagerTraceSubject
+import android.tools.common.traces.component.IComponentMatcher
+
+abstract class BaseFlickerTest(
+    private val defaultAssertionName: String,
+    private val assertionFactory: AssertionFactory = AssertionFactory()
+) : FlickerTest {
+    protected abstract fun doProcess(assertion: AssertionData)
+
+    override fun assertWmStart(name: String, assertion: WindowManagerStateSubject.() -> Unit) {
+        Logger.withTracing("assertWmStart") {
+            val assertionData = assertionFactory.createWmStartAssertion(name, assertion)
+            doProcess(assertionData)
+        }
+    }
+
+    override fun assertWmEnd(name: String, assertion: WindowManagerStateSubject.() -> Unit) {
+        Logger.withTracing("assertWmEnd") {
+            val assertionData = assertionFactory.createWmEndAssertion(name, assertion)
+            doProcess(assertionData)
+        }
+    }
+
+    override fun assertWm(name: String, assertion: WindowManagerTraceSubject.() -> Unit) {
+        Logger.withTracing("assertWm") {
+            val assertionData = assertionFactory.createWmAssertion(name, assertion)
+            doProcess(assertionData)
+        }
+    }
+
+    override fun assertWmTag(
+        name: String,
+        tag: String,
+        assertion: WindowManagerStateSubject.() -> Unit
+    ) {
+        Logger.withTracing("assertWmTag") {
+            val assertionData = assertionFactory.createWmTagAssertion(tag, name, assertion)
+            doProcess(assertionData)
+        }
+    }
+
+    override fun assertWmVisibleRegion(
+        name: String,
+        componentMatcher: IComponentMatcher,
+        assertion: RegionTraceSubject.() -> Unit
+    ) {
+        Logger.withTracing("assertWmVisibleRegion") {
+            val assertionData =
+                assertionFactory.createWmVisibleRegionAssertion(componentMatcher, name, assertion)
+            doProcess(assertionData)
+        }
+    }
+
+    override fun assertLayersStart(name: String, assertion: LayerTraceEntrySubject.() -> Unit) {
+        Logger.withTracing("assertLayersStart") {
+            val assertionData = assertionFactory.createLayersStartAssertion(name, assertion)
+            doProcess(assertionData)
+        }
+    }
+
+    override fun assertLayersEnd(name: String, assertion: LayerTraceEntrySubject.() -> Unit) {
+        Logger.withTracing("assertLayersEnd") {
+            val assertionData = assertionFactory.createLayersEndAssertion(name, assertion)
+            doProcess(assertionData)
+        }
+    }
+
+    override fun assertLayers(name: String, assertion: LayersTraceSubject.() -> Unit) {
+        Logger.withTracing("assertLayers") {
+            val assertionData =
+                assertionFactory.createLayersAssertion(name = defaultAssertionName, assertion)
+            doProcess(assertionData)
+        }
+    }
+
+    override fun assertLayersTag(
+        name: String,
+        tag: String,
+        assertion: LayerTraceEntrySubject.() -> Unit
+    ) {
+        Logger.withTracing("assertLayersTag") {
+            val assertionData =
+                assertionFactory.createLayersTagAssertion(
+                    tag,
+                    name = defaultAssertionName,
+                    assertion
+                )
+            doProcess(assertionData)
+        }
+    }
+
+    override fun assertLayersVisibleRegion(
+        name: String,
+        componentMatcher: IComponentMatcher,
+        useCompositionEngineRegionOnly: Boolean,
+        assertion: RegionTraceSubject.() -> Unit
+    ) {
+        Logger.withTracing("assertLayersVisibleRegion") {
+            val assertionData =
+                assertionFactory.createLayersVisibleRegionAssertion(
+                    componentMatcher,
+                    name = defaultAssertionName,
+                    useCompositionEngineRegionOnly,
+                    assertion
+                )
+            doProcess(assertionData)
+        }
+    }
+
+    override fun assertEventLog(name: String, assertion: EventLogSubject.() -> Unit) {
+        Logger.withTracing("assertEventLog") {
+            val assertionData =
+                assertionFactory.createEventLogAssertion(name = defaultAssertionName, assertion)
+            doProcess(assertionData)
+        }
+    }
+
+    override fun assertWmStart(assertion: WindowManagerStateSubject.() -> Unit) =
+        assertWmStart(name = defaultAssertionName, assertion)
+
+    override fun assertWmEnd(assertion: WindowManagerStateSubject.() -> Unit) =
+        assertWmEnd(name = defaultAssertionName, assertion)
+
+    override fun assertWm(assertion: WindowManagerTraceSubject.() -> Unit) =
+        assertWm(name = defaultAssertionName, assertion)
+
+    override fun assertWmTag(tag: String, assertion: WindowManagerStateSubject.() -> Unit) =
+        assertWmTag(name = defaultAssertionName, tag, assertion)
+
+    override fun assertWmVisibleRegion(
+        componentMatcher: IComponentMatcher,
+        assertion: RegionTraceSubject.() -> Unit
+    ) = assertWmVisibleRegion(name = defaultAssertionName, componentMatcher, assertion)
+
+    override fun assertLayersStart(assertion: LayerTraceEntrySubject.() -> Unit) =
+        assertLayersStart(name = defaultAssertionName, assertion)
+
+    override fun assertLayersEnd(assertion: LayerTraceEntrySubject.() -> Unit) =
+        assertLayersEnd(name = defaultAssertionName, assertion)
+
+    override fun assertLayers(assertion: LayersTraceSubject.() -> Unit) =
+        assertLayers(name = defaultAssertionName, assertion)
+
+    override fun assertLayersTag(tag: String, assertion: LayerTraceEntrySubject.() -> Unit) =
+        assertLayersTag(name = defaultAssertionName, tag, assertion)
+
+    override fun assertLayersVisibleRegion(
+        componentMatcher: IComponentMatcher,
+        useCompositionEngineRegionOnly: Boolean,
+        assertion: RegionTraceSubject.() -> Unit
+    ) =
+        assertLayersVisibleRegion(
+            name = defaultAssertionName,
+            componentMatcher,
+            useCompositionEngineRegionOnly,
+            assertion
+        )
+
+    override fun assertEventLog(assertion: EventLogSubject.() -> Unit) =
+        assertEventLog(name = defaultAssertionName, assertion)
+}
diff --git a/libraries/flicker/src/android/tools/device/flicker/legacy/FlickerTest.kt b/libraries/flicker/src/android/tools/common/flicker/assertions/FlickerTest.kt
similarity index 77%
rename from libraries/flicker/src/android/tools/device/flicker/legacy/FlickerTest.kt
rename to libraries/flicker/src/android/tools/common/flicker/assertions/FlickerTest.kt
index 3c11bc8..9042fec 100644
--- a/libraries/flicker/src/android/tools/device/flicker/legacy/FlickerTest.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertions/FlickerTest.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.tools.device.flicker.legacy
+package android.tools.common.flicker.assertions
 
 import android.tools.common.flicker.subject.events.EventLogSubject
 import android.tools.common.flicker.subject.layers.LayerTraceEntrySubject
@@ -30,6 +30,7 @@
      *
      * @param assertion Assertion predicate
      */
+    fun assertWmStart(name: String, assertion: WindowManagerStateSubject.() -> Unit)
     fun assertWmStart(assertion: WindowManagerStateSubject.() -> Unit)
 
     /**
@@ -37,6 +38,7 @@
      *
      * @param assertion Assertion predicate
      */
+    fun assertWmEnd(name: String, assertion: WindowManagerStateSubject.() -> Unit)
     fun assertWmEnd(assertion: WindowManagerStateSubject.() -> Unit)
 
     /**
@@ -44,6 +46,7 @@
      *
      * @param assertion Assertion predicate
      */
+    fun assertWm(name: String, assertion: WindowManagerTraceSubject.() -> Unit)
     fun assertWm(assertion: WindowManagerTraceSubject.() -> Unit)
 
     /**
@@ -51,6 +54,7 @@
      *
      * @param assertion Assertion predicate
      */
+    fun assertWmTag(name: String, tag: String, assertion: WindowManagerStateSubject.() -> Unit)
     fun assertWmTag(tag: String, assertion: WindowManagerStateSubject.() -> Unit)
 
     /**
@@ -60,6 +64,11 @@
      * @param assertion Assertion predicate
      */
     fun assertWmVisibleRegion(
+        name: String,
+        componentMatcher: IComponentMatcher,
+        assertion: RegionTraceSubject.() -> Unit
+    )
+    fun assertWmVisibleRegion(
         componentMatcher: IComponentMatcher,
         assertion: RegionTraceSubject.() -> Unit
     )
@@ -69,6 +78,7 @@
      *
      * @param assertion Assertion predicate
      */
+    fun assertLayersStart(name: String, assertion: LayerTraceEntrySubject.() -> Unit)
     fun assertLayersStart(assertion: LayerTraceEntrySubject.() -> Unit)
 
     /**
@@ -76,6 +86,7 @@
      *
      * @param assertion Assertion predicate
      */
+    fun assertLayersEnd(name: String, assertion: LayerTraceEntrySubject.() -> Unit)
     fun assertLayersEnd(assertion: LayerTraceEntrySubject.() -> Unit)
 
     /**
@@ -83,6 +94,7 @@
      *
      * @param assertion Assertion predicate
      */
+    fun assertLayers(name: String, assertion: LayersTraceSubject.() -> Unit)
     fun assertLayers(assertion: LayersTraceSubject.() -> Unit)
 
     /**
@@ -90,6 +102,7 @@
      *
      * @param assertion Assertion predicate
      */
+    fun assertLayersTag(name: String, tag: String, assertion: LayerTraceEntrySubject.() -> Unit)
     fun assertLayersTag(tag: String, assertion: LayerTraceEntrySubject.() -> Unit)
 
     /**
@@ -103,6 +116,12 @@
      * @param assertion Assertion predicate
      */
     fun assertLayersVisibleRegion(
+        name: String,
+        componentMatcher: IComponentMatcher,
+        useCompositionEngineRegionOnly: Boolean = true,
+        assertion: RegionTraceSubject.() -> Unit
+    )
+    fun assertLayersVisibleRegion(
         componentMatcher: IComponentMatcher,
         useCompositionEngineRegionOnly: Boolean = true,
         assertion: RegionTraceSubject.() -> Unit
@@ -113,5 +132,6 @@
      *
      * @param assertion Assertion predicate
      */
+    fun assertEventLog(name: String, assertion: EventLogSubject.() -> Unit)
     fun assertEventLog(assertion: EventLogSubject.() -> Unit)
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertions/ScenarioAssertion.kt b/libraries/flicker/src/android/tools/common/flicker/assertions/ScenarioAssertion.kt
index 3ae3d4b..149dade 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertions/ScenarioAssertion.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertions/ScenarioAssertion.kt
@@ -17,7 +17,6 @@
 package android.tools.common.flicker.assertions
 
 import android.tools.common.flicker.AssertionInvocationGroup
-import android.tools.common.flicker.assertors.AssertionResult
 
 interface ScenarioAssertion {
     val stabilityGroup: AssertionInvocationGroup
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertions/ScenarioAssertionImpl.kt b/libraries/flicker/src/android/tools/common/flicker/assertions/ScenarioAssertionImpl.kt
index f4a2505..23fc093 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertions/ScenarioAssertionImpl.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertions/ScenarioAssertionImpl.kt
@@ -16,21 +16,19 @@
 
 package android.tools.common.flicker.assertions
 
-import android.tools.common.CrossPlatform
 import android.tools.common.FLICKER_TAG
+import android.tools.common.Logger
 import android.tools.common.flicker.AssertionInvocationGroup
-import android.tools.common.flicker.assertors.AssertionResult
-import android.tools.common.flicker.assertors.AssertionResultImpl
 import android.tools.common.io.Reader
 
-class ScenarioAssertionImpl(
+internal data class ScenarioAssertionImpl(
     private val reader: Reader,
     private val assertionData: AssertionData,
     override val stabilityGroup: AssertionInvocationGroup,
     private val assertionRunner: AssertionRunner = ReaderAssertionRunner(reader)
 ) : ScenarioAssertion {
-    override fun execute(): AssertionResult =
-        CrossPlatform.log.withTracing("executeAssertion") {
+    override fun execute() =
+        Logger.withTracing("executeAssertion") {
             AssertionResultImpl(
                     assertionData,
                     assertionRunner.runAssertion(assertionData),
@@ -39,15 +37,17 @@
                 .also { log(it) }
         }
 
+    override fun toString() = assertionData.name
+
     private fun log(result: AssertionResult) {
         if (result.failed) {
-            CrossPlatform.log.w(
+            Logger.w(
                 "$FLICKER_TAG-SERVICE",
                 "${result.assertion} FAILED :: " +
                     (result.assertionError?.message ?: "<NO ERROR MESSAGE>")
             )
         } else {
-            CrossPlatform.log.w("$FLICKER_TAG-SERVICE", "${result.assertion} PASSED")
+            Logger.w("$FLICKER_TAG-SERVICE", "${result.assertion} PASSED")
         }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertions/ServiceFlickerTest.kt b/libraries/flicker/src/android/tools/common/flicker/assertions/ServiceFlickerTest.kt
new file mode 100644
index 0000000..4b5620c
--- /dev/null
+++ b/libraries/flicker/src/android/tools/common/flicker/assertions/ServiceFlickerTest.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.tools.common.flicker.assertions
+
+class ServiceFlickerTest(defaultAssertionName: String) : BaseFlickerTest(defaultAssertionName) {
+    private val assertionsMap = mutableMapOf<String, AssertionData>()
+    val assertions: Collection<AssertionData> = assertionsMap.values
+
+    override fun doProcess(assertion: AssertionData) {
+        val name = assertion.name
+        require(!assertionsMap.containsKey(assertion.name)) { "Assertion name $name already used" }
+        assertionsMap[name] = assertion
+    }
+}
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/AssertionTemplate.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/AssertionTemplate.kt
index 8de1360..66e5560 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/AssertionTemplate.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/AssertionTemplate.kt
@@ -16,114 +16,35 @@
 
 package android.tools.common.flicker.assertors
 
-import android.tools.common.Tag
 import android.tools.common.flicker.AssertionInvocationGroup
 import android.tools.common.flicker.AssertionInvocationGroup.NON_BLOCKING
 import android.tools.common.flicker.ScenarioInstance
 import android.tools.common.flicker.assertions.AssertionData
-import android.tools.common.flicker.assertions.AssertionDataImpl
-import android.tools.common.flicker.subject.FlickerSubject
-import android.tools.common.flicker.subject.events.EventLogSubject
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
-import android.tools.common.flicker.subject.wm.WindowManagerTraceSubject
+import android.tools.common.flicker.assertions.FlickerTest
+import android.tools.common.flicker.assertions.ServiceFlickerTest
 
 /** Base class for a FaaS assertion */
-abstract class AssertionTemplate {
-    open val assertionName = "${this@AssertionTemplate::class.simpleName}"
-    var stabilityGroup: AssertionInvocationGroup = NON_BLOCKING
-        protected set
+abstract class AssertionTemplate(nameOverride: String? = null) {
+    private val name = nameOverride ?: this::class.simpleName
 
-    fun createAssertion(scenarioInstance: ScenarioInstance): AssertionData {
-        // TODO(Implement)
-        return AssertionDataImpl(
-            name = "${scenarioInstance.type}::${this@AssertionTemplate.assertionName}",
-            tag = Tag.ALL,
-            FlickerSubject::class,
-        ) {}
-        /*return object : IFaasAssertion {
-            override val name = "${scenarioInstance.type}::${this@AssertionTemplate.assertionName}"
+    open fun defaultAssertionName(scenarioInstance: ScenarioInstance): String =
+        "${scenarioInstance.type}::$name"
+    open val stabilityGroup: AssertionInvocationGroup = NON_BLOCKING
 
-            override val stabilityGroup
-                get() = this@AssertionTemplate.stabilityGroup
+    /** Evaluates assertions */
+    abstract fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest)
 
-            override fun evaluate(): AssertionResult {
-                val wmTraceSubject =
-                    scenarioInstance.reader.readWmTrace()?.let {
-                        WindowManagerTraceSubject(it, scenarioInstance.reader)
-                    }
-                val layersTraceSubject =
-                    scenarioInstance.reader.readLayersTrace()?.let {
-                        LayersTraceSubject(it, scenarioInstance.reader)
-                    }
-                val eventLogSubject =
-                    scenarioInstance.reader.readEventLogTrace()?.let {
-                        EventLogSubject(it, scenarioInstance.reader)
-                    }
+    fun createAssertions(scenarioInstance: ScenarioInstance): Collection<AssertionData> {
+        val flicker = ServiceFlickerTest(defaultAssertionName(scenarioInstance))
+        doEvaluate(scenarioInstance, flicker)
 
-                var assertionError: Throwable? = null
-                try {
-                    if (wmTraceSubject !== null) {
-                        doEvaluate(scenarioInstance, wmTraceSubject)
-                    }
-                    if (layersTraceSubject !== null) {
-                        doEvaluate(scenarioInstance, layersTraceSubject)
-                    }
-                    if (wmTraceSubject !== null && layersTraceSubject !== null) {
-                        doEvaluate(scenarioInstance, wmTraceSubject, layersTraceSubject)
-                    }
-                    if (eventLogSubject != null) {
-                        doEvaluate(scenarioInstance, eventLogSubject)
-                    }
-                } catch (e: Throwable) {
-                    assertionError = e
-                }
-
-                return AssertionResult(this, assertionError)
-            }
-        }*/
+        return flicker.assertions + doCreateExtraAssertions(scenarioInstance)
     }
 
-    /**
-     * Evaluates assertions that require only WM traces. NOTE: Will not run if WM trace is not
-     * available.
-     */
-    protected open fun doEvaluate(
-        scenarioInstance: ScenarioInstance,
-        wmSubject: WindowManagerTraceSubject
-    ) {
-        // Does nothing, unless overridden
-    }
-
-    /**
-     * Evaluates assertions that require only SF traces. NOTE: Will not run if layers trace is not
-     * available.
-     */
-    protected open fun doEvaluate(
-        scenarioInstance: ScenarioInstance,
-        layerSubject: LayersTraceSubject
-    ) {
-        // Does nothing, unless overridden
-    }
-
-    /**
-     * Evaluates assertions that require both SF and WM traces. NOTE: Will not run if any of the
-     * traces are not available.
-     */
-    protected open fun doEvaluate(
-        scenarioInstance: ScenarioInstance,
-        wmSubject: WindowManagerTraceSubject,
-        layerSubject: LayersTraceSubject
-    ) {
-        // Does nothing, unless overridden
-    }
-
-    /**
-     * Evaluates assertions that require the vent log. NOTE: Will not run if the event log traces is
-     * not available.
-     */
-    protected open fun doEvaluate(scenarioInstance: ScenarioInstance, eventLog: EventLogSubject) {
-        // Does nothing, unless overridden
-    }
+    /** Evaluates assertions */
+    protected open fun doCreateExtraAssertions(
+        scenarioInstance: ScenarioInstance
+    ): List<AssertionData> = emptyList()
 
     override fun equals(other: Any?): Boolean {
         if (other == null) {
@@ -135,7 +56,7 @@
 
     override fun hashCode(): Int {
         var result = stabilityGroup.hashCode()
-        result = 31 * result + assertionName.hashCode()
+        result = 31 * result + this::class.simpleName.hashCode()
         return result
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppLayerBecomesInvisible.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppLayerBecomesInvisible.kt
index 958d463..57e133b 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppLayerBecomesInvisible.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppLayerBecomesInvisible.kt
@@ -17,8 +17,8 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
 
 /**
  * Checks that the app layer doesn't exist or is invisible at the start of the transition, but is
@@ -27,11 +27,11 @@
 class AppLayerBecomesInvisible(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(scenarioInstance: ScenarioInstance, layerSubject: LayersTraceSubject) {
-        layerSubject
-            .isVisible(component.build(scenarioInstance))
-            .then()
-            .isInvisible(component.build(scenarioInstance))
-            .forAllEntries()
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertLayers {
+            isVisible(component.build(scenarioInstance))
+                .then()
+                .isInvisible(component.build(scenarioInstance))
+        }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppLayerBecomesVisible.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppLayerBecomesVisible.kt
index 6891343..6e8c57d 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppLayerBecomesVisible.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppLayerBecomesVisible.kt
@@ -17,8 +17,8 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
 import android.tools.common.traces.component.ComponentNameMatcher
 
 /**
@@ -28,25 +28,24 @@
 class AppLayerBecomesVisible(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(scenarioInstance: ScenarioInstance, layerSubject: LayersTraceSubject) {
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
         // The app launch transition can finish when the splashscreen or SnapshotStartingWindows
         // are shown before the app window and layers are actually shown. (b/284302118)
+        flicker.assertLayers {
+            isInvisible(component.build(scenarioInstance))
+                .then()
+                .isVisible(ComponentNameMatcher.SNAPSHOT, isOptional = true)
+                .then()
+                .isVisible(ComponentNameMatcher.SPLASH_SCREEN, isOptional = true)
+                .then()
+                .isVisible(component.build(scenarioInstance), isOptional = true)
+        }
 
-        layerSubject
-            .isInvisible(component.build(scenarioInstance))
-            .then()
-            .isVisible(ComponentNameMatcher.SNAPSHOT, isOptional = true)
-            .then()
-            .isVisible(ComponentNameMatcher.SPLASH_SCREEN, isOptional = true)
-            .then()
-            .isVisible(component.build(scenarioInstance), isOptional = true)
-            .forAllEntries()
-
-        layerSubject
-            .last()
-            .isVisible(
+        flicker.assertLayersEnd("AppLayerBecomesVisibleEnd") {
+            isVisible(
                 ComponentNameMatcher.SNAPSHOT.or(ComponentNameMatcher.SPLASH_SCREEN)
                     .or(component.build(scenarioInstance))
             )
+        }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppLayerCoversFullScreenAtEnd.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppLayerCoversFullScreenAtEnd.kt
index 8e6598f..e468243 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppLayerCoversFullScreenAtEnd.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppLayerCoversFullScreenAtEnd.kt
@@ -17,24 +17,20 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
 import android.tools.common.traces.component.ComponentNameMatcher
 
 class AppLayerCoversFullScreenAtEnd(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(scenarioInstance: ScenarioInstance, layerSubject: LayersTraceSubject) {
-        val layersTrace = scenarioInstance.reader.readLayersTrace() ?: error("Missing layers trace")
-        val startDisplayBounds =
-            layersTrace.entries.last().physicalDisplayBounds
-                ?: error("Missing physical display bounds")
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertLayersEnd {
+            val displayBounds =
+                entry.physicalDisplayBounds ?: error("Missing physical display bounds")
 
-        val visibleRegionSubject =
-            layerSubject
-                .last()
-                .visibleRegion(component.build(scenarioInstance).or(ComponentNameMatcher.LETTERBOX))
-
-        visibleRegionSubject.coversExactly(startDisplayBounds)
+            visibleRegion(component.build(scenarioInstance).or(ComponentNameMatcher.LETTERBOX))
+                .coversExactly(displayBounds)
+        }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppLayerCoversFullScreenAtStart.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppLayerCoversFullScreenAtStart.kt
index ad172d7..151fce5 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppLayerCoversFullScreenAtStart.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppLayerCoversFullScreenAtStart.kt
@@ -17,25 +17,19 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
 import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.common.traces.component.ComponentNameMatcher.Companion.LETTERBOX
 
 class AppLayerCoversFullScreenAtStart(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(scenarioInstance: ScenarioInstance, layerSubject: LayersTraceSubject) {
-        val layersTrace = scenarioInstance.reader.readLayersTrace() ?: error("Missing layers trace")
-        val startDisplayBounds =
-            layersTrace.entries.first().physicalDisplayBounds
-                ?: error("Missing physical display bounds")
-
-        val visibleRegionSubject =
-            layerSubject
-                .first()
-                .visibleRegion(component.build(scenarioInstance).or(ComponentNameMatcher.LETTERBOX))
-
-        visibleRegionSubject.coversExactly(startDisplayBounds)
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertLayersStart {
+            val displayBounds =
+                entry.physicalDisplayBounds ?: error("Missing physical display bounds")
+            visibleRegion(component.build(scenarioInstance).or(ComponentNameMatcher.LETTERBOX))
+                .coversExactly(displayBounds)
+        }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppLayerIsInvisibleAtEnd.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppLayerIsInvisibleAtEnd.kt
index 84bb859..c02f59f 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppLayerIsInvisibleAtEnd.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppLayerIsInvisibleAtEnd.kt
@@ -17,14 +17,14 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
 
 /** Checks if the [component] layer is invisible at the end of the transition */
 class AppLayerIsInvisibleAtEnd(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(scenarioInstance: ScenarioInstance, layerSubject: LayersTraceSubject) {
-        layerSubject.last().isInvisible(component.build(scenarioInstance))
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertLayersEnd { isInvisible(component.build(scenarioInstance)) }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppLayerIsInvisibleAtStart.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppLayerIsInvisibleAtStart.kt
index 2c4316d..4db0f92 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppLayerIsInvisibleAtStart.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppLayerIsInvisibleAtStart.kt
@@ -17,14 +17,14 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
 
 /** Checks if the [component] layer is invisible at the start of the transition */
 class AppLayerIsInvisibleAtStart(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(scenarioInstance: ScenarioInstance, layerSubject: LayersTraceSubject) {
-        layerSubject.first().isInvisible(component.build(scenarioInstance))
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertLayersStart { isInvisible(component.build(scenarioInstance)) }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppLayerIsVisibleAlways.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppLayerIsVisibleAlways.kt
index 19c964e..d07ab53 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppLayerIsVisibleAlways.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppLayerIsVisibleAlways.kt
@@ -17,14 +17,14 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
 
 /** Checks if the [component] layer is visible throughout the animation */
 class AppLayerIsVisibleAlways(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(scenarioInstance: ScenarioInstance, layerSubject: LayersTraceSubject) {
-        layerSubject.isVisible(component.build(scenarioInstance)).forAllEntries()
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertLayers { isVisible(component.build(scenarioInstance)) }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppLayerIsVisibleAtEnd.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppLayerIsVisibleAtEnd.kt
index 78ed36a..ad2fce9 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppLayerIsVisibleAtEnd.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppLayerIsVisibleAtEnd.kt
@@ -17,22 +17,22 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
 import android.tools.common.traces.component.ComponentNameMatcher
 
 /** Checks if the [component] layer is visible at the end of the transition */
 class AppLayerIsVisibleAtEnd(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(scenarioInstance: ScenarioInstance, layerSubject: LayersTraceSubject) {
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
         // The app launch transition can finish when the splashscreen or SnapshotStartingWindows are
         // shown before the app window and layers are actually shown. (b/284302118)
-        layerSubject
-            .last()
-            .isVisible(
+        flicker.assertLayersEnd {
+            isVisible(
                 ComponentNameMatcher.SNAPSHOT.or(ComponentNameMatcher.SPLASH_SCREEN)
                     .or(component.build(scenarioInstance))
             )
+        }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppLayerIsVisibleAtStart.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppLayerIsVisibleAtStart.kt
index ec8d3c8..57f4f62 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppLayerIsVisibleAtStart.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppLayerIsVisibleAtStart.kt
@@ -17,14 +17,14 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
 
 /** Checks if the [component] layer is visible at the start of the transition */
 class AppLayerIsVisibleAtStart(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(scenarioInstance: ScenarioInstance, layerSubject: LayersTraceSubject) {
-        layerSubject.first().isVisible(component.build(scenarioInstance))
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertLayersStart { isVisible(component.build(scenarioInstance)) }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppLayerReduces.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppLayerReduces.kt
index f339c3c..3d76f68 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppLayerReduces.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppLayerReduces.kt
@@ -17,18 +17,20 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
 
 /** Checks that the visible region of [component] always reduces during the animation */
 class AppLayerReduces(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(scenarioInstance: ScenarioInstance, layerSubject: LayersTraceSubject) {
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
         val layerMatcher = component.build(scenarioInstance)
-        val layerList = layerSubject.layers { layerMatcher.layerMatchesAnyOf(it) && it.isVisible }
-        layerList.zipWithNext { previous, current ->
-            current.visibleRegion.coversAtMost(previous.visibleRegion.region)
+        flicker.assertLayers {
+            val layerList = layers { layerMatcher.layerMatchesAnyOf(it) && it.isVisible }
+            layerList.zipWithNext { previous, current ->
+                current.visibleRegion.coversAtMost(previous.visibleRegion.region)
+            }
         }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppLayerRemainInsideDisplayBounds.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppLayerRemainInsideDisplayBounds.kt
index 4cd4a80..1a80516 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppLayerRemainInsideDisplayBounds.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppLayerRemainInsideDisplayBounds.kt
@@ -17,8 +17,8 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
 
 /**
  * Checks if the [component] layer remains inside the display bounds throughout the whole animation
@@ -26,16 +26,15 @@
 class AppLayerRemainInsideDisplayBounds(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(scenarioInstance: ScenarioInstance, layerSubject: LayersTraceSubject) {
-        layerSubject
-            .containsAtLeastOneDisplay()
-            .invoke("appLayerRemainInsideDisplayBounds") { subject ->
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertLayers {
+            containsAtLeastOneDisplay().invoke("appLayerRemainInsideDisplayBounds") { subject ->
                 subject.entry.displays.forEach { display ->
                     subject
                         .visibleRegion(component.build(scenarioInstance))
                         .coversAtMost(display.layerStackSpace)
                 }
             }
-            .forAllEntries()
+        }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppLayerReplacesLauncher.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppLayerReplacesLauncher.kt
index 95f70ea..eea8dbd 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppLayerReplacesLauncher.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppLayerReplacesLauncher.kt
@@ -17,8 +17,8 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
 import android.tools.common.traces.component.ComponentNameMatcher
 
 /**
@@ -33,11 +33,11 @@
 class AppLayerReplacesLauncher(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(scenarioInstance: ScenarioInstance, layerSubject: LayersTraceSubject) {
-        layerSubject
-            .isVisible(ComponentNameMatcher.LAUNCHER)
-            .then()
-            .isVisible(component.build(scenarioInstance))
-            .forAllEntries()
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertLayers {
+            isVisible(ComponentNameMatcher.LAUNCHER)
+                .then()
+                .isVisible(component.build(scenarioInstance))
+        }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowBecomesInvisible.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowBecomesInvisible.kt
index 368a945..abf48f8 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowBecomesInvisible.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowBecomesInvisible.kt
@@ -17,8 +17,8 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.wm.WindowManagerTraceSubject
 
 /**
  * Checks that the app layer doesn't exist or is invisible at the start of the transition, but is
@@ -27,14 +27,11 @@
 class AppWindowBecomesInvisible(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(
-        scenarioInstance: ScenarioInstance,
-        wmSubject: WindowManagerTraceSubject
-    ) {
-        wmSubject
-            .isAppWindowVisible(component.build(scenarioInstance))
-            .then()
-            .isAppWindowInvisible(component.build(scenarioInstance))
-            .forAllEntries()
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertWm {
+            isAppWindowVisible(component.build(scenarioInstance))
+                .then()
+                .isAppWindowInvisible(component.build(scenarioInstance))
+        }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowBecomesPinned.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowBecomesPinned.kt
index 74172ba..c53963b 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowBecomesPinned.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowBecomesPinned.kt
@@ -17,21 +17,18 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.wm.WindowManagerTraceSubject
 
 /** Checks that [component] window becomes pinned */
 class AppWindowBecomesPinned(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(
-        scenarioInstance: ScenarioInstance,
-        wmSubject: WindowManagerTraceSubject
-    ) {
-        wmSubject
-            .invoke("appWindowIsNotPinned") { it.isNotPinned(component.build(scenarioInstance)) }
-            .then()
-            .invoke("appWindowIsPinned") { it.isPinned(component.build(scenarioInstance)) }
-            .forAllEntries()
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertWm {
+            invoke("appWindowIsNotPinned") { it.isNotPinned(component.build(scenarioInstance)) }
+                .then()
+                .invoke("appWindowIsPinned") { it.isPinned(component.build(scenarioInstance)) }
+        }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowBecomesTopWindow.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowBecomesTopWindow.kt
index b109876..40abc9a 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowBecomesTopWindow.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowBecomesTopWindow.kt
@@ -17,8 +17,8 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.wm.WindowManagerTraceSubject
 import android.tools.common.traces.component.ComponentNameMatcher
 
 /**
@@ -28,17 +28,14 @@
 class AppWindowBecomesTopWindow(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(
-        scenarioInstance: ScenarioInstance,
-        wmSubject: WindowManagerTraceSubject
-    ) {
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
         val testApp = component.build(scenarioInstance)
-        wmSubject
-            .isAppWindowNotOnTop(testApp)
-            .then()
-            .isAppWindowOnTop(
-                testApp.or(ComponentNameMatcher.SNAPSHOT).or(ComponentNameMatcher.SPLASH_SCREEN)
-            )
-            .forAllEntries()
+        flicker.assertWm {
+            isAppWindowNotOnTop(testApp)
+                .then()
+                .isAppWindowOnTop(
+                    testApp.or(ComponentNameMatcher.SNAPSHOT).or(ComponentNameMatcher.SPLASH_SCREEN)
+                )
+        }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowBecomesVisible.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowBecomesVisible.kt
index 8aaa3a8..7ea9bec 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowBecomesVisible.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowBecomesVisible.kt
@@ -17,8 +17,8 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.wm.WindowManagerTraceSubject
 import android.tools.common.traces.component.ComponentNameMatcher
 
 /**
@@ -28,28 +28,24 @@
 class AppWindowBecomesVisible(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(
-        scenarioInstance: ScenarioInstance,
-        wmSubject: WindowManagerTraceSubject
-    ) {
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
         // The app launch transition can finish when the splashscreen or SnapshotStartingWindows
         // are shown before the app window and layers are actually shown. (b/284302118)
+        flicker.assertWm {
+            isAppWindowInvisible(component.build(scenarioInstance))
+                .then()
+                .isAppWindowVisible(ComponentNameMatcher.SNAPSHOT, isOptional = true)
+                .then()
+                .isAppWindowVisible(ComponentNameMatcher.SPLASH_SCREEN, isOptional = true)
+                .then()
+                .isAppWindowVisible(component.build(scenarioInstance), isOptional = true)
+        }
 
-        wmSubject
-            .isAppWindowInvisible(component.build(scenarioInstance))
-            .then()
-            .isAppWindowVisible(ComponentNameMatcher.SNAPSHOT, isOptional = true)
-            .then()
-            .isAppWindowVisible(ComponentNameMatcher.SPLASH_SCREEN, isOptional = true)
-            .then()
-            .isAppWindowVisible(component.build(scenarioInstance), isOptional = true)
-            .forAllEntries()
-
-        wmSubject
-            .last()
-            .isAppWindowVisible(
+        flicker.assertWmEnd("AppWindowBecomesVisibleEnd") {
+            isAppWindowVisible(
                 ComponentNameMatcher.SNAPSHOT.or(ComponentNameMatcher.SPLASH_SCREEN)
                     .or(component.build(scenarioInstance))
             )
+        }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowCoversFullScreenAtEnd.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowCoversFullScreenAtEnd.kt
index b64a8ce..7bc04a2 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowCoversFullScreenAtEnd.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowCoversFullScreenAtEnd.kt
@@ -17,24 +17,18 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.wm.WindowManagerTraceSubject
 
 class AppWindowCoversFullScreenAtEnd(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(
-        scenarioInstance: ScenarioInstance,
-        wmSubject: WindowManagerTraceSubject
-    ) {
-        val layersTrace = scenarioInstance.reader.readLayersTrace() ?: error("Missing layers trace")
-        val startDisplayBounds =
-            layersTrace.entries.last().physicalDisplayBounds
-                ?: error("Missing physical display bounds")
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertLayersEnd {
+            val displayBounds =
+                entry.physicalDisplayBounds ?: error("Missing physical display bounds")
 
-        wmSubject
-            .last()
-            .visibleRegion(component.build(scenarioInstance))
-            .coversExactly(startDisplayBounds)
+            visibleRegion(component.build(scenarioInstance)).coversExactly(displayBounds)
+        }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowCoversFullScreenAtStart.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowCoversFullScreenAtStart.kt
index c615612..11aa1c0 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowCoversFullScreenAtStart.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowCoversFullScreenAtStart.kt
@@ -17,24 +17,18 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.wm.WindowManagerTraceSubject
 
 class AppWindowCoversFullScreenAtStart(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(
-        scenarioInstance: ScenarioInstance,
-        wmSubject: WindowManagerTraceSubject
-    ) {
-        val layersTrace = scenarioInstance.reader.readLayersTrace() ?: error("Missing layers trace")
-        val startDisplayBounds =
-            layersTrace.entries.first().physicalDisplayBounds
-                ?: error("Missing physical display bounds")
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertLayersStart {
+            val displayBounds =
+                entry.physicalDisplayBounds ?: error("Missing physical display bounds")
 
-        wmSubject
-            .first()
-            .visibleRegion(component.build(scenarioInstance))
-            .coversExactly(startDisplayBounds)
+            visibleRegion(component.build(scenarioInstance)).coversExactly(displayBounds)
+        }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowIsInvisibleAtEnd.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowIsInvisibleAtEnd.kt
index 903fc7c..77b25d2 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowIsInvisibleAtEnd.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowIsInvisibleAtEnd.kt
@@ -17,17 +17,14 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.wm.WindowManagerTraceSubject
 
-/** Checks if the [getWindowState] layer is invisible at the end of the transition */
+/** Checks if the [component] layer is invisible at the end of the transition */
 class AppWindowIsInvisibleAtEnd(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(
-        scenarioInstance: ScenarioInstance,
-        wmSubject: WindowManagerTraceSubject
-    ) {
-        wmSubject.last().isAppWindowInvisible(component.build(scenarioInstance))
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertWmEnd { isAppWindowInvisible(component.build(scenarioInstance)) }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowIsInvisibleAtStart.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowIsInvisibleAtStart.kt
index 41134d0..ced86c0 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowIsInvisibleAtStart.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowIsInvisibleAtStart.kt
@@ -17,16 +17,13 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.wm.WindowManagerTraceSubject
 
 class AppWindowIsInvisibleAtStart(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(
-        scenarioInstance: ScenarioInstance,
-        wmSubject: WindowManagerTraceSubject
-    ) {
-        wmSubject.first().isAppWindowInvisible(component.build(scenarioInstance))
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertWmStart { isAppWindowInvisible(component.build(scenarioInstance)) }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowIsTopWindowAtStart.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowIsTopWindowAtStart.kt
index 8da472d..8f56644 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowIsTopWindowAtStart.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowIsTopWindowAtStart.kt
@@ -17,16 +17,13 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.wm.WindowManagerTraceSubject
 
 class AppWindowIsTopWindowAtStart(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(
-        scenarioInstance: ScenarioInstance,
-        wmSubject: WindowManagerTraceSubject
-    ) {
-        wmSubject.first().isAppWindowOnTop(component.build(scenarioInstance))
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertWmStart { isAppWindowOnTop(component.build(scenarioInstance)) }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowIsVisibleAlways.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowIsVisibleAlways.kt
index d5e5c90..9bddf73 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowIsVisibleAlways.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowIsVisibleAlways.kt
@@ -17,17 +17,14 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.wm.WindowManagerTraceSubject
 
 /** Checks that [component] window remains visible throughout the transition */
 class AppWindowIsVisibleAlways(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(
-        scenarioInstance: ScenarioInstance,
-        wmSubject: WindowManagerTraceSubject
-    ) {
-        wmSubject.isAppWindowVisible(component.build(scenarioInstance)).forAllEntries()
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertWm { isAppWindowVisible(component.build(scenarioInstance)) }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowIsVisibleAtEnd.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowIsVisibleAtEnd.kt
index 5faeff4..0ea5ac3 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowIsVisibleAtEnd.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowIsVisibleAtEnd.kt
@@ -17,16 +17,13 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.wm.WindowManagerTraceSubject
 
 class AppWindowIsVisibleAtEnd(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(
-        scenarioInstance: ScenarioInstance,
-        wmSubject: WindowManagerTraceSubject
-    ) {
-        wmSubject.last().isAppWindowVisible(component.build(scenarioInstance))
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertWmEnd { isAppWindowVisible(component.build(scenarioInstance)) }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowIsVisibleAtStart.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowIsVisibleAtStart.kt
index 068cad9..6eefc20 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowIsVisibleAtStart.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowIsVisibleAtStart.kt
@@ -17,16 +17,13 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.wm.WindowManagerTraceSubject
 
 class AppWindowIsVisibleAtStart(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(
-        scenarioInstance: ScenarioInstance,
-        wmSubject: WindowManagerTraceSubject
-    ) {
-        wmSubject.first().isAppWindowVisible(component.build(scenarioInstance))
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertWmStart { isAppWindowVisible(component.build(scenarioInstance)) }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowOnTopAtEnd.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowOnTopAtEnd.kt
index d8aeb64..4cca686 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowOnTopAtEnd.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowOnTopAtEnd.kt
@@ -17,16 +17,13 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.wm.WindowManagerTraceSubject
 
 class AppWindowOnTopAtEnd(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(
-        scenarioInstance: ScenarioInstance,
-        wmSubject: WindowManagerTraceSubject
-    ) {
-        wmSubject.last().isAppWindowOnTop(component.build(scenarioInstance))
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertWmEnd { isAppWindowOnTop(component.build(scenarioInstance)) }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowOnTopAtStart.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowOnTopAtStart.kt
index e57e70c..c7479f0 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowOnTopAtStart.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowOnTopAtStart.kt
@@ -17,16 +17,13 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.wm.WindowManagerTraceSubject
 
 class AppWindowOnTopAtStart(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(
-        scenarioInstance: ScenarioInstance,
-        wmSubject: WindowManagerTraceSubject
-    ) {
-        wmSubject.first().isAppWindowOnTop(component.build(scenarioInstance))
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertWmStart { isAppWindowOnTop(component.build(scenarioInstance)) }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowRemainInsideDisplayBounds.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowRemainInsideDisplayBounds.kt
index a94acf2..17de4d9 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowRemainInsideDisplayBounds.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowRemainInsideDisplayBounds.kt
@@ -17,8 +17,8 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.wm.WindowManagerTraceSubject
 
 /**
  * Checks that [component] window remains inside the display bounds throughout the whole animation
@@ -26,18 +26,14 @@
 class AppWindowRemainInsideDisplayBounds(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(
-        scenarioInstance: ScenarioInstance,
-        wmSubject: WindowManagerTraceSubject
-    ) {
-        wmSubject
-            .containsAtLeastOneDisplay()
-            .invoke("appWindowRemainInsideDisplayBounds") { entry ->
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertWm {
+            containsAtLeastOneDisplay().invoke("appWindowRemainInsideDisplayBounds") { entry ->
                 val display = entry.wmState.displays.minByOrNull { it.id }!!
                 entry
                     .visibleRegion(component.build(scenarioInstance))
                     .coversAtMost(display.displayRect)
             }
-            .forAllEntries()
+        }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowReplacesLauncherAsTopWindow.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowReplacesLauncherAsTopWindow.kt
index 651055f..e11a719 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowReplacesLauncherAsTopWindow.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AppWindowReplacesLauncherAsTopWindow.kt
@@ -17,9 +17,9 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
 import android.tools.common.flicker.assertors.Components
-import android.tools.common.flicker.subject.wm.WindowManagerTraceSubject
 import android.tools.common.traces.component.ComponentNameMatcher
 
 /**
@@ -29,14 +29,11 @@
 class AppWindowReplacesLauncherAsTopWindow(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(
-        scenarioInstance: ScenarioInstance,
-        wmSubject: WindowManagerTraceSubject
-    ) {
-        wmSubject
-            .isAppWindowOnTop(ComponentNameMatcher.LAUNCHER)
-            .then()
-            .isAppWindowOnTop(component.build(scenarioInstance))
-            .forAllEntries()
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertWm {
+            isAppWindowOnTop(ComponentNameMatcher.LAUNCHER)
+                .then()
+                .isAppWindowOnTop(component.build(scenarioInstance))
+        }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AssertionTemplateWithComponent.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AssertionTemplateWithComponent.kt
index 63d55eb..64a10c3 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AssertionTemplateWithComponent.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/AssertionTemplateWithComponent.kt
@@ -16,6 +16,7 @@
 
 package android.tools.common.flicker.assertors.assertions
 
+import android.tools.common.flicker.ScenarioInstance
 import android.tools.common.flicker.assertors.AssertionTemplate
 import android.tools.common.flicker.assertors.ComponentTemplate
 
@@ -23,7 +24,8 @@
 abstract class AssertionTemplateWithComponent(vararg val components: ComponentTemplate) :
     AssertionTemplate() {
 
-    override val assertionName = "${this::class.simpleName}(${components.joinToString { it.name }})"
+    override fun defaultAssertionName(scenarioInstance: ScenarioInstance) =
+        "${super.defaultAssertionName(scenarioInstance)}(${components.joinToString { it.name }})"
 
     override fun equals(other: Any?): Boolean {
         if (other !is AssertionTemplateWithComponent) {
@@ -46,7 +48,7 @@
 
     override fun hashCode(): Int {
         var result = super.hashCode()
-        result = 31 * result + assertionName.hashCode()
+        result = 31 * result + components.hashCode()
         return result
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/EntireScreenCoveredAlways.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/EntireScreenCoveredAlways.kt
index 0cefeb5..b2e6695 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/EntireScreenCoveredAlways.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/EntireScreenCoveredAlways.kt
@@ -17,8 +17,8 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.AssertionTemplate
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
 
 /**
  * Checks if the stack space of all displays is fully covered by any visible layer, during the whole
@@ -26,24 +26,16 @@
  */
 class EntireScreenCoveredAlways : AssertionTemplate() {
     /** {@inheritDoc} */
-    override fun doEvaluate(scenarioInstance: ScenarioInstance, layerSubject: LayersTraceSubject) {
-        layerSubject.atLeastOneEntryContainsOneDisplayOn()
-        layerSubject
-            .invoke("entireScreenCovered") { entry ->
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertLayers {
+            atLeastOneEntryContainsOneDisplayOn()
+            invoke("entireScreenCovered") { entry ->
                 entry.entry.displays
                     .filter { it.isOn }
                     .forEach { display ->
                         entry.visibleRegion().coversAtLeast(display.layerStackSpace)
                     }
             }
-            .forAllEntries()
-    }
-
-    override fun equals(other: Any?): Boolean {
-        return other is EntireScreenCoveredAlways
-    }
-
-    override fun hashCode(): Int {
-        return this::class.hashCode()
+        }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/EntireScreenCoveredAtEnd.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/EntireScreenCoveredAtEnd.kt
index b78341d..9e17370 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/EntireScreenCoveredAtEnd.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/EntireScreenCoveredAtEnd.kt
@@ -17,8 +17,8 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.AssertionTemplate
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
 
 /**
  * Checks if the stack space of all displays is fully covered by any visible layer, at the end of
@@ -26,12 +26,11 @@
  */
 class EntireScreenCoveredAtEnd : AssertionTemplate() {
     /** {@inheritDoc} */
-    override fun doEvaluate(scenarioInstance: ScenarioInstance, layerSubject: LayersTraceSubject) {
-        val subject = layerSubject.last()
-        subject.containsAtLeastOneDisplay()
-        val onDisplays = subject.entry.displays.filter { it.isOn }
-        onDisplays.forEach { display ->
-            subject.visibleRegion().coversAtLeast(display.layerStackSpace)
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertLayersEnd {
+            containsAtLeastOneDisplay()
+            val onDisplays = entry.displays.filter { it.isOn }
+            onDisplays.forEach { display -> visibleRegion().coversAtLeast(display.layerStackSpace) }
         }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/EntireScreenCoveredAtStart.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/EntireScreenCoveredAtStart.kt
index 36c3e1a..85c9f71 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/EntireScreenCoveredAtStart.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/EntireScreenCoveredAtStart.kt
@@ -17,8 +17,8 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.AssertionTemplate
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
 
 /**
  * Checks if the stack space of all displays is fully covered by any visible layer, at the start of
@@ -26,12 +26,11 @@
  */
 class EntireScreenCoveredAtStart : AssertionTemplate() {
     /** {@inheritDoc} */
-    override fun doEvaluate(scenarioInstance: ScenarioInstance, layerSubject: LayersTraceSubject) {
-        val subject = layerSubject.first()
-        subject.containsAtLeastOneDisplay()
-        val onDisplays = subject.entry.displays.filter { it.isOn }
-        onDisplays.forEach { display ->
-            subject.visibleRegion().coversAtLeast(display.layerStackSpace)
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertLayersStart {
+            containsAtLeastOneDisplay()
+            val onDisplays = entry.displays.filter { it.isOn }
+            onDisplays.forEach { display -> visibleRegion().coversAtLeast(display.layerStackSpace) }
         }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/FocusChanges.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/FocusChanges.kt
index ec885e0..b38e456 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/FocusChanges.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/FocusChanges.kt
@@ -17,8 +17,8 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.events.EventLogSubject
 import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.common.traces.component.IComponentNameMatcher
 
@@ -30,7 +30,7 @@
 ) : AssertionTemplateWithComponent(fromComponent, toComponent) {
 
     // TODO: Make parent call this when appropriate
-    override fun doEvaluate(scenarioInstance: ScenarioInstance, eventLog: EventLogSubject) {
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
         val layersTrace = scenarioInstance.reader.readLayersTrace()
         val fromComponent = fromComponent.build(scenarioInstance)
         val toComponent = toComponent.build(scenarioInstance)
@@ -57,6 +57,6 @@
                     .packageName
             }
 
-        eventLog.focusChanges(fromPackage, toPackage)
+        flicker.assertEventLog { focusChanges(fromPackage, toPackage) }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/HasAtMostOneWindowMatching.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/HasAtMostOneWindowMatching.kt
index 3d6b141..1fae1d7 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/HasAtMostOneWindowMatching.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/HasAtMostOneWindowMatching.kt
@@ -17,8 +17,8 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.wm.WindowManagerTraceSubject
 
 /**
  * Checks that the app layer doesn't exist or is invisible at the start of the transition, but is
@@ -27,17 +27,14 @@
 class HasAtMostOneWindowMatching(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(
-        scenarioInstance: ScenarioInstance,
-        wmSubject: WindowManagerTraceSubject
-    ) {
-        wmSubject
-            .invoke("HasAtMostOneWindowMatching") {
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertWm {
+            invoke("HasAtMostOneWindowMatching") {
                 val matcher = component.build(scenarioInstance)
                 val windowCount =
                     it.wmState.windowStates.count { window -> matcher.windowMatchesAnyOf(window) }
                 require(windowCount <= 1) { "Matched more than 1 $matcher" }
             }
-            .forAllEntries()
+        }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/LauncherReplacesAppLayer.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/LauncherReplacesAppLayer.kt
index ab91a2a..a035889 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/LauncherReplacesAppLayer.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/LauncherReplacesAppLayer.kt
@@ -17,8 +17,8 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
 import android.tools.common.traces.component.ComponentNameMatcher
 
 /**
@@ -32,11 +32,11 @@
 class LauncherReplacesAppLayer(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(scenarioInstance: ScenarioInstance, layerSubject: LayersTraceSubject) {
-        layerSubject
-            .isVisible(component.build(scenarioInstance))
-            .then()
-            .isVisible(ComponentNameMatcher.LAUNCHER)
-            .forAllEntries()
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertLayers {
+            isVisible(component.build(scenarioInstance))
+                .then()
+                .isVisible(ComponentNameMatcher.LAUNCHER)
+        }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/LauncherWindowReplacesAppAsTopWindow.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/LauncherWindowReplacesAppAsTopWindow.kt
index eec4ee2..47505f9 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/LauncherWindowReplacesAppAsTopWindow.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/LauncherWindowReplacesAppAsTopWindow.kt
@@ -17,9 +17,9 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
 import android.tools.common.flicker.assertors.Components
-import android.tools.common.flicker.subject.wm.WindowManagerTraceSubject
 import android.tools.common.traces.component.ComponentNameMatcher
 
 /**
@@ -28,14 +28,11 @@
  */
 class LauncherWindowReplacesAppAsTopWindow(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
-    override fun doEvaluate(
-        scenarioInstance: ScenarioInstance,
-        wmSubject: WindowManagerTraceSubject
-    ) {
-        wmSubject
-            .isAppWindowOnTop(component.build(scenarioInstance))
-            .then()
-            .isAppWindowOnTop(ComponentNameMatcher.LAUNCHER)
-            .forAllEntries()
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertWm {
+            isAppWindowOnTop(component.build(scenarioInstance))
+                .then()
+                .isAppWindowOnTop(ComponentNameMatcher.LAUNCHER)
+        }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/LayerBecomesInvisible.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/LayerBecomesInvisible.kt
index a0606ec..0561d7c 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/LayerBecomesInvisible.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/LayerBecomesInvisible.kt
@@ -17,21 +17,20 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
 
 /**
- * Checks if the [componentMatcher] layer is visible at the start of the transition and becomes
- * invisible
+ * Checks if the [component] layer is visible at the start of the transition and becomes invisible
  */
 class LayerBecomesInvisible(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(scenarioInstance: ScenarioInstance, layerSubject: LayersTraceSubject) {
-        layerSubject
-            .isVisible(component.build(scenarioInstance))
-            .then()
-            .isInvisible(component.build(scenarioInstance))
-            .forAllEntries()
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertLayers {
+            isVisible(component.build(scenarioInstance))
+                .then()
+                .isInvisible(component.build(scenarioInstance))
+        }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/LayerBecomesVisible.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/LayerBecomesVisible.kt
index 97bd604..861fe79 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/LayerBecomesVisible.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/LayerBecomesVisible.kt
@@ -17,21 +17,20 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
 
 /**
- * Checks if the [componentMatcher] layer is invisible at the start of the transition and becomes
- * visible
+ * Checks if the [component] layer is invisible at the start of the transition and becomes visible
  */
 class LayerBecomesVisible(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(scenarioInstance: ScenarioInstance, layerSubject: LayersTraceSubject) {
-        layerSubject
-            .isInvisible(component.build(scenarioInstance))
-            .then()
-            .isVisible(component.build(scenarioInstance))
-            .forAllEntries()
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertLayers {
+            isInvisible(component.build(scenarioInstance))
+                .then()
+                .isVisible(component.build(scenarioInstance))
+        }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/LayerIsInvisibleAlways.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/LayerIsInvisibleAlways.kt
index 8b4fe87..d19d4e5 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/LayerIsInvisibleAlways.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/LayerIsInvisibleAlways.kt
@@ -17,14 +17,14 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
 
-/** Checks if the [componentMatcher] layer is invisible during the entire transition */
+/** Checks if the [component] layer is invisible during the entire transition */
 class LayerIsInvisibleAlways(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(scenarioInstance: ScenarioInstance, layerSubject: LayersTraceSubject) {
-        layerSubject.isVisible(component.build(scenarioInstance)).forAllEntries()
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertLayers { isVisible(component.build(scenarioInstance)) }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/LayerIsInvisibleAtEnd.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/LayerIsInvisibleAtEnd.kt
index 1542471..b172e86 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/LayerIsInvisibleAtEnd.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/LayerIsInvisibleAtEnd.kt
@@ -17,14 +17,14 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
 
-/** Checks if the [componentMatcher] layer is invisible at the end of the transition */
+/** Checks if the [component] layer is invisible at the end of the transition */
 class LayerIsInvisibleAtEnd(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(scenarioInstance: ScenarioInstance, layerSubject: LayersTraceSubject) {
-        layerSubject.last().isInvisible(component.build(scenarioInstance))
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertLayersEnd { isInvisible(component.build(scenarioInstance)) }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/LayerIsInvisibleAtStart.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/LayerIsInvisibleAtStart.kt
index 1262582..724ce70 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/LayerIsInvisibleAtStart.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/LayerIsInvisibleAtStart.kt
@@ -17,14 +17,14 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
 
-/** Checks if the [componentMatcher] layer is invisible at the start of the transition */
+/** Checks if the [component] layer is invisible at the start of the transition */
 class LayerIsInvisibleAtStart(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(scenarioInstance: ScenarioInstance, layerSubject: LayersTraceSubject) {
-        layerSubject.first().isInvisible(component.build(scenarioInstance))
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertLayersStart { isInvisible(component.build(scenarioInstance)) }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/LayerIsVisibleAlways.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/LayerIsVisibleAlways.kt
index 947c680..7efb6aa 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/LayerIsVisibleAlways.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/LayerIsVisibleAlways.kt
@@ -17,14 +17,14 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
 
-/** Checks if the [componentMatcher] layer is visible during the entire transition */
+/** Checks if the [component] layer is visible during the entire transition */
 class LayerIsVisibleAlways(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(scenarioInstance: ScenarioInstance, layerSubject: LayersTraceSubject) {
-        layerSubject.isVisible(component.build(scenarioInstance)).forAllEntries()
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertLayers { isVisible(component.build(scenarioInstance)) }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/LayerIsVisibleAtEnd.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/LayerIsVisibleAtEnd.kt
index c75c1b9..5da013e 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/LayerIsVisibleAtEnd.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/LayerIsVisibleAtEnd.kt
@@ -17,14 +17,14 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
 
 /** Checks if the [component] layer is visible at the end of the transition */
 class LayerIsVisibleAtEnd(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(scenarioInstance: ScenarioInstance, layerSubject: LayersTraceSubject) {
-        layerSubject.last().isVisible(component.build(scenarioInstance))
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertLayersEnd { isVisible(component.build(scenarioInstance)) }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/LayerIsVisibleAtStart.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/LayerIsVisibleAtStart.kt
index b97abda..5ecb36a 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/LayerIsVisibleAtStart.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/LayerIsVisibleAtStart.kt
@@ -17,14 +17,14 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
 
 /** Checks if the [component] layer is visible at the start of the transition */
 class LayerIsVisibleAtStart(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(scenarioInstance: ScenarioInstance, layerSubject: LayersTraceSubject) {
-        layerSubject.first().isVisible(component.build(scenarioInstance))
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertLayersStart { isVisible(component.build(scenarioInstance)) }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/LayerReduces.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/LayerReduces.kt
index f6129ad..f5a8b2c 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/LayerReduces.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/LayerReduces.kt
@@ -17,18 +17,19 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
 
 class LayerReduces(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
-    override fun doEvaluate(scenarioInstance: ScenarioInstance, layersTrace: LayersTraceSubject) {
-        val pipLayerList =
-            layersTrace.layers {
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertLayers {
+            val pipLayerList = layers {
                 component.build(scenarioInstance).layerMatchesAnyOf(it) && it.isVisible
             }
-        pipLayerList.zipWithNext { previous, current ->
-            current.visibleRegion.notBiggerThan(previous.visibleRegion.region)
+            pipLayerList.zipWithNext { previous, current ->
+                current.visibleRegion.notBiggerThan(previous.visibleRegion.region)
+            }
         }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/LayerRemainInsideVisibleBounds.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/LayerRemainInsideVisibleBounds.kt
index 54c98ee..68205f5 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/LayerRemainInsideVisibleBounds.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/LayerRemainInsideVisibleBounds.kt
@@ -16,10 +16,9 @@
 
 package android.tools.common.flicker.assertors.assertions
 
-import android.tools.common.datatypes.Rect
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
 
 /**
  * Checks that the app layer doesn't exist or is invisible at the start of the transition, but is
@@ -28,14 +27,14 @@
 class LayerRemainInsideVisibleBounds(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(
-        scenarioInstance: ScenarioInstance,
-        layersTraceSubject: LayersTraceSubject
-    ) {
-        val displayBounds = Rect.EMPTY // TODO: Get display bounds from subject
-        layersTraceSubject
-            .visibleRegion(component.build(scenarioInstance))
-            .coversAtMost(displayBounds)
-            .forAllEntries()
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertLayers {
+            subjects.forEach {
+                val displayBounds =
+                    it.entry.physicalDisplayBounds ?: error("Missing physical display bounds")
+
+                it.visibleRegion(component.build(scenarioInstance)).coversAtMost(displayBounds)
+            }
+        }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/NonAppWindowBecomesInvisible.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/NonAppWindowBecomesInvisible.kt
index 711d629..387000c 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/NonAppWindowBecomesInvisible.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/NonAppWindowBecomesInvisible.kt
@@ -17,8 +17,8 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.wm.WindowManagerTraceSubject
 
 /**
  * Checks that non-app window [component] is visible at the start of the transition and becomes
@@ -27,14 +27,11 @@
 open class NonAppWindowBecomesInvisible(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(
-        scenarioInstance: ScenarioInstance,
-        wmSubject: WindowManagerTraceSubject
-    ) {
-        wmSubject
-            .isNonAppWindowVisible(component.build(scenarioInstance))
-            .then()
-            .isNonAppWindowInvisible(component.build(scenarioInstance))
-            .forAllEntries()
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertWm {
+            isNonAppWindowVisible(component.build(scenarioInstance))
+                .then()
+                .isNonAppWindowInvisible(component.build(scenarioInstance))
+        }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/NonAppWindowBecomesVisible.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/NonAppWindowBecomesVisible.kt
index 62e60ed..8f5ee53 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/NonAppWindowBecomesVisible.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/NonAppWindowBecomesVisible.kt
@@ -17,8 +17,8 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.wm.WindowManagerTraceSubject
 
 /**
  * Checks that non-app window [component] is invisible at the start of the transition and becomes
@@ -27,14 +27,11 @@
 class NonAppWindowBecomesVisible(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(
-        scenarioInstance: ScenarioInstance,
-        wmSubject: WindowManagerTraceSubject
-    ) {
-        wmSubject
-            .isNonAppWindowInvisible(component.build(scenarioInstance))
-            .then()
-            .isAppWindowVisible(component.build(scenarioInstance))
-            .forAllEntries()
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertWm {
+            isNonAppWindowInvisible(component.build(scenarioInstance))
+                .then()
+                .isAppWindowVisible(component.build(scenarioInstance))
+        }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/NonAppWindowIsInvisibleAlways.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/NonAppWindowIsInvisibleAlways.kt
index b84dfa3..d9be69c 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/NonAppWindowIsInvisibleAlways.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/NonAppWindowIsInvisibleAlways.kt
@@ -17,17 +17,14 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.wm.WindowManagerTraceSubject
 
 /** Checks if the [component] window is invisible during the entire transition */
 class NonAppWindowIsInvisibleAlways(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(
-        scenarioInstance: ScenarioInstance,
-        wmSubject: WindowManagerTraceSubject
-    ) {
-        wmSubject.isNonAppWindowInvisible(component.build(scenarioInstance)).forAllEntries()
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertWm { isNonAppWindowInvisible(component.build(scenarioInstance)) }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/NonAppWindowIsVisibleAlways.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/NonAppWindowIsVisibleAlways.kt
index 0f08b70..40277e7 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/NonAppWindowIsVisibleAlways.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/NonAppWindowIsVisibleAlways.kt
@@ -17,17 +17,14 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.wm.WindowManagerTraceSubject
 
 /** Checks if the [component] window is visible during the entire transition */
 class NonAppWindowIsVisibleAlways(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(
-        scenarioInstance: ScenarioInstance,
-        wmSubject: WindowManagerTraceSubject
-    ) {
-        wmSubject.isNonAppWindowVisible(component.build(scenarioInstance)).forAllEntries()
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertWm { isNonAppWindowVisible(component.build(scenarioInstance)) }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/NonAppWindowIsVisibleAtEnd.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/NonAppWindowIsVisibleAtEnd.kt
index ae184e2..cca969b 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/NonAppWindowIsVisibleAtEnd.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/NonAppWindowIsVisibleAtEnd.kt
@@ -17,17 +17,14 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.wm.WindowManagerTraceSubject
 
 /** Checks if the [component] window is visible at the end of the transition */
 class NonAppWindowIsVisibleAtEnd(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(
-        scenarioInstance: ScenarioInstance,
-        wmSubject: WindowManagerTraceSubject
-    ) {
-        wmSubject.last().isNonAppWindowVisible(component.build(scenarioInstance))
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertWmEnd { isNonAppWindowVisible(component.build(scenarioInstance)) }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/NonAppWindowIsVisibleAtStart.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/NonAppWindowIsVisibleAtStart.kt
index 3037f57..fb5dfb6 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/NonAppWindowIsVisibleAtStart.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/NonAppWindowIsVisibleAtStart.kt
@@ -17,17 +17,14 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.wm.WindowManagerTraceSubject
 
 /** Checks if the [component] window is visible at the end of the transition */
 class NonAppWindowIsVisibleAtStart(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(
-        scenarioInstance: ScenarioInstance,
-        wmSubject: WindowManagerTraceSubject
-    ) {
-        wmSubject.first().isNonAppWindowVisible(component.build(scenarioInstance))
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertWmStart { isNonAppWindowVisible(component.build(scenarioInstance)) }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/PipWindowBecomesInvisible.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/PipWindowBecomesInvisible.kt
index 23b0df7..350b8f3 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/PipWindowBecomesInvisible.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/PipWindowBecomesInvisible.kt
@@ -17,8 +17,8 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.wm.WindowManagerTraceSubject
 
 /**
  * Checks that [component] window is pinned and visible at the start and then becomes unpinned and
@@ -27,21 +27,17 @@
 class PipWindowBecomesInvisible(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(
-        scenarioInstance: ScenarioInstance,
-        wmSubject: WindowManagerTraceSubject
-    ) {
-        val appComponent = component
-        wmSubject
-            .invoke("hasPipWindow") {
-                it.isPinned(appComponent.build(scenarioInstance))
-                    .isAppWindowVisible(appComponent.build(scenarioInstance))
-            }
-            .then()
-            .invoke("!hasPipWindow") {
-                it.isNotPinned(appComponent.build(scenarioInstance))
-                    .isAppWindowInvisible(appComponent.build(scenarioInstance))
-            }
-            .forAllEntries()
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertWm {
+            invoke("hasPipWindow") {
+                    it.isPinned(component.build(scenarioInstance))
+                        .isAppWindowVisible(component.build(scenarioInstance))
+                }
+                .then()
+                .invoke("!hasPipWindow") {
+                    it.isNotPinned(component.build(scenarioInstance))
+                        .isAppWindowInvisible(component.build(scenarioInstance))
+                }
+        }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/RotationLayerAppearsAndVanishes.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/RotationLayerAppearsAndVanishes.kt
index 020e8bc..5335f06 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/RotationLayerAppearsAndVanishes.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/RotationLayerAppearsAndVanishes.kt
@@ -17,8 +17,8 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
 import android.tools.common.traces.component.ComponentNameMatcher
 
 /**
@@ -28,14 +28,14 @@
 class RotationLayerAppearsAndVanishes(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(scenarioInstance: ScenarioInstance, layerSubject: LayersTraceSubject) {
-        layerSubject
-            .isVisible(component.build(scenarioInstance))
-            .then()
-            .isVisible(ComponentNameMatcher.ROTATION)
-            .then()
-            .isVisible(component.build(scenarioInstance))
-            .isInvisible(ComponentNameMatcher.ROTATION)
-            .forAllEntries()
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertLayers {
+            isVisible(component.build(scenarioInstance))
+                .then()
+                .isVisible(ComponentNameMatcher.ROTATION)
+                .then()
+                .isVisible(component.build(scenarioInstance))
+                .isInvisible(ComponentNameMatcher.ROTATION)
+        }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/ScreenLockedAtStart.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/ScreenLockedAtStart.kt
index 87b5672..841c997 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/ScreenLockedAtStart.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/ScreenLockedAtStart.kt
@@ -17,12 +17,12 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.AssertionTemplate
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
 
 class ScreenLockedAtStart : AssertionTemplate() {
 
-    override fun doEvaluate(scenarioInstance: ScenarioInstance, layersTrace: LayersTraceSubject) {
-        layersTrace.first().isEmpty()
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertLayersStart { isEmpty() }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/SplitAppLayerBoundsBecomesVisible.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/SplitAppLayerBoundsBecomesVisible.kt
index bcd4d50..f678f84 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/SplitAppLayerBoundsBecomesVisible.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/SplitAppLayerBoundsBecomesVisible.kt
@@ -18,23 +18,19 @@
 
 import android.tools.common.datatypes.Region
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
 import android.tools.common.flicker.assertors.Components
 import android.tools.common.flicker.subject.layers.LayerTraceEntrySubject
 import android.tools.common.flicker.subject.layers.LayersTraceSubject
-import android.tools.common.flicker.subject.wm.WindowManagerTraceSubject
 import android.tools.common.traces.component.IComponentMatcher
 
 class SplitAppLayerBoundsBecomesVisible(
     private val component: ComponentTemplate,
     val isPrimaryApp: Boolean
 ) : AssertionTemplateWithComponent(component) {
-    override fun doEvaluate(
-        scenarioInstance: ScenarioInstance,
-        wmSubject: WindowManagerTraceSubject,
-        layerSubject: LayersTraceSubject
-    ) {
-        val splitscreenDivider = Components.SPLIT_SCREEN_DIVIDER.build(scenarioInstance)
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        val splitScreenDivider = Components.SPLIT_SCREEN_DIVIDER.build(scenarioInstance)
         val app = component.build(scenarioInstance)
 
         val landscapePosLeft: Boolean
@@ -48,86 +44,88 @@
             portraitPosTop = true
         }
 
-        layerSubject
-            .notContains(splitscreenDivider.or(app), isOptional = true)
-            .then()
-            .isInvisible(splitscreenDivider.or(app))
-            .then()
-            .splitAppLayerBoundsSnapToDivider(
-                app,
-                splitscreenDivider,
-                landscapePosLeft,
-                portraitPosTop
-            )
-            .forAllEntries()
+        flicker.assertLayers {
+            notContains(splitScreenDivider.or(app), isOptional = true)
+                .then()
+                .isInvisible(splitScreenDivider.or(app))
+                .then()
+                .splitAppLayerBoundsSnapToDivider(
+                    app,
+                    splitScreenDivider,
+                    landscapePosLeft,
+                    portraitPosTop
+                )
+        }
     }
-}
 
-fun LayersTraceSubject.splitAppLayerBoundsSnapToDivider(
-    component: IComponentMatcher,
-    splitscreenDivider: IComponentMatcher,
-    landscapePosLeft: Boolean,
-    portraitPosTop: Boolean
-): LayersTraceSubject {
-    return invoke("splitAppLayerBoundsSnapToDivider") {
-        it.splitAppLayerBoundsSnapToDivider(
-            component,
-            splitscreenDivider,
-            landscapePosLeft,
-            portraitPosTop
-        )
-    }
-}
+    companion object {
+        fun LayersTraceSubject.splitAppLayerBoundsSnapToDivider(
+            component: IComponentMatcher,
+            splitScreenDivider: IComponentMatcher,
+            landscapePosLeft: Boolean,
+            portraitPosTop: Boolean
+        ): LayersTraceSubject {
+            return invoke("splitAppLayerBoundsSnapToDivider") {
+                it.splitAppLayerBoundsSnapToDivider(
+                    component,
+                    splitScreenDivider,
+                    landscapePosLeft,
+                    portraitPosTop
+                )
+            }
+        }
 
-fun LayerTraceEntrySubject.splitAppLayerBoundsSnapToDivider(
-    component: IComponentMatcher,
-    splitscreenDivider: IComponentMatcher,
-    landscapePosLeft: Boolean,
-    portraitPosTop: Boolean
-): LayerTraceEntrySubject {
-    val activeDisplay =
-        this.entry.displays.firstOrNull { it.isOn && !it.isVirtual }
-            ?: error("No non-virtual and on display found")
+        private fun LayerTraceEntrySubject.splitAppLayerBoundsSnapToDivider(
+            component: IComponentMatcher,
+            splitScreenDivider: IComponentMatcher,
+            landscapePosLeft: Boolean,
+            portraitPosTop: Boolean
+        ): LayerTraceEntrySubject {
+            val activeDisplay =
+                this.entry.displays.firstOrNull { it.isOn && !it.isVirtual }
+                    ?: error("No non-virtual and on display found")
 
-    return invoke {
-        val dividerRegion =
-            layer(splitscreenDivider)?.visibleRegion?.region
-                ?: error("$splitscreenDivider component not found")
-        visibleRegion(component)
-            .coversAtMost(
-                if (activeDisplay.bounds.width > activeDisplay.bounds.height) {
-                    if (landscapePosLeft) {
-                        Region.from(
-                            0,
-                            0,
-                            (dividerRegion.bounds.left + dividerRegion.bounds.right) / 2,
-                            activeDisplay.bounds.bottom
-                        )
-                    } else {
-                        Region.from(
-                            (dividerRegion.bounds.left + dividerRegion.bounds.right) / 2,
-                            0,
-                            activeDisplay.bounds.right,
-                            activeDisplay.bounds.bottom
-                        )
-                    }
-                } else {
-                    if (portraitPosTop) {
-                        Region.from(
-                            0,
-                            0,
-                            activeDisplay.bounds.right,
-                            (dividerRegion.bounds.top + dividerRegion.bounds.bottom) / 2
-                        )
-                    } else {
-                        Region.from(
-                            0,
-                            (dividerRegion.bounds.top + dividerRegion.bounds.bottom) / 2,
-                            activeDisplay.bounds.right,
-                            activeDisplay.bounds.bottom
-                        )
-                    }
-                }
-            )
+            return invoke {
+                val dividerRegion =
+                    layer(splitScreenDivider)?.visibleRegion?.region
+                        ?: error("$splitScreenDivider component not found")
+                visibleRegion(component)
+                    .coversAtMost(
+                        if (activeDisplay.bounds.width > activeDisplay.bounds.height) {
+                            if (landscapePosLeft) {
+                                Region.from(
+                                    0,
+                                    0,
+                                    (dividerRegion.bounds.left + dividerRegion.bounds.right) / 2,
+                                    activeDisplay.bounds.bottom
+                                )
+                            } else {
+                                Region.from(
+                                    (dividerRegion.bounds.left + dividerRegion.bounds.right) / 2,
+                                    0,
+                                    activeDisplay.bounds.right,
+                                    activeDisplay.bounds.bottom
+                                )
+                            }
+                        } else {
+                            if (portraitPosTop) {
+                                Region.from(
+                                    0,
+                                    0,
+                                    activeDisplay.bounds.right,
+                                    (dividerRegion.bounds.top + dividerRegion.bounds.bottom) / 2
+                                )
+                            } else {
+                                Region.from(
+                                    0,
+                                    (dividerRegion.bounds.top + dividerRegion.bounds.bottom) / 2,
+                                    activeDisplay.bounds.right,
+                                    activeDisplay.bounds.bottom
+                                )
+                            }
+                        }
+                    )
+            }
+        }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/SplitAppLayerBoundsSnapToDivider.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/SplitAppLayerBoundsSnapToDivider.kt
index d563fcc..38802db 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/SplitAppLayerBoundsSnapToDivider.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/SplitAppLayerBoundsSnapToDivider.kt
@@ -18,76 +18,80 @@
 
 import android.tools.common.datatypes.Region
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
 import android.tools.common.flicker.assertors.Components.SPLIT_SCREEN_DIVIDER
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
-import android.tools.common.flicker.subject.wm.WindowManagerTraceSubject
+import android.tools.common.flicker.subject.layers.LayerTraceEntrySubject
+import android.tools.common.traces.wm.WindowManagerTrace
 
 class SplitAppLayerBoundsSnapToDivider(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(
-        scenarioInstance: ScenarioInstance,
-        wmSubject: WindowManagerTraceSubject,
-        layerSubject: LayersTraceSubject
-    ) {
-        // TODO: Replace with always on tracing available data
-        val landscapePosLeft = !wmSubject.trace.isTablet
-        val portraitPosTop = true // TODO: Figure out how to know if we are top or bottom app
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        val wmTrace = scenarioInstance.reader.readWmTrace() ?: return
 
-        val splitscreenDivider = SPLIT_SCREEN_DIVIDER.build(scenarioInstance)
-
-        layerSubject
-            .invoke("splitAppLayerBoundsSnapToDivider") {
-                val displaySize =
-                    it.entry.displays
-                        .first()
-                        .size // TODO: Better way of getting correct display instead of just first
-                val dividerRegion =
-                    it.layer(splitscreenDivider)?.visibleRegion?.region
-                        ?: error("Missing splitscreen divider")
-
-                require(dividerRegion.isNotEmpty) {
-                    "Splitscreen divider region should not be empty"
-                }
-
+        flicker.assertLayers {
+            invoke("splitAppLayerBoundsSnapToDivider") {
                 it.visibleRegion(component.build(scenarioInstance))
-                    .coversAtMost(
-                        if (displaySize.width > displaySize.height) {
-                            if (landscapePosLeft) {
-                                Region.from(
-                                    0,
-                                    0,
-                                    (dividerRegion.bounds.left + dividerRegion.bounds.right) / 2,
-                                    displaySize.height
-                                )
-                            } else {
-                                Region.from(
-                                    (dividerRegion.bounds.left + dividerRegion.bounds.right) / 2,
-                                    0,
-                                    displaySize.width,
-                                    displaySize.height
-                                )
-                            }
-                        } else {
-                            if (portraitPosTop) {
-                                Region.from(
-                                    0,
-                                    0,
-                                    displaySize.width,
-                                    (dividerRegion.bounds.top + dividerRegion.bounds.bottom) / 2
-                                )
-                            } else {
-                                Region.from(
-                                    0,
-                                    (dividerRegion.bounds.top + dividerRegion.bounds.bottom) / 2,
-                                    displaySize.width,
-                                    displaySize.height
-                                )
-                            }
-                        }
-                    )
+                    .coversAtMost(it.calculateExpectedDisplaySize(scenarioInstance, wmTrace))
             }
-            .forAllEntries()
+        }
+    }
+
+    companion object {
+        private fun LayerTraceEntrySubject.calculateExpectedDisplaySize(
+            scenarioInstance: ScenarioInstance,
+            wmTrace: WindowManagerTrace
+        ): Region {
+            // TODO: Replace with always on tracing available data
+            val landscapePosLeft = !wmTrace.isTablet
+            val portraitPosTop = true // TODO: Figure out how to know if we are top or bottom app
+
+            val splitScreenDivider = SPLIT_SCREEN_DIVIDER.build(scenarioInstance)
+
+            val displaySize =
+                entry.displays
+                    .first()
+                    .size // TODO: Better way of getting correct display instead of just first
+            val dividerRegion =
+                layer(splitScreenDivider)?.visibleRegion?.region
+                    ?: error("Missing splitscreen divider")
+
+            require(dividerRegion.isNotEmpty) { "Splitscreen divider region should not be empty" }
+
+            return if (displaySize.width > displaySize.height) {
+                if (landscapePosLeft) {
+                    Region.from(
+                        0,
+                        0,
+                        (dividerRegion.bounds.left + dividerRegion.bounds.right) / 2,
+                        displaySize.height
+                    )
+                } else {
+                    Region.from(
+                        (dividerRegion.bounds.left + dividerRegion.bounds.right) / 2,
+                        0,
+                        displaySize.width,
+                        displaySize.height
+                    )
+                }
+            } else {
+                if (portraitPosTop) {
+                    Region.from(
+                        0,
+                        0,
+                        displaySize.width,
+                        (dividerRegion.bounds.top + dividerRegion.bounds.bottom) / 2
+                    )
+                } else {
+                    Region.from(
+                        0,
+                        (dividerRegion.bounds.top + dividerRegion.bounds.bottom) / 2,
+                        displaySize.width,
+                        displaySize.height
+                    )
+                }
+            }
+        }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/StatusBarLayerPositionAtEnd.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/StatusBarLayerPositionAtEnd.kt
index 2e74bbe..33227a6 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/StatusBarLayerPositionAtEnd.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/StatusBarLayerPositionAtEnd.kt
@@ -19,8 +19,8 @@
 import android.tools.common.PlatformConsts
 import android.tools.common.datatypes.Region
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.AssertionTemplate
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
 import android.tools.common.traces.component.ComponentNameMatcher
 
 /**
@@ -29,17 +29,17 @@
  */
 class StatusBarLayerPositionAtEnd : AssertionTemplate() {
     /** {@inheritDoc} */
-    override fun doEvaluate(scenarioInstance: ScenarioInstance, layerSubject: LayersTraceSubject) {
-        layerSubject
-            .last()
-            .visibleRegion(ComponentNameMatcher.STATUS_BAR)
-            .coversExactly(getExpectedStatusbarPosition(scenarioInstance))
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertLayersEnd {
+            visibleRegion(ComponentNameMatcher.STATUS_BAR)
+                .coversExactly(getExpectedStatusBarPosition(scenarioInstance))
+        }
     }
 
     // TODO: Maybe find another way to get the expected position that doesn't rely on use the data
     // from the WM trace
     // can we maybe dump another trace that just has system info for this purpose?
-    private fun getExpectedStatusbarPosition(scenarioInstance: ScenarioInstance): Region {
+    private fun getExpectedStatusBarPosition(scenarioInstance: ScenarioInstance): Region {
         val wmState =
             scenarioInstance.reader.readWmTrace()?.entries?.last()
                 ?: error("Missing wm trace entries")
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/StatusBarLayerPositionAtStart.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/StatusBarLayerPositionAtStart.kt
index a913f84..9db6f39 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/StatusBarLayerPositionAtStart.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/StatusBarLayerPositionAtStart.kt
@@ -19,8 +19,8 @@
 import android.tools.common.PlatformConsts
 import android.tools.common.datatypes.Region
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.AssertionTemplate
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
 import android.tools.common.traces.component.ComponentNameMatcher
 
 /**
@@ -29,18 +29,18 @@
  */
 class StatusBarLayerPositionAtStart : AssertionTemplate() {
     /** {@inheritDoc} */
-    override fun doEvaluate(scenarioInstance: ScenarioInstance, layerSubject: LayersTraceSubject) {
-        layerSubject
-            .first()
-            .visibleRegion(ComponentNameMatcher.STATUS_BAR)
-            .coversExactly(getExpectedStatusbarPosition(scenarioInstance))
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertWmStart {
+            visibleRegion(ComponentNameMatcher.STATUS_BAR)
+                .coversExactly(getExpectedStatusBarPosition(scenarioInstance))
+        }
     }
 
     // TODO: Maybe find another way to get the expected position that doesn't rely on use the data
     // from the WM trace
     // can we maybe dump another trace that just has system info for this purpose?
     // TODO: Also this is duplicated code we can probably extract this out
-    private fun getExpectedStatusbarPosition(scenarioInstance: ScenarioInstance): Region {
+    private fun getExpectedStatusBarPosition(scenarioInstance: ScenarioInstance): Region {
         val wmState =
             scenarioInstance.reader.readWmTrace()?.entries?.last()
                 ?: error("Missing wm trace entries")
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/VisibleLayersShownMoreThanOneConsecutiveEntry.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/VisibleLayersShownMoreThanOneConsecutiveEntry.kt
index 5bf0197..6b18928 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/VisibleLayersShownMoreThanOneConsecutiveEntry.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/VisibleLayersShownMoreThanOneConsecutiveEntry.kt
@@ -17,8 +17,8 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.AssertionTemplate
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
 import android.tools.common.flicker.subject.layers.LayersTraceSubject.Companion.VISIBLE_FOR_MORE_THAN_ONE_ENTRY_IGNORE_LAYERS
 import android.tools.common.traces.component.IComponentMatcher
 
@@ -30,11 +30,11 @@
     private val ignore: List<IComponentMatcher> = listOf()
 ) : AssertionTemplate() {
     /** {@inheritDoc} */
-    override fun doEvaluate(scenarioInstance: ScenarioInstance, layerSubject: LayersTraceSubject) {
-        layerSubject
-            .visibleLayersShownMoreThanOneConsecutiveEntry(
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertLayers {
+            visibleLayersShownMoreThanOneConsecutiveEntry(
                 ignoreLayers = VISIBLE_FOR_MORE_THAN_ONE_ENTRY_IGNORE_LAYERS + ignore
             )
-            .forAllEntries()
+        }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/VisibleWindowsShownMoreThanOneConsecutiveEntry.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/VisibleWindowsShownMoreThanOneConsecutiveEntry.kt
index f33f024..a0d158f 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/VisibleWindowsShownMoreThanOneConsecutiveEntry.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/VisibleWindowsShownMoreThanOneConsecutiveEntry.kt
@@ -17,8 +17,8 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.AssertionTemplate
-import android.tools.common.flicker.subject.wm.WindowManagerTraceSubject
 
 /**
  * Checks that all windows that are visible on the trace, are visible for at least 2 consecutive
@@ -26,10 +26,7 @@
  */
 class VisibleWindowsShownMoreThanOneConsecutiveEntry : AssertionTemplate() {
     /** {@inheritDoc} */
-    override fun doEvaluate(
-        scenarioInstance: ScenarioInstance,
-        wmSubject: WindowManagerTraceSubject
-    ) {
-        wmSubject.visibleWindowsShownMoreThanOneConsecutiveEntry().forAllEntries()
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertWm { visibleWindowsShownMoreThanOneConsecutiveEntry() }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/WindowBecomesPinned.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/WindowBecomesPinned.kt
index 7e4ab6a..09ee9d0 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/WindowBecomesPinned.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/WindowBecomesPinned.kt
@@ -17,8 +17,8 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.wm.WindowManagerTraceSubject
 
 /**
  * Checks that the app layer doesn't exist or is invisible at the start of the transition, but is
@@ -27,11 +27,8 @@
 class WindowBecomesPinned(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(
-        scenarioInstance: ScenarioInstance,
-        wmSubject: WindowManagerTraceSubject
-    ) {
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
         val component = component.build(scenarioInstance)
-        wmSubject.isNotPinned(component).then().isPinned(component).forAllEntries()
+        flicker.assertWm { isNotPinned(component).then().isPinned(component) }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/WindowMovesOutOfTop.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/WindowMovesOutOfTop.kt
index 0479e04..4689288 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/WindowMovesOutOfTop.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/WindowMovesOutOfTop.kt
@@ -17,21 +17,18 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.wm.WindowManagerTraceSubject
 
 /** Checks that [component] starts on top and moves out of top during the transition */
 open class WindowMovesOutOfTop(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(
-        scenarioInstance: ScenarioInstance,
-        wmSubject: WindowManagerTraceSubject
-    ) {
-        wmSubject
-            .isAppWindowOnTop(component.build(scenarioInstance))
-            .then()
-            .isAppWindowNotOnTop(component.build(scenarioInstance))
-            .forAllEntries()
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertWm {
+            isAppWindowOnTop(component.build(scenarioInstance))
+                .then()
+                .isAppWindowNotOnTop(component.build(scenarioInstance))
+        }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/WindowMovesToTop.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/WindowMovesToTop.kt
index 5797e46..492c036 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/WindowMovesToTop.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/WindowMovesToTop.kt
@@ -17,21 +17,18 @@
 package android.tools.common.flicker.assertors.assertions
 
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.wm.WindowManagerTraceSubject
 
 /** Checks that [component] starts not on top and moves to top during the transition */
 open class WindowMovesToTop(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(
-        scenarioInstance: ScenarioInstance,
-        wmSubject: WindowManagerTraceSubject
-    ) {
-        wmSubject
-            .isAppWindowNotOnTop(component.build(scenarioInstance))
-            .then()
-            .isAppWindowOnTop(component.build(scenarioInstance))
-            .forAllEntries()
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
+        flicker.assertWm {
+            isAppWindowNotOnTop(component.build(scenarioInstance))
+                .then()
+                .isAppWindowOnTop(component.build(scenarioInstance))
+        }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/WindowRemainInsideVisibleBounds.kt b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/WindowRemainInsideVisibleBounds.kt
index 67014af..409ab04 100644
--- a/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/WindowRemainInsideVisibleBounds.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/WindowRemainInsideVisibleBounds.kt
@@ -18,8 +18,8 @@
 
 import android.tools.common.datatypes.Rect
 import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.flicker.assertors.ComponentTemplate
-import android.tools.common.flicker.subject.wm.WindowManagerTraceSubject
 
 /**
  * Checks that the app layer doesn't exist or is invisible at the start of the transition, but is
@@ -28,14 +28,10 @@
 class WindowRemainInsideVisibleBounds(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
-    override fun doEvaluate(
-        scenarioInstance: ScenarioInstance,
-        wmSubject: WindowManagerTraceSubject
-    ) {
+    override fun doEvaluate(scenarioInstance: ScenarioInstance, flicker: FlickerTest) {
         val displayBounds = Rect.EMPTY // TODO: Get display bounds from wmSubject
-        wmSubject
-            .visibleRegion(component.build(scenarioInstance))
-            .coversAtMost(displayBounds)
-            .forAllEntries()
+        flicker.assertWm {
+            visibleRegion(component.build(scenarioInstance)).coversAtMost(displayBounds)
+        }
     }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/appclose/AppCloseToHome.kt b/libraries/flicker/src/android/tools/common/flicker/config/appclose/AppCloseToHome.kt
index 95bbbd1..33a9721 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/appclose/AppCloseToHome.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/appclose/AppCloseToHome.kt
@@ -32,7 +32,7 @@
 
     override val assertionTemplates = AssertionTemplates.APP_CLOSE_TO_HOME_ASSERTIONS
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_LAUNCHER_APP_CLOSE_TO_HOME)
@@ -40,4 +40,5 @@
                 TaggedCujTransitionMatcher(TransitionFilters.CLOSE_APP_TO_LAUNCHER_FILTER)
             )
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/applaunch/AppLaunchFromIcon.kt b/libraries/flicker/src/android/tools/common/flicker/config/applaunch/AppLaunchFromIcon.kt
index 61f1619..66644e1 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/applaunch/AppLaunchFromIcon.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/applaunch/AppLaunchFromIcon.kt
@@ -32,7 +32,7 @@
 
     override val assertionTemplates = AssertionTemplates.APP_LAUNCH_FROM_HOME_ASSERTIONS
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_LAUNCHER_APP_LAUNCH_FROM_ICON)
@@ -40,4 +40,5 @@
                 TaggedCujTransitionMatcher(TransitionFilters.OPEN_APP_TRANSITION_FILTER)
             )
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/applaunch/AppLaunchFromNotification.kt b/libraries/flicker/src/android/tools/common/flicker/config/applaunch/AppLaunchFromNotification.kt
index 037651a..c299c86 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/applaunch/AppLaunchFromNotification.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/applaunch/AppLaunchFromNotification.kt
@@ -32,7 +32,7 @@
 
     override val assertionTemplates = AssertionTemplates.APP_LAUNCH_FROM_NOTIFICATION_ASSERTIONS
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_NOTIFICATION_APP_START)
@@ -40,4 +40,5 @@
                 TaggedCujTransitionMatcher(TransitionFilters.OPEN_APP_TRANSITION_FILTER)
             )
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/applaunch/AppLaunchFromRecents.kt b/libraries/flicker/src/android/tools/common/flicker/config/applaunch/AppLaunchFromRecents.kt
index 700079a..e03afb1 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/applaunch/AppLaunchFromRecents.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/applaunch/AppLaunchFromRecents.kt
@@ -32,7 +32,7 @@
 
     override val assertionTemplates = AssertionTemplates.APP_LAUNCH_FROM_HOME_ASSERTIONS
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_LAUNCHER_APP_LAUNCH_FROM_RECENTS)
@@ -40,4 +40,5 @@
                 TaggedCujTransitionMatcher(TransitionFilters.OPEN_APP_TRANSITION_FILTER)
             )
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/applaunch/AppLaunchFromStatusBarCallChip.kt b/libraries/flicker/src/android/tools/common/flicker/config/applaunch/AppLaunchFromStatusBarCallChip.kt
index 3930f2d..7ce6da3 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/applaunch/AppLaunchFromStatusBarCallChip.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/applaunch/AppLaunchFromStatusBarCallChip.kt
@@ -32,7 +32,7 @@
 
     override val assertionTemplates = AssertionTemplates.APP_LAUNCH_ASSERTIONS
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP)
@@ -40,4 +40,5 @@
                 TaggedCujTransitionMatcher(TransitionFilters.OPEN_APP_TRANSITION_FILTER)
             )
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/applaunch/AppLaunchFromWidget.kt b/libraries/flicker/src/android/tools/common/flicker/config/applaunch/AppLaunchFromWidget.kt
index 58335f0..88a676a 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/applaunch/AppLaunchFromWidget.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/applaunch/AppLaunchFromWidget.kt
@@ -32,7 +32,7 @@
 
     override val assertionTemplates = AssertionTemplates.APP_LAUNCH_FROM_HOME_ASSERTIONS
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_LAUNCHER_APP_LAUNCH_FROM_WIDGET)
@@ -40,4 +40,5 @@
                 TaggedCujTransitionMatcher(TransitionFilters.OPEN_APP_TRANSITION_FILTER)
             )
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/foldables/FoldablesUnfoldAnimation.kt b/libraries/flicker/src/android/tools/common/flicker/config/foldables/FoldablesUnfoldAnimation.kt
index c7959ea..3c93232 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/foldables/FoldablesUnfoldAnimation.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/foldables/FoldablesUnfoldAnimation.kt
@@ -32,7 +32,7 @@
     override val assertionTemplates =
         AssertionTemplates.COMMON_ASSERTIONS // TODO: Add specific assertions
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_UNFOLD_ANIM)
@@ -40,4 +40,5 @@
                 TaggedCujTransitionMatcher(associatedTransitionRequired = false),
             )
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/gesturenav/Quickswitch.kt b/libraries/flicker/src/android/tools/common/flicker/config/gesturenav/Quickswitch.kt
index a0425b7..5805566 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/gesturenav/Quickswitch.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/gesturenav/Quickswitch.kt
@@ -32,7 +32,7 @@
 
     override val assertionTemplates = AssertionTemplates.LAUNCHER_QUICK_SWITCH_ASSERTIONS
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_LAUNCHER_QUICK_SWITCH)
@@ -43,4 +43,5 @@
                 )
             )
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/gesturenav/SwipeToRecents.kt b/libraries/flicker/src/android/tools/common/flicker/config/gesturenav/SwipeToRecents.kt
index 6638b5f..a12c7a0 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/gesturenav/SwipeToRecents.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/gesturenav/SwipeToRecents.kt
@@ -32,7 +32,7 @@
 
     override val assertionTemplates = AssertionTemplates.APP_SWIPE_TO_RECENTS_ASSERTIONS
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS)
@@ -40,4 +40,5 @@
                 TaggedCujTransitionMatcher(TransitionFilters.CLOSE_APP_TO_LAUNCHER_FILTER)
             )
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/ime/ImeInsetsAnimation.kt b/libraries/flicker/src/android/tools/common/flicker/config/ime/ImeInsetsAnimation.kt
index 3f8cf01..f7cebec 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/ime/ImeInsetsAnimation.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/ime/ImeInsetsAnimation.kt
@@ -32,10 +32,11 @@
     override val assertionTemplates =
         AssertionTemplates.COMMON_ASSERTIONS // TODO: Add specific assertions
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_IME_INSETS_ANIMATION)
             .setTransitionMatcher(TaggedCujTransitionMatcher(associatedTransitionRequired = false))
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/launcher/LauncherAllAppsCloseSwipe.kt b/libraries/flicker/src/android/tools/common/flicker/config/launcher/LauncherAllAppsCloseSwipe.kt
index 18aea2a..f708f02 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/launcher/LauncherAllAppsCloseSwipe.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/launcher/LauncherAllAppsCloseSwipe.kt
@@ -32,10 +32,11 @@
     override val assertionTemplates =
         AssertionTemplates.COMMON_ASSERTIONS // TODO: Add specific assertions
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_LAUNCHER_CLOSE_ALL_APPS_SWIPE)
             .setTransitionMatcher(TaggedCujTransitionMatcher(associatedTransitionRequired = false))
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/launcher/LauncherAllAppsCloseToHome.kt b/libraries/flicker/src/android/tools/common/flicker/config/launcher/LauncherAllAppsCloseToHome.kt
index 2a522b2..001fea4 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/launcher/LauncherAllAppsCloseToHome.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/launcher/LauncherAllAppsCloseToHome.kt
@@ -32,7 +32,7 @@
 
     override val assertionTemplates = AssertionTemplates.APP_CLOSE_TO_HOME_ASSERTIONS
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_LAUNCHER_CLOSE_ALL_APPS_TO_HOME)
@@ -40,4 +40,5 @@
                 TaggedCujTransitionMatcher(TransitionFilters.CLOSE_APP_TO_LAUNCHER_FILTER)
             )
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/launcher/LauncherAllAppsOpen.kt b/libraries/flicker/src/android/tools/common/flicker/config/launcher/LauncherAllAppsOpen.kt
index 287015a..239ac6c 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/launcher/LauncherAllAppsOpen.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/launcher/LauncherAllAppsOpen.kt
@@ -32,10 +32,11 @@
     override val assertionTemplates =
         AssertionTemplates.COMMON_ASSERTIONS // TODO: Add specific assertions
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_LAUNCHER_OPEN_ALL_APPS)
             .setTransitionMatcher(TaggedCujTransitionMatcher(associatedTransitionRequired = false))
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/launcher/LauncherAllAppsScroll.kt b/libraries/flicker/src/android/tools/common/flicker/config/launcher/LauncherAllAppsScroll.kt
index 328cb02..1bf0943 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/launcher/LauncherAllAppsScroll.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/launcher/LauncherAllAppsScroll.kt
@@ -32,10 +32,11 @@
     override val assertionTemplates =
         AssertionTemplates.COMMON_ASSERTIONS // TODO: Add specific assertions
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_LAUNCHER_ALL_APPS_SCROLL)
             .setTransitionMatcher(TaggedCujTransitionMatcher(associatedTransitionRequired = false))
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/launcher/LauncherRecentsScrolling.kt b/libraries/flicker/src/android/tools/common/flicker/config/launcher/LauncherRecentsScrolling.kt
index 99b9d9b..89b23b5 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/launcher/LauncherRecentsScrolling.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/launcher/LauncherRecentsScrolling.kt
@@ -32,10 +32,11 @@
     override val assertionTemplates =
         AssertionTemplates.COMMON_ASSERTIONS // TODO: Add specific assertions
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_RECENTS_SCROLLING)
             .setTransitionMatcher(TaggedCujTransitionMatcher(associatedTransitionRequired = false))
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/launcher/LauncherUnlockEntranceAnimation.kt b/libraries/flicker/src/android/tools/common/flicker/config/launcher/LauncherUnlockEntranceAnimation.kt
index b5aa59e..1f09025 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/launcher/LauncherUnlockEntranceAnimation.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/launcher/LauncherUnlockEntranceAnimation.kt
@@ -32,10 +32,11 @@
     override val assertionTemplates =
         AssertionTemplates.COMMON_ASSERTIONS // TODO: Add specific assertions
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_LAUNCHER_UNLOCK_ENTRANCE_ANIMATION)
             .setTransitionMatcher(TaggedCujTransitionMatcher(associatedTransitionRequired = false))
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/lockscreen/LockscreenAppLaunchCamera.kt b/libraries/flicker/src/android/tools/common/flicker/config/lockscreen/LockscreenAppLaunchCamera.kt
index d2c91ea..b00b8bf 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/lockscreen/LockscreenAppLaunchCamera.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/lockscreen/LockscreenAppLaunchCamera.kt
@@ -32,7 +32,7 @@
 
     override val assertionTemplates = AssertionTemplates.APP_LAUNCH_FROM_LOCK_ASSERTIONS
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_LOCKSCREEN_LAUNCH_CAMERA)
@@ -40,4 +40,5 @@
                 TaggedCujTransitionMatcher(TransitionFilters.OPEN_APP_TRANSITION_FILTER)
             )
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/lockscreen/LockscreenOcclusion.kt b/libraries/flicker/src/android/tools/common/flicker/config/lockscreen/LockscreenOcclusion.kt
index a2c3b5d..329d692 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/lockscreen/LockscreenOcclusion.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/lockscreen/LockscreenOcclusion.kt
@@ -32,10 +32,11 @@
     override val assertionTemplates =
         AssertionTemplates.COMMON_ASSERTIONS // TODO: Add specific assertions
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_LOCKSCREEN_OCCLUSION)
             .setTransitionMatcher(TaggedCujTransitionMatcher(associatedTransitionRequired = false))
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/lockscreen/LockscreenPasswordAppear.kt b/libraries/flicker/src/android/tools/common/flicker/config/lockscreen/LockscreenPasswordAppear.kt
index 146d23c..7f724c0 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/lockscreen/LockscreenPasswordAppear.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/lockscreen/LockscreenPasswordAppear.kt
@@ -32,10 +32,11 @@
     override val assertionTemplates =
         AssertionTemplates.COMMON_ASSERTIONS // TODO: Add specific assertions
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_LOCKSCREEN_PASSWORD_APPEAR)
             .setTransitionMatcher(TaggedCujTransitionMatcher(associatedTransitionRequired = false))
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/lockscreen/LockscreenPasswordDisappear.kt b/libraries/flicker/src/android/tools/common/flicker/config/lockscreen/LockscreenPasswordDisappear.kt
index f0db1eb..53ec4f0 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/lockscreen/LockscreenPasswordDisappear.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/lockscreen/LockscreenPasswordDisappear.kt
@@ -32,10 +32,11 @@
     override val assertionTemplates =
         AssertionTemplates.COMMON_ASSERTIONS // TODO: Add specific assertions
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_LOCKSCREEN_PASSWORD_DISAPPEAR)
             .setTransitionMatcher(TaggedCujTransitionMatcher(associatedTransitionRequired = false))
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/lockscreen/LockscreenPatternAppear.kt b/libraries/flicker/src/android/tools/common/flicker/config/lockscreen/LockscreenPatternAppear.kt
index 293435f..5536de3 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/lockscreen/LockscreenPatternAppear.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/lockscreen/LockscreenPatternAppear.kt
@@ -32,10 +32,11 @@
     override val assertionTemplates =
         AssertionTemplates.COMMON_ASSERTIONS // TODO: Add specific assertions
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_LOCKSCREEN_PATTERN_APPEAR)
             .setTransitionMatcher(TaggedCujTransitionMatcher(associatedTransitionRequired = false))
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/lockscreen/LockscreenPatternDisappear.kt b/libraries/flicker/src/android/tools/common/flicker/config/lockscreen/LockscreenPatternDisappear.kt
index 132780b..826445d 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/lockscreen/LockscreenPatternDisappear.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/lockscreen/LockscreenPatternDisappear.kt
@@ -32,10 +32,11 @@
     override val assertionTemplates =
         AssertionTemplates.COMMON_ASSERTIONS // TODO: Add specific assertions
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_LOCKSCREEN_PATTERN_DISAPPEAR)
             .setTransitionMatcher(TaggedCujTransitionMatcher(associatedTransitionRequired = false))
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/lockscreen/LockscreenPinAppear.kt b/libraries/flicker/src/android/tools/common/flicker/config/lockscreen/LockscreenPinAppear.kt
index 45c0096..37c9bc9 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/lockscreen/LockscreenPinAppear.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/lockscreen/LockscreenPinAppear.kt
@@ -32,10 +32,11 @@
     override val assertionTemplates =
         AssertionTemplates.COMMON_ASSERTIONS // TODO: Add specific assertions
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_LOCKSCREEN_PIN_APPEAR)
             .setTransitionMatcher(TaggedCujTransitionMatcher(associatedTransitionRequired = false))
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/lockscreen/LockscreenPinDisappear.kt b/libraries/flicker/src/android/tools/common/flicker/config/lockscreen/LockscreenPinDisappear.kt
index 57b2d6b..ad1c06e 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/lockscreen/LockscreenPinDisappear.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/lockscreen/LockscreenPinDisappear.kt
@@ -32,10 +32,11 @@
     override val assertionTemplates =
         AssertionTemplates.COMMON_ASSERTIONS // TODO: Add specific assertions
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_LOCKSCREEN_PIN_DISAPPEAR)
             .setTransitionMatcher(TaggedCujTransitionMatcher(associatedTransitionRequired = false))
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/lockscreen/LockscreenTransitionFromAod.kt b/libraries/flicker/src/android/tools/common/flicker/config/lockscreen/LockscreenTransitionFromAod.kt
index b778edf..0d58255 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/lockscreen/LockscreenTransitionFromAod.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/lockscreen/LockscreenTransitionFromAod.kt
@@ -31,10 +31,11 @@
 
     override val assertionTemplates = AssertionTemplates.LOCKSCREEN_TRANSITION_FROM_AOD_ASSERTIONS
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_LOCKSCREEN_TRANSITION_FROM_AOD)
             .setTransitionMatcher(TaggedCujTransitionMatcher(associatedTransitionRequired = false))
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/lockscreen/LockscreenTransitionToAod.kt b/libraries/flicker/src/android/tools/common/flicker/config/lockscreen/LockscreenTransitionToAod.kt
index 5c35047..8140c41 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/lockscreen/LockscreenTransitionToAod.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/lockscreen/LockscreenTransitionToAod.kt
@@ -31,10 +31,11 @@
 
     override val assertionTemplates = AssertionTemplates.LOCKSCREEN_TRANSITION_TO_AOD_ASSERTIONS
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_LOCKSCREEN_TRANSITION_TO_AOD)
             .setTransitionMatcher(TaggedCujTransitionMatcher(associatedTransitionRequired = false))
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/lockscreen/LockscreenUnlockAnimation.kt b/libraries/flicker/src/android/tools/common/flicker/config/lockscreen/LockscreenUnlockAnimation.kt
index 17f2e89..176e0e1 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/lockscreen/LockscreenUnlockAnimation.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/lockscreen/LockscreenUnlockAnimation.kt
@@ -31,10 +31,11 @@
 
     override val assertionTemplates = AssertionTemplates.LOCKSCREEN_UNLOCK_ANIMATION_ASSERTIONS
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_LOCKSCREEN_UNLOCK_ANIMATION)
             .setTransitionMatcher(TaggedCujTransitionMatcher(associatedTransitionRequired = false))
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationAdd.kt b/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationAdd.kt
index 2c2ff6c..365d94e 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationAdd.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationAdd.kt
@@ -32,10 +32,11 @@
     override val assertionTemplates =
         AssertionTemplates.COMMON_ASSERTIONS // TODO: Add specific assertions
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_NOTIFICATION_ADD)
             .setTransitionMatcher(TaggedCujTransitionMatcher(associatedTransitionRequired = false))
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationAppLaunchFromHistory.kt b/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationAppLaunchFromHistory.kt
index 2347d12..bffa63c 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationAppLaunchFromHistory.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationAppLaunchFromHistory.kt
@@ -32,7 +32,7 @@
 
     override val assertionTemplates = AssertionTemplates.APP_LAUNCH_ASSERTIONS
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_SHADE_APP_LAUNCH_FROM_HISTORY_BUTTON)
@@ -40,4 +40,5 @@
                 TaggedCujTransitionMatcher(TransitionFilters.OPEN_APP_TRANSITION_FILTER)
             )
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationAppLaunchFromMediaPlayer.kt b/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationAppLaunchFromMediaPlayer.kt
index 4650e1d..dc08d78 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationAppLaunchFromMediaPlayer.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationAppLaunchFromMediaPlayer.kt
@@ -32,7 +32,7 @@
 
     override val assertionTemplates = AssertionTemplates.APP_LAUNCH_ASSERTIONS
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_SHADE_APP_LAUNCH_FROM_MEDIA_PLAYER)
@@ -40,4 +40,5 @@
                 TaggedCujTransitionMatcher(TransitionFilters.OPEN_APP_TRANSITION_FILTER)
             )
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationAppLaunchFromQsTile.kt b/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationAppLaunchFromQsTile.kt
index 0a27974..9070769 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationAppLaunchFromQsTile.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationAppLaunchFromQsTile.kt
@@ -32,7 +32,7 @@
 
     override val assertionTemplates = AssertionTemplates.APP_LAUNCH_ASSERTIONS
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_SHADE_APP_LAUNCH_FROM_QS_TILE)
@@ -40,4 +40,5 @@
                 TaggedCujTransitionMatcher(TransitionFilters.OPEN_APP_TRANSITION_FILTER)
             )
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationAppLaunchFromSettingsButton.kt b/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationAppLaunchFromSettingsButton.kt
index 1e38969..7c3c875 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationAppLaunchFromSettingsButton.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationAppLaunchFromSettingsButton.kt
@@ -32,7 +32,7 @@
 
     override val assertionTemplates = AssertionTemplates.APP_LAUNCH_ASSERTIONS
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_SHADE_APP_LAUNCH_FROM_SETTINGS_BUTTON)
@@ -40,4 +40,5 @@
                 TaggedCujTransitionMatcher(TransitionFilters.OPEN_APP_TRANSITION_FILTER)
             )
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationClearAll.kt b/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationClearAll.kt
index 1496978..f9cf10d 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationClearAll.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationClearAll.kt
@@ -32,10 +32,11 @@
     override val assertionTemplates =
         AssertionTemplates.COMMON_ASSERTIONS // TODO: Add specific assertions
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_SHADE_CLEAR_ALL)
             .setTransitionMatcher(TaggedCujTransitionMatcher(associatedTransitionRequired = false))
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationDialogOpen.kt b/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationDialogOpen.kt
index 3fd7a75..8f4482e 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationDialogOpen.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationDialogOpen.kt
@@ -32,10 +32,11 @@
     override val assertionTemplates =
         AssertionTemplates.COMMON_ASSERTIONS // TODO: Add specific assertions
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_SHADE_DIALOG_OPEN)
             .setTransitionMatcher(TaggedCujTransitionMatcher(associatedTransitionRequired = false))
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationExpandCollapse.kt b/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationExpandCollapse.kt
index f0f0a7d..0a88c77 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationExpandCollapse.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationExpandCollapse.kt
@@ -32,10 +32,11 @@
     override val assertionTemplates =
         AssertionTemplates.COMMON_ASSERTIONS // TODO: Add specific assertions
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE)
             .setTransitionMatcher(TaggedCujTransitionMatcher(associatedTransitionRequired = false))
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationExpandCollapseLockscreen.kt b/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationExpandCollapseLockscreen.kt
index 7b0b3d3..f2e85c4 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationExpandCollapseLockscreen.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationExpandCollapseLockscreen.kt
@@ -32,10 +32,11 @@
     override val assertionTemplates =
         AssertionTemplates.COMMON_ASSERTIONS // TODO: Add specific assertions
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE_LOCK)
             .setTransitionMatcher(TaggedCujTransitionMatcher(associatedTransitionRequired = false))
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationHeadsUpAppear.kt b/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationHeadsUpAppear.kt
index c406757..59a3d13 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationHeadsUpAppear.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationHeadsUpAppear.kt
@@ -32,10 +32,11 @@
     override val assertionTemplates =
         AssertionTemplates.COMMON_ASSERTIONS // TODO: Add specific assertions
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_NOTIFICATION_HEADS_UP_APPEAR)
             .setTransitionMatcher(TaggedCujTransitionMatcher(associatedTransitionRequired = false))
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationHeadsUpDisappear.kt b/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationHeadsUpDisappear.kt
index 722e66f..e4b9d8b 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationHeadsUpDisappear.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationHeadsUpDisappear.kt
@@ -32,10 +32,11 @@
     override val assertionTemplates =
         AssertionTemplates.COMMON_ASSERTIONS // TODO: Add specific assertions
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_NOTIFICATION_HEADS_UP_DISAPPEAR)
             .setTransitionMatcher(TaggedCujTransitionMatcher(associatedTransitionRequired = false))
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationQsExpandCollapse.kt b/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationQsExpandCollapse.kt
index dfcc545..56bac61 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationQsExpandCollapse.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationQsExpandCollapse.kt
@@ -32,10 +32,11 @@
     override val assertionTemplates =
         AssertionTemplates.COMMON_ASSERTIONS // TODO: Add specific assertions
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE)
             .setTransitionMatcher(TaggedCujTransitionMatcher(associatedTransitionRequired = false))
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationQsScrollSwipe.kt b/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationQsScrollSwipe.kt
index 883a1c2..ceed1d2 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationQsScrollSwipe.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationQsScrollSwipe.kt
@@ -32,10 +32,11 @@
     override val assertionTemplates =
         AssertionTemplates.COMMON_ASSERTIONS // TODO: Add specific assertions
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_NOTIFICATION_SHADE_QS_SCROLL_SWIPE)
             .setTransitionMatcher(TaggedCujTransitionMatcher(associatedTransitionRequired = false))
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationRemove.kt b/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationRemove.kt
index 5008a07..2c9aab1 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationRemove.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationRemove.kt
@@ -32,10 +32,11 @@
     override val assertionTemplates =
         AssertionTemplates.COMMON_ASSERTIONS // TODO: Add specific assertions
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_NOTIFICATION_REMOVE)
             .setTransitionMatcher(TaggedCujTransitionMatcher(associatedTransitionRequired = false))
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationRowExpand.kt b/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationRowExpand.kt
index f77a84d..4050767 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationRowExpand.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationRowExpand.kt
@@ -32,10 +32,11 @@
     override val assertionTemplates =
         AssertionTemplates.COMMON_ASSERTIONS // TODO: Add specific assertions
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_NOTIFICATION_SHADE_ROW_EXPAND)
             .setTransitionMatcher(TaggedCujTransitionMatcher(associatedTransitionRequired = false))
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationRowSwipe.kt b/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationRowSwipe.kt
index 0a7113a..b462bd0 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationRowSwipe.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationRowSwipe.kt
@@ -32,10 +32,11 @@
     override val assertionTemplates =
         AssertionTemplates.COMMON_ASSERTIONS // TODO: Add specific assertions
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_NOTIFICATION_SHADE_ROW_SWIPE)
             .setTransitionMatcher(TaggedCujTransitionMatcher(associatedTransitionRequired = false))
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationScrollFling.kt b/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationScrollFling.kt
index e885a34..5fb399d 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationScrollFling.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/notification/NotificationScrollFling.kt
@@ -32,10 +32,11 @@
     override val assertionTemplates =
         AssertionTemplates.COMMON_ASSERTIONS // TODO: Add specific assertions
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_NOTIFICATION_SHADE_SCROLL_FLING)
             .setTransitionMatcher(TaggedCujTransitionMatcher(associatedTransitionRequired = false))
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/others/OthersBiometricPromptTransition.kt b/libraries/flicker/src/android/tools/common/flicker/config/others/OthersBiometricPromptTransition.kt
index 02853f7..484667a 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/others/OthersBiometricPromptTransition.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/others/OthersBiometricPromptTransition.kt
@@ -32,10 +32,11 @@
     override val assertionTemplates =
         AssertionTemplates.COMMON_ASSERTIONS // TODO: Add specific assertions
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_BIOMETRIC_PROMPT_TRANSITION)
             .setTransitionMatcher(TaggedCujTransitionMatcher(associatedTransitionRequired = false))
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/others/OthersDefault.kt b/libraries/flicker/src/android/tools/common/flicker/config/others/OthersDefault.kt
index 8bf42ed..66782a3 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/others/OthersDefault.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/others/OthersDefault.kt
@@ -25,8 +25,9 @@
 class OthersDefault : ScenarioConfig {
     override val assertionTemplates = AssertionTemplates.ENTIRE_TRACE_ASSERTIONS
 
-    override val extractor =
+    override val extractor by lazy {
         EntireTraceExtractor(FlickerServiceConfig.getScenarioConfigFor(FaasScenarioType.COMMON))
+    }
 
     override val enabled = true
 
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/others/OthersOneHandedEnterTransition.kt b/libraries/flicker/src/android/tools/common/flicker/config/others/OthersOneHandedEnterTransition.kt
index 65802a6..f809c08 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/others/OthersOneHandedEnterTransition.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/others/OthersOneHandedEnterTransition.kt
@@ -32,10 +32,11 @@
     override val assertionTemplates =
         AssertionTemplates.COMMON_ASSERTIONS // TODO: Add specific assertions
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_ONE_HANDED_ENTER_TRANSITION)
             .setTransitionMatcher(TaggedCujTransitionMatcher(associatedTransitionRequired = false))
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/others/OthersOneHandedExitTransition.kt b/libraries/flicker/src/android/tools/common/flicker/config/others/OthersOneHandedExitTransition.kt
index aef96c1..2fa37d6 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/others/OthersOneHandedExitTransition.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/others/OthersOneHandedExitTransition.kt
@@ -32,10 +32,11 @@
     override val assertionTemplates =
         AssertionTemplates.COMMON_ASSERTIONS // TODO: Add specific assertions
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_ONE_HANDED_EXIT_TRANSITION)
             .setTransitionMatcher(TaggedCujTransitionMatcher(associatedTransitionRequired = false))
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/others/OthersScreenOff.kt b/libraries/flicker/src/android/tools/common/flicker/config/others/OthersScreenOff.kt
index db1e618..5ae20d2 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/others/OthersScreenOff.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/others/OthersScreenOff.kt
@@ -32,10 +32,11 @@
     override val assertionTemplates =
         AssertionTemplates.COMMON_ASSERTIONS // TODO: Add specific assertions
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_SCREEN_OFF)
             .setTransitionMatcher(TaggedCujTransitionMatcher(associatedTransitionRequired = false))
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/others/OthersScreenOffShowAod.kt b/libraries/flicker/src/android/tools/common/flicker/config/others/OthersScreenOffShowAod.kt
index ba4d02c..284f738 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/others/OthersScreenOffShowAod.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/others/OthersScreenOffShowAod.kt
@@ -32,10 +32,11 @@
     override val assertionTemplates =
         AssertionTemplates.COMMON_ASSERTIONS // TODO: Add specific assertions
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_SCREEN_OFF_SHOW_AOD)
             .setTransitionMatcher(TaggedCujTransitionMatcher(associatedTransitionRequired = false))
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/others/OthersTakeScreenshot.kt b/libraries/flicker/src/android/tools/common/flicker/config/others/OthersTakeScreenshot.kt
index 3a98fa1..7611420 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/others/OthersTakeScreenshot.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/others/OthersTakeScreenshot.kt
@@ -32,10 +32,11 @@
     override val assertionTemplates =
         AssertionTemplates.COMMON_ASSERTIONS // TODO: Add specific assertions
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_TAKE_SCREENSHOT)
             .setTransitionMatcher(TaggedCujTransitionMatcher(associatedTransitionRequired = false))
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/others/OthersUserDialogOpen.kt b/libraries/flicker/src/android/tools/common/flicker/config/others/OthersUserDialogOpen.kt
index 67b096c..b5e29ed 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/others/OthersUserDialogOpen.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/others/OthersUserDialogOpen.kt
@@ -32,10 +32,11 @@
     override val assertionTemplates =
         AssertionTemplates.COMMON_ASSERTIONS // TODO: Add specific assertions
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_USER_DIALOG_OPEN)
             .setTransitionMatcher(TaggedCujTransitionMatcher(associatedTransitionRequired = false))
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/others/OthersUserSwitch.kt b/libraries/flicker/src/android/tools/common/flicker/config/others/OthersUserSwitch.kt
index 1299c09..ae469b4 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/others/OthersUserSwitch.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/others/OthersUserSwitch.kt
@@ -32,10 +32,11 @@
     override val assertionTemplates =
         AssertionTemplates.COMMON_ASSERTIONS // TODO: Add specific assertions
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_USER_SWITCH)
             .setTransitionMatcher(TaggedCujTransitionMatcher(associatedTransitionRequired = false))
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/others/OthersVolumeControl.kt b/libraries/flicker/src/android/tools/common/flicker/config/others/OthersVolumeControl.kt
index 6977293..23dbbc0 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/others/OthersVolumeControl.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/others/OthersVolumeControl.kt
@@ -32,10 +32,11 @@
     override val assertionTemplates =
         AssertionTemplates.COMMON_ASSERTIONS // TODO: Add specific assertions
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_VOLUME_CONTROL)
             .setTransitionMatcher(TaggedCujTransitionMatcher(associatedTransitionRequired = false))
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/pip/AppCloseToPip.kt b/libraries/flicker/src/android/tools/common/flicker/config/pip/AppCloseToPip.kt
index 06e258f..eb112b7 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/pip/AppCloseToPip.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/pip/AppCloseToPip.kt
@@ -35,7 +35,7 @@
 
     override val assertionTemplates = AssertionTemplates.APP_CLOSE_TO_PIP_ASSERTIONS
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_LAUNCHER_APP_CLOSE_TO_PIP)
@@ -67,4 +67,5 @@
                 }
             )
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/pip/PipTransition.kt b/libraries/flicker/src/android/tools/common/flicker/config/pip/PipTransition.kt
index 293454e..1d0a416 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/pip/PipTransition.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/pip/PipTransition.kt
@@ -32,10 +32,11 @@
     override val assertionTemplates =
         AssertionTemplates.COMMON_ASSERTIONS // TODO: Add specific assertions
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_PIP_TRANSITION)
             .setTransitionMatcher(TaggedCujTransitionMatcher(associatedTransitionRequired = false))
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/settings/SettingsPageScroll.kt b/libraries/flicker/src/android/tools/common/flicker/config/settings/SettingsPageScroll.kt
index 00c7838..36896fc 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/settings/SettingsPageScroll.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/settings/SettingsPageScroll.kt
@@ -32,10 +32,11 @@
     override val assertionTemplates =
         AssertionTemplates.COMMON_ASSERTIONS // TODO: Add specific assertions
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_SETTINGS_PAGE_SCROLL)
             .setTransitionMatcher(TaggedCujTransitionMatcher(associatedTransitionRequired = false))
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/settings/SettingsSlider.kt b/libraries/flicker/src/android/tools/common/flicker/config/settings/SettingsSlider.kt
index d1a0da5..d854951 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/settings/SettingsSlider.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/settings/SettingsSlider.kt
@@ -32,10 +32,11 @@
     override val assertionTemplates =
         AssertionTemplates.COMMON_ASSERTIONS // TODO: Add specific assertions
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_SETTINGS_SLIDER)
             .setTransitionMatcher(TaggedCujTransitionMatcher(associatedTransitionRequired = false))
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/settings/SettingsToggle.kt b/libraries/flicker/src/android/tools/common/flicker/config/settings/SettingsToggle.kt
index b370e82..625992a 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/settings/SettingsToggle.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/settings/SettingsToggle.kt
@@ -32,10 +32,11 @@
     override val assertionTemplates =
         AssertionTemplates.COMMON_ASSERTIONS // TODO: Add specific assertions
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_SETTINGS_TOGGLE)
             .setTransitionMatcher(TaggedCujTransitionMatcher(associatedTransitionRequired = false))
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/splashscreen/SplashscreenAvd.kt b/libraries/flicker/src/android/tools/common/flicker/config/splashscreen/SplashscreenAvd.kt
index 889d6c9..4e0831c 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/splashscreen/SplashscreenAvd.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/splashscreen/SplashscreenAvd.kt
@@ -32,10 +32,11 @@
     override val assertionTemplates =
         AssertionTemplates.COMMON_ASSERTIONS // TODO: Add specific assertions
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_SPLASHSCREEN_AVD)
             .setTransitionMatcher(TaggedCujTransitionMatcher(associatedTransitionRequired = false))
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/splashscreen/SplashscreenExitAnimation.kt b/libraries/flicker/src/android/tools/common/flicker/config/splashscreen/SplashscreenExitAnimation.kt
index e05b200..8b89e60 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/splashscreen/SplashscreenExitAnimation.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/splashscreen/SplashscreenExitAnimation.kt
@@ -32,10 +32,11 @@
     override val assertionTemplates =
         AssertionTemplates.COMMON_ASSERTIONS // TODO: Add specific assertions
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_SPLASHSCREEN_EXIT_ANIM)
             .setTransitionMatcher(TaggedCujTransitionMatcher(associatedTransitionRequired = false))
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/splitscreen/SplitScreenEnter.kt b/libraries/flicker/src/android/tools/common/flicker/config/splitscreen/SplitScreenEnter.kt
index c3762d2..a96bde2 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/splitscreen/SplitScreenEnter.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/splitscreen/SplitScreenEnter.kt
@@ -30,9 +30,10 @@
 
     override val assertionTemplates = AssertionTemplates.ENTER_SPLITSCREEN_ASSERTIONS
 
-    override val extractor =
+    override val extractor by lazy {
         ShellTransitionScenarioExtractor(
             FlickerServiceConfig.getScenarioConfigFor(type),
             transitionMatcher = TransitionFilters.ENTER_SPLIT_SCREEN_MATCHER
         )
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/splitscreen/SplitScreenExit.kt b/libraries/flicker/src/android/tools/common/flicker/config/splitscreen/SplitScreenExit.kt
index 269e0ab..751238b 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/splitscreen/SplitScreenExit.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/splitscreen/SplitScreenExit.kt
@@ -32,7 +32,7 @@
 
     override val assertionTemplates = AssertionTemplates.EXIT_SPLITSCREEN_ASSERTIONS
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_SPLIT_SCREEN_EXIT)
@@ -40,4 +40,5 @@
                 TaggedCujTransitionMatcher(TransitionFilters.EXIT_SPLIT_SCREEN_FILTER)
             )
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/splitscreen/SplitScreenResize.kt b/libraries/flicker/src/android/tools/common/flicker/config/splitscreen/SplitScreenResize.kt
index 807a9df..84a89fe 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/splitscreen/SplitScreenResize.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/splitscreen/SplitScreenResize.kt
@@ -32,7 +32,7 @@
 
     override val assertionTemplates = AssertionTemplates.RESIZE_SPLITSCREEN_ASSERTIONS
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_SPLIT_SCREEN_RESIZE)
@@ -40,4 +40,5 @@
                 TaggedCujTransitionMatcher(TransitionFilters.RESIZE_SPLIT_SCREEN_FILTER)
             )
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/suw/SuwLoadingScreenForStatus.kt b/libraries/flicker/src/android/tools/common/flicker/config/suw/SuwLoadingScreenForStatus.kt
index 92ad439..6743026 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/suw/SuwLoadingScreenForStatus.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/suw/SuwLoadingScreenForStatus.kt
@@ -32,10 +32,11 @@
     override val assertionTemplates =
         AssertionTemplates.COMMON_ASSERTIONS // TODO: Add specific assertions
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_SUW_LOADING_SCREEN_FOR_STATUS)
             .setTransitionMatcher(TaggedCujTransitionMatcher(associatedTransitionRequired = false))
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/suw/SuwLoadingToNextFlow.kt b/libraries/flicker/src/android/tools/common/flicker/config/suw/SuwLoadingToNextFlow.kt
index ae8d731..0b044a5 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/suw/SuwLoadingToNextFlow.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/suw/SuwLoadingToNextFlow.kt
@@ -32,10 +32,11 @@
     override val assertionTemplates =
         AssertionTemplates.COMMON_ASSERTIONS // TODO: Add specific assertions
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_SUW_LOADING_TO_NEXT_FLOW)
             .setTransitionMatcher(TaggedCujTransitionMatcher(associatedTransitionRequired = false))
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/suw/SuwLoadingToShowInfoWithActions.kt b/libraries/flicker/src/android/tools/common/flicker/config/suw/SuwLoadingToShowInfoWithActions.kt
index de32ea0..d35852d 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/suw/SuwLoadingToShowInfoWithActions.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/suw/SuwLoadingToShowInfoWithActions.kt
@@ -32,10 +32,11 @@
     override val assertionTemplates =
         AssertionTemplates.COMMON_ASSERTIONS // TODO: Add specific assertions
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_SUW_LOADING_TO_SHOW_INFO_WITH_ACTIONS)
             .setTransitionMatcher(TaggedCujTransitionMatcher(associatedTransitionRequired = false))
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/suw/SuwShowFunctionScreenWithActions.kt b/libraries/flicker/src/android/tools/common/flicker/config/suw/SuwShowFunctionScreenWithActions.kt
index 33f43ac..d413741 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/suw/SuwShowFunctionScreenWithActions.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/suw/SuwShowFunctionScreenWithActions.kt
@@ -32,10 +32,11 @@
     override val assertionTemplates =
         AssertionTemplates.COMMON_ASSERTIONS // TODO: Add specific assertions
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_SUW_SHOW_FUNCTION_SCREEN_WITH_ACTIONS)
             .setTransitionMatcher(TaggedCujTransitionMatcher(associatedTransitionRequired = false))
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/taskbar/TaskbarCollapse.kt b/libraries/flicker/src/android/tools/common/flicker/config/taskbar/TaskbarCollapse.kt
index 1986183..b96504a 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/taskbar/TaskbarCollapse.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/taskbar/TaskbarCollapse.kt
@@ -32,10 +32,11 @@
     override val assertionTemplates =
         AssertionTemplates.COMMON_ASSERTIONS // TODO: Add specific assertions
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_TASKBAR_COLLAPSE)
             .setTransitionMatcher(TaggedCujTransitionMatcher(associatedTransitionRequired = false))
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/taskbar/TaskbarExpand.kt b/libraries/flicker/src/android/tools/common/flicker/config/taskbar/TaskbarExpand.kt
index ccd13b7..6a19c8b 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/taskbar/TaskbarExpand.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/taskbar/TaskbarExpand.kt
@@ -32,10 +32,11 @@
     override val assertionTemplates =
         AssertionTemplates.COMMON_ASSERTIONS // TODO: Add specific assertions
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_TASKBAR_EXPAND)
             .setTransitionMatcher(TaggedCujTransitionMatcher(associatedTransitionRequired = false))
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/config/wallpaper/WallpaperTransition.kt b/libraries/flicker/src/android/tools/common/flicker/config/wallpaper/WallpaperTransition.kt
index de6524b..991124f 100644
--- a/libraries/flicker/src/android/tools/common/flicker/config/wallpaper/WallpaperTransition.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/config/wallpaper/WallpaperTransition.kt
@@ -32,10 +32,11 @@
     override val assertionTemplates =
         AssertionTemplates.COMMON_ASSERTIONS // TODO: Add specific assertions
 
-    override val extractor =
+    override val extractor by lazy {
         TaggedScenarioExtractorBuilder()
             .setConfig(FlickerServiceConfig.getScenarioConfigFor(type))
             .setTargetTag(CujType.CUJ_WALLPAPER_TRANSITION)
             .setTransitionMatcher(TaggedCujTransitionMatcher(associatedTransitionRequired = false))
             .build()
+    }
 }
diff --git a/libraries/flicker/src/android/tools/common/flicker/extractors/CombinedScenarioExtractor.kt b/libraries/flicker/src/android/tools/common/flicker/extractors/CombinedScenarioExtractor.kt
index 706d6f1..f0fc679 100644
--- a/libraries/flicker/src/android/tools/common/flicker/extractors/CombinedScenarioExtractor.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/extractors/CombinedScenarioExtractor.kt
@@ -16,14 +16,14 @@
 
 package android.tools.common.flicker.extractors
 
-import android.tools.common.CrossPlatform
+import android.tools.common.Logger
 import android.tools.common.flicker.ScenarioInstance
 import android.tools.common.io.Reader
 
 class CombinedScenarioExtractor(private val extractors: List<ScenarioExtractor>) :
     ScenarioExtractor {
     override fun extract(reader: Reader): List<ScenarioInstance> {
-        return CrossPlatform.log.withTracing("CombinedScenarioExtractor#extract") {
+        return Logger.withTracing("CombinedScenarioExtractor#extract") {
             extractors.flatMap { it.extract(reader) }
         }
     }
diff --git a/libraries/flicker/src/android/tools/common/flicker/extractors/TaggedScenarioExtractor.kt b/libraries/flicker/src/android/tools/common/flicker/extractors/TaggedScenarioExtractor.kt
index bc2e68a..8b65cfd 100644
--- a/libraries/flicker/src/android/tools/common/flicker/extractors/TaggedScenarioExtractor.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/extractors/TaggedScenarioExtractor.kt
@@ -16,8 +16,8 @@
 
 package android.tools.common.flicker.extractors
 
-import android.tools.common.CrossPlatform
 import android.tools.common.Timestamp
+import android.tools.common.Timestamps
 import android.tools.common.flicker.ScenarioInstance
 import android.tools.common.flicker.ScenarioInstanceImpl
 import android.tools.common.flicker.config.ScenarioConfig
@@ -92,7 +92,7 @@
                 null
             }
 
-        return CrossPlatform.timestamp.from(
+        return Timestamps.from(
             elapsedNanos =
                 min(
                     cujEntry.startTimestamp.elapsedNanos,
@@ -124,7 +124,7 @@
                 null
             }
 
-        return CrossPlatform.timestamp.from(
+        return Timestamps.from(
             elapsedNanos =
                 max(
                     cujEntry.endTimestamp.elapsedNanos,
diff --git a/libraries/flicker/src/android/tools/common/flicker/extractors/Utils.kt b/libraries/flicker/src/android/tools/common/flicker/extractors/Utils.kt
index 87ea529..8da5a1d 100644
--- a/libraries/flicker/src/android/tools/common/flicker/extractors/Utils.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/extractors/Utils.kt
@@ -16,8 +16,8 @@
 
 package android.tools.common.flicker.extractors
 
-import android.tools.common.CrossPlatform
 import android.tools.common.Timestamp
+import android.tools.common.Timestamps
 import android.tools.common.io.Reader
 import android.tools.common.traces.surfaceflinger.Display
 import android.tools.common.traces.surfaceflinger.LayerTraceEntry
@@ -47,7 +47,7 @@
             startTransactionAppliedTimestamp?.systemUptimeNanos
                 ?: transition.createTime.systemUptimeNanos
 
-        return CrossPlatform.timestamp.from(elapsedNanos, systemUptimeNanos, unixNanos)
+        return Timestamps.from(elapsedNanos, systemUptimeNanos, unixNanos)
     }
 
     fun interpolateFinishTimestampFromTransition(
@@ -118,7 +118,7 @@
                 layersTrace.getEntryAt(finishTransactionAppliedTimestamp).timestamp.unixNanos
         }
 
-        return CrossPlatform.timestamp.from(elapsedNanos, systemUptimeNanos, unixNanos)
+        return Timestamps.from(elapsedNanos, systemUptimeNanos, unixNanos)
     }
 
     fun getOnDisplayFor(layerTraceEntry: LayerTraceEntry): Display {
diff --git a/libraries/flicker/src/android/tools/common/flicker/subject/FlickerTraceSubject.kt b/libraries/flicker/src/android/tools/common/flicker/subject/FlickerTraceSubject.kt
index f427d78..2da4268 100644
--- a/libraries/flicker/src/android/tools/common/flicker/subject/FlickerTraceSubject.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/subject/FlickerTraceSubject.kt
@@ -16,7 +16,7 @@
 
 package android.tools.common.flicker.subject
 
-import android.tools.common.CrossPlatform
+import android.tools.common.Timestamps
 import android.tools.common.flicker.assertions.AssertionsChecker
 import android.tools.common.flicker.subject.exceptions.ExceptionMessageBuilder
 import android.tools.common.flicker.subject.exceptions.SubjectAssertionError
@@ -24,7 +24,7 @@
 /** Base subject for flicker trace assertions */
 abstract class FlickerTraceSubject<EntrySubject : FlickerSubject> : FlickerSubject() {
     override val timestamp
-        get() = subjects.firstOrNull()?.timestamp ?: CrossPlatform.timestamp.empty()
+        get() = subjects.firstOrNull()?.timestamp ?: Timestamps.empty()
 
     protected val assertionsChecker = AssertionsChecker<EntrySubject>()
     private var newAssertionBlock = true
diff --git a/libraries/flicker/src/android/tools/common/flicker/subject/events/EventLogSubject.kt b/libraries/flicker/src/android/tools/common/flicker/subject/events/EventLogSubject.kt
index bc1e85e..ae9515b 100644
--- a/libraries/flicker/src/android/tools/common/flicker/subject/events/EventLogSubject.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/subject/events/EventLogSubject.kt
@@ -16,7 +16,7 @@
 
 package android.tools.common.flicker.subject.events
 
-import android.tools.common.CrossPlatform
+import android.tools.common.Timestamps
 import android.tools.common.flicker.subject.FlickerSubject
 import android.tools.common.flicker.subject.exceptions.ExceptionMessageBuilder
 import android.tools.common.flicker.subject.exceptions.IncorrectFocusException
@@ -26,7 +26,7 @@
 
 /** Truth subject for [FocusEvent] objects. */
 class EventLogSubject(val eventLog: EventLog, override val reader: Reader) : FlickerSubject() {
-    override val timestamp = CrossPlatform.timestamp.empty()
+    override val timestamp = Timestamps.empty()
 
     private val _focusChanges by lazy {
         val focusList = mutableListOf<String>()
diff --git a/libraries/flicker/src/android/tools/common/flicker/subject/exceptions/ExceptionMessageBuilder.kt b/libraries/flicker/src/android/tools/common/flicker/subject/exceptions/ExceptionMessageBuilder.kt
index 1c343a2..3a8254f 100644
--- a/libraries/flicker/src/android/tools/common/flicker/subject/exceptions/ExceptionMessageBuilder.kt
+++ b/libraries/flicker/src/android/tools/common/flicker/subject/exceptions/ExceptionMessageBuilder.kt
@@ -16,15 +16,15 @@
 
 package android.tools.common.flicker.subject.exceptions
 
-import android.tools.common.CrossPlatform
 import android.tools.common.Timestamp
+import android.tools.common.Timestamps
 import android.tools.common.flicker.assertions.Fact
 import android.tools.common.flicker.subject.FlickerSubject
 import android.tools.common.io.Reader
 
 /** Class to build flicker exception messages */
 class ExceptionMessageBuilder {
-    private var timestamp = CrossPlatform.timestamp.empty()
+    private var timestamp = Timestamps.empty()
     private var expected = ""
     private var actual = mutableListOf<String>()
     private var headerDescription = ""
diff --git a/libraries/flicker/src/android/tools/common/parsers/AbstractTraceParser.kt b/libraries/flicker/src/android/tools/common/parsers/AbstractTraceParser.kt
index 032c4d1..fcf0a02 100644
--- a/libraries/flicker/src/android/tools/common/parsers/AbstractTraceParser.kt
+++ b/libraries/flicker/src/android/tools/common/parsers/AbstractTraceParser.kt
@@ -17,8 +17,9 @@
 package android.tools.common.parsers
 
 import android.tools.common.Cache
-import android.tools.common.CrossPlatform
+import android.tools.common.Logger
 import android.tools.common.Timestamp
+import android.tools.common.Timestamps
 
 /** Base trace parser class */
 abstract class AbstractTraceParser<
@@ -35,8 +36,8 @@
     final override fun parse(bytes: ByteArray, clearCache: Boolean): OutputTypeTrace {
         return parse(
             bytes,
-            from = CrossPlatform.timestamp.min(),
-            to = CrossPlatform.timestamp.max(),
+            from = Timestamps.min(),
+            to = Timestamps.max(),
             addInitialEntry = true,
             clearCache = clearCache
         )
@@ -45,8 +46,8 @@
     final override fun parse(input: InputTypeTrace, clearCache: Boolean): OutputTypeTrace {
         return parse(
             input,
-            from = CrossPlatform.timestamp.min(),
-            to = CrossPlatform.timestamp.max(),
+            from = Timestamps.min(),
+            to = Timestamps.max(),
             addInitialEntry = true,
             clearCache = clearCache
         )
@@ -55,8 +56,8 @@
     final override fun doParse(input: InputTypeTrace): OutputTypeTrace {
         return doParse(
             input,
-            from = CrossPlatform.timestamp.min(),
-            to = CrossPlatform.timestamp.max(),
+            from = Timestamps.min(),
+            to = Timestamps.max(),
             addInitialEntry = true
         )
     }
@@ -86,8 +87,7 @@
             if (!selectedInputTimestamps.contains(currTimestamp) || !shouldParseEntry(rawEntry)) {
                 continue
             }
-            val parsedEntry =
-                CrossPlatform.log.withTracing("doParseEntry") { doParseEntry(rawEntry) }
+            val parsedEntry = Logger.withTracing("doParseEntry") { doParseEntry(rawEntry) }
             parsedEntries.add(parsedEntry)
         }
         return createTrace(parsedEntries)
@@ -109,7 +109,7 @@
         addInitialEntry: Boolean = true,
         clearCache: Boolean = true
     ): OutputTypeTrace {
-        return CrossPlatform.log.withTracing("${this::class.simpleName}#parse") {
+        return Logger.withTracing("${this::class.simpleName}#parse") {
             try {
                 doParse(input, from, to, addInitialEntry)
             } finally {
diff --git a/libraries/flicker/src/android/tools/common/parsers/events/EventLogParser.kt b/libraries/flicker/src/android/tools/common/parsers/events/EventLogParser.kt
index 710d03c..e8d4177 100644
--- a/libraries/flicker/src/android/tools/common/parsers/events/EventLogParser.kt
+++ b/libraries/flicker/src/android/tools/common/parsers/events/EventLogParser.kt
@@ -16,8 +16,8 @@
 
 package android.tools.common.parsers.events
 
-import android.tools.common.CrossPlatform
 import android.tools.common.Timestamp
+import android.tools.common.Timestamps
 import android.tools.common.parsers.AbstractParser
 import android.tools.common.traces.events.CujEvent
 import android.tools.common.traces.events.Event
@@ -50,8 +50,7 @@
                 val (rawTimestamp, uid, pid, tid, priority, tag) =
                     metaData.split(" ").filter { it.isNotEmpty() }
 
-                val timestamp =
-                    CrossPlatform.timestamp.from(unixNanos = rawTimestamp.replace(".", "").toLong())
+                val timestamp = Timestamps.from(unixNanos = rawTimestamp.replace(".", "").toLong())
                 parseEvent(timestamp, pid.toInt(), uid, tid.toInt(), tag, eventData)
             }
 
@@ -105,7 +104,7 @@
     private fun getTimestampFromRawEntry(entry: String): Timestamp {
         val (metaData, _) = entry.split(":", limit = 2).map { it.trim() }
         val (rawTimestamp, _, _, _, _, _) = metaData.split(" ").filter { it.isNotEmpty() }
-        return CrossPlatform.timestamp.from(unixNanos = rawTimestamp.replace(".", "").toLong())
+        return Timestamps.from(unixNanos = rawTimestamp.replace(".", "").toLong())
     }
 
     companion object {
diff --git a/libraries/flicker/src/android/tools/common/traces/events/CujEvent.kt b/libraries/flicker/src/android/tools/common/traces/events/CujEvent.kt
index 5c3d577..84a3ddb 100644
--- a/libraries/flicker/src/android/tools/common/traces/events/CujEvent.kt
+++ b/libraries/flicker/src/android/tools/common/traces/events/CujEvent.kt
@@ -16,8 +16,8 @@
 
 package android.tools.common.traces.events
 
-import android.tools.common.CrossPlatform
 import android.tools.common.Timestamp
+import android.tools.common.Timestamps
 import kotlin.js.JsExport
 import kotlin.js.JsName
 
@@ -60,7 +60,7 @@
             data: String
         ): CujEvent {
             return CujEvent(
-                CrossPlatform.timestamp.from(
+                Timestamps.from(
                     elapsedNanos = getElapsedTimestampFromData(data, eventTag.asCujType()),
                     systemUptimeNanos = getSystemUptimeNanosFromData(data, eventTag.asCujType()),
                     unixNanos = getUnixTimestampFromData(data, eventTag.asCujType())
diff --git a/libraries/flicker/src/android/tools/common/traces/events/CujTrace.kt b/libraries/flicker/src/android/tools/common/traces/events/CujTrace.kt
index e717cff..3b788bb 100644
--- a/libraries/flicker/src/android/tools/common/traces/events/CujTrace.kt
+++ b/libraries/flicker/src/android/tools/common/traces/events/CujTrace.kt
@@ -16,9 +16,9 @@
 
 package android.tools.common.traces.events
 
-import android.tools.common.CrossPlatform
 import android.tools.common.ITrace
 import android.tools.common.Timestamp
+import android.tools.common.Timestamps
 import kotlin.js.JsExport
 
 @JsExport
@@ -60,7 +60,7 @@
 
                 val closingEvent =
                     listOf(matchingCancelEvent, matchingEndEvent).minBy {
-                        it?.timestamp ?: CrossPlatform.timestamp.max()
+                        it?.timestamp ?: Timestamps.max()
                     }
                         ?: error("Should have found one matching closing event")
                 val canceled = closingEvent.type == CujEvent.Companion.Type.CANCEL
diff --git a/libraries/flicker/src/android/tools/common/traces/inputmethod/ImeClientEntry.kt b/libraries/flicker/src/android/tools/common/traces/inputmethod/ImeClientEntry.kt
index 720b47a..ab7f03e 100644
--- a/libraries/flicker/src/android/tools/common/traces/inputmethod/ImeClientEntry.kt
+++ b/libraries/flicker/src/android/tools/common/traces/inputmethod/ImeClientEntry.kt
@@ -15,8 +15,8 @@
  */
 package android.tools.common.traces.inputmethod
 
-import android.tools.common.CrossPlatform
 import android.tools.common.ITraceEntry
+import android.tools.common.Timestamps
 
 /**
  * Represents a single Ime Client trace entry.
@@ -38,7 +38,7 @@
     // val inputConnectionCall: InputConnectionCall,
     val elapsedTimestamp: Long
 ) : ITraceEntry {
-    override val timestamp = CrossPlatform.timestamp.from(systemUptimeNanos = elapsedTimestamp)
+    override val timestamp = Timestamps.from(systemUptimeNanos = elapsedTimestamp)
     val stableId: String
         get() = this::class.simpleName ?: error("Unable to determine class")
     val name: String
diff --git a/libraries/flicker/src/android/tools/common/traces/inputmethod/InputMethodManagerServiceEntry.kt b/libraries/flicker/src/android/tools/common/traces/inputmethod/InputMethodManagerServiceEntry.kt
index 9b5c46a..ccbb54d 100644
--- a/libraries/flicker/src/android/tools/common/traces/inputmethod/InputMethodManagerServiceEntry.kt
+++ b/libraries/flicker/src/android/tools/common/traces/inputmethod/InputMethodManagerServiceEntry.kt
@@ -16,8 +16,8 @@
 
 package android.tools.common.traces.inputmethod
 
-import android.tools.common.CrossPlatform
 import android.tools.common.ITraceEntry
+import android.tools.common.Timestamps
 
 /**
  * Represents a single InputMethodManagerService trace entry.
@@ -53,7 +53,7 @@
     val isAccessibilityRequestingNoSoftKeyboard: Boolean,
     val elapsedTimestamp: Long
 ) : ITraceEntry {
-    override val timestamp = CrossPlatform.timestamp.from(systemUptimeNanos = elapsedTimestamp)
+    override val timestamp = Timestamps.from(systemUptimeNanos = elapsedTimestamp)
     val stableId: String
         get() = this::class.simpleName ?: error("Unable to determine class")
     val name: String
diff --git a/libraries/flicker/src/android/tools/common/traces/inputmethod/InputMethodServiceEntry.kt b/libraries/flicker/src/android/tools/common/traces/inputmethod/InputMethodServiceEntry.kt
index e66402c..e1fbbcb 100644
--- a/libraries/flicker/src/android/tools/common/traces/inputmethod/InputMethodServiceEntry.kt
+++ b/libraries/flicker/src/android/tools/common/traces/inputmethod/InputMethodServiceEntry.kt
@@ -16,8 +16,8 @@
 
 package android.tools.common.traces.inputmethod
 
-import android.tools.common.CrossPlatform
 import android.tools.common.ITraceEntry
+import android.tools.common.Timestamps
 
 /**
  * Represents a single Ime InputMethodService trace entry.
@@ -55,7 +55,7 @@
     //    val inputConnectionCall: InputConnectionCallState,
     val elapsedTimestamp: Long
 ) : ITraceEntry {
-    override val timestamp = CrossPlatform.timestamp.from(systemUptimeNanos = elapsedTimestamp)
+    override val timestamp = Timestamps.from(systemUptimeNanos = elapsedTimestamp)
     val stableId: String
         get() = this::class.simpleName ?: error("Unable to determine class")
     val name: String
diff --git a/libraries/flicker/src/android/tools/common/traces/surfaceflinger/LayerTraceEntry.kt b/libraries/flicker/src/android/tools/common/traces/surfaceflinger/LayerTraceEntry.kt
index 646a369..1f23dc9 100644
--- a/libraries/flicker/src/android/tools/common/traces/surfaceflinger/LayerTraceEntry.kt
+++ b/libraries/flicker/src/android/tools/common/traces/surfaceflinger/LayerTraceEntry.kt
@@ -16,8 +16,8 @@
 
 package android.tools.common.traces.surfaceflinger
 
-import android.tools.common.CrossPlatform
 import android.tools.common.ITraceEntry
+import android.tools.common.Timestamps
 import android.tools.common.datatypes.Rect
 import android.tools.common.datatypes.RectF
 import android.tools.common.traces.component.ComponentNameMatcher
@@ -42,10 +42,7 @@
     _rootLayers: Array<Layer>
 ) : ITraceEntry {
     override val timestamp =
-        CrossPlatform.timestamp.from(
-            systemUptimeNanos = elapsedTimestamp,
-            unixNanos = clockTimestamp
-        )
+        Timestamps.from(systemUptimeNanos = elapsedTimestamp, unixNanos = clockTimestamp)
 
     @JsName("stableId")
     val stableId: String = this::class.simpleName ?: error("Unable to determine class")
diff --git a/libraries/flicker/src/android/tools/common/traces/wm/Transition.kt b/libraries/flicker/src/android/tools/common/traces/wm/Transition.kt
index 7089c7e..19eebe2 100644
--- a/libraries/flicker/src/android/tools/common/traces/wm/Transition.kt
+++ b/libraries/flicker/src/android/tools/common/traces/wm/Transition.kt
@@ -16,9 +16,9 @@
 
 package android.tools.common.traces.wm
 
-import android.tools.common.CrossPlatform
 import android.tools.common.ITraceEntry
 import android.tools.common.Timestamp
+import android.tools.common.Timestamps
 import android.tools.common.traces.surfaceflinger.LayersTrace
 import android.tools.common.traces.surfaceflinger.Transaction
 import android.tools.common.traces.surfaceflinger.TransactionsTrace
@@ -52,16 +52,13 @@
                 ?: shellData.mergeTime ?: shellData.abortTime ?: wmData.finishTime
                 ?: wmData.abortTime ?: error("Missing non-null timestamp")
 
-    @JsName("createTime")
-    val createTime: Timestamp = wmData.createTime ?: CrossPlatform.timestamp.min()
-    @JsName("sendTime") val sendTime: Timestamp = wmData.sendTime ?: CrossPlatform.timestamp.min()
+    @JsName("createTime") val createTime: Timestamp = wmData.createTime ?: Timestamps.min()
+    @JsName("sendTime") val sendTime: Timestamp = wmData.sendTime ?: Timestamps.min()
     @JsName("abortTime") val abortTime: Timestamp? = wmData.abortTime
     @JsName("finishTime")
-    val finishTime: Timestamp =
-        wmData.finishTime ?: wmData.abortTime ?: CrossPlatform.timestamp.max()
+    val finishTime: Timestamp = wmData.finishTime ?: wmData.abortTime ?: Timestamps.max()
 
-    @JsName("dispatchTime")
-    val dispatchTime: Timestamp = shellData.dispatchTime ?: CrossPlatform.timestamp.min()
+    @JsName("dispatchTime") val dispatchTime: Timestamp = shellData.dispatchTime ?: Timestamps.min()
     @JsName("mergeRequestTime") val mergeRequestTime: Timestamp? = shellData.mergeRequestTime
     @JsName("mergeTime") val mergeTime: Timestamp? = shellData.mergeTime
     @JsName("shellAbortTime") val shellAbortTime: Timestamp? = shellData.abortTime
diff --git a/libraries/flicker/src/android/tools/common/traces/wm/WindowManagerState.kt b/libraries/flicker/src/android/tools/common/traces/wm/WindowManagerState.kt
index da26219..9dddb5b 100644
--- a/libraries/flicker/src/android/tools/common/traces/wm/WindowManagerState.kt
+++ b/libraries/flicker/src/android/tools/common/traces/wm/WindowManagerState.kt
@@ -16,10 +16,10 @@
 
 package android.tools.common.traces.wm
 
-import android.tools.common.CrossPlatform
 import android.tools.common.ITraceEntry
 import android.tools.common.PlatformConsts
 import android.tools.common.Rotation
+import android.tools.common.Timestamps
 import android.tools.common.traces.component.IComponentMatcher
 import android.tools.common.traces.wm.Utils.collectDescendants
 import kotlin.js.JsExport
@@ -50,7 +50,7 @@
     val keyguardControllerState: KeyguardControllerState
 ) : ITraceEntry {
     override val timestamp =
-        CrossPlatform.timestamp.from(elapsedNanos = elapsedTimestamp, unixNanos = clockTimestamp)
+        Timestamps.from(elapsedNanos = elapsedTimestamp, unixNanos = clockTimestamp)
     @JsName("isVisible") val isVisible: Boolean = true
     @JsName("stableId")
     val stableId: String
diff --git a/libraries/flicker/src/android/tools/device/AndroidLogger.kt b/libraries/flicker/src/android/tools/device/AndroidLogger.kt
new file mode 100644
index 0000000..c7547aa
--- /dev/null
+++ b/libraries/flicker/src/android/tools/device/AndroidLogger.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.tools.device
+
+import android.os.Trace
+import android.tools.common.ILogger
+import android.util.Log
+
+class AndroidLogger : ILogger {
+    override fun v(tag: String, msg: String) {
+        Log.v(tag, msg)
+    }
+
+    override fun d(tag: String, msg: String) {
+        Log.d(tag, msg)
+    }
+
+    override fun i(tag: String, msg: String) {
+        Log.i(tag, msg)
+    }
+
+    override fun w(tag: String, msg: String) {
+        Log.w(tag, msg)
+    }
+
+    override fun e(tag: String, msg: String, error: Throwable?) {
+        Log.e(tag, msg, error)
+    }
+
+    override fun <T> withTracing(name: String, predicate: () -> T): T =
+        try {
+            Trace.beginSection(name)
+            predicate()
+        } finally {
+            Trace.endSection()
+        }
+}
diff --git a/libraries/flicker/src/android/tools/device/apphelpers/StandardAppHelper.kt b/libraries/flicker/src/android/tools/device/apphelpers/StandardAppHelper.kt
index 4883768..4205302 100644
--- a/libraries/flicker/src/android/tools/device/apphelpers/StandardAppHelper.kt
+++ b/libraries/flicker/src/android/tools/device/apphelpers/StandardAppHelper.kt
@@ -23,7 +23,7 @@
 import android.content.Intent
 import android.content.pm.PackageManager
 import android.platform.helpers.AbstractStandardAppHelper
-import android.tools.common.CrossPlatform
+import android.tools.common.Logger
 import android.tools.common.PlatformConsts
 import android.tools.common.traces.Condition
 import android.tools.common.traces.ConditionsFactory
@@ -107,7 +107,7 @@
 
     /** {@inheritDoc} */
     override fun exit() {
-        CrossPlatform.log.withTracing("exit") {
+        Logger.withTracing("exit") {
             // Ensure all testing components end up being closed.
             activityManager?.forceStopPackage(packageName)
         }
@@ -115,7 +115,7 @@
 
     /** Exits the activity and wait for activity destroyed */
     fun exit(wmHelper: WindowManagerStateHelper) {
-        CrossPlatform.log.withTracing("${this::class.simpleName}#exitAndWait") {
+        Logger.withTracing("${this::class.simpleName}#exitAndWait") {
             exit()
             waitForActivityDestroyed(wmHelper)
         }
@@ -140,7 +140,7 @@
         action: String? = null,
         stringExtras: Map<String, String> = mapOf()
     ) {
-        CrossPlatform.log.withTracing("${this::class.simpleName}#launchAppViaIntent") {
+        Logger.withTracing("${this::class.simpleName}#launchAppViaIntent") {
             val intent = openAppIntent
             intent.action = action ?: Intent.ACTION_MAIN
             stringExtras.forEach { intent.putExtra(it.key, it.value) }
@@ -207,7 +207,7 @@
         launchedAppComponentMatcherOverride: IComponentMatcher? = null,
         waitConditions: Array<Condition<DeviceStateDump>> = emptyArray()
     ) {
-        CrossPlatform.log.withTracing("${this::class.simpleName}#doWaitShown") {
+        Logger.withTracing("${this::class.simpleName}#doWaitShown") {
             val expectedWindow = launchedAppComponentMatcherOverride ?: componentMatcher
             val builder =
                 wmHelper
diff --git a/libraries/flicker/src/android/tools/device/flicker/FlickerServiceImpl.kt b/libraries/flicker/src/android/tools/device/flicker/FlickerServiceImpl.kt
deleted file mode 100644
index f2c8cc1..0000000
--- a/libraries/flicker/src/android/tools/device/flicker/FlickerServiceImpl.kt
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.tools.device.flicker
-
-import android.tools.common.CrossPlatform
-import android.tools.common.flicker.FlickerService
-import android.tools.common.flicker.ScenarioInstance
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.common.flicker.extractors.CombinedScenarioExtractor
-import android.tools.common.flicker.extractors.ScenarioExtractor
-import android.tools.common.io.Reader
-
-/** Contains the logic for Flicker as a Service. */
-class FlickerServiceImpl(
-    val scenarioExtractor: ScenarioExtractor =
-        CombinedScenarioExtractor(FlickerServiceConfig.getExtractors())
-) : FlickerService {
-    /*override fun process(reader: IReader): Collection<AssertionResult> {
-        return CrossPlatform.log.withTracing("FlickerService#process") {
-            try {
-                detectScenarios(reader)
-                    .flatMap { it.generateAssertions() }
-                    .map { it.execute() }
-            } catch (exception: Throwable) {
-                CrossPlatform.log.e("$FLICKER_TAG-ASSERT", "FAILED PROCESSING", exception)
-                throw exception
-            }
-        }
-    }*/
-
-    override fun detectScenarios(reader: Reader): Collection<ScenarioInstance> {
-        return CrossPlatform.log.withTracing("FlickerService#detectScenarios") {
-            scenarioExtractor.extract(reader)
-        }
-    }
-}
diff --git a/libraries/flicker/src/android/tools/device/flicker/FlickerServiceResultsCollector.kt b/libraries/flicker/src/android/tools/device/flicker/FlickerServiceResultsCollector.kt
index 0ed8634..978b5b2 100644
--- a/libraries/flicker/src/android/tools/device/flicker/FlickerServiceResultsCollector.kt
+++ b/libraries/flicker/src/android/tools/device/flicker/FlickerServiceResultsCollector.kt
@@ -19,13 +19,13 @@
 import android.app.Instrumentation
 import android.device.collectors.BaseMetricListener
 import android.device.collectors.DataRecord
-import android.tools.common.CrossPlatform
 import android.tools.common.FLICKER_TAG
+import android.tools.common.Logger
 import android.tools.common.ScenarioBuilder
 import android.tools.common.flicker.AssertionInvocationGroup
 import android.tools.common.flicker.FlickerService
 import android.tools.common.flicker.TracesCollector
-import android.tools.common.flicker.assertors.AssertionResult
+import android.tools.common.flicker.assertions.AssertionResult
 import android.tools.common.flicker.config.FaasScenarioType
 import android.tools.common.io.RunStatus
 import androidx.test.platform.app.InstrumentationRegistry
@@ -40,7 +40,7 @@
  */
 class FlickerServiceResultsCollector(
     private val tracesCollector: TracesCollector,
-    private val flickerService: FlickerService = FlickerServiceImpl(),
+    private val flickerService: FlickerService = FlickerService(),
     instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation(),
     private val collectMetricsPerTest: Boolean = true,
     private val reportOnlyForPassingTests: Boolean = true
@@ -66,10 +66,7 @@
         errorReportingBlock {
             tracesCollector.cleanup() // Cleanup any trace archives from previous runs
 
-            CrossPlatform.log.i(
-                LOG_TAG,
-                "onTestRunStart :: collectMetricsPerTest = $collectMetricsPerTest"
-            )
+            Logger.i(LOG_TAG, "onTestRunStart :: collectMetricsPerTest = $collectMetricsPerTest")
             if (!collectMetricsPerTest) {
                 hasFailedTest = false
                 val scenario =
@@ -84,10 +81,7 @@
 
     override fun onTestStart(testData: DataRecord, description: Description) {
         errorReportingBlock {
-            CrossPlatform.log.i(
-                LOG_TAG,
-                "onTestStart :: collectMetricsPerTest = $collectMetricsPerTest"
-            )
+            Logger.i(LOG_TAG, "onTestStart :: collectMetricsPerTest = $collectMetricsPerTest")
             if (collectMetricsPerTest) {
                 hasFailedTest = false
                 val scenario =
@@ -105,24 +99,21 @@
 
     override fun onTestFail(testData: DataRecord, description: Description, failure: Failure) {
         errorReportingBlock {
-            CrossPlatform.log.i(LOG_TAG, "onTestFail")
+            Logger.i(LOG_TAG, "onTestFail")
             hasFailedTest = true
         }
     }
 
     override fun testSkipped(description: Description) {
         errorReportingBlock {
-            CrossPlatform.log.i(LOG_TAG, "testSkipped")
+            Logger.i(LOG_TAG, "testSkipped")
             testSkipped = true
         }
     }
 
     override fun onTestEnd(testData: DataRecord, description: Description) {
         errorReportingBlock {
-            CrossPlatform.log.i(
-                LOG_TAG,
-                "onTestEnd :: collectMetricsPerTest = $collectMetricsPerTest"
-            )
+            Logger.i(LOG_TAG, "onTestEnd :: collectMetricsPerTest = $collectMetricsPerTest")
             if (collectMetricsPerTest && !testSkipped) {
                 stopTracingAndCollectFlickerMetrics(testData, description)
             }
@@ -131,10 +122,7 @@
 
     override fun onTestRunEnd(runData: DataRecord, result: Result) {
         errorReportingBlock {
-            CrossPlatform.log.i(
-                LOG_TAG,
-                "onTestRunEnd :: collectMetricsPerTest = $collectMetricsPerTest"
-            )
+            Logger.i(LOG_TAG, "onTestRunEnd :: collectMetricsPerTest = $collectMetricsPerTest")
             if (!collectMetricsPerTest) {
                 stopTracingAndCollectFlickerMetrics(runData)
             }
@@ -146,19 +134,19 @@
         description: Description? = null
     ) {
         errorReportingBlock {
-            CrossPlatform.log.i(LOG_TAG, "Stopping trace collection")
+            Logger.i(LOG_TAG, "Stopping trace collection")
             val reader = tracesCollector.stop()
-            CrossPlatform.log.i(LOG_TAG, "Stopped trace collection")
+            Logger.i(LOG_TAG, "Stopped trace collection")
             if (reportOnlyForPassingTests && hasFailedTest) {
                 return@errorReportingBlock
             }
 
             try {
-                CrossPlatform.log.i(LOG_TAG, "Processing traces")
+                Logger.i(LOG_TAG, "Processing traces")
                 val scenarios = flickerService.detectScenarios(reader)
                 val results = scenarios.flatMap { it.generateAssertions() }.map { it.execute() }
                 reader.artifact.updateStatus(RunStatus.RUN_EXECUTED)
-                CrossPlatform.log.i(LOG_TAG, "Got ${results.size} results")
+                Logger.i(LOG_TAG, "Got ${results.size} results")
                 assertionResults.addAll(results)
                 if (description != null) {
                     require(assertionResultsByTest[description] == null) {
@@ -176,19 +164,13 @@
                     reader.artifact.updateStatus(RunStatus.ASSERTION_SUCCESS)
                 }
 
-                CrossPlatform.log.v(
-                    LOG_TAG,
-                    "Adding metric $FLICKER_ASSERTIONS_COUNT_KEY = ${results.size}"
-                )
+                Logger.v(LOG_TAG, "Adding metric $FLICKER_ASSERTIONS_COUNT_KEY = ${results.size}")
                 dataRecord.addStringMetric(FLICKER_ASSERTIONS_COUNT_KEY, "${results.size}")
 
                 val aggregatedResults = processFlickerResults(results)
                 collectMetrics(dataRecord, aggregatedResults)
             } finally {
-                CrossPlatform.log.v(
-                    LOG_TAG,
-                    "Adding metric $WINSCOPE_FILE_PATH_KEY = ${reader.artifactPath}"
-                )
+                Logger.v(LOG_TAG, "Adding metric $WINSCOPE_FILE_PATH_KEY = ${reader.artifactPath}")
                 dataRecord.addStringMetric(WINSCOPE_FILE_PATH_KEY, reader.artifactPath)
             }
         }
@@ -218,7 +200,7 @@
             val (key, aggregatedResult) = it.next()
             aggregatedResult.results.forEachIndexed { index, result ->
                 val resultStatus = if (result.passed) 0 else 1
-                CrossPlatform.log.v(LOG_TAG, "Adding metric ${key}_$index = $resultStatus")
+                Logger.v(LOG_TAG, "Adding metric ${key}_$index = $resultStatus")
                 data.addStringMetric("${key}_$index", "$resultStatus")
             }
         }
@@ -228,7 +210,7 @@
         try {
             function()
         } catch (e: Throwable) {
-            CrossPlatform.log.e(FLICKER_TAG, "Error executing in FlickerServiceResultsCollector", e)
+            Logger.e(FLICKER_TAG, "Error executing in FlickerServiceResultsCollector", e)
             _executionErrors.add(e)
         }
     }
diff --git a/libraries/flicker/src/android/tools/device/flicker/FlickerServiceTracesCollector.kt b/libraries/flicker/src/android/tools/device/flicker/FlickerServiceTracesCollector.kt
index 5b4a5a7..4e6ecb9 100644
--- a/libraries/flicker/src/android/tools/device/flicker/FlickerServiceTracesCollector.kt
+++ b/libraries/flicker/src/android/tools/device/flicker/FlickerServiceTracesCollector.kt
@@ -16,8 +16,8 @@
 
 package android.tools.device.flicker
 
-import android.tools.common.CrossPlatform
 import android.tools.common.FLICKER_TAG
+import android.tools.common.Logger
 import android.tools.common.Scenario
 import android.tools.common.flicker.TracesCollector
 import android.tools.common.io.Reader
@@ -61,10 +61,10 @@
             val scenario = this.scenario
             require(scenario != null) { "Scenario not set - make sure trace was started properly" }
 
-            CrossPlatform.log.v(LOG_TAG, "Creating output directory for trace files")
+            Logger.v(LOG_TAG, "Creating output directory for trace files")
             outputDir.mkdirs()
 
-            CrossPlatform.log.v(LOG_TAG, "Stopping trace monitors")
+            Logger.v(LOG_TAG, "Stopping trace monitors")
             val writer = ResultWriter().forScenario(scenario).withOutputDir(outputDir)
             traceMonitors.forEach { it.stop(writer) }
             this.scenario = null
@@ -84,7 +84,7 @@
         try {
             return block()
         } catch (e: Throwable) {
-            CrossPlatform.log.e(LOG_TAG, msg, e)
+            Logger.e(LOG_TAG, msg, e)
             throw e
         }
     }
diff --git a/libraries/flicker/src/android/tools/device/flicker/IFlickerServiceResultsCollector.kt b/libraries/flicker/src/android/tools/device/flicker/IFlickerServiceResultsCollector.kt
index 8ca1968..9a1f269 100644
--- a/libraries/flicker/src/android/tools/device/flicker/IFlickerServiceResultsCollector.kt
+++ b/libraries/flicker/src/android/tools/device/flicker/IFlickerServiceResultsCollector.kt
@@ -16,7 +16,7 @@
 
 package android.tools.device.flicker
 
-import android.tools.common.flicker.assertors.AssertionResult
+import android.tools.common.flicker.assertions.AssertionResult
 import android.tools.common.flicker.config.FaasScenarioType
 import org.junit.runner.Description
 import org.junit.runner.notification.Failure
diff --git a/libraries/flicker/src/android/tools/device/flicker/junit/AbstractFlickerRunnerDecorator.kt b/libraries/flicker/src/android/tools/device/flicker/junit/AbstractFlickerRunnerDecorator.kt
index f18077a..843df56 100644
--- a/libraries/flicker/src/android/tools/device/flicker/junit/AbstractFlickerRunnerDecorator.kt
+++ b/libraries/flicker/src/android/tools/device/flicker/junit/AbstractFlickerRunnerDecorator.kt
@@ -17,10 +17,10 @@
 package android.tools.device.flicker.junit
 
 import android.app.Instrumentation
-import android.tools.common.CrossPlatform
 import android.tools.common.FLICKER_TAG
+import android.tools.common.Logger
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
 import androidx.test.platform.app.InstrumentationRegistry
 import java.lang.reflect.Modifier
 import org.junit.runners.model.FrameworkMethod
@@ -115,7 +115,7 @@
                 ?: error("Provider method not found")
 
     private fun getFlickerBuilder(test: Any): FlickerBuilder {
-        CrossPlatform.log.v(FLICKER_TAG, "Obtaining flicker builder for $testClass")
+        Logger.v(FLICKER_TAG, "Obtaining flicker builder for $testClass")
         return providerMethod.invokeExplosively(test) as FlickerBuilder
     }
 
diff --git a/libraries/flicker/src/android/tools/device/flicker/junit/FlickerParametersRunnerFactory.kt b/libraries/flicker/src/android/tools/device/flicker/junit/FlickerParametersRunnerFactory.kt
index 8753c5c..e55f415 100644
--- a/libraries/flicker/src/android/tools/device/flicker/junit/FlickerParametersRunnerFactory.kt
+++ b/libraries/flicker/src/android/tools/device/flicker/junit/FlickerParametersRunnerFactory.kt
@@ -18,8 +18,9 @@
 
 import android.tools.common.CrossPlatform
 import android.tools.common.TimestampFactory
+import android.tools.common.flicker.assertions.FlickerTest
+import android.tools.device.AndroidLogger
 import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.traces.ANDROID_LOGGER
 import android.tools.device.traces.formatRealTimestamp
 import org.junit.runner.Runner
 import org.junit.runners.parameterized.ParametersRunnerFactory
@@ -31,7 +32,7 @@
  */
 class FlickerParametersRunnerFactory : ParametersRunnerFactory {
     init {
-        CrossPlatform.setLogger(ANDROID_LOGGER)
+        CrossPlatform.setLogger(AndroidLogger())
             .setTimestampFactory(TimestampFactory { formatRealTimestamp(it) })
     }
 
@@ -40,7 +41,7 @@
         val flickerTest =
             test.parameters.filterIsInstance<LegacyFlickerTest>().firstOrNull()
                 ?: error(
-                    "Unable to extract ${LegacyFlickerTest::class.simpleName} " +
+                    "Unable to extract ${FlickerTest::class.simpleName} " +
                         "for class $simpleClassName"
                 )
         val scenario = flickerTest.initialize(simpleClassName)
diff --git a/libraries/flicker/src/android/tools/device/flicker/junit/FlickerServiceCachedTestCase.kt b/libraries/flicker/src/android/tools/device/flicker/junit/FlickerServiceCachedTestCase.kt
index 04ecf5a..0b37127 100644
--- a/libraries/flicker/src/android/tools/device/flicker/junit/FlickerServiceCachedTestCase.kt
+++ b/libraries/flicker/src/android/tools/device/flicker/junit/FlickerServiceCachedTestCase.kt
@@ -21,7 +21,6 @@
 import android.os.Bundle
 import android.tools.common.Cache
 import android.tools.common.flicker.AssertionInvocationGroup
-import android.tools.common.flicker.FlickerService
 import android.tools.common.flicker.assertions.ScenarioAssertion
 import android.tools.device.flicker.FlickerServiceResultsCollector.Companion.getKeyForAssertionResult
 import java.lang.reflect.Method
@@ -30,7 +29,6 @@
 
 class FlickerServiceCachedTestCase(
     private val assertion: ScenarioAssertion,
-    private val flickerService: FlickerService,
     method: Method,
     private val onlyBlocking: Boolean,
     private val isLast: Boolean,
diff --git a/libraries/flicker/src/android/tools/device/flicker/junit/FlickerServiceDecorator.kt b/libraries/flicker/src/android/tools/device/flicker/junit/FlickerServiceDecorator.kt
index 1c3e02b..f0c654b 100644
--- a/libraries/flicker/src/android/tools/device/flicker/junit/FlickerServiceDecorator.kt
+++ b/libraries/flicker/src/android/tools/device/flicker/junit/FlickerServiceDecorator.kt
@@ -27,7 +27,6 @@
 import android.tools.common.flicker.assertions.ScenarioAssertion
 import android.tools.common.flicker.config.FaasScenarioType
 import android.tools.common.io.Reader
-import android.tools.device.flicker.FlickerServiceImpl
 import android.tools.device.flicker.FlickerServiceResultsCollector.Companion.FLICKER_ASSERTIONS_COUNT_KEY
 import android.tools.device.flicker.Utils.captureTrace
 import android.tools.device.flicker.annotation.ExpectedScenarios
@@ -49,7 +48,7 @@
     val paramString: String?,
     inner: IFlickerJUnitDecorator
 ) : AbstractFlickerRunnerDecorator(testClass, inner) {
-    private val flickerService = FlickerServiceImpl()
+    private val flickerService = FlickerService()
 
     private val scenario =
         ScenarioBuilder().forClass("${testClass.name}${paramString ?: ""}").build()
@@ -62,15 +61,15 @@
         }
     }
 
-    private val flickerServiceMethodsFor = mutableMapOf<FrameworkMethod, Collection<InjectedTestCase>>()
+    private val flickerServiceMethodsFor =
+        mutableMapOf<FrameworkMethod, Collection<InjectedTestCase>>()
     private val innerMethodsResults = mutableMapOf<FrameworkMethod, Throwable?>()
 
     override fun getTestMethods(test: Any): List<FrameworkMethod> {
-        val testMethods = mutableListOf<FrameworkMethod>()
         val innerMethods =
             inner?.getTestMethods(test)
                 ?: error("FlickerServiceDecorator requires a non-null inner decorator")
-        testMethods.addAll(innerMethods)
+        val testMethods = innerMethods.toMutableList()
 
         if (shouldComputeTestMethods()) {
             for (method in innerMethods) {
@@ -219,9 +218,7 @@
         ): Map<ScenarioInstance, Collection<ScenarioAssertion>> {
             if (!DataStore.containsFlickerServiceResult(testScenario)) {
                 val detectedScenarios = flickerService.detectScenarios(reader)
-                val groupedAssertions =
-                    mutableMapOf<ScenarioInstance, Collection<ScenarioAssertion>>()
-                detectedScenarios.forEach { groupedAssertions[it] = it.generateAssertions() }
+                val groupedAssertions = detectedScenarios.associateWith { it.generateAssertions() }
                 DataStore.addFlickerServiceAssertions(testScenario, groupedAssertions)
             }
 
@@ -238,9 +235,7 @@
             caller: IFlickerJUnitDecorator,
         ): Collection<InjectedTestCase> {
             val groupedAssertions = getGroupedAssertions(testScenario, reader, flickerService)
-
-            val organizedScenarioInstances: Map<FaasScenarioType, List<ScenarioInstance>> =
-                groupedAssertions.keys.groupBy { it.type }
+            val organizedScenarioInstances = groupedAssertions.keys.groupBy { it.type }
 
             val faasTestCases = mutableListOf<FlickerServiceCachedTestCase>()
             organizedScenarioInstances.values.forEachIndexed {
@@ -254,7 +249,6 @@
                         faasTestCases.add(
                             FlickerServiceCachedTestCase(
                                 assertion = it,
-                                flickerService = flickerService,
                                 method = getCachedResultMethod(),
                                 onlyBlocking = false,
                                 isLast =
diff --git a/libraries/flicker/src/android/tools/device/flicker/junit/InjectedTestCase.kt b/libraries/flicker/src/android/tools/device/flicker/junit/InjectedTestCase.kt
index 4cd1ff6..8005b70 100644
--- a/libraries/flicker/src/android/tools/device/flicker/junit/InjectedTestCase.kt
+++ b/libraries/flicker/src/android/tools/device/flicker/junit/InjectedTestCase.kt
@@ -32,4 +32,17 @@
     override fun getName(): String = _name
 
     abstract fun execute(description: Description)
+
+    override fun toString() = _name
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other !is InjectedTestCase) return false
+        if (!super.equals(other)) return false
+
+        if (_name != other._name) return false
+
+        return true
+    }
+
+    override fun hashCode() = _name.hashCode()
 }
diff --git a/libraries/flicker/src/android/tools/device/flicker/junit/LegacyFlickerJUnit4ClassRunner.kt b/libraries/flicker/src/android/tools/device/flicker/junit/LegacyFlickerJUnit4ClassRunner.kt
index 4b958b1..5105143 100644
--- a/libraries/flicker/src/android/tools/device/flicker/junit/LegacyFlickerJUnit4ClassRunner.kt
+++ b/libraries/flicker/src/android/tools/device/flicker/junit/LegacyFlickerJUnit4ClassRunner.kt
@@ -19,8 +19,8 @@
 import android.app.Instrumentation
 import android.os.Bundle
 import android.platform.test.util.TestFilter
-import android.tools.common.CrossPlatform
 import android.tools.common.FLICKER_TAG
+import android.tools.common.Logger
 import android.tools.common.Scenario
 import android.tools.device.flicker.legacy.FlickerBuilder
 import android.tools.device.flicker.legacy.runner.TransitionRunner
@@ -82,13 +82,13 @@
                 InstrumentationRegistry.getInstrumentation()
 
             override fun runTransition(scenario: Scenario, test: Any, description: Description?) {
-                CrossPlatform.log.withTracing("LegacyFlickerJUnit4ClassRunner#runTransition") {
-                    CrossPlatform.log.v(FLICKER_TAG, "Creating flicker object for $scenario")
+                Logger.withTracing("LegacyFlickerJUnit4ClassRunner#runTransition") {
+                    Logger.v(FLICKER_TAG, "Creating flicker object for $scenario")
                     val builder = getFlickerBuilder(test)
-                    CrossPlatform.log.v(FLICKER_TAG, "Creating flicker object for $scenario")
+                    Logger.v(FLICKER_TAG, "Creating flicker object for $scenario")
                     val flicker = builder.build()
                     val runner = TransitionRunner(scenario, instrumentation)
-                    CrossPlatform.log.v(FLICKER_TAG, "Running transition for $scenario")
+                    Logger.v(FLICKER_TAG, "Running transition for $scenario")
                     runner.execute(flicker, description)
                 }
             }
@@ -99,7 +99,7 @@
                         ?: error("Provider method not found")
 
             private fun getFlickerBuilder(test: Any): FlickerBuilder {
-                CrossPlatform.log.v(FLICKER_TAG, "Obtaining flicker builder for $testClass")
+                Logger.v(FLICKER_TAG, "Obtaining flicker builder for $testClass")
                 return providerMethod.invokeExplosively(test) as FlickerBuilder
             }
         }
diff --git a/libraries/flicker/src/android/tools/device/flicker/junit/LegacyFlickerServiceDecorator.kt b/libraries/flicker/src/android/tools/device/flicker/junit/LegacyFlickerServiceDecorator.kt
index ccf9e78..ba536be 100644
--- a/libraries/flicker/src/android/tools/device/flicker/junit/LegacyFlickerServiceDecorator.kt
+++ b/libraries/flicker/src/android/tools/device/flicker/junit/LegacyFlickerServiceDecorator.kt
@@ -17,10 +17,10 @@
 package android.tools.device.flicker.junit
 
 import android.os.Bundle
-import android.tools.common.CrossPlatform
 import android.tools.common.FLICKER_TAG
+import android.tools.common.Logger
 import android.tools.common.Scenario
-import android.tools.device.flicker.FlickerServiceImpl
+import android.tools.common.flicker.FlickerService
 import android.tools.device.flicker.FlickerServiceResultsCollector.Companion.FAAS_METRICS_PREFIX
 import android.tools.device.flicker.IS_FAAS_ENABLED
 import android.tools.device.flicker.annotation.FlickerServiceCompatible
@@ -37,11 +37,11 @@
 class LegacyFlickerServiceDecorator(
     testClass: TestClass,
     val scenario: Scenario?,
-    val transitionRunner: ITransitionRunner,
+    private val transitionRunner: ITransitionRunner,
     inner: IFlickerJUnitDecorator?
 ) : AbstractFlickerRunnerDecorator(testClass, inner) {
     private val arguments: Bundle = InstrumentationRegistry.getArguments()
-    private val flickerService = FlickerServiceImpl()
+    private val flickerService = FlickerService()
 
     private val onlyBlocking
         get() =
@@ -68,12 +68,12 @@
     override fun getTestMethods(test: Any): List<FrameworkMethod> {
         val result = inner?.getTestMethods(test)?.toMutableList() ?: mutableListOf()
         if (shouldComputeTestMethods()) {
-            CrossPlatform.log.withTracing(
+            Logger.withTracing(
                 "$FAAS_METRICS_PREFIX getTestMethods ${testClass.javaClass.simpleName}"
             ) {
                 requireNotNull(scenario) { "Expected to have a scenario to run" }
                 result.addAll(computeFlickerServiceTests(test, scenario))
-                CrossPlatform.log.d(FLICKER_TAG, "Computed ${result.size} flicker tests")
+                Logger.d(FLICKER_TAG, "Computed ${result.size} flicker tests")
             }
         }
         return result
@@ -133,7 +133,7 @@
         for (testFilter in testFilters.split(",")) {
             val filterComponents = testFilter.split("#")
             if (filterComponents.size != 2) {
-                CrossPlatform.log.e(
+                Logger.e(
                     LOG_TAG,
                     "Invalid filter-tests instrumentation argument supplied, $testFilter."
                 )
@@ -154,7 +154,7 @@
     private fun computeFlickerServiceTests(
         test: Any,
         testScenario: Scenario
-    ): List<InjectedTestCase> {
+    ): Collection<InjectedTestCase> {
         if (!DataStore.containsResult(testScenario)) {
             val description =
                 Description.createTestDescription(
diff --git a/libraries/flicker/src/android/tools/device/flicker/junit/LegacyFlickerTraceCollector.kt b/libraries/flicker/src/android/tools/device/flicker/junit/LegacyFlickerTraceCollector.kt
index f01bfee..1c7a490 100644
--- a/libraries/flicker/src/android/tools/device/flicker/junit/LegacyFlickerTraceCollector.kt
+++ b/libraries/flicker/src/android/tools/device/flicker/junit/LegacyFlickerTraceCollector.kt
@@ -16,7 +16,7 @@
 
 package android.tools.device.flicker.junit
 
-import android.tools.common.CrossPlatform
+import android.tools.common.Logger
 import android.tools.common.Scenario
 import android.tools.common.flicker.TracesCollector
 import android.tools.common.io.Reader
@@ -25,15 +25,15 @@
 
 class LegacyFlickerTraceCollector(private val scenario: Scenario) : TracesCollector {
     override fun start(scenario: Scenario) {
-        CrossPlatform.log.d("FAAS", "LegacyFlickerTraceCollector#start")
+        Logger.d("FAAS", "LegacyFlickerTraceCollector#start")
     }
 
     override fun stop(): Reader {
-        CrossPlatform.log.d("FAAS", "LegacyFlickerTraceCollector#stop")
+        Logger.d("FAAS", "LegacyFlickerTraceCollector#stop")
         return CachedResultReader(scenario, TRACE_CONFIG_REQUIRE_CHANGES)
     }
 
     override fun cleanup() {
-        CrossPlatform.log.d("FAAS", "LegacyFlickerTraceCollector#cleanup")
+        Logger.d("FAAS", "LegacyFlickerTraceCollector#cleanup")
     }
 }
diff --git a/libraries/flicker/src/android/tools/device/flicker/legacy/LegacyFlickerTest.kt b/libraries/flicker/src/android/tools/device/flicker/legacy/LegacyFlickerTest.kt
index 59fbb06..6ee21be 100644
--- a/libraries/flicker/src/android/tools/device/flicker/legacy/LegacyFlickerTest.kt
+++ b/libraries/flicker/src/android/tools/device/flicker/legacy/LegacyFlickerTest.kt
@@ -16,22 +16,14 @@
 
 package android.tools.device.flicker.legacy
 
-import android.tools.common.CrossPlatform
 import android.tools.common.Scenario
 import android.tools.common.ScenarioBuilder
 import android.tools.common.ScenarioImpl
 import android.tools.common.flicker.assertions.AssertionData
-import android.tools.common.flicker.assertions.AssertionFactory
+import android.tools.common.flicker.assertions.AssertionRunner
+import android.tools.common.flicker.assertions.BaseFlickerTest
 import android.tools.common.flicker.assertions.SubjectsParser
-import android.tools.common.flicker.subject.events.EventLogSubject
-import android.tools.common.flicker.subject.layers.LayerTraceEntrySubject
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
-import android.tools.common.flicker.subject.region.RegionTraceSubject
-import android.tools.common.flicker.subject.wm.WindowManagerStateSubject
-import android.tools.common.flicker.subject.wm.WindowManagerTraceSubject
 import android.tools.common.io.Reader
-import android.tools.common.traces.component.IComponentMatcher
-import android.tools.device.flicker.assertions.BaseAssertionRunner
 import android.tools.device.flicker.datastore.CachedAssertionRunner
 import android.tools.device.flicker.datastore.CachedResultReader
 import android.tools.device.traces.TRACE_CONFIG_REQUIRE_CHANGES
@@ -43,13 +35,11 @@
         CachedResultReader(it, TRACE_CONFIG_REQUIRE_CHANGES)
     },
     private val subjectsParserProvider: (Reader) -> SubjectsParser = { SubjectsParser(it) },
-    private val runnerProvider: (Scenario) -> BaseAssertionRunner = {
+    private val runnerProvider: (Scenario) -> AssertionRunner = {
         val reader = resultReaderProvider(it)
         CachedAssertionRunner(it, reader)
     }
-) : FlickerTest {
-    private val assertionFactory = AssertionFactory()
-
+) : BaseFlickerTest(defaultAssertionName = "") {
     var scenario: ScenarioImpl = ScenarioBuilder().createEmptyScenario() as ScenarioImpl
         private set
 
@@ -64,133 +54,7 @@
     val reader: Reader
         get() = resultReaderProvider(scenario)
 
-    /**
-     * Execute [assertion] on the initial state of a WM trace (before transition)
-     *
-     * @param assertion Assertion predicate
-     */
-    override fun assertWmStart(assertion: WindowManagerStateSubject.() -> Unit) {
-        CrossPlatform.log.withTracing("assertWmStart") {
-            val assertionData = assertionFactory.createWmStartAssertion(assertion)
-            doRunAssertion(assertionData)
-        }
-    }
-
-    /**
-     * Execute [assertion] on the final state of a WM trace (after transition)
-     *
-     * @param assertion Assertion predicate
-     */
-    override fun assertWmEnd(assertion: WindowManagerStateSubject.() -> Unit) {
-        CrossPlatform.log.withTracing("assertWmEnd") {
-            val assertionData = assertionFactory.createWmEndAssertion(assertion)
-            doRunAssertion(assertionData)
-        }
-    }
-
-    /**
-     * Execute [assertion] on a WM trace
-     *
-     * @param assertion Assertion predicate
-     */
-    override fun assertWm(assertion: WindowManagerTraceSubject.() -> Unit) {
-        CrossPlatform.log.withTracing("assertWm") {
-            val assertionData = assertionFactory.createWmAssertion(assertion)
-            doRunAssertion(assertionData)
-        }
-    }
-
-    /**
-     * Execute [assertion] on a user defined moment ([tag]) of a WM trace
-     *
-     * @param assertion Assertion predicate
-     */
-    override fun assertWmTag(tag: String, assertion: WindowManagerStateSubject.() -> Unit) {
-        CrossPlatform.log.withTracing("assertWmTag") {
-            val assertionData = assertionFactory.createWmTagAssertion(tag, assertion)
-            doRunAssertion(assertionData)
-        }
-    }
-
-    /**
-     * Execute [assertion] on the visible region of WM state matching [componentMatcher]
-     *
-     * @param componentMatcher Components to search
-     * @param assertion Assertion predicate
-     */
-    override fun assertWmVisibleRegion(
-        componentMatcher: IComponentMatcher,
-        assertion: RegionTraceSubject.() -> Unit
-    ) {
-        CrossPlatform.log.withTracing("assertWmVisibleRegion") {
-            val assertionData =
-                assertionFactory.createWmVisibleRegionAssertion(componentMatcher, assertion)
-            doRunAssertion(assertionData)
-        }
-    }
-
-    /**
-     * Execute [assertion] on the initial state of a SF trace (before transition)
-     *
-     * @param assertion Assertion predicate
-     */
-    override fun assertLayersStart(assertion: LayerTraceEntrySubject.() -> Unit) {
-        CrossPlatform.log.withTracing("assertLayersStart") {
-            val assertionData = assertionFactory.createLayersStartAssertion(assertion)
-            doRunAssertion(assertionData)
-        }
-    }
-
-    /**
-     * Execute [assertion] on the final state of a SF trace (after transition)
-     *
-     * @param assertion Assertion predicate
-     */
-    override fun assertLayersEnd(assertion: LayerTraceEntrySubject.() -> Unit) {
-        CrossPlatform.log.withTracing("assertLayersEnd") {
-            val assertionData = assertionFactory.createLayersEndAssertion(assertion)
-            doRunAssertion(assertionData)
-        }
-    }
-
-    override fun assertLayers(assertion: LayersTraceSubject.() -> Unit) {
-        CrossPlatform.log.withTracing("assertLayers") {
-            val assertionData = assertionFactory.createLayersAssertion(assertion)
-            doRunAssertion(assertionData)
-        }
-    }
-
-    override fun assertLayersTag(tag: String, assertion: LayerTraceEntrySubject.() -> Unit) {
-        CrossPlatform.log.withTracing("assertLayersTag") {
-            val assertionData = assertionFactory.createLayersTagAssertion(tag, assertion)
-            doRunAssertion(assertionData)
-        }
-    }
-
-    override fun assertLayersVisibleRegion(
-        componentMatcher: IComponentMatcher,
-        useCompositionEngineRegionOnly: Boolean,
-        assertion: RegionTraceSubject.() -> Unit
-    ) {
-        CrossPlatform.log.withTracing("assertLayersVisibleRegion") {
-            val assertionData =
-                assertionFactory.createLayersVisibleRegionAssertion(
-                    componentMatcher,
-                    useCompositionEngineRegionOnly,
-                    assertion
-                )
-            doRunAssertion(assertionData)
-        }
-    }
-
-    override fun assertEventLog(assertion: EventLogSubject.() -> Unit) {
-        CrossPlatform.log.withTracing("assertEventLog") {
-            val assertionData = assertionFactory.createEventLogAssertion(assertion)
-            doRunAssertion(assertionData)
-        }
-    }
-
-    private fun doRunAssertion(assertion: AssertionData) {
+    override fun doProcess(assertion: AssertionData) {
         require(!scenario.isEmpty) { "Scenario shouldn't be empty" }
         runnerProvider.invoke(scenario).runAssertion(assertion)?.let { throw it }
     }
diff --git a/libraries/flicker/src/android/tools/device/flicker/legacy/FlickerTestFactory.kt b/libraries/flicker/src/android/tools/device/flicker/legacy/LegacyFlickerTestFactory.kt
similarity index 96%
rename from libraries/flicker/src/android/tools/device/flicker/legacy/FlickerTestFactory.kt
rename to libraries/flicker/src/android/tools/device/flicker/legacy/LegacyFlickerTestFactory.kt
index af1a886..8fd4fed 100644
--- a/libraries/flicker/src/android/tools/device/flicker/legacy/FlickerTestFactory.kt
+++ b/libraries/flicker/src/android/tools/device/flicker/legacy/LegacyFlickerTestFactory.kt
@@ -19,13 +19,14 @@
 import android.tools.common.NavBar
 import android.tools.common.Rotation
 import android.tools.common.ScenarioBuilder
+import android.tools.common.flicker.assertions.FlickerTest
 
 /**
  * Factory for creating JUnit4 compatible tests based on the flicker DSL
  *
  * This class recreates behavior from JUnit5 TestFactory that is not available on JUnit4
  */
-object FlickerTestFactory {
+object LegacyFlickerTestFactory {
     /**
      * Gets a list of test configurations.
      *
diff --git a/libraries/flicker/src/android/tools/device/flicker/legacy/runner/SetupTeardownRule.kt b/libraries/flicker/src/android/tools/device/flicker/legacy/runner/SetupTeardownRule.kt
index 48d13a8..769c6ff 100644
--- a/libraries/flicker/src/android/tools/device/flicker/legacy/runner/SetupTeardownRule.kt
+++ b/libraries/flicker/src/android/tools/device/flicker/legacy/runner/SetupTeardownRule.kt
@@ -18,7 +18,7 @@
 
 import android.app.Instrumentation
 import android.platform.test.rule.ArtifactSaver
-import android.tools.common.CrossPlatform
+import android.tools.common.Logger
 import android.tools.common.Scenario
 import android.tools.device.flicker.legacy.FlickerTestData
 import android.tools.device.traces.io.ResultWriter
@@ -61,7 +61,7 @@
     }
 
     private fun doRunTransitionSetup(description: Description?) {
-        CrossPlatform.log.withTracing("doRunTransitionSetup") {
+        Logger.withTracing("doRunTransitionSetup") {
             Utils.notifyRunnerProgress(scenario, "Running transition setup for $description")
             try {
                 setupCommands.forEach { it.invoke(flicker) }
@@ -74,7 +74,7 @@
     }
 
     private fun doRunTransitionTeardown(description: Description?) {
-        CrossPlatform.log.withTracing("doRunTransitionTeardown") {
+        Logger.withTracing("doRunTransitionTeardown") {
             Utils.notifyRunnerProgress(scenario, "Running transition teardown for $description")
             try {
                 teardownCommands.forEach { it.invoke(flicker) }
diff --git a/libraries/flicker/src/android/tools/device/flicker/legacy/runner/TraceMonitorRule.kt b/libraries/flicker/src/android/tools/device/flicker/legacy/runner/TraceMonitorRule.kt
index 0acbe2c..9c0f008 100644
--- a/libraries/flicker/src/android/tools/device/flicker/legacy/runner/TraceMonitorRule.kt
+++ b/libraries/flicker/src/android/tools/device/flicker/legacy/runner/TraceMonitorRule.kt
@@ -18,8 +18,8 @@
 
 import android.app.Instrumentation
 import android.platform.test.rule.ArtifactSaver
-import android.tools.common.CrossPlatform
 import android.tools.common.FLICKER_TAG
+import android.tools.common.Logger
 import android.tools.common.Scenario
 import android.tools.device.traces.io.ResultWriter
 import android.tools.device.traces.monitors.ITransitionMonitor
@@ -58,7 +58,7 @@
     }
 
     private fun doStartMonitors(description: Description?) {
-        CrossPlatform.log.withTracing("doStartMonitors") {
+        Logger.withTracing("doStartMonitors") {
             Utils.notifyRunnerProgress(scenario, "Starting traces for $description")
             traceMonitors.forEach {
                 try {
@@ -72,7 +72,7 @@
     }
 
     private fun doStopMonitors(description: Description?) {
-        CrossPlatform.log.withTracing("doStopMonitors") {
+        Logger.withTracing("doStopMonitors") {
             Utils.notifyRunnerProgress(scenario, "Stopping traces for $description")
             val errors =
                 traceMonitors.map {
@@ -84,7 +84,7 @@
                                 Utils.expandDescription(description, "stopTrace"),
                                 e
                             )
-                            CrossPlatform.log.e(FLICKER_TAG, "Unable to stop $it", e)
+                            Logger.e(FLICKER_TAG, "Unable to stop $it", e)
                             throw e
                         }
                     }
diff --git a/libraries/flicker/src/android/tools/device/flicker/legacy/runner/TransitionExecutionRule.kt b/libraries/flicker/src/android/tools/device/flicker/legacy/runner/TransitionExecutionRule.kt
index 038bb61..eac9584 100644
--- a/libraries/flicker/src/android/tools/device/flicker/legacy/runner/TransitionExecutionRule.kt
+++ b/libraries/flicker/src/android/tools/device/flicker/legacy/runner/TransitionExecutionRule.kt
@@ -18,7 +18,7 @@
 
 import android.app.Instrumentation
 import android.platform.test.rule.ArtifactSaver
-import android.tools.common.CrossPlatform
+import android.tools.common.Logger
 import android.tools.common.Scenario
 import android.tools.common.io.TraceType
 import android.tools.device.flicker.FlickerTag
@@ -57,7 +57,7 @@
     override fun apply(base: Statement?, description: Description?): Statement {
         return object : Statement() {
             override fun evaluate() {
-                CrossPlatform.log.withTracing("transition") {
+                Logger.withTracing("transition") {
                     try {
                         Utils.notifyRunnerProgress(scenario, "Running transition $description")
                         doRunBeforeTransition()
@@ -75,9 +75,9 @@
     }
 
     private fun doRunBeforeTransition() {
-        CrossPlatform.log.withTracing("doRunBeforeTransition") {
+        Logger.withTracing("doRunBeforeTransition") {
             Utils.notifyRunnerProgress(scenario, "Running doRunBeforeTransition")
-            CrossPlatform.log.d(FLICKER_RUNNER_TAG, "doRunBeforeTransition")
+            Logger.d(FLICKER_RUNNER_TAG, "doRunBeforeTransition")
             val now = now()
             resultWriter.setTransitionStartTime(now)
             EventLog.writeEvent(
@@ -92,9 +92,9 @@
     }
 
     private fun doRunAfterTransition() {
-        CrossPlatform.log.withTracing("doRunAfterTransition") {
+        Logger.withTracing("doRunAfterTransition") {
             Utils.notifyRunnerProgress(scenario, "Running doRunAfterTransition")
-            CrossPlatform.log.d(FLICKER_RUNNER_TAG, "doRunAfterTransition")
+            Logger.d(FLICKER_RUNNER_TAG, "doRunAfterTransition")
             Utils.doWaitForUiStabilize(wmHelper)
             val now = now()
             resultWriter.setTransitionEndTime(now)
@@ -122,7 +122,7 @@
     }
 
     private fun doCreateTag(tag: String) {
-        CrossPlatform.log.withTracing("doRunAfterTransition") {
+        Logger.withTracing("doRunAfterTransition") {
             Utils.notifyRunnerProgress(scenario, "Creating tag $tag")
             doValidateTag(tag)
             tags.add(tag)
diff --git a/libraries/flicker/src/android/tools/device/flicker/legacy/runner/TransitionRunner.kt b/libraries/flicker/src/android/tools/device/flicker/legacy/runner/TransitionRunner.kt
index 4f60c71..539dd8f 100644
--- a/libraries/flicker/src/android/tools/device/flicker/legacy/runner/TransitionRunner.kt
+++ b/libraries/flicker/src/android/tools/device/flicker/legacy/runner/TransitionRunner.kt
@@ -20,7 +20,7 @@
 import android.platform.test.rule.NavigationModeRule
 import android.platform.test.rule.PressHomeRule
 import android.platform.test.rule.UnlockScreenRule
-import android.tools.common.CrossPlatform
+import android.tools.common.Logger
 import android.tools.common.Scenario
 import android.tools.device.apphelpers.MessagingAppHelper
 import android.tools.device.flicker.datastore.CachedResultWriter
@@ -44,7 +44,7 @@
 ) {
     /** Executes [flicker] transition and returns the result */
     fun execute(flicker: FlickerTestData, description: Description?): IResultData {
-        return CrossPlatform.log.withTracing("TransitionRunner:execute") {
+        return Logger.withTracing("TransitionRunner:execute") {
             resultWriter.forScenario(scenario).withOutputDir(flicker.outputDir)
 
             val ruleChain = buildTestRuleChain(flicker)
diff --git a/libraries/flicker/src/android/tools/device/flicker/legacy/runner/Utils.kt b/libraries/flicker/src/android/tools/device/flicker/legacy/runner/Utils.kt
index 6fef039..4d7a594 100644
--- a/libraries/flicker/src/android/tools/device/flicker/legacy/runner/Utils.kt
+++ b/libraries/flicker/src/android/tools/device/flicker/legacy/runner/Utils.kt
@@ -18,7 +18,7 @@
 
 import android.app.Instrumentation
 import android.os.Bundle
-import android.tools.common.CrossPlatform
+import android.tools.common.Logger
 import android.tools.common.Scenario
 import android.tools.common.traces.ConditionList
 import android.tools.common.traces.ConditionsFactory
@@ -46,7 +46,7 @@
     }
 
     internal fun notifyRunnerProgress(scenario: Scenario, msg: String) {
-        CrossPlatform.log.d(FLICKER_RUNNER_TAG, "${scenario.key} - $msg")
+        Logger.d(FLICKER_RUNNER_TAG, "${scenario.key} - $msg")
         val results = Bundle()
         results.putString(Instrumentation.REPORT_KEY_STREAMRESULT, "$msg\n")
         instrumentation.sendStatus(1, results)
diff --git a/libraries/flicker/src/android/tools/device/flicker/rules/ChangeDisplayOrientationRule.kt b/libraries/flicker/src/android/tools/device/flicker/rules/ChangeDisplayOrientationRule.kt
index 3c5ea2e..b2812e9 100644
--- a/libraries/flicker/src/android/tools/device/flicker/rules/ChangeDisplayOrientationRule.kt
+++ b/libraries/flicker/src/android/tools/device/flicker/rules/ChangeDisplayOrientationRule.kt
@@ -19,8 +19,8 @@
 import android.app.Instrumentation
 import android.content.Context
 import android.os.RemoteException
-import android.tools.common.CrossPlatform
 import android.tools.common.FLICKER_TAG
+import android.tools.common.Logger
 import android.tools.common.Rotation
 import android.tools.device.traces.parsers.WindowManagerStateHelper
 import android.view.WindowManager
@@ -51,8 +51,8 @@
     private var initialOrientation = Rotation.ROTATION_0
 
     override fun starting(description: Description?) {
-        CrossPlatform.log.withTracing("ChangeDisplayOrientationRule:starting") {
-            CrossPlatform.log.v(
+        Logger.withTracing("ChangeDisplayOrientationRule:starting") {
+            Logger.v(
                 FLICKER_TAG,
                 "Changing display orientation to " +
                     "$targetOrientation ${targetOrientation.description}"
@@ -65,7 +65,7 @@
     }
 
     override fun finished(description: Description?) {
-        CrossPlatform.log.withTracing("ChangeDisplayOrientationRule:finished") {
+        Logger.withTracing("ChangeDisplayOrientationRule:finished") {
             if (resetOrientationAfterTest) {
                 setRotation(initialOrientation, instrumentation, clearCacheAfterParsing)
             }
@@ -98,7 +98,7 @@
                     wmHelper.StateSyncBuilder().withRotation(rotation).waitForAndVerify()
                 } else {
                     wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify()
-                    CrossPlatform.log.v(FLICKER_TAG, "Rotation is not allowed in the state")
+                    Logger.v(FLICKER_TAG, "Rotation is not allowed in the state")
                     return
                 }
 
diff --git a/libraries/flicker/src/android/tools/device/flicker/rules/FlickerServiceRule.kt b/libraries/flicker/src/android/tools/device/flicker/rules/FlickerServiceRule.kt
index a9258f6..1f13491 100644
--- a/libraries/flicker/src/android/tools/device/flicker/rules/FlickerServiceRule.kt
+++ b/libraries/flicker/src/android/tools/device/flicker/rules/FlickerServiceRule.kt
@@ -19,12 +19,13 @@
 import android.platform.test.rule.TestWatcher
 import android.tools.common.CrossPlatform
 import android.tools.common.FLICKER_TAG
+import android.tools.common.Logger
 import android.tools.common.TimestampFactory
+import android.tools.device.AndroidLogger
 import android.tools.device.flicker.FlickerServiceResultsCollector
 import android.tools.device.flicker.FlickerServiceTracesCollector
 import android.tools.device.flicker.IFlickerServiceResultsCollector
 import android.tools.device.flicker.annotation.FlickerTest
-import android.tools.device.traces.ANDROID_LOGGER
 import android.tools.device.traces.formatRealTimestamp
 import android.tools.device.traces.getDefaultFlickerOutputDir
 import androidx.test.platform.app.InstrumentationRegistry
@@ -64,7 +65,7 @@
             ?: failTestOnFaasFailure
 
     init {
-        CrossPlatform.setLogger(ANDROID_LOGGER)
+        CrossPlatform.setLogger(AndroidLogger())
             .setTimestampFactory(TimestampFactory { formatRealTimestamp(it) })
     }
 
@@ -104,21 +105,21 @@
     }
 
     private fun handleStarting(description: Description) {
-        CrossPlatform.log.i(LOG_TAG, "Test starting $description")
+        Logger.i(LOG_TAG, "Test starting $description")
         metricsCollector.testStarted(description)
     }
 
     private fun handleSucceeded(description: Description) {
-        CrossPlatform.log.i(LOG_TAG, "Test succeeded $description")
+        Logger.i(LOG_TAG, "Test succeeded $description")
     }
 
     private fun handleFailed(e: Throwable?, description: Description) {
-        CrossPlatform.log.e(LOG_TAG, "$description test failed  with $e")
+        Logger.e(LOG_TAG, "$description test failed  with $e")
         metricsCollector.testFailure(Failure(description, e))
     }
 
     private fun handleSkipped(e: AssumptionViolatedException, description: Description) {
-        CrossPlatform.log.i(LOG_TAG, "Test skipped $description with $e")
+        Logger.i(LOG_TAG, "Test skipped $description with $e")
         metricsCollector.testSkipped(description)
     }
 
@@ -135,11 +136,11 @@
     }
 
     private fun handleFinished(description: Description) {
-        CrossPlatform.log.i(LOG_TAG, "Test finished $description")
+        Logger.i(LOG_TAG, "Test finished $description")
         metricsCollector.testFinished(description)
         if (metricsCollector.executionErrors.isNotEmpty()) {
             for (executionError in metricsCollector.executionErrors) {
-                CrossPlatform.log.e(LOG_TAG, "FaaS reported execution errors", executionError)
+                Logger.e(LOG_TAG, "FaaS reported execution errors", executionError)
             }
             throw metricsCollector.executionErrors[0]
         }
diff --git a/libraries/flicker/src/android/tools/device/flicker/rules/LaunchAppRule.kt b/libraries/flicker/src/android/tools/device/flicker/rules/LaunchAppRule.kt
index 1d3e415..b98f4b2 100644
--- a/libraries/flicker/src/android/tools/device/flicker/rules/LaunchAppRule.kt
+++ b/libraries/flicker/src/android/tools/device/flicker/rules/LaunchAppRule.kt
@@ -17,8 +17,8 @@
 package android.tools.device.flicker.rules
 
 import android.app.Instrumentation
-import android.tools.common.CrossPlatform
 import android.tools.common.FLICKER_TAG
+import android.tools.common.Logger
 import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
 import android.tools.device.traces.parsers.WindowManagerStateHelper
@@ -63,8 +63,8 @@
     )
 
     override fun starting(description: Description?) {
-        CrossPlatform.log.withTracing("LaunchAppRule:finished") {
-            CrossPlatform.log.v(FLICKER_TAG, "Launching app $appHelper")
+        Logger.withTracing("LaunchAppRule:finished") {
+            Logger.v(FLICKER_TAG, "Launching app $appHelper")
             appHelper.launchViaIntent()
             appHelper.exit(wmHelper)
         }
diff --git a/libraries/flicker/src/android/tools/device/flicker/rules/RemoveAllTasksButHomeRule.kt b/libraries/flicker/src/android/tools/device/flicker/rules/RemoveAllTasksButHomeRule.kt
index 487de0e..7db7f88 100644
--- a/libraries/flicker/src/android/tools/device/flicker/rules/RemoveAllTasksButHomeRule.kt
+++ b/libraries/flicker/src/android/tools/device/flicker/rules/RemoveAllTasksButHomeRule.kt
@@ -18,16 +18,16 @@
 
 import android.app.ActivityTaskManager
 import android.app.WindowConfiguration
-import android.tools.common.CrossPlatform
 import android.tools.common.FLICKER_TAG
+import android.tools.common.Logger
 import org.junit.rules.TestWatcher
 import org.junit.runner.Description
 
 /** Test rule to ensure no tasks as running before executing the test */
 class RemoveAllTasksButHomeRule() : TestWatcher() {
     override fun starting(description: Description?) {
-        CrossPlatform.log.withTracing("RemoveAllTasksButHomeRule:finished") {
-            CrossPlatform.log.v(FLICKER_TAG, "Removing all tasks (except home)")
+        Logger.withTracing("RemoveAllTasksButHomeRule:finished") {
+            Logger.v(FLICKER_TAG, "Removing all tasks (except home)")
             removeAllTasksButHome()
         }
     }
diff --git a/libraries/flicker/src/android/tools/device/helpers/AutomationUtils.kt b/libraries/flicker/src/android/tools/device/helpers/AutomationUtils.kt
index 1ea4ea3..fd1475c 100644
--- a/libraries/flicker/src/android/tools/device/helpers/AutomationUtils.kt
+++ b/libraries/flicker/src/android/tools/device/helpers/AutomationUtils.kt
@@ -22,7 +22,7 @@
 import android.graphics.Rect
 import android.os.RemoteException
 import android.os.SystemClock
-import android.tools.common.CrossPlatform
+import android.tools.common.Logger
 import android.tools.common.Rotation
 import android.tools.common.traces.ConditionsFactory
 import android.tools.common.traces.component.ComponentNameMatcher
@@ -68,7 +68,7 @@
 /** Checks if the device is running on gestural or 2-button navigation modes */
 fun UiDevice.isQuickstepEnabled(): Boolean {
     val enabled = this.findObject(By.res(SYSTEMUI_PACKAGE, "recent_apps")) == null
-    CrossPlatform.log.d(TAG, "Quickstep enabled: $enabled")
+    Logger.d(TAG, "Quickstep enabled: $enabled")
     return enabled
 }
 
@@ -100,7 +100,7 @@
             if (navBar != null) {
                 navBar.visibleBounds
             } else {
-                CrossPlatform.log.e(TAG, "Could not find nav bar, infer location")
+                Logger.e(TAG, "Could not find nav bar, infer location")
                 estimateNavigationBarPosition(Rotation.ROTATION_0).bounds.toAndroidRect()
             }
 
@@ -175,7 +175,7 @@
         try {
             device.pressRecentApps()
         } catch (e: RemoteException) {
-            CrossPlatform.log.e(TAG, "launchSplitScreen", e)
+            Logger.e(TAG, "launchSplitScreen", e)
         }
     }
     val overviewIconSelector = By.res(device.launcherPackageName, "icon").clazz(View::class.java)
@@ -191,7 +191,7 @@
         try {
             this.pressRecentApps()
         } catch (e: RemoteException) {
-            CrossPlatform.log.e(TAG, "launchSplitScreen", e)
+            Logger.e(TAG, "launchSplitScreen", e)
         }
     }
     for (i in 0..9) {
diff --git a/libraries/flicker/src/android/tools/device/traces/Consts.kt b/libraries/flicker/src/android/tools/device/traces/Consts.kt
index 4e0b9aa..45d9666 100644
--- a/libraries/flicker/src/android/tools/device/traces/Consts.kt
+++ b/libraries/flicker/src/android/tools/device/traces/Consts.kt
@@ -18,28 +18,8 @@
 
 package android.tools.device.traces
 
-import android.os.Trace
-import android.tools.common.LoggerBuilder
-import android.util.Log
-
 internal const val LOG_TAG = "FLICKER-PARSER"
 
-val ANDROID_LOGGER =
-    LoggerBuilder()
-        .setD { tag, msg -> Log.d(tag, msg) }
-        .setI { tag, msg -> Log.i(tag, msg) }
-        .setW { tag, msg -> Log.w(tag, msg) }
-        .setE { tag, msg, error -> Log.e(tag, msg, error) }
-        .setOnTracing { name, predicate ->
-            try {
-                Trace.beginSection(name)
-                predicate()
-            } finally {
-                Trace.endSection()
-            }
-        }
-        .build()
-
 val TRACE_CONFIG_REQUIRE_CHANGES =
     TraceConfigs(
         wmTrace = TraceConfig(required = true, allowNoChange = false, usingExistingTraces = false),
diff --git a/libraries/flicker/src/android/tools/device/traces/Extensions.kt b/libraries/flicker/src/android/tools/device/traces/Extensions.kt
index edbc1b3..9507b25 100644
--- a/libraries/flicker/src/android/tools/device/traces/Extensions.kt
+++ b/libraries/flicker/src/android/tools/device/traces/Extensions.kt
@@ -19,9 +19,9 @@
 package android.tools.device.traces
 
 import android.os.SystemClock
-import android.tools.common.CrossPlatform
 import android.tools.common.SECOND_AS_NANOSECONDS
 import android.tools.common.Timestamp
+import android.tools.common.Timestamps
 import androidx.test.platform.app.InstrumentationRegistry
 import java.io.File
 import java.time.Instant
@@ -36,7 +36,7 @@
 /** @return the current timestamp as [Timestamp] */
 fun now(): Timestamp {
     val now = Instant.now()
-    return CrossPlatform.timestamp.from(
+    return Timestamps.from(
         elapsedNanos = SystemClock.elapsedRealtimeNanos(),
         systemUptimeNanos = SystemClock.uptimeNanos(),
         unixNanos = now.epochSecond * SECOND_AS_NANOSECONDS + now.nano
diff --git a/libraries/flicker/src/android/tools/device/traces/Utils.kt b/libraries/flicker/src/android/tools/device/traces/Utils.kt
index e30d467..1ad6ef5 100644
--- a/libraries/flicker/src/android/tools/device/traces/Utils.kt
+++ b/libraries/flicker/src/android/tools/device/traces/Utils.kt
@@ -21,7 +21,7 @@
 import android.app.UiAutomation
 import android.os.IBinder
 import android.os.ParcelFileDescriptor
-import android.tools.common.CrossPlatform
+import android.tools.common.Logger
 import android.tools.common.MILLISECOND_AS_NANOSECONDS
 import android.tools.common.io.TraceType
 import android.tools.common.traces.DeviceStateDump
@@ -100,7 +100,7 @@
         throw IllegalArgumentException("Only dump types are supported. Invalid types: $traceTypes")
     }
 
-    CrossPlatform.log.d(LOG_TAG, "Requesting new device state dump")
+    Logger.d(LOG_TAG, "Requesting new device state dump")
     val wmTraceData =
         if (dumpTypes.contains(TraceType.WM_DUMP)) {
             getCurrentWindowManagerState()
diff --git a/libraries/flicker/src/android/tools/device/traces/io/Artifact.kt b/libraries/flicker/src/android/tools/device/traces/io/Artifact.kt
index df45f3f..381a564 100644
--- a/libraries/flicker/src/android/tools/device/traces/io/Artifact.kt
+++ b/libraries/flicker/src/android/tools/device/traces/io/Artifact.kt
@@ -32,7 +32,7 @@
 
 package android.tools.device.traces.io
 
-import android.tools.common.CrossPlatform
+import android.tools.common.Logger
 import android.tools.common.Scenario
 import android.tools.common.io.Artifact
 import android.tools.common.io.BUFFER_SIZE
@@ -120,7 +120,7 @@
 
     @Throws(IOException::class)
     override fun readBytes(descriptor: ResultArtifactDescriptor): ByteArray? {
-        CrossPlatform.log.d(FLICKER_IO_TAG, "Reading descriptor=$descriptor from $this")
+        Logger.d(FLICKER_IO_TAG, "Reading descriptor=$descriptor from $this")
 
         var foundFile = false
         val outByteArray = ByteArrayOutputStream()
diff --git a/libraries/flicker/src/android/tools/device/traces/io/ArtifactBuilder.kt b/libraries/flicker/src/android/tools/device/traces/io/ArtifactBuilder.kt
index 1666328..c9ae97c 100644
--- a/libraries/flicker/src/android/tools/device/traces/io/ArtifactBuilder.kt
+++ b/libraries/flicker/src/android/tools/device/traces/io/ArtifactBuilder.kt
@@ -16,7 +16,7 @@
 
 package android.tools.device.traces.io
 
-import android.tools.common.CrossPlatform
+import android.tools.common.Logger
 import android.tools.common.Scenario
 import android.tools.common.io.BUFFER_SIZE
 import android.tools.common.io.FLICKER_IO_TAG
@@ -54,11 +54,11 @@
     }
 
     fun build(): Artifact {
-        return CrossPlatform.log.withTracing("ArtifactBuilder#build") {
+        return Logger.withTracing("ArtifactBuilder#build") {
             val scenario = scenario ?: error("Missing scenario")
             require(!scenario.isEmpty) { "Scenario shouldn't be empty" }
             val artifactFile = createArtifactFile()
-            CrossPlatform.log.d(FLICKER_IO_TAG, "Creating artifact archive at $artifactFile")
+            Logger.d(FLICKER_IO_TAG, "Creating artifact archive at $artifactFile")
 
             writeToZip(artifactFile, files)
 
@@ -106,7 +106,7 @@
     }
 
     private fun addFile(zipOutputStream: ZipOutputStream, artifact: File, nameInArchive: String) {
-        CrossPlatform.log.v(FLICKER_IO_TAG, "Adding $artifact with name $nameInArchive to zip")
+        Logger.v(FLICKER_IO_TAG, "Adding $artifact with name $nameInArchive to zip")
         val fi = FileInputStream(artifact)
         val inputStream = BufferedInputStream(fi, BUFFER_SIZE)
         inputStream.use {
diff --git a/libraries/flicker/src/android/tools/device/traces/io/ResultReader.kt b/libraries/flicker/src/android/tools/device/traces/io/ResultReader.kt
index ab96653..17d552f 100644
--- a/libraries/flicker/src/android/tools/device/traces/io/ResultReader.kt
+++ b/libraries/flicker/src/android/tools/device/traces/io/ResultReader.kt
@@ -16,7 +16,7 @@
 
 package android.tools.device.traces.io
 
-import android.tools.common.CrossPlatform
+import android.tools.common.Logger
 import android.tools.common.Tag
 import android.tools.common.Timestamp
 import android.tools.common.io.Artifact
@@ -73,12 +73,9 @@
      */
     @Throws(IOException::class)
     override fun readWmState(tag: String): WindowManagerTrace? {
-        return CrossPlatform.log.withTracing("readWmState#$tag") {
+        return Logger.withTracing("readWmState#$tag") {
             val descriptor = ResultArtifactDescriptor(TraceType.WM_DUMP, tag)
-            CrossPlatform.log.d(
-                FLICKER_IO_TAG,
-                "Reading WM trace descriptor=$descriptor from $result"
-            )
+            Logger.d(FLICKER_IO_TAG, "Reading WM trace descriptor=$descriptor from $result")
             val traceData = artifact.readBytes(descriptor)
             traceData?.let { WindowManagerDumpParser().parse(it, clearCache = true) }
         }
@@ -91,7 +88,7 @@
      */
     @Throws(IOException::class)
     override fun readWmTrace(): WindowManagerTrace? {
-        return CrossPlatform.log.withTracing("readWmTrace") {
+        return Logger.withTracing("readWmTrace") {
             val descriptor = ResultArtifactDescriptor(TraceType.WM)
             artifact.readBytes(descriptor)?.let {
                 val trace =
@@ -122,7 +119,7 @@
      */
     @Throws(IOException::class)
     override fun readLayersTrace(): LayersTrace? {
-        return CrossPlatform.log.withTracing("readLayersTrace") {
+        return Logger.withTracing("readLayersTrace") {
             val descriptor = ResultArtifactDescriptor(TraceType.SF)
             artifact.readBytes(descriptor)?.let {
                 val trace =
@@ -153,7 +150,7 @@
      */
     @Throws(IOException::class)
     override fun readLayersDump(tag: String): LayersTrace? {
-        return CrossPlatform.log.withTracing("readLayersDump#$tag") {
+        return Logger.withTracing("readLayersDump#$tag") {
             val descriptor = ResultArtifactDescriptor(TraceType.SF_DUMP, tag)
             val traceData = artifact.readBytes(descriptor)
             traceData?.let { LayersTraceParser().parse(it, clearCache = true) }
@@ -167,7 +164,7 @@
      */
     @Throws(IOException::class)
     override fun readTransactionsTrace(): TransactionsTrace? =
-        CrossPlatform.log.withTracing("readTransactionsTrace") {
+        Logger.withTracing("readTransactionsTrace") {
             doReadTransactionsTrace(from = transitionTimeRange.start, to = transitionTimeRange.end)
         }
 
@@ -187,7 +184,7 @@
      */
     @Throws(IOException::class)
     override fun readTransitionsTrace(): TransitionsTrace? {
-        return CrossPlatform.log.withTracing("readTransitionsTrace") {
+        return Logger.withTracing("readTransitionsTrace") {
             val wmSideTraceData =
                 artifact.readBytes(ResultArtifactDescriptor(TraceType.WM_TRANSITION))
             val shellSideTraceData =
@@ -223,7 +220,7 @@
      */
     @Throws(IOException::class)
     override fun readEventLogTrace(): EventLog? {
-        return CrossPlatform.log.withTracing("readEventLogTrace") {
+        return Logger.withTracing("readEventLogTrace") {
             val descriptor = ResultArtifactDescriptor(TraceType.EVENT_LOG)
             artifact.readBytes(descriptor)?.let {
                 EventLogParser()
diff --git a/libraries/flicker/src/android/tools/device/traces/io/ResultWriter.kt b/libraries/flicker/src/android/tools/device/traces/io/ResultWriter.kt
index 5fdbfe0..a588d87 100644
--- a/libraries/flicker/src/android/tools/device/traces/io/ResultWriter.kt
+++ b/libraries/flicker/src/android/tools/device/traces/io/ResultWriter.kt
@@ -16,11 +16,12 @@
 
 package android.tools.device.traces.io
 
-import android.tools.common.CrossPlatform
+import android.tools.common.Logger
 import android.tools.common.Scenario
 import android.tools.common.ScenarioBuilder
 import android.tools.common.Tag
 import android.tools.common.Timestamp
+import android.tools.common.Timestamps
 import android.tools.common.io.FLICKER_IO_TAG
 import android.tools.common.io.ResultArtifactDescriptor
 import android.tools.common.io.RunStatus
@@ -33,8 +34,8 @@
     protected var scenario: Scenario = ScenarioBuilder().createEmptyScenario()
     private var runStatus: RunStatus = RunStatus.UNDEFINED
     private val files = mutableMapOf<ResultArtifactDescriptor, File>()
-    private var transitionStartTime = CrossPlatform.timestamp.min()
-    private var transitionEndTime = CrossPlatform.timestamp.max()
+    private var transitionStartTime = Timestamps.min()
+    private var transitionEndTime = Timestamps.max()
     private var executionError: Throwable? = null
     private var outputDir: File? = null
 
@@ -70,7 +71,7 @@
      * @param tag used when adding [artifact] to the result artifact
      */
     fun addTraceResult(traceType: TraceType, artifact: File, tag: String = Tag.ALL) = apply {
-        CrossPlatform.log.d(
+        Logger.d(
             FLICKER_IO_TAG,
             "Add trace result file=$artifact type=$traceType tag=$tag scenario=$scenario"
         )
@@ -80,13 +81,13 @@
 
     /** @return writes the result artifact to disk and returns it */
     open fun write(): IResultData {
-        return CrossPlatform.log.withTracing("write") {
+        return Logger.withTracing("write") {
             val outputDir = outputDir
             requireNotNull(outputDir) { "Output dir not configured" }
             require(!scenario.isEmpty) { "Scenario shouldn't be empty" }
 
             if (runStatus == RunStatus.UNDEFINED) {
-                CrossPlatform.log.w(FLICKER_IO_TAG, "Writing result with $runStatus run status")
+                Logger.w(FLICKER_IO_TAG, "Writing result with $runStatus run status")
             }
 
             val artifact =
diff --git a/libraries/flicker/src/android/tools/device/traces/monitors/NoTraceMonitor.kt b/libraries/flicker/src/android/tools/device/traces/monitors/NoTraceMonitor.kt
index 39f1283..b0550f8 100644
--- a/libraries/flicker/src/android/tools/device/traces/monitors/NoTraceMonitor.kt
+++ b/libraries/flicker/src/android/tools/device/traces/monitors/NoTraceMonitor.kt
@@ -16,7 +16,7 @@
 
 package android.tools.device.traces.monitors
 
-import android.tools.common.CrossPlatform
+import android.tools.common.Timestamps
 import android.tools.device.traces.io.ResultWriter
 
 /**
@@ -29,8 +29,8 @@
     }
 
     override fun stop(writer: ResultWriter) {
-        writer.setTransitionStartTime(CrossPlatform.timestamp.min())
-        writer.setTransitionEndTime(CrossPlatform.timestamp.max())
+        writer.setTransitionStartTime(Timestamps.min())
+        writer.setTransitionEndTime(Timestamps.max())
         this.resultSetter.invoke(writer)
     }
 }
diff --git a/libraries/flicker/src/android/tools/device/traces/monitors/ScreenRecorder.kt b/libraries/flicker/src/android/tools/device/traces/monitors/ScreenRecorder.kt
index fddd9b0..355b9a8 100644
--- a/libraries/flicker/src/android/tools/device/traces/monitors/ScreenRecorder.kt
+++ b/libraries/flicker/src/android/tools/device/traces/monitors/ScreenRecorder.kt
@@ -18,8 +18,8 @@
 
 import android.content.Context
 import android.os.SystemClock
-import android.tools.common.CrossPlatform
 import android.tools.common.FLICKER_TAG
+import android.tools.common.Logger
 import android.tools.common.io.TraceType
 import androidx.annotation.VisibleForTesting
 import java.io.File
@@ -58,7 +58,7 @@
 
         val recordingThread = newRecordingThread()
         this.recordingThread = recordingThread
-        CrossPlatform.log.d(FLICKER_TAG, "Starting screen recording thread")
+        Logger.d(FLICKER_TAG, "Starting screen recording thread")
         recordingThread.start()
 
         var remainingTime = WAIT_TIMEOUT_MS
@@ -73,7 +73,7 @@
     override fun doStop(): File {
         require(recordingThread != null) { "Screen recorder was not started" }
 
-        CrossPlatform.log.d(FLICKER_TAG, "Stopping screen recording. Storing result in $outputFile")
+        Logger.d(FLICKER_TAG, "Stopping screen recording. Storing result in $outputFile")
         try {
             recordingRunnable?.stop()
             recordingThread?.join()
diff --git a/libraries/flicker/src/android/tools/device/traces/monitors/ScreenRecordingRunnable.kt b/libraries/flicker/src/android/tools/device/traces/monitors/ScreenRecordingRunnable.kt
index 6e4a2a3..d362c75 100644
--- a/libraries/flicker/src/android/tools/device/traces/monitors/ScreenRecordingRunnable.kt
+++ b/libraries/flicker/src/android/tools/device/traces/monitors/ScreenRecordingRunnable.kt
@@ -23,8 +23,8 @@
 import android.media.MediaFormat
 import android.media.MediaMuxer
 import android.os.SystemClock
-import android.tools.common.CrossPlatform
 import android.tools.common.FLICKER_TAG
+import android.tools.common.Logger
 import android.tools.device.traces.deleteIfExists
 import android.util.DisplayMetrics
 import android.view.WindowManager
@@ -76,7 +76,7 @@
     }
 
     override fun run() {
-        CrossPlatform.log.d(FLICKER_TAG, "Starting screen recording to file $outputFile")
+        Logger.d(FLICKER_TAG, "Starting screen recording to file $outputFile")
 
         val timestampsMonotonicUs = mutableListOf<Long>()
         try {
@@ -158,11 +158,11 @@
      */
     private fun writeMetadata(timestampsMonotonicUs: List<Long>) {
         if (timestampsMonotonicUs.isEmpty()) {
-            CrossPlatform.log.v(FLICKER_TAG, "Not writing winscope metadata (no frames/timestamps)")
+            Logger.v(FLICKER_TAG, "Not writing winscope metadata (no frames/timestamps)")
             return
         }
 
-        CrossPlatform.log.v(
+        Logger.v(
             FLICKER_TAG,
             "Writing winscope metadata (size=${timestampsMonotonicUs.size} " +
                 ", monotonic timestamps range [us] = " +
diff --git a/libraries/flicker/src/android/tools/device/traces/monitors/events/EventLogMonitor.kt b/libraries/flicker/src/android/tools/device/traces/monitors/events/EventLogMonitor.kt
index 178f20f..dc0a686 100644
--- a/libraries/flicker/src/android/tools/device/traces/monitors/events/EventLogMonitor.kt
+++ b/libraries/flicker/src/android/tools/device/traces/monitors/events/EventLogMonitor.kt
@@ -16,8 +16,8 @@
 
 package android.tools.device.traces.monitors.events
 
-import android.tools.common.CrossPlatform
 import android.tools.common.FLICKER_TAG
+import android.tools.common.Logger
 import android.tools.common.Timestamp
 import android.tools.common.io.TraceType
 import android.tools.common.traces.events.EventLog
@@ -54,7 +54,7 @@
             val command =
                 "logcat -b events -v threadtime -v printable -v uid -v nsec " +
                     "-v epoch -t $sinceTime >> $outputFile"
-            CrossPlatform.log.d(FLICKER_TAG, "Running '$command'")
+            Logger.d(FLICKER_TAG, "Running '$command'")
             val eventLogString = executeShellCommand(command)
             it.write(eventLogString)
         }
diff --git a/libraries/flicker/src/android/tools/device/traces/monitors/wm/ShellTransitionTraceMonitor.kt b/libraries/flicker/src/android/tools/device/traces/monitors/wm/ShellTransitionTraceMonitor.kt
index 0183b0a..5b3f4b9 100644
--- a/libraries/flicker/src/android/tools/device/traces/monitors/wm/ShellTransitionTraceMonitor.kt
+++ b/libraries/flicker/src/android/tools/device/traces/monitors/wm/ShellTransitionTraceMonitor.kt
@@ -16,8 +16,8 @@
 
 package android.tools.device.traces.monitors.wm
 
-import android.tools.common.CrossPlatform
 import android.tools.common.FLICKER_TAG
+import android.tools.common.Logger
 import android.tools.common.io.TraceType
 import android.tools.common.traces.wm.TransitionsTrace
 import android.tools.device.traces.executeShellCommand
@@ -33,14 +33,14 @@
     override fun doStart() {
         require(!isEnabled) { "Trace already running" }
         isEnabled = true
-        CrossPlatform.log.d(FLICKER_TAG, "Running '$START_TRACING_COMMAND'")
+        Logger.d(FLICKER_TAG, "Running '$START_TRACING_COMMAND'")
         executeShellCommand(START_TRACING_COMMAND)
     }
 
     override fun doStop(): File {
         require(isEnabled) { "Trace not running" }
         isEnabled = false
-        CrossPlatform.log.d(FLICKER_TAG, "Running '$START_TRACING_COMMAND'")
+        Logger.d(FLICKER_TAG, "Running '$START_TRACING_COMMAND'")
         executeShellCommand(STOP_TRACING_COMMAND)
 
         return TRACE_DIR.resolve(traceType.fileName)
diff --git a/libraries/flicker/src/android/tools/device/traces/parsers/DeviceDumpParser.kt b/libraries/flicker/src/android/tools/device/traces/parsers/DeviceDumpParser.kt
index d2c61f6..c90468e 100644
--- a/libraries/flicker/src/android/tools/device/traces/parsers/DeviceDumpParser.kt
+++ b/libraries/flicker/src/android/tools/device/traces/parsers/DeviceDumpParser.kt
@@ -16,7 +16,7 @@
 
 package android.tools.device.traces.parsers
 
-import android.tools.common.CrossPlatform
+import android.tools.common.Logger
 import android.tools.common.traces.DeviceStateDump
 import android.tools.common.traces.DeviceTraceDump
 import android.tools.common.traces.NullableDeviceStateDump
@@ -53,7 +53,7 @@
             layersTraceData: ByteArray,
             clearCacheAfterParsing: Boolean
         ): NullableDeviceStateDump {
-            return CrossPlatform.log.withTracing("fromNullableDump") {
+            return Logger.withTracing("fromNullableDump") {
                 NullableDeviceStateDump(
                     wmState =
                         if (wmTraceData.isNotEmpty()) {
@@ -84,7 +84,7 @@
             layersTraceData: ByteArray,
             clearCacheAfterParsing: Boolean
         ): DeviceStateDump {
-            return CrossPlatform.log.withTracing("fromDump") {
+            return Logger.withTracing("fromDump") {
                 val nullableDump =
                     fromNullableDump(wmTraceData, layersTraceData, clearCacheAfterParsing)
                 DeviceStateDump(
@@ -113,7 +113,7 @@
             layersTraceData: ByteArray,
             clearCache: Boolean
         ): DeviceTraceDump {
-            return CrossPlatform.log.withTracing("fromTrace") {
+            return Logger.withTracing("fromTrace") {
                 DeviceTraceDump(
                     wmTrace =
                         if (wmTraceData.isNotEmpty()) {
diff --git a/libraries/flicker/src/android/tools/device/traces/parsers/WindowManagerStateHelper.kt b/libraries/flicker/src/android/tools/device/traces/parsers/WindowManagerStateHelper.kt
index 3bf067c..cd2ec75 100644
--- a/libraries/flicker/src/android/tools/device/traces/parsers/WindowManagerStateHelper.kt
+++ b/libraries/flicker/src/android/tools/device/traces/parsers/WindowManagerStateHelper.kt
@@ -21,7 +21,7 @@
 import android.app.WindowConfiguration
 import android.os.SystemClock
 import android.os.Trace
-import android.tools.common.CrossPlatform
+import android.tools.common.Logger
 import android.tools.common.Rotation
 import android.tools.common.datatypes.Region
 import android.tools.common.traces.Condition
@@ -115,9 +115,9 @@
                 .onLog { msg, isError ->
                     lastMessage = msg
                     if (isError) {
-                        CrossPlatform.log.e(LOG_TAG, msg)
+                        Logger.e(LOG_TAG, msg)
                     } else {
-                        CrossPlatform.log.d(LOG_TAG, msg)
+                        Logger.d(LOG_TAG, msg)
                     }
                 }
                 .onRetry { SystemClock.sleep(retryIntervalMs) }
@@ -426,16 +426,13 @@
                 val activityWindowVisible = matchingWindowStates.isNotEmpty()
 
                 if (!activityWindowVisible) {
-                    CrossPlatform.log.i(
+                    Logger.i(
                         LOG_TAG,
                         "Activity window not visible: ${activityState.windowIdentifier}"
                     )
                     allActivityWindowsVisible = false
                 } else if (!state.wmState.isActivityVisible(activityState.activityMatcher)) {
-                    CrossPlatform.log.i(
-                        LOG_TAG,
-                        "Activity not visible: ${activityState.activityMatcher}"
-                    )
+                    Logger.i(LOG_TAG, "Activity not visible: ${activityState.activityMatcher}")
                     allActivityWindowsVisible = false
                 } else {
                     // Check if window is already the correct state requested by test.
@@ -461,7 +458,7 @@
                         break
                     }
                     if (!windowInCorrectState) {
-                        CrossPlatform.log.i(LOG_TAG, "Window in incorrect stack: $activityState")
+                        Logger.i(LOG_TAG, "Window in incorrect stack: $activityState")
                         tasksInCorrectStacks = false
                     }
                 }
diff --git a/libraries/flicker/src/android/tools/device/traces/parsers/surfaceflinger/LayersTraceParser.kt b/libraries/flicker/src/android/tools/device/traces/parsers/surfaceflinger/LayersTraceParser.kt
index bf7d27a..becad70 100644
--- a/libraries/flicker/src/android/tools/device/traces/parsers/surfaceflinger/LayersTraceParser.kt
+++ b/libraries/flicker/src/android/tools/device/traces/parsers/surfaceflinger/LayersTraceParser.kt
@@ -20,8 +20,8 @@
 import android.surfaceflinger.Display
 import android.surfaceflinger.Layers
 import android.surfaceflinger.Layerstrace
-import android.tools.common.CrossPlatform
 import android.tools.common.Timestamp
+import android.tools.common.Timestamps
 import android.tools.common.datatypes.ActiveBuffer
 import android.tools.common.datatypes.Color
 import android.tools.common.datatypes.Matrix33
@@ -65,7 +65,7 @@
 
     override fun getTimestamp(entry: Layerstrace.LayersTraceProto): Timestamp {
         require(legacyTrace || realToElapsedTimeOffsetNanos != 0L)
-        return CrossPlatform.timestamp.from(
+        return Timestamps.from(
             systemUptimeNanos = entry.elapsedRealtimeNanos,
             unixNanos = entry.elapsedRealtimeNanos + realToElapsedTimeOffsetNanos
         )
diff --git a/libraries/flicker/src/android/tools/device/traces/parsers/surfaceflinger/TransactionsTraceParser.kt b/libraries/flicker/src/android/tools/device/traces/parsers/surfaceflinger/TransactionsTraceParser.kt
index b0a236f..5e69665 100644
--- a/libraries/flicker/src/android/tools/device/traces/parsers/surfaceflinger/TransactionsTraceParser.kt
+++ b/libraries/flicker/src/android/tools/device/traces/parsers/surfaceflinger/TransactionsTraceParser.kt
@@ -19,8 +19,8 @@
 import android.surfaceflinger.proto.Transactions
 import android.surfaceflinger.proto.Transactions.TransactionState
 import android.surfaceflinger.proto.Transactions.TransactionTraceFile
-import android.tools.common.CrossPlatform
 import android.tools.common.Timestamp
+import android.tools.common.Timestamps
 import android.tools.common.parsers.AbstractTraceParser
 import android.tools.common.traces.surfaceflinger.Transaction
 import android.tools.common.traces.surfaceflinger.TransactionsTrace
@@ -44,7 +44,7 @@
 
     override fun getTimestamp(entry: Transactions.TransactionTraceEntry): Timestamp {
         require(timestampOffset != 0L)
-        return CrossPlatform.timestamp.from(
+        return Timestamps.from(
             elapsedNanos = entry.elapsedRealtimeNanos,
             unixNanos = entry.elapsedRealtimeNanos + timestampOffset
         )
@@ -63,7 +63,7 @@
         val transactions = parseTransactionsProto(entry.transactionsList)
         val transactionsTraceEntry =
             TransactionsTraceEntry(
-                CrossPlatform.timestamp.from(
+                Timestamps.from(
                     elapsedNanos = entry.elapsedRealtimeNanos,
                     elapsedOffsetNanos = timestampOffset
                 ),
diff --git a/libraries/flicker/src/android/tools/device/traces/parsers/view/ViewFrameBuilder.kt b/libraries/flicker/src/android/tools/device/traces/parsers/view/ViewFrameBuilder.kt
index e687275..7b3dbfa 100644
--- a/libraries/flicker/src/android/tools/device/traces/parsers/view/ViewFrameBuilder.kt
+++ b/libraries/flicker/src/android/tools/device/traces/parsers/view/ViewFrameBuilder.kt
@@ -16,7 +16,7 @@
 
 package android.tools.device.traces.parsers.view
 
-import android.tools.common.CrossPlatform
+import android.tools.common.Timestamps
 import android.tools.common.datatypes.Point
 import android.tools.common.datatypes.PointF
 import android.tools.common.datatypes.Rect
@@ -63,7 +63,7 @@
         require(systemUptimeNanos > 0) { "Timestamp not specified" }
 
         return ViewFrame(
-            timestamp = CrossPlatform.timestamp.from(systemUptimeNanos = systemUptimeNanos),
+            timestamp = Timestamps.from(systemUptimeNanos = systemUptimeNanos),
             root = parseViewNode(root)
         )
     }
diff --git a/libraries/flicker/src/android/tools/device/traces/parsers/view/ViewTraceParser.kt b/libraries/flicker/src/android/tools/device/traces/parsers/view/ViewTraceParser.kt
index f9af7cc..40de116 100644
--- a/libraries/flicker/src/android/tools/device/traces/parsers/view/ViewTraceParser.kt
+++ b/libraries/flicker/src/android/tools/device/traces/parsers/view/ViewTraceParser.kt
@@ -16,7 +16,7 @@
 
 package android.tools.device.traces.parsers.view
 
-import android.tools.common.CrossPlatform
+import android.tools.common.Timestamps
 import android.tools.common.parsers.AbstractTraceParser
 import android.tools.common.traces.view.ViewTrace
 import com.android.app.viewcapture.data.ExportedData
@@ -36,9 +36,9 @@
 
     override fun getTimestamp(entry: WindowData) =
         if (entry.frameDataList.isEmpty()) {
-            CrossPlatform.timestamp.empty()
+            Timestamps.empty()
         } else {
-            CrossPlatform.timestamp.from(systemUptimeNanos = entry.frameDataList.first()?.timestamp)
+            Timestamps.from(systemUptimeNanos = entry.frameDataList.first()?.timestamp)
         }
 
     override fun doParseEntry(entry: WindowData): ViewTrace =
diff --git a/libraries/flicker/src/android/tools/device/traces/parsers/view/WindowDataParser.kt b/libraries/flicker/src/android/tools/device/traces/parsers/view/WindowDataParser.kt
index 4bd2b99..4b03a15 100644
--- a/libraries/flicker/src/android/tools/device/traces/parsers/view/WindowDataParser.kt
+++ b/libraries/flicker/src/android/tools/device/traces/parsers/view/WindowDataParser.kt
@@ -16,8 +16,8 @@
 
 package android.tools.device.traces.parsers.view
 
-import android.tools.common.CrossPlatform
 import android.tools.common.Timestamp
+import android.tools.common.Timestamps
 import android.tools.common.parsers.AbstractTraceParser
 import android.tools.common.traces.view.ViewFrame
 import android.tools.common.traces.view.ViewTrace
@@ -36,7 +36,7 @@
     override fun getEntries(input: WindowData): List<FrameData> = input.frameDataList
 
     override fun getTimestamp(entry: FrameData): Timestamp =
-        CrossPlatform.timestamp.from(systemUptimeNanos = entry.timestamp)
+        Timestamps.from(systemUptimeNanos = entry.timestamp)
 
     override fun doParseEntry(entry: FrameData): ViewFrame {
         return ViewFrameBuilder().forSystemUptime(entry.timestamp).fromRootNode(entry.node).build()
diff --git a/libraries/flicker/src/android/tools/device/traces/parsers/wm/ShellTransitionTraceParser.kt b/libraries/flicker/src/android/tools/device/traces/parsers/wm/ShellTransitionTraceParser.kt
index accb0cd..1a4039e 100644
--- a/libraries/flicker/src/android/tools/device/traces/parsers/wm/ShellTransitionTraceParser.kt
+++ b/libraries/flicker/src/android/tools/device/traces/parsers/wm/ShellTransitionTraceParser.kt
@@ -16,8 +16,8 @@
 
 package android.tools.device.traces.parsers.wm
 
-import android.tools.common.CrossPlatform
 import android.tools.common.Timestamp
+import android.tools.common.Timestamps
 import android.tools.common.parsers.AbstractTraceParser
 import android.tools.common.traces.wm.ShellTransitionData
 import android.tools.common.traces.wm.Transition
@@ -53,16 +53,16 @@
         requireValidTimestamp(entry)
 
         if (entry.dispatchTimeNs != 0L) {
-            return CrossPlatform.timestamp.from(elapsedNanos = entry.dispatchTimeNs)
+            return Timestamps.from(elapsedNanos = entry.dispatchTimeNs)
         }
         if (entry.mergeRequestTimeNs != 0L) {
-            return CrossPlatform.timestamp.from(elapsedNanos = entry.mergeRequestTimeNs)
+            return Timestamps.from(elapsedNanos = entry.mergeRequestTimeNs)
         }
         if (entry.mergeTimeNs != 0L) {
-            return CrossPlatform.timestamp.from(elapsedNanos = entry.mergeTimeNs)
+            return Timestamps.from(elapsedNanos = entry.mergeTimeNs)
         }
         if (entry.abortTimeNs != 0L) {
-            return CrossPlatform.timestamp.from(elapsedNanos = entry.abortTimeNs)
+            return Timestamps.from(elapsedNanos = entry.abortTimeNs)
         }
 
         error("No valid timestamp for entry")
@@ -97,16 +97,16 @@
                 ShellTransitionData(
                     dispatchTime =
                         if (entry.dispatchTimeNs == 0L) null
-                        else CrossPlatform.timestamp.from(elapsedNanos = entry.dispatchTimeNs),
+                        else Timestamps.from(elapsedNanos = entry.dispatchTimeNs),
                     mergeRequestTime =
                         if (entry.mergeRequestTimeNs == 0L) null
-                        else CrossPlatform.timestamp.from(elapsedNanos = entry.mergeRequestTimeNs),
+                        else Timestamps.from(elapsedNanos = entry.mergeRequestTimeNs),
                     mergeTime =
                         if (entry.mergeTimeNs == 0L) null
-                        else CrossPlatform.timestamp.from(elapsedNanos = entry.mergeTimeNs),
+                        else Timestamps.from(elapsedNanos = entry.mergeTimeNs),
                     abortTime =
                         if (entry.abortTimeNs == 0L) null
-                        else CrossPlatform.timestamp.from(elapsedNanos = entry.abortTimeNs),
+                        else Timestamps.from(elapsedNanos = entry.abortTimeNs),
                     handler = handlerMapping[entry.handler],
                     mergedInto = if (entry.mergedInto == 0) null else entry.mergedInto
                 )
diff --git a/libraries/flicker/src/android/tools/device/traces/parsers/wm/TransitionTraceParser.kt b/libraries/flicker/src/android/tools/device/traces/parsers/wm/TransitionTraceParser.kt
index 0cd9106..1ea3680 100644
--- a/libraries/flicker/src/android/tools/device/traces/parsers/wm/TransitionTraceParser.kt
+++ b/libraries/flicker/src/android/tools/device/traces/parsers/wm/TransitionTraceParser.kt
@@ -16,8 +16,8 @@
 
 package android.tools.device.traces.parsers.wm
 
-import android.tools.common.CrossPlatform
 import android.tools.common.Timestamp
+import android.tools.common.Timestamps
 import android.tools.common.traces.wm.TransitionsTrace
 
 class TransitionTraceParser {
@@ -27,8 +27,8 @@
     fun parse(
         wmSideTraceData: ByteArray,
         shellSideTraceData: ByteArray,
-        from: Timestamp = CrossPlatform.timestamp.min(),
-        to: Timestamp = CrossPlatform.timestamp.max(),
+        from: Timestamp = Timestamps.min(),
+        to: Timestamp = Timestamps.max(),
     ): TransitionsTrace {
         val wmTransitionTrace = wmTransitionTraceParser.parse(wmSideTraceData, from, to)
         val shellTransitionTrace = shellTransitionTraceParser.parse(shellSideTraceData, from, to)
diff --git a/libraries/flicker/src/android/tools/device/traces/parsers/wm/WindowManagerTraceParser.kt b/libraries/flicker/src/android/tools/device/traces/parsers/wm/WindowManagerTraceParser.kt
index 64f4873..2836064 100644
--- a/libraries/flicker/src/android/tools/device/traces/parsers/wm/WindowManagerTraceParser.kt
+++ b/libraries/flicker/src/android/tools/device/traces/parsers/wm/WindowManagerTraceParser.kt
@@ -16,8 +16,8 @@
 
 package android.tools.device.traces.parsers.wm
 
-import android.tools.common.CrossPlatform
 import android.tools.common.Timestamp
+import android.tools.common.Timestamps
 import android.tools.common.parsers.AbstractTraceParser
 import android.tools.common.traces.wm.WindowManagerState
 import android.tools.common.traces.wm.WindowManagerTrace
@@ -44,7 +44,7 @@
 
     override fun getTimestamp(entry: WindowManagerTraceProto): Timestamp {
         require(legacyTrace || realToElapsedTimeOffsetNanos != 0L)
-        return CrossPlatform.timestamp.from(
+        return Timestamps.from(
             elapsedNanos = entry.elapsedRealtimeNanos,
             unixNanos = entry.elapsedRealtimeNanos + realToElapsedTimeOffsetNanos
         )
diff --git a/libraries/flicker/src/android/tools/device/traces/parsers/wm/WmTransitionTraceParser.kt b/libraries/flicker/src/android/tools/device/traces/parsers/wm/WmTransitionTraceParser.kt
index 74e00d1..fd77923 100644
--- a/libraries/flicker/src/android/tools/device/traces/parsers/wm/WmTransitionTraceParser.kt
+++ b/libraries/flicker/src/android/tools/device/traces/parsers/wm/WmTransitionTraceParser.kt
@@ -16,8 +16,8 @@
 
 package android.tools.device.traces.parsers.wm
 
-import android.tools.common.CrossPlatform
 import android.tools.common.Timestamp
+import android.tools.common.Timestamps
 import android.tools.common.parsers.AbstractTraceParser
 import android.tools.common.traces.wm.Transition
 import android.tools.common.traces.wm.TransitionChange
@@ -55,16 +55,16 @@
         requireValidTimestamp(entry)
 
         if (entry.createTimeNs != 0L) {
-            return CrossPlatform.timestamp.from(elapsedNanos = entry.createTimeNs)
+            return Timestamps.from(elapsedNanos = entry.createTimeNs)
         }
         if (entry.sendTimeNs != 0L) {
-            return CrossPlatform.timestamp.from(elapsedNanos = entry.sendTimeNs)
+            return Timestamps.from(elapsedNanos = entry.sendTimeNs)
         }
         if (entry.abortTimeNs != 0L) {
-            return CrossPlatform.timestamp.from(elapsedNanos = entry.abortTimeNs)
+            return Timestamps.from(elapsedNanos = entry.abortTimeNs)
         }
         if (entry.finishTimeNs != 0L) {
-            return CrossPlatform.timestamp.from(elapsedNanos = entry.finishTimeNs)
+            return Timestamps.from(elapsedNanos = entry.finishTimeNs)
         }
 
         error("No valid timestamp available in entry")
@@ -105,16 +105,16 @@
                 WmTransitionData(
                     createTime =
                         if (entry.createTimeNs == 0L) null
-                        else CrossPlatform.timestamp.from(elapsedNanos = entry.createTimeNs),
+                        else Timestamps.from(elapsedNanos = entry.createTimeNs),
                     sendTime =
                         if (entry.sendTimeNs == 0L) null
-                        else CrossPlatform.timestamp.from(elapsedNanos = entry.sendTimeNs),
+                        else Timestamps.from(elapsedNanos = entry.sendTimeNs),
                     abortTime =
                         if (entry.abortTimeNs == 0L) null
-                        else CrossPlatform.timestamp.from(elapsedNanos = entry.abortTimeNs),
+                        else Timestamps.from(elapsedNanos = entry.abortTimeNs),
                     finishTime =
                         if (entry.finishTimeNs == 0L) null
-                        else CrossPlatform.timestamp.from(elapsedNanos = entry.finishTimeNs),
+                        else Timestamps.from(elapsedNanos = entry.finishTimeNs),
                     startTransactionId =
                         if (entry.startTransactionId == 0L) null
                         else entry.startTransactionId.toString(),
diff --git a/libraries/flicker/test/src/android/tools/TestTraces.kt b/libraries/flicker/test/src/android/tools/TestTraces.kt
index a00e706..c567b28 100644
--- a/libraries/flicker/test/src/android/tools/TestTraces.kt
+++ b/libraries/flicker/test/src/android/tools/TestTraces.kt
@@ -16,34 +16,34 @@
 
 package android.tools
 
-import android.tools.common.CrossPlatform
+import android.tools.common.Timestamps
 import android.tools.device.traces.TraceConfig
 import android.tools.device.traces.TraceConfigs
 
 object TestTraces {
     object LayerTrace {
         private const val ASSET = "layers_trace.winscope"
-        val START_TIME = CrossPlatform.timestamp.from(systemUptimeNanos = 1618663562444)
-        val SLICE_TIME = CrossPlatform.timestamp.from(systemUptimeNanos = 1618715108595)
-        val END_TIME = CrossPlatform.timestamp.from(systemUptimeNanos = 1620770824112)
+        val START_TIME = Timestamps.from(systemUptimeNanos = 1618663562444)
+        val SLICE_TIME = Timestamps.from(systemUptimeNanos = 1618715108595)
+        val END_TIME = Timestamps.from(systemUptimeNanos = 1620770824112)
         val FILE
             get() = readAssetAsFile(ASSET)
     }
 
     object WMTrace {
         private const val ASSET = "wm_trace.winscope"
-        val START_TIME = CrossPlatform.timestamp.from(elapsedNanos = 1618650751245)
-        val SLICE_TIME = CrossPlatform.timestamp.from(elapsedNanos = 1618730362295)
-        val END_TIME = CrossPlatform.timestamp.from(elapsedNanos = 1620756218174)
+        val START_TIME = Timestamps.from(elapsedNanos = 1618650751245)
+        val SLICE_TIME = Timestamps.from(elapsedNanos = 1618730362295)
+        val END_TIME = Timestamps.from(elapsedNanos = 1620756218174)
         val FILE
             get() = readAssetAsFile(ASSET)
     }
 
     object EventLog {
         private const val ASSET = "eventlog.winscope"
-        val START_TIME = CrossPlatform.timestamp.from(unixNanos = 1670594369069951546)
-        val SLICE_TIME = CrossPlatform.timestamp.from(unixNanos = 1670594384516466159)
-        val END_TIME = CrossPlatform.timestamp.from(unixNanos = 1670594389958451901)
+        val START_TIME = Timestamps.from(unixNanos = 1670594369069951546)
+        val SLICE_TIME = Timestamps.from(unixNanos = 1670594384516466159)
+        val END_TIME = Timestamps.from(unixNanos = 1670594389958451901)
         val FILE
             get() = readAssetAsFile(ASSET)
     }
@@ -51,21 +51,12 @@
     object TransactionTrace {
         private const val ASSET = "transactions_trace.winscope"
         val START_TIME =
-            CrossPlatform.timestamp.from(
-                systemUptimeNanos = 1556111744859,
-                elapsedNanos = 1556111744859
-            )
+            Timestamps.from(systemUptimeNanos = 1556111744859, elapsedNanos = 1556111744859)
         val VALID_SLICE_TIME =
-            CrossPlatform.timestamp.from(
-                systemUptimeNanos = 1556147625539,
-                elapsedNanos = 1556147625539
-            )
-        val INVALID_SLICE_TIME = CrossPlatform.timestamp.from(systemUptimeNanos = 1622127714039 + 1)
+            Timestamps.from(systemUptimeNanos = 1556147625539, elapsedNanos = 1556147625539)
+        val INVALID_SLICE_TIME = Timestamps.from(systemUptimeNanos = 1622127714039 + 1)
         val END_TIME =
-            CrossPlatform.timestamp.from(
-                systemUptimeNanos = 1622127714039,
-                elapsedNanos = 1622127714039
-            )
+            Timestamps.from(systemUptimeNanos = 1622127714039, elapsedNanos = 1622127714039)
         val FILE
             get() = readAssetAsFile(ASSET)
     }
@@ -73,32 +64,24 @@
     object TransitionTrace {
         private val WM_ASSET = "wm_transition_trace.winscope"
 
-        private val SHELL_ASSET = "shell_transition_trace.winscope"
+        private const val SHELL_ASSET = "shell_transition_trace.winscope"
 
         val START_TIME =
-            CrossPlatform.timestamp.from(
-                elapsedNanos = 760760231809,
-                systemUptimeNanos = 0,
-                unixNanos = 0
-            )
+            Timestamps.from(elapsedNanos = 760760231809, systemUptimeNanos = 0, unixNanos = 0)
         val VALID_SLICE_TIME =
-            CrossPlatform.timestamp.from(
+            Timestamps.from(
                 elapsedNanos = 2770105426934 - 1000,
                 systemUptimeNanos = 0,
                 unixNanos = 0
             )
         val INVALID_SLICE_TIME =
-            CrossPlatform.timestamp.from(
+            Timestamps.from(
                 elapsedNanos = 2770105426934 + 1,
                 systemUptimeNanos = 0,
                 unixNanos = 0,
             )
         val END_TIME =
-            CrossPlatform.timestamp.from(
-                elapsedNanos = 2770105426934,
-                systemUptimeNanos = 0,
-                unixNanos = 0
-            )
+            Timestamps.from(elapsedNanos = 2770105426934, systemUptimeNanos = 0, unixNanos = 0)
 
         val WM_FILE
             get() = readAssetAsFile(WM_ASSET)
@@ -108,8 +91,8 @@
             get() = listOf(WM_FILE, SHELL_FILE)
     }
 
-    val TIME_5 = CrossPlatform.timestamp.from(5, 5, 5)
-    val TIME_10 = CrossPlatform.timestamp.from(10, 10, 10)
+    val TIME_5 = Timestamps.from(5, 5, 5)
+    val TIME_10 = Timestamps.from(10, 10, 10)
 
     val TEST_TRACE_CONFIG =
         TraceConfigs(
diff --git a/libraries/flicker/test/src/android/tools/Utils.kt b/libraries/flicker/test/src/android/tools/Utils.kt
index 4f2b255..dfe2611 100644
--- a/libraries/flicker/test/src/android/tools/Utils.kt
+++ b/libraries/flicker/test/src/android/tools/Utils.kt
@@ -18,10 +18,10 @@
 
 import android.app.Instrumentation
 import android.content.Context
-import android.tools.common.CrossPlatform
 import android.tools.common.Scenario
 import android.tools.common.ScenarioBuilder
 import android.tools.common.ScenarioImpl
+import android.tools.common.Timestamps
 import android.tools.common.io.Reader
 import android.tools.common.io.ResultArtifactDescriptor
 import android.tools.common.io.RunStatus
@@ -77,9 +77,9 @@
         .withOutputDir(createTempDirectory().toFile())
         .setRunComplete()
 
-internal fun newTestCachedResultWriter() =
+internal fun newTestCachedResultWriter(scenario: Scenario = TEST_SCENARIO) =
     CachedResultWriter()
-        .forScenario(TEST_SCENARIO)
+        .forScenario(scenario)
         .withOutputDir(createTempDirectory().toFile())
         .setRunComplete()
 
@@ -96,8 +96,8 @@
             WindowManagerTraceParser(legacyTrace)
                 .parse(
                     readAsset(relativePath),
-                    CrossPlatform.timestamp.from(elapsedNanos = from),
-                    CrossPlatform.timestamp.from(elapsedNanos = to),
+                    Timestamps.from(elapsedNanos = from),
+                    Timestamps.from(elapsedNanos = to),
                     addInitialEntry,
                     clearCache = false
                 )
diff --git a/libraries/flicker/test/src/android/tools/common/flicker/FlickerServiceResultsCollectorTest.kt b/libraries/flicker/test/src/android/tools/common/flicker/FlickerServiceResultsCollectorTest.kt
index 603f3bb..e72b1cd 100644
--- a/libraries/flicker/test/src/android/tools/common/flicker/FlickerServiceResultsCollectorTest.kt
+++ b/libraries/flicker/test/src/android/tools/common/flicker/FlickerServiceResultsCollectorTest.kt
@@ -19,9 +19,9 @@
 import android.annotation.SuppressLint
 import android.device.collectors.DataRecord
 import android.tools.common.flicker.assertions.AssertionData
+import android.tools.common.flicker.assertions.AssertionResult
+import android.tools.common.flicker.assertions.ScenarioAssertion
 import android.tools.common.flicker.assertions.SubjectsParser
-import android.tools.common.flicker.assertors.AssertionResult
-import android.tools.common.flicker.assertors.AssertionResultImpl
 import android.tools.common.io.Reader
 import android.tools.common.traces.wm.TransitionsTrace
 import android.tools.device.flicker.FlickerServiceResultsCollector
@@ -270,6 +270,20 @@
                     mockFlickerService.detectScenarios(KotlinMockito.any(Reader::class.java))
                 )
                 .thenThrow(RuntimeException("Flicker Service Processing Error"))
+        } else {
+            val mockScenarioInstance = Mockito.mock(ScenarioInstance::class.java)
+            val mockedAssertions =
+                assertionResults.map { assertion ->
+                    val mockScenarioAssertion = Mockito.mock(ScenarioAssertion::class.java)
+                    Mockito.`when`(mockScenarioAssertion.execute()).thenReturn(assertion)
+                    mockScenarioAssertion
+                }
+            Mockito.`when`(mockScenarioInstance.generateAssertions()).thenReturn(mockedAssertions)
+
+            Mockito.`when`(
+                    mockFlickerService.detectScenarios(KotlinMockito.any(Reader::class.java))
+                )
+                .thenReturn(listOf(mockScenarioInstance))
         }
 
         return FlickerServiceResultsCollector(
@@ -282,28 +296,32 @@
 
     companion object {
         val mockSuccessfulAssertionResult =
-            AssertionResultImpl(
-                object : AssertionData {
-                    override val name = "MockPassedAssertion"
-                    override fun checkAssertion(run: SubjectsParser) {
-                        error("Unimplemented - shouldn't be called")
+            object : AssertionResult {
+                override val assertion =
+                    object : AssertionData {
+                        override val name = "MockPassedAssertion"
+                        override fun checkAssertion(run: SubjectsParser) {
+                            error("Unimplemented - shouldn't be called")
+                        }
                     }
-                },
-                assertionError = null,
-                stabilityGroup = AssertionInvocationGroup.BLOCKING
-            )
+                override val assertionError = null
+                override val stabilityGroup = AssertionInvocationGroup.BLOCKING
+                override val passed = true
+            }
 
         val mockFailedAssertionResult =
-            AssertionResultImpl(
-                object : AssertionData {
-                    override val name = "MockFailedAssertion"
-                    override fun checkAssertion(run: SubjectsParser) {
-                        error("Unimplemented - shouldn't be called")
+            object : AssertionResult {
+                override val assertion =
+                    object : AssertionData {
+                        override val name = "MockFailedAssertion"
+                        override fun checkAssertion(run: SubjectsParser) {
+                            error("Unimplemented - shouldn't be called")
+                        }
                     }
-                },
-                assertionError = Throwable("Assertion failed"),
-                stabilityGroup = AssertionInvocationGroup.BLOCKING
-            )
+                override val assertionError = Throwable("Assertion failed")
+                override val stabilityGroup = AssertionInvocationGroup.BLOCKING
+                override val passed = false
+            }
 
         private class SpyDataRecord : DataRecord() {
             val stringMetrics = mutableMapOf<String, String>()
diff --git a/libraries/flicker/test/src/android/tools/common/flicker/FlickerServiceRuleTest.kt b/libraries/flicker/test/src/android/tools/common/flicker/FlickerServiceRuleTest.kt
index 9eb3110..2aabca7 100644
--- a/libraries/flicker/test/src/android/tools/common/flicker/FlickerServiceRuleTest.kt
+++ b/libraries/flicker/test/src/android/tools/common/flicker/FlickerServiceRuleTest.kt
@@ -17,9 +17,8 @@
 package android.tools.common.flicker
 
 import android.tools.common.flicker.assertions.AssertionData
+import android.tools.common.flicker.assertions.AssertionResult
 import android.tools.common.flicker.assertions.SubjectsParser
-import android.tools.common.flicker.assertors.AssertionResult
-import android.tools.common.flicker.assertors.AssertionResultImpl
 import android.tools.device.flicker.IFlickerServiceResultsCollector
 import android.tools.device.flicker.isShellTransitionsEnabled
 import android.tools.device.flicker.legacy.runner.Consts
@@ -197,18 +196,19 @@
     }
 
     companion object {
-        fun mockFailureAssertionResult(error: Throwable): AssertionResult {
-            return AssertionResultImpl(
-                object : AssertionData {
-                    override val name = "MockAssertion"
-                    override fun checkAssertion(run: SubjectsParser) {
-                        error("Unimplemented - shouldn't be called")
+        fun mockFailureAssertionResult(error: Throwable) =
+            object : AssertionResult {
+                override val assertion =
+                    object : AssertionData {
+                        override val name = "MockAssertion"
+                        override fun checkAssertion(run: SubjectsParser) {
+                            error("Unimplemented - shouldn't be called")
+                        }
                     }
-                },
-                assertionError = error,
-                stabilityGroup = AssertionInvocationGroup.BLOCKING
-            )
-        }
+                override val assertionError = error
+                override val stabilityGroup = AssertionInvocationGroup.BLOCKING
+                override val passed = false
+            }
 
         @ClassRule @JvmField val ENV_CLEANUP = CleanFlickerEnvironmentRule()
     }
diff --git a/libraries/flicker/test/src/android/tools/common/flicker/FlickerServiceTest.kt b/libraries/flicker/test/src/android/tools/common/flicker/FlickerServiceTest.kt
index 8def28c..558473a 100644
--- a/libraries/flicker/test/src/android/tools/common/flicker/FlickerServiceTest.kt
+++ b/libraries/flicker/test/src/android/tools/common/flicker/FlickerServiceTest.kt
@@ -16,25 +16,18 @@
 
 package android.tools.common.flicker
 
-import android.app.Instrumentation
-import android.tools.common.flicker.assertions.AssertionData
 import android.tools.common.flicker.extractors.ScenarioExtractor
 import android.tools.common.io.Reader
-import android.tools.device.flicker.FlickerServiceImpl
 import android.tools.rules.CleanFlickerEnvironmentRule
-import androidx.test.platform.app.InstrumentationRegistry
 import org.junit.ClassRule
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runners.MethodSorters
 import org.mockito.Mockito
 
-/**
- * Contains [FlickerServiceImpl] tests. To run this test: `atest FlickerLibTest:FlickerServiceTest`
- */
+/** Contains [FlickerService] tests. To run this test: `atest FlickerLibTest:FlickerServiceTest` */
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 class FlickerServiceTest {
-    private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
 
     @Test
     fun generatesAssertionsFromExtractedScenarios() {
@@ -47,7 +40,7 @@
             .thenReturn(listOf(scenarioInstance))
 
         val service =
-            FlickerServiceImpl(
+            FlickerService(
                 scenarioExtractor = mockScenarioExtractor,
             )
         service.detectScenarios(mockReader)
@@ -61,12 +54,11 @@
         val mockScenarioExtractor = Mockito.mock(ScenarioExtractor::class.java)
 
         val scenarioInstance = Mockito.mock(ScenarioInstance::class.java)
-        val assertions = listOf(Mockito.mock(AssertionData::class.java))
 
         Mockito.`when`(mockScenarioExtractor.extract(mockReader))
             .thenReturn(listOf(scenarioInstance))
 
-        val service = FlickerServiceImpl(scenarioExtractor = mockScenarioExtractor)
+        val service = FlickerService(scenarioExtractor = mockScenarioExtractor)
         service.detectScenarios(mockReader)
 
         Mockito.verify(mockScenarioExtractor).extract(mockReader)
diff --git a/libraries/flicker/test/src/android/tools/device/flicker/assertions/AssertionDataFactoryTest.kt b/libraries/flicker/test/src/android/tools/common/flicker/assertions/AssertionDataFactoryTest.kt
similarity index 88%
rename from libraries/flicker/test/src/android/tools/device/flicker/assertions/AssertionDataFactoryTest.kt
rename to libraries/flicker/test/src/android/tools/common/flicker/assertions/AssertionDataFactoryTest.kt
index b3ccd74..9d54102 100644
--- a/libraries/flicker/test/src/android/tools/device/flicker/assertions/AssertionDataFactoryTest.kt
+++ b/libraries/flicker/test/src/android/tools/common/flicker/assertions/AssertionDataFactoryTest.kt
@@ -14,12 +14,9 @@
  * limitations under the License.
  */
 
-package android.tools.device.flicker.assertions
+package android.tools.common.flicker.assertions
 
 import android.tools.common.Tag
-import android.tools.common.flicker.assertions.AssertionDataFactory
-import android.tools.common.flicker.assertions.AssertionDataImpl
-import android.tools.common.flicker.assertions.AssertionStateDataFactory
 import android.tools.common.flicker.subject.layers.LayerTraceEntrySubject
 import android.tools.common.flicker.subject.layers.LayersTraceSubject
 import android.tools.common.flicker.subject.wm.WindowManagerStateSubject
diff --git a/libraries/flicker/test/src/android/tools/device/flicker/assertions/AssertionStateDataFactoryTest.kt b/libraries/flicker/test/src/android/tools/common/flicker/assertions/AssertionStateDataFactoryTest.kt
similarity index 78%
rename from libraries/flicker/test/src/android/tools/device/flicker/assertions/AssertionStateDataFactoryTest.kt
rename to libraries/flicker/test/src/android/tools/common/flicker/assertions/AssertionStateDataFactoryTest.kt
index 8466dfe..52b82b0 100644
--- a/libraries/flicker/test/src/android/tools/device/flicker/assertions/AssertionStateDataFactoryTest.kt
+++ b/libraries/flicker/test/src/android/tools/common/flicker/assertions/AssertionStateDataFactoryTest.kt
@@ -14,11 +14,9 @@
  * limitations under the License.
  */
 
-package android.tools.device.flicker.assertions
+package android.tools.common.flicker.assertions
 
 import android.tools.common.Tag
-import android.tools.common.flicker.assertions.AssertionDataImpl
-import android.tools.common.flicker.assertions.AssertionStateDataFactory
 import android.tools.common.flicker.subject.events.EventLogSubject
 import android.tools.common.flicker.subject.layers.LayerTraceEntrySubject
 import android.tools.common.flicker.subject.wm.WindowManagerStateSubject
@@ -40,17 +38,17 @@
     @Test
     open fun checkBuildsStartAssertion() {
         validate(
-            wmAssertionFactory.createStartStateAssertion {},
+            wmAssertionFactory.createStartStateAssertion(name = "") {},
             WindowManagerStateSubject::class,
             Tag.START
         )
         validate(
-            layersAssertionFactory.createStartStateAssertion {},
+            layersAssertionFactory.createStartStateAssertion(name = "") {},
             LayerTraceEntrySubject::class,
             Tag.START
         )
         validate(
-            eventLogAssertionFactory.createStartStateAssertion {},
+            eventLogAssertionFactory.createStartStateAssertion(name = "") {},
             EventLogSubject::class,
             Tag.START
         )
@@ -59,17 +57,17 @@
     @Test
     open fun checkBuildsEndAssertion() {
         validate(
-            wmAssertionFactory.createEndStateAssertion {},
+            wmAssertionFactory.createEndStateAssertion(name = "") {},
             WindowManagerStateSubject::class,
             Tag.END
         )
         validate(
-            layersAssertionFactory.createEndStateAssertion {},
+            layersAssertionFactory.createEndStateAssertion(name = "") {},
             LayerTraceEntrySubject::class,
             Tag.END
         )
         validate(
-            eventLogAssertionFactory.createEndStateAssertion {},
+            eventLogAssertionFactory.createEndStateAssertion(name = "") {},
             EventLogSubject::class,
             Tag.END
         )
@@ -78,16 +76,20 @@
     @Test
     open fun checkBuildsTagAssertion() {
         validate(
-            wmAssertionFactory.createTagAssertion(TAG) {},
+            wmAssertionFactory.createTagAssertion(name = "", TAG) {},
             WindowManagerStateSubject::class,
             TAG
         )
         validate(
-            layersAssertionFactory.createTagAssertion(TAG) {},
+            layersAssertionFactory.createTagAssertion(name = "", TAG) {},
             LayerTraceEntrySubject::class,
             TAG
         )
-        validate(eventLogAssertionFactory.createTagAssertion(TAG) {}, EventLogSubject::class, TAG)
+        validate(
+            eventLogAssertionFactory.createTagAssertion(name = "", TAG) {},
+            EventLogSubject::class,
+            TAG
+        )
     }
 
     protected fun validate(
diff --git a/libraries/flicker/test/src/android/tools/common/flicker/assertions/AssertionsCheckerTest.kt b/libraries/flicker/test/src/android/tools/common/flicker/assertions/AssertionsCheckerTest.kt
index d5ebf7f..edc0a21 100644
--- a/libraries/flicker/test/src/android/tools/common/flicker/assertions/AssertionsCheckerTest.kt
+++ b/libraries/flicker/test/src/android/tools/common/flicker/assertions/AssertionsCheckerTest.kt
@@ -17,9 +17,9 @@
 package android.tools.common.flicker.assertions
 
 import android.tools.assertFail
-import android.tools.common.CrossPlatform
 import android.tools.common.ITraceEntry
 import android.tools.common.Timestamp
+import android.tools.common.Timestamps
 import android.tools.common.flicker.subject.FlickerSubject
 import android.tools.rules.CleanFlickerEnvironmentRule
 import org.junit.ClassRule
@@ -135,7 +135,7 @@
     }
 
     private class SimpleEntrySubject(private val entry: SimpleEntry) : FlickerSubject() {
-        override val timestamp = CrossPlatform.timestamp.empty()
+        override val timestamp = Timestamps.empty()
 
         fun isData42() = apply { check { "data is 42" }.that(entry.mData).isEqual(42) }
 
@@ -162,7 +162,7 @@
         private fun getTestEntries(vararg data: Int): List<SimpleEntrySubject> =
             data.indices.map {
                 SimpleEntrySubject(
-                    SimpleEntry(CrossPlatform.timestamp.from(elapsedNanos = it.toLong()), data[it])
+                    SimpleEntry(Timestamps.from(elapsedNanos = it.toLong()), data[it])
                 )
             }
         @ClassRule @JvmField val ENV_CLEANUP = CleanFlickerEnvironmentRule()
diff --git a/libraries/flicker/test/src/android/tools/common/flicker/assertions/CompoundAssertionTest.kt b/libraries/flicker/test/src/android/tools/common/flicker/assertions/CompoundAssertionTest.kt
new file mode 100644
index 0000000..0725e3e
--- /dev/null
+++ b/libraries/flicker/test/src/android/tools/common/flicker/assertions/CompoundAssertionTest.kt
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.tools.common.flicker.assertions
+
+import org.junit.Assert
+import org.junit.Test
+
+class CompoundAssertionTest {
+    @Test
+    fun correctNameSingle() {
+        val assertion = assertion1()
+        Assert.assertEquals(NAME, assertion.name)
+    }
+
+    @Test
+    fun correctNamePair() {
+        val assertion = assertion1()
+        Assert.assertEquals(NAME, assertion.name)
+        assertion.add({}, OTHER, optional = false)
+        Assert.assertEquals("$NAME and $OTHER", assertion.name)
+    }
+
+    @Test
+    fun correctNameTriple() {
+        val assertion = assertion1()
+
+        Assert.assertEquals(NAME, assertion.name)
+        assertion.add({}, OTHER, optional = false)
+        assertion.add({}, OTHER, optional = false)
+        Assert.assertEquals("$NAME and $OTHER and $OTHER", assertion.name)
+    }
+
+    @Test
+    fun executes() {
+        var count = 0
+        val assertion = CompoundAssertion<String>({ count++ }, NAME, optional = false)
+        assertion.invoke("")
+        Assert.assertEquals(1, count)
+        assertion.add({ count++ }, NAME, optional = false)
+        assertion.invoke("")
+        Assert.assertEquals(3, count)
+    }
+
+    @Test
+    fun assertionsPass() {
+        assertion1().invoke("")
+    }
+
+    @Test(expected = IllegalStateException::class)
+    fun oneAssertionFail() {
+        val assertion = assertion1()
+        assertion.add({ error("EXPECTED") }, OTHER, optional = false)
+        assertion.invoke("")
+    }
+
+    @Test
+    fun oneOptionalAssertionFail() {
+        val assertion = assertion1()
+        assertion.add({ error("EXPECTED") }, OTHER, optional = true)
+        assertion1().invoke("")
+    }
+
+    companion object {
+        private const val NAME = "Name"
+        private const val OTHER = "Other"
+
+        private fun assertion1(optional: Boolean = false) =
+            CompoundAssertion<String>({}, NAME, optional)
+    }
+}
diff --git a/libraries/flicker/test/src/android/tools/common/flicker/config/QuickswitchTest.kt b/libraries/flicker/test/src/android/tools/common/flicker/config/QuickswitchTest.kt
index 7d40897..a633f9c 100644
--- a/libraries/flicker/test/src/android/tools/common/flicker/config/QuickswitchTest.kt
+++ b/libraries/flicker/test/src/android/tools/common/flicker/config/QuickswitchTest.kt
@@ -26,6 +26,7 @@
 import android.tools.device.flicker.Utils
 import android.tools.device.traces.getDefaultFlickerOutputDir
 import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.rules.CleanFlickerEnvironmentRule
 import android.view.Display
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.launcher3.tapl.LauncherInstrumentation
@@ -52,7 +53,7 @@
         browser.launchViaIntent(wmHelper)
         camera.launchViaIntent(wmHelper)
 
-        val scenario = ScenarioBuilder().forClass("Quickswitch").build()
+        val scenario = ScenarioBuilder().forClass("QuickSwitch").build()
         val reader =
             Utils.captureTrace(scenario, getDefaultFlickerOutputDir()) {
                 tapl.launchedAppState.quickSwitchToPreviousApp()
@@ -68,13 +69,14 @@
         browser.exit()
         camera.exit()
 
-        val quickswitchExtractor = Quickswitch().extractor
-        val scenarioInstances = quickswitchExtractor.extract(reader)
+        val quickSwitchExtractor = Quickswitch().extractor
+        val scenarioInstances = quickSwitchExtractor.extract(reader)
 
         Truth.assertThat(scenarioInstances).hasSize(1)
     }
 
     companion object {
-        @ClassRule @JvmField val navigationModeRule = NavigationModeRule(NavBar.MODE_GESTURAL.value)
+        @ClassRule @JvmField val NAV_MODE_RULE = NavigationModeRule(NavBar.MODE_GESTURAL.value)
+        @ClassRule @JvmField val ENV_CLEANUP = CleanFlickerEnvironmentRule()
     }
 }
diff --git a/libraries/flicker/test/src/android/tools/common/flicker/extractor/ShellTransitionScenarioExtractorTest.kt b/libraries/flicker/test/src/android/tools/common/flicker/extractor/ShellTransitionScenarioExtractorTest.kt
index e4eca46..62ef10a 100644
--- a/libraries/flicker/test/src/android/tools/common/flicker/extractor/ShellTransitionScenarioExtractorTest.kt
+++ b/libraries/flicker/test/src/android/tools/common/flicker/extractor/ShellTransitionScenarioExtractorTest.kt
@@ -16,7 +16,7 @@
 
 package android.tools.common.flicker.extractor
 
-import android.tools.common.CrossPlatform
+import android.tools.common.Timestamps
 import android.tools.common.flicker.config.FaasScenarioType
 import android.tools.common.flicker.config.FlickerServiceConfig
 import android.tools.common.flicker.extractors.ITransitionMatcher
@@ -88,7 +88,7 @@
         val layersTrace = scenarios.first().reader.readLayersTrace() ?: error("Missing layer trace")
         Truth.assertThat(layersTrace.entries.first().timestamp)
             .isEqualTo(
-                CrossPlatform.timestamp.from(
+                Timestamps.from(
                     unixNanos = 1682433275759078118,
                     systemUptimeNanos = 2766599071189,
                     elapsedNanos = 0
@@ -96,7 +96,7 @@
             )
         Truth.assertThat(layersTrace.entries.first().timestamp)
             .isEqualTo(
-                CrossPlatform.timestamp.from(
+                Timestamps.from(
                     unixNanos = 1682433275759078118,
                     systemUptimeNanos = 2766599071189,
                     elapsedNanos = 0
diff --git a/libraries/flicker/test/src/android/tools/common/flicker/subject/events/EventLogSubjectTest.kt b/libraries/flicker/test/src/android/tools/common/flicker/subject/events/EventLogSubjectTest.kt
index ea9cb6e..a93e2c6 100644
--- a/libraries/flicker/test/src/android/tools/common/flicker/subject/events/EventLogSubjectTest.kt
+++ b/libraries/flicker/test/src/android/tools/common/flicker/subject/events/EventLogSubjectTest.kt
@@ -16,7 +16,7 @@
 
 package android.tools.common.flicker.subject.events
 
-import android.tools.common.CrossPlatform
+import android.tools.common.Timestamps
 import android.tools.common.flicker.assertions.SubjectsParser
 import android.tools.common.traces.events.EventLog
 import android.tools.common.traces.events.FocusEvent
@@ -39,7 +39,7 @@
                     EventLog(
                         arrayOf(
                             FocusEvent(
-                                CrossPlatform.timestamp.from(unixNanos = 0),
+                                Timestamps.from(unixNanos = 0),
                                 "WinB",
                                 FocusEvent.Type.GAINED,
                                 "test",
@@ -48,7 +48,7 @@
                                 0
                             ),
                             FocusEvent(
-                                CrossPlatform.timestamp.from(unixNanos = 0),
+                                Timestamps.from(unixNanos = 0),
                                 "test WinA window",
                                 FocusEvent.Type.LOST,
                                 "test",
@@ -57,7 +57,7 @@
                                 0
                             ),
                             FocusEvent(
-                                CrossPlatform.timestamp.from(unixNanos = 0),
+                                Timestamps.from(unixNanos = 0),
                                 "WinB",
                                 FocusEvent.Type.LOST,
                                 "test",
@@ -66,7 +66,7 @@
                                 0
                             ),
                             FocusEvent(
-                                CrossPlatform.timestamp.from(unixNanos = 0),
+                                Timestamps.from(unixNanos = 0),
                                 "test WinC",
                                 FocusEvent.Type.GAINED,
                                 "test",
diff --git a/libraries/flicker/test/src/android/tools/common/flicker/subject/region/RegionSubjectTest.kt b/libraries/flicker/test/src/android/tools/common/flicker/subject/region/RegionSubjectTest.kt
index a5d0350..e6b6ca3 100644
--- a/libraries/flicker/test/src/android/tools/common/flicker/subject/region/RegionSubjectTest.kt
+++ b/libraries/flicker/test/src/android/tools/common/flicker/subject/region/RegionSubjectTest.kt
@@ -17,7 +17,7 @@
 package android.tools.common.flicker.subject.region
 
 import android.tools.assertFail
-import android.tools.common.CrossPlatform
+import android.tools.common.Timestamps
 import android.tools.common.datatypes.Rect
 import android.tools.common.datatypes.Region
 import android.tools.rules.CleanFlickerEnvironmentRule
@@ -31,16 +31,16 @@
 class RegionSubjectTest {
     private fun expectAllFailPositionChange(expectedMessage: String, rectA: Rect, rectB: Rect) {
         assertFail(expectedMessage) {
-            RegionSubject(rectA, timestamp = CrossPlatform.timestamp.empty()).isHigher(rectB)
+            RegionSubject(rectA, timestamp = Timestamps.empty()).isHigher(rectB)
         }
         assertFail(expectedMessage) {
-            RegionSubject(rectA, timestamp = CrossPlatform.timestamp.empty()).isHigherOrEqual(rectB)
+            RegionSubject(rectA, timestamp = Timestamps.empty()).isHigherOrEqual(rectB)
         }
         assertFail(expectedMessage) {
-            RegionSubject(rectA, timestamp = CrossPlatform.timestamp.empty()).isLower(rectB)
+            RegionSubject(rectA, timestamp = Timestamps.empty()).isLower(rectB)
         }
         assertFail(expectedMessage) {
-            RegionSubject(rectA, timestamp = CrossPlatform.timestamp.empty()).isLowerOrEqual(rectB)
+            RegionSubject(rectA, timestamp = Timestamps.empty()).isLowerOrEqual(rectB)
         }
     }
 
@@ -48,13 +48,13 @@
     fun detectPositionChangeHigher() {
         val rectA = Rect.from(left = 0, top = 0, right = 1, bottom = 1)
         val rectB = Rect.from(left = 0, top = 1, right = 1, bottom = 2)
-        RegionSubject(rectA, timestamp = CrossPlatform.timestamp.empty()).isHigher(rectB)
-        RegionSubject(rectA, timestamp = CrossPlatform.timestamp.empty()).isHigherOrEqual(rectB)
+        RegionSubject(rectA, timestamp = Timestamps.empty()).isHigher(rectB)
+        RegionSubject(rectA, timestamp = Timestamps.empty()).isHigherOrEqual(rectB)
         assertFail(MSG_ERROR_TOP_POSITION) {
-            RegionSubject(rectA, timestamp = CrossPlatform.timestamp.empty()).isLower(rectB)
+            RegionSubject(rectA, timestamp = Timestamps.empty()).isLower(rectB)
         }
         assertFail(MSG_ERROR_TOP_POSITION) {
-            RegionSubject(rectA, timestamp = CrossPlatform.timestamp.empty()).isLowerOrEqual(rectB)
+            RegionSubject(rectA, timestamp = Timestamps.empty()).isLowerOrEqual(rectB)
         }
     }
 
@@ -62,13 +62,13 @@
     fun detectPositionChangeLower() {
         val rectA = Rect.from(left = 0, top = 2, right = 1, bottom = 3)
         val rectB = Rect.from(left = 0, top = 0, right = 1, bottom = 1)
-        RegionSubject(rectA, timestamp = CrossPlatform.timestamp.empty()).isLower(rectB)
-        RegionSubject(rectA, timestamp = CrossPlatform.timestamp.empty()).isLowerOrEqual(rectB)
+        RegionSubject(rectA, timestamp = Timestamps.empty()).isLower(rectB)
+        RegionSubject(rectA, timestamp = Timestamps.empty()).isLowerOrEqual(rectB)
         assertFail(MSG_ERROR_TOP_POSITION) {
-            RegionSubject(rectA, timestamp = CrossPlatform.timestamp.empty()).isHigher(rectB)
+            RegionSubject(rectA, timestamp = Timestamps.empty()).isHigher(rectB)
         }
         assertFail(MSG_ERROR_TOP_POSITION) {
-            RegionSubject(rectA, timestamp = CrossPlatform.timestamp.empty()).isHigherOrEqual(rectB)
+            RegionSubject(rectA, timestamp = Timestamps.empty()).isHigherOrEqual(rectB)
         }
     }
 
@@ -76,13 +76,13 @@
     fun detectPositionChangeEqualHigherLower() {
         val rectA = Rect.from(left = 0, top = 1, right = 1, bottom = 0)
         val rectB = Rect.from(left = 1, top = 1, right = 2, bottom = 0)
-        RegionSubject(rectA, timestamp = CrossPlatform.timestamp.empty()).isHigherOrEqual(rectB)
-        RegionSubject(rectA, timestamp = CrossPlatform.timestamp.empty()).isLowerOrEqual(rectB)
+        RegionSubject(rectA, timestamp = Timestamps.empty()).isHigherOrEqual(rectB)
+        RegionSubject(rectA, timestamp = Timestamps.empty()).isLowerOrEqual(rectB)
         assertFail(MSG_ERROR_TOP_POSITION) {
-            RegionSubject(rectA, timestamp = CrossPlatform.timestamp.empty()).isHigher(rectB)
+            RegionSubject(rectA, timestamp = Timestamps.empty()).isHigher(rectB)
         }
         assertFail(MSG_ERROR_TOP_POSITION) {
-            RegionSubject(rectA, timestamp = CrossPlatform.timestamp.empty()).isLower(rectB)
+            RegionSubject(rectA, timestamp = Timestamps.empty()).isLower(rectB)
         }
     }
 
@@ -99,10 +99,10 @@
     fun detectCoversAtLeast() {
         val rectA = Rect.from(left = 1, top = 1, right = 2, bottom = 2)
         val rectB = Rect.from(left = 0, top = 0, right = 2, bottom = 2)
-        RegionSubject(rectA, timestamp = CrossPlatform.timestamp.empty()).coversAtLeast(rectA)
-        RegionSubject(rectB, timestamp = CrossPlatform.timestamp.empty()).coversAtLeast(rectA)
+        RegionSubject(rectA, timestamp = Timestamps.empty()).coversAtLeast(rectA)
+        RegionSubject(rectB, timestamp = Timestamps.empty()).coversAtLeast(rectA)
         assertFail("SkRegion((0,0,2,1)(0,1,1,2))") {
-            RegionSubject(rectA, timestamp = CrossPlatform.timestamp.empty()).coversAtLeast(rectB)
+            RegionSubject(rectA, timestamp = Timestamps.empty()).coversAtLeast(rectB)
         }
     }
 
@@ -110,10 +110,10 @@
     fun detectCoversAtMost() {
         val rectA = Rect.from(left = 1, top = 1, right = 2, bottom = 2)
         val rectB = Rect.from(left = 0, top = 0, right = 2, bottom = 2)
-        RegionSubject(rectA, timestamp = CrossPlatform.timestamp.empty()).coversAtMost(rectA)
-        RegionSubject(rectA, timestamp = CrossPlatform.timestamp.empty()).coversAtMost(rectB)
+        RegionSubject(rectA, timestamp = Timestamps.empty()).coversAtMost(rectA)
+        RegionSubject(rectA, timestamp = Timestamps.empty()).coversAtMost(rectB)
         assertFail("SkRegion((0,0,2,1)(0,1,1,2))") {
-            RegionSubject(rectB, timestamp = CrossPlatform.timestamp.empty()).coversAtMost(rectA)
+            RegionSubject(rectB, timestamp = Timestamps.empty()).coversAtMost(rectA)
         }
     }
 
@@ -121,9 +121,9 @@
     fun detectCoversExactly() {
         val rectA = Rect.from(left = 1, top = 1, right = 2, bottom = 2)
         val rectB = Rect.from(left = 0, top = 0, right = 2, bottom = 2)
-        RegionSubject(rectA, timestamp = CrossPlatform.timestamp.empty()).coversExactly(rectA)
+        RegionSubject(rectA, timestamp = Timestamps.empty()).coversExactly(rectA)
         assertFail("SkRegion((0,0,2,1)(0,1,1,2))") {
-            RegionSubject(rectA, timestamp = CrossPlatform.timestamp.empty()).coversExactly(rectB)
+            RegionSubject(rectA, timestamp = Timestamps.empty()).coversExactly(rectB)
         }
     }
 
@@ -132,10 +132,10 @@
         val rectA = Rect.from(left = 1, top = 1, right = 2, bottom = 2)
         val rectB = Rect.from(left = 0, top = 0, right = 2, bottom = 2)
         val rectC = Rect.from(left = 2, top = 2, right = 3, bottom = 3)
-        RegionSubject(rectA, timestamp = CrossPlatform.timestamp.empty()).overlaps(rectB)
-        RegionSubject(rectB, timestamp = CrossPlatform.timestamp.empty()).overlaps(rectA)
+        RegionSubject(rectA, timestamp = Timestamps.empty()).overlaps(rectB)
+        RegionSubject(rectB, timestamp = Timestamps.empty()).overlaps(rectA)
         assertFail("should overlap with ${Region.from(rectC)}") {
-            RegionSubject(rectA, timestamp = CrossPlatform.timestamp.empty()).overlaps(rectC)
+            RegionSubject(rectA, timestamp = Timestamps.empty()).overlaps(rectC)
         }
     }
 
@@ -144,10 +144,10 @@
         val rectA = Rect.from(left = 1, top = 1, right = 2, bottom = 2)
         val rectB = Rect.from(left = 2, top = 2, right = 3, bottom = 3)
         val rectC = Rect.from(left = 0, top = 0, right = 2, bottom = 2)
-        RegionSubject(rectA, timestamp = CrossPlatform.timestamp.empty()).notOverlaps(rectB)
-        RegionSubject(rectB, timestamp = CrossPlatform.timestamp.empty()).notOverlaps(rectA)
+        RegionSubject(rectA, timestamp = Timestamps.empty()).notOverlaps(rectB)
+        RegionSubject(rectB, timestamp = Timestamps.empty()).notOverlaps(rectA)
         assertFail("SkRegion((1,1,2,2))") {
-            RegionSubject(rectA, timestamp = CrossPlatform.timestamp.empty()).notOverlaps(rectC)
+            RegionSubject(rectA, timestamp = Timestamps.empty()).notOverlaps(rectC)
         }
     }
 
diff --git a/libraries/flicker/test/src/android/tools/common/traces/ITraceTest.kt b/libraries/flicker/test/src/android/tools/common/traces/ITraceTest.kt
index e351c48..23b535b 100644
--- a/libraries/flicker/test/src/android/tools/common/traces/ITraceTest.kt
+++ b/libraries/flicker/test/src/android/tools/common/traces/ITraceTest.kt
@@ -17,10 +17,10 @@
 package android.tools.common.traces
 
 import android.tools.assertThrows
-import android.tools.common.CrossPlatform
 import android.tools.common.ITrace
 import android.tools.common.ITraceEntry
 import android.tools.common.Timestamp
+import android.tools.common.Timestamps
 import com.google.common.truth.Truth
 import org.junit.Test
 
@@ -28,22 +28,17 @@
 class ITraceTest {
     @Test
     fun getEntryExactlyAtTest() {
-        val entry1 = SimpleTraceEntry(CrossPlatform.timestamp.from(1, 1, 1))
-        val entry2 = SimpleTraceEntry(CrossPlatform.timestamp.from(5, 5, 5))
-        val entry3 = SimpleTraceEntry(CrossPlatform.timestamp.from(25, 25, 25))
+        val entry1 = SimpleTraceEntry(Timestamps.from(1, 1, 1))
+        val entry2 = SimpleTraceEntry(Timestamps.from(5, 5, 5))
+        val entry3 = SimpleTraceEntry(Timestamps.from(25, 25, 25))
         val trace = SimpleTrace(arrayOf(entry1, entry2, entry3))
 
-        Truth.assertThat(trace.getEntryExactlyAt(CrossPlatform.timestamp.from(1, 1, 1)))
-            .isEqualTo(entry1)
-        Truth.assertThat(trace.getEntryExactlyAt(CrossPlatform.timestamp.from(5, 5, 5)))
-            .isEqualTo(entry2)
-        Truth.assertThat(trace.getEntryExactlyAt(CrossPlatform.timestamp.from(25, 25, 25)))
-            .isEqualTo(entry3)
+        Truth.assertThat(trace.getEntryExactlyAt(Timestamps.from(1, 1, 1))).isEqualTo(entry1)
+        Truth.assertThat(trace.getEntryExactlyAt(Timestamps.from(5, 5, 5))).isEqualTo(entry2)
+        Truth.assertThat(trace.getEntryExactlyAt(Timestamps.from(25, 25, 25))).isEqualTo(entry3)
 
         Truth.assertThat(
-                assertThrows<Throwable> {
-                    trace.getEntryExactlyAt(CrossPlatform.timestamp.from(6, 6, 6))
-                }
+                assertThrows<Throwable> { trace.getEntryExactlyAt(Timestamps.from(6, 6, 6)) }
             )
             .hasMessageThat()
             .contains("does not exist")
@@ -51,24 +46,20 @@
 
     @Test
     fun getEntryAtTest() {
-        val entry1 = SimpleTraceEntry(CrossPlatform.timestamp.from(2, 2, 2))
-        val entry2 = SimpleTraceEntry(CrossPlatform.timestamp.from(5, 5, 5))
-        val entry3 = SimpleTraceEntry(CrossPlatform.timestamp.from(25, 25, 25))
+        val entry1 = SimpleTraceEntry(Timestamps.from(2, 2, 2))
+        val entry2 = SimpleTraceEntry(Timestamps.from(5, 5, 5))
+        val entry3 = SimpleTraceEntry(Timestamps.from(25, 25, 25))
         val trace = SimpleTrace(arrayOf(entry1, entry2, entry3))
 
-        Truth.assertThat(trace.getEntryAt(CrossPlatform.timestamp.from(2, 2, 2))).isEqualTo(entry1)
-        Truth.assertThat(trace.getEntryAt(CrossPlatform.timestamp.from(5, 5, 5))).isEqualTo(entry2)
-        Truth.assertThat(trace.getEntryAt(CrossPlatform.timestamp.from(25, 25, 25)))
-            .isEqualTo(entry3)
+        Truth.assertThat(trace.getEntryAt(Timestamps.from(2, 2, 2))).isEqualTo(entry1)
+        Truth.assertThat(trace.getEntryAt(Timestamps.from(5, 5, 5))).isEqualTo(entry2)
+        Truth.assertThat(trace.getEntryAt(Timestamps.from(25, 25, 25))).isEqualTo(entry3)
 
-        Truth.assertThat(trace.getEntryAt(CrossPlatform.timestamp.from(4, 4, 4))).isEqualTo(entry1)
-        Truth.assertThat(trace.getEntryAt(CrossPlatform.timestamp.from(6, 6, 6))).isEqualTo(entry2)
-        Truth.assertThat(trace.getEntryAt(CrossPlatform.timestamp.from(100, 100, 100)))
-            .isEqualTo(entry3)
+        Truth.assertThat(trace.getEntryAt(Timestamps.from(4, 4, 4))).isEqualTo(entry1)
+        Truth.assertThat(trace.getEntryAt(Timestamps.from(6, 6, 6))).isEqualTo(entry2)
+        Truth.assertThat(trace.getEntryAt(Timestamps.from(100, 100, 100))).isEqualTo(entry3)
 
-        Truth.assertThat(
-                assertThrows<Throwable> { trace.getEntryAt(CrossPlatform.timestamp.from(1, 1, 1)) }
-            )
+        Truth.assertThat(assertThrows<Throwable> { trace.getEntryAt(Timestamps.from(1, 1, 1)) })
             .hasMessageThat()
             .contains("No entry at or before timestamp")
     }
@@ -80,7 +71,7 @@
             startTimestamp: Timestamp,
             endTimestamp: Timestamp
         ): ITrace<ITraceEntry> {
-            TODO("Not yet implemented")
+            error("Not yet implemented")
         }
     }
 }
diff --git a/libraries/flicker/test/src/android/tools/common/traces/events/CujTraceTest.kt b/libraries/flicker/test/src/android/tools/common/traces/events/CujTraceTest.kt
index 8776114..2d9ae53 100644
--- a/libraries/flicker/test/src/android/tools/common/traces/events/CujTraceTest.kt
+++ b/libraries/flicker/test/src/android/tools/common/traces/events/CujTraceTest.kt
@@ -16,7 +16,7 @@
 
 package android.tools.common.traces.events
 
-import android.tools.common.CrossPlatform
+import android.tools.common.Timestamps
 import android.tools.rules.CleanFlickerEnvironmentRule
 import com.google.common.truth.Truth
 import org.junit.ClassRule
@@ -153,7 +153,7 @@
         tag: String? = null
     ): CujEvent {
         return CujEvent(
-            CrossPlatform.timestamp.from(unixNanos = timestamp),
+            Timestamps.from(unixNanos = timestamp),
             cuj,
             0,
             "root",
diff --git a/libraries/flicker/test/src/android/tools/common/traces/surfaceflinger/LayerTraceEntryBuilderTest.kt b/libraries/flicker/test/src/android/tools/common/traces/surfaceflinger/LayerTraceEntryBuilderTest.kt
index 250b03c..b22f792 100644
--- a/libraries/flicker/test/src/android/tools/common/traces/surfaceflinger/LayerTraceEntryBuilderTest.kt
+++ b/libraries/flicker/test/src/android/tools/common/traces/surfaceflinger/LayerTraceEntryBuilderTest.kt
@@ -16,7 +16,7 @@
 
 package android.tools.common.traces.surfaceflinger
 
-import android.tools.common.CrossPlatform
+import android.tools.common.Timestamps
 import android.tools.common.datatypes.ActiveBuffer
 import android.tools.common.datatypes.Color
 import android.tools.common.datatypes.Rect
@@ -51,8 +51,7 @@
         Truth.assertThat(entry.elapsedTimestamp).isEqualTo(100)
         Truth.assertThat(entry.clockTimestamp).isEqualTo(600)
 
-        Truth.assertThat(entry.timestamp.elapsedNanos)
-            .isEqualTo(CrossPlatform.timestamp.empty().elapsedNanos)
+        Truth.assertThat(entry.timestamp.elapsedNanos).isEqualTo(Timestamps.empty().elapsedNanos)
         Truth.assertThat(entry.timestamp.systemUptimeNanos).isEqualTo(100)
         Truth.assertThat(entry.timestamp.unixNanos).isEqualTo(600)
     }
@@ -69,11 +68,9 @@
         Truth.assertThat(entry.elapsedTimestamp).isEqualTo(100)
         Truth.assertThat(entry.clockTimestamp).isEqualTo(null)
 
-        Truth.assertThat(entry.timestamp.elapsedNanos)
-            .isEqualTo(CrossPlatform.timestamp.empty().elapsedNanos)
+        Truth.assertThat(entry.timestamp.elapsedNanos).isEqualTo(Timestamps.empty().elapsedNanos)
         Truth.assertThat(entry.timestamp.systemUptimeNanos).isEqualTo(100)
-        Truth.assertThat(entry.timestamp.unixNanos)
-            .isEqualTo(CrossPlatform.timestamp.empty().unixNanos)
+        Truth.assertThat(entry.timestamp.unixNanos).isEqualTo(Timestamps.empty().unixNanos)
     }
 
     @Test
diff --git a/libraries/flicker/test/src/android/tools/common/traces/surfaceflinger/LayersTraceEntryTest.kt b/libraries/flicker/test/src/android/tools/common/traces/surfaceflinger/LayersTraceEntryTest.kt
index ff7ae89..758c418 100644
--- a/libraries/flicker/test/src/android/tools/common/traces/surfaceflinger/LayersTraceEntryTest.kt
+++ b/libraries/flicker/test/src/android/tools/common/traces/surfaceflinger/LayersTraceEntryTest.kt
@@ -20,7 +20,7 @@
 import android.tools.assertThatErrorContainsDebugInfo
 import android.tools.assertThrows
 import android.tools.common.Cache
-import android.tools.common.CrossPlatform
+import android.tools.common.Timestamps
 import android.tools.common.flicker.subject.layers.LayersTraceSubject
 import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.getLayerTraceReaderFromAsset
@@ -68,7 +68,7 @@
         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
         val visibleLayers =
             trace
-                .getEntryExactlyAt(CrossPlatform.timestamp.from(systemUptimeNanos = 90480846872160))
+                .getEntryExactlyAt(Timestamps.from(systemUptimeNanos = 90480846872160))
                 .visibleLayers
         val msg = "Visible Layers:\n" + visibleLayers.joinToString("\n") { "\t" + it.name }
         Truth.assertWithMessage(msg).that(visibleLayers).asList().hasSize(6)
@@ -87,7 +87,7 @@
         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
         val visibleLayers =
             trace
-                .getEntryExactlyAt(CrossPlatform.timestamp.from(systemUptimeNanos = 90493757372977))
+                .getEntryExactlyAt(Timestamps.from(systemUptimeNanos = 90493757372977))
                 .visibleLayers
         val msg = "Visible Layers:\n" + visibleLayers.joinToString("\n") { "\t" + it.name }
         Truth.assertWithMessage(msg).that(visibleLayers).asList().hasSize(7)
@@ -107,7 +107,7 @@
         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
         val visibleLayers =
             trace
-                .getEntryExactlyAt(CrossPlatform.timestamp.from(systemUptimeNanos = 90488463619533))
+                .getEntryExactlyAt(Timestamps.from(systemUptimeNanos = 90488463619533))
                 .visibleLayers
         val msg = "Visible Layers:\n" + visibleLayers.joinToString("\n") { "\t" + it.name }
         Truth.assertWithMessage(msg).that(visibleLayers).asList().hasSize(10)
@@ -164,8 +164,7 @@
         val reader =
             getLayerTraceReaderFromAsset("layers_trace_backcolorsurface.pb", legacyTrace = true)
         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
-        val entry =
-            trace.getEntryExactlyAt(CrossPlatform.timestamp.from(systemUptimeNanos = 131954021476))
+        val entry = trace.getEntryExactlyAt(Timestamps.from(systemUptimeNanos = 131954021476))
         Truth.assertWithMessage("$layerName should not be visible")
             .that(entry.visibleLayers.map { it.name })
             .doesNotContain(layerName)
@@ -224,8 +223,7 @@
                 vSyncId = 123,
                 _rootLayers = emptyArray()
             )
-        Truth.assertThat(entry.timestamp.elapsedNanos)
-            .isEqualTo(CrossPlatform.timestamp.empty().elapsedNanos)
+        Truth.assertThat(entry.timestamp.elapsedNanos).isEqualTo(Timestamps.empty().elapsedNanos)
         Truth.assertThat(entry.timestamp.systemUptimeNanos).isEqualTo(100)
         Truth.assertThat(entry.timestamp.unixNanos).isEqualTo(600)
 
@@ -239,11 +237,9 @@
                 vSyncId = 123,
                 _rootLayers = emptyArray()
             )
-        Truth.assertThat(entry.timestamp.elapsedNanos)
-            .isEqualTo(CrossPlatform.timestamp.empty().elapsedNanos)
+        Truth.assertThat(entry.timestamp.elapsedNanos).isEqualTo(Timestamps.empty().elapsedNanos)
         Truth.assertThat(entry.timestamp.systemUptimeNanos).isEqualTo(100)
-        Truth.assertThat(entry.timestamp.unixNanos)
-            .isEqualTo(CrossPlatform.timestamp.empty().unixNanos)
+        Truth.assertThat(entry.timestamp.unixNanos).isEqualTo(Timestamps.empty().unixNanos)
     }
 
     companion object {
diff --git a/libraries/flicker/test/src/android/tools/common/traces/surfaceflinger/LayersTraceTest.kt b/libraries/flicker/test/src/android/tools/common/traces/surfaceflinger/LayersTraceTest.kt
index 624a846..0a30796 100644
--- a/libraries/flicker/test/src/android/tools/common/traces/surfaceflinger/LayersTraceTest.kt
+++ b/libraries/flicker/test/src/android/tools/common/traces/surfaceflinger/LayersTraceTest.kt
@@ -19,7 +19,7 @@
 import android.tools.assertThatErrorContainsDebugInfo
 import android.tools.assertThrows
 import android.tools.common.Cache
-import android.tools.common.CrossPlatform
+import android.tools.common.Timestamps
 import android.tools.common.flicker.subject.layers.LayersTraceSubject
 import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.getLayerTraceReaderFromAsset
@@ -68,10 +68,7 @@
     fun canTestLayerOccludedByAppLayerHasVisibleRegion() {
         val reader = getLayerTraceReaderFromAsset("layers_trace_occluded.pb", legacyTrace = true)
         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
-        val entry =
-            trace.getEntryExactlyAt(
-                CrossPlatform.timestamp.from(systemUptimeNanos = 1700382131522L)
-            )
+        val entry = trace.getEntryExactlyAt(Timestamps.from(systemUptimeNanos = 1700382131522L))
         val component =
             ComponentNameMatcher("", "com.android.server.wm.flicker.testapp.SimpleActivity#0")
         val layer = entry.getLayerWithBuffer(component)
@@ -99,10 +96,7 @@
         val component = ComponentNameMatcher("", layerName)
         val reader = getLayerTraceReaderFromAsset("layers_trace_occluded.pb", legacyTrace = true)
         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
-        val entry =
-            trace.getEntryExactlyAt(
-                CrossPlatform.timestamp.from(systemUptimeNanos = 1700382131522L)
-            )
+        val entry = trace.getEntryExactlyAt(Timestamps.from(systemUptimeNanos = 1700382131522L))
         val layer = entry.getLayerWithBuffer(component)
         val occludedBy = layer?.occludedBy ?: emptyArray()
         val partiallyOccludedBy = layer?.partiallyOccludedBy ?: emptyArray()
@@ -135,13 +129,13 @@
                 legacyTrace = false
             )
         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
-        val matchingEntry = trace.getFirstEntryWithOnDisplayAfter(CrossPlatform.timestamp.min())
+        val matchingEntry = trace.getFirstEntryWithOnDisplayAfter(Timestamps.min())
 
         Truth.assertThat(matchingEntry.timestamp)
-            .isEqualTo(CrossPlatform.timestamp.from(null, 20143030557279, 1685030549975607247))
+            .isEqualTo(Timestamps.from(null, 20143030557279, 1685030549975607247))
 
         try {
-            trace.getFirstEntryWithOnDisplayAfter(CrossPlatform.timestamp.max())
+            trace.getFirstEntryWithOnDisplayAfter(Timestamps.max())
         } catch (e: Throwable) {
             Truth.assertThat(e).hasMessageThat().contains("No entry after")
         }
@@ -155,13 +149,13 @@
                 legacyTrace = false
             )
         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
-        val matchingEntry = trace.getLastEntryWithOnDisplayBefore(CrossPlatform.timestamp.max())
+        val matchingEntry = trace.getLastEntryWithOnDisplayBefore(Timestamps.max())
 
         Truth.assertThat(matchingEntry.timestamp)
-            .isEqualTo(CrossPlatform.timestamp.from(null, 20147964614573, 1685030554909664541))
+            .isEqualTo(Timestamps.from(null, 20147964614573, 1685030554909664541))
 
         try {
-            trace.getLastEntryWithOnDisplayBefore(CrossPlatform.timestamp.min())
+            trace.getLastEntryWithOnDisplayBefore(Timestamps.min())
         } catch (e: Throwable) {
             Truth.assertThat(e).hasMessageThat().contains("No entry before")
         }
diff --git a/libraries/flicker/test/src/android/tools/common/traces/wm/TransitionTest.kt b/libraries/flicker/test/src/android/tools/common/traces/wm/TransitionTest.kt
index 22c94d6..e4ca552 100644
--- a/libraries/flicker/test/src/android/tools/common/traces/wm/TransitionTest.kt
+++ b/libraries/flicker/test/src/android/tools/common/traces/wm/TransitionTest.kt
@@ -16,7 +16,7 @@
 
 package android.tools.common.traces.wm
 
-import android.tools.common.CrossPlatform
+import android.tools.common.Timestamps
 import android.tools.common.traces.surfaceflinger.Transaction
 import android.tools.common.traces.surfaceflinger.TransactionsTrace
 import android.tools.common.traces.surfaceflinger.TransactionsTraceEntry
@@ -35,8 +35,8 @@
                 id = 1,
                 wmData =
                     WmTransitionData(
-                        createTime = CrossPlatform.timestamp.from(10),
-                        sendTime = CrossPlatform.timestamp.from(20),
+                        createTime = Timestamps.from(10),
+                        sendTime = Timestamps.from(20),
                     ),
             )
 
@@ -45,7 +45,7 @@
                 id = 1,
                 shellData =
                     ShellTransitionData(
-                        dispatchTime = CrossPlatform.timestamp.from(22),
+                        dispatchTime = Timestamps.from(22),
                         handler = "DefaultHandler"
                     ),
             )
@@ -55,7 +55,7 @@
                 id = 1,
                 wmData =
                     WmTransitionData(
-                        finishTime = CrossPlatform.timestamp.from(40),
+                        finishTime = Timestamps.from(40),
                     ),
             )
 
@@ -78,10 +78,10 @@
                 id = 1,
                 wmData =
                     WmTransitionData(
-                        createTime = CrossPlatform.timestamp.from(10),
-                        sendTime = CrossPlatform.timestamp.from(20),
-                        abortTime = CrossPlatform.timestamp.from(30),
-                        finishTime = CrossPlatform.timestamp.from(40),
+                        createTime = Timestamps.from(10),
+                        sendTime = Timestamps.from(20),
+                        abortTime = Timestamps.from(30),
+                        finishTime = Timestamps.from(40),
                         startTransactionId = "1",
                         finishTransactionId = "2",
                         type = TransitionType.CLOSE,
@@ -89,10 +89,10 @@
                     ),
                 shellData =
                     ShellTransitionData(
-                        dispatchTime = CrossPlatform.timestamp.from(21),
-                        mergeRequestTime = CrossPlatform.timestamp.from(22),
-                        mergeTime = CrossPlatform.timestamp.from(23),
-                        abortTime = CrossPlatform.timestamp.from(24),
+                        dispatchTime = Timestamps.from(21),
+                        mergeRequestTime = Timestamps.from(22),
+                        mergeTime = Timestamps.from(23),
+                        abortTime = Timestamps.from(24),
                         handler = "Handler1",
                         mergedInto = 1,
                     )
@@ -103,10 +103,10 @@
                 id = 1,
                 wmData =
                     WmTransitionData(
-                        createTime = CrossPlatform.timestamp.from(100),
-                        sendTime = CrossPlatform.timestamp.from(200),
-                        abortTime = CrossPlatform.timestamp.from(300),
-                        finishTime = CrossPlatform.timestamp.from(400),
+                        createTime = Timestamps.from(100),
+                        sendTime = Timestamps.from(200),
+                        abortTime = Timestamps.from(300),
+                        finishTime = Timestamps.from(400),
                         startTransactionId = "10",
                         finishTransactionId = "20",
                         type = TransitionType.OPEN,
@@ -114,10 +114,10 @@
                     ),
                 shellData =
                     ShellTransitionData(
-                        dispatchTime = CrossPlatform.timestamp.from(210),
-                        mergeRequestTime = CrossPlatform.timestamp.from(220),
-                        mergeTime = CrossPlatform.timestamp.from(230),
-                        abortTime = CrossPlatform.timestamp.from(240),
+                        dispatchTime = Timestamps.from(210),
+                        mergeRequestTime = Timestamps.from(220),
+                        mergeTime = Timestamps.from(230),
+                        abortTime = Timestamps.from(240),
                         handler = "Handler2",
                         mergedInto = 10,
                     )
@@ -148,7 +148,7 @@
                 id = 1,
                 wmData =
                     WmTransitionData(
-                        sendTime = CrossPlatform.timestamp.from(1),
+                        sendTime = Timestamps.from(1),
                         startTransactionId = transactionId.toString()
                     )
             )
@@ -167,7 +167,7 @@
         val transactionsTraceEntry =
             arrayOf(
                 TransactionsTraceEntry(
-                    timestamp = CrossPlatform.timestamp.from(1),
+                    timestamp = Timestamps.from(1),
                     vSyncId = 1,
                     transactions = transactions
                 )
@@ -187,7 +187,7 @@
                 id = 1,
                 wmData =
                     WmTransitionData(
-                        sendTime = CrossPlatform.timestamp.from(1),
+                        sendTime = Timestamps.from(1),
                         startTransactionId = transactionId.toString()
                     )
             )
@@ -206,7 +206,7 @@
         val transactionsTraceEntry =
             arrayOf(
                 TransactionsTraceEntry(
-                    timestamp = CrossPlatform.timestamp.from(1),
+                    timestamp = Timestamps.from(1),
                     vSyncId = 1,
                     transactions = transactions
                 )
@@ -226,7 +226,7 @@
                 id = 1,
                 wmData =
                     WmTransitionData(
-                        sendTime = CrossPlatform.timestamp.from(1),
+                        sendTime = Timestamps.from(1),
                         startTransactionId = transactionId.toString()
                     )
             )
@@ -245,7 +245,7 @@
         val transactionsTraceEntry =
             arrayOf(
                 TransactionsTraceEntry(
-                    timestamp = CrossPlatform.timestamp.from(1),
+                    timestamp = Timestamps.from(1),
                     vSyncId = 1,
                     transactions = transactions
                 )
@@ -265,7 +265,7 @@
                 id = 1,
                 wmData =
                     WmTransitionData(
-                        sendTime = CrossPlatform.timestamp.from(1),
+                        sendTime = Timestamps.from(1),
                         finishTransactionId = transactionId.toString()
                     )
             )
@@ -284,7 +284,7 @@
         val transactionsTraceEntry =
             arrayOf(
                 TransactionsTraceEntry(
-                    timestamp = CrossPlatform.timestamp.from(1),
+                    timestamp = Timestamps.from(1),
                     vSyncId = 1,
                     transactions = transactions
                 )
@@ -304,7 +304,7 @@
                 id = 1,
                 wmData =
                     WmTransitionData(
-                        sendTime = CrossPlatform.timestamp.from(1),
+                        sendTime = Timestamps.from(1),
                         finishTransactionId = transactionId.toString()
                     )
             )
@@ -323,7 +323,7 @@
         val transactionsTraceEntry =
             arrayOf(
                 TransactionsTraceEntry(
-                    timestamp = CrossPlatform.timestamp.from(1),
+                    timestamp = Timestamps.from(1),
                     vSyncId = 1,
                     transactions = transactions
                 )
@@ -343,7 +343,7 @@
                 id = 1,
                 wmData =
                     WmTransitionData(
-                        sendTime = CrossPlatform.timestamp.from(1),
+                        sendTime = Timestamps.from(1),
                         finishTransactionId = transactionId.toString()
                     )
             )
@@ -362,7 +362,7 @@
         val transactionsTraceEntry =
             arrayOf(
                 TransactionsTraceEntry(
-                    timestamp = CrossPlatform.timestamp.from(1),
+                    timestamp = Timestamps.from(1),
                     vSyncId = 1,
                     transactions = transactions
                 )
diff --git a/libraries/flicker/test/src/android/tools/common/traces/wm/TransitionsTraceTest.kt b/libraries/flicker/test/src/android/tools/common/traces/wm/TransitionsTraceTest.kt
index 0fd2a5f..674b26d 100644
--- a/libraries/flicker/test/src/android/tools/common/traces/wm/TransitionsTraceTest.kt
+++ b/libraries/flicker/test/src/android/tools/common/traces/wm/TransitionsTraceTest.kt
@@ -16,7 +16,7 @@
 
 package android.tools.common.traces.wm
 
-import android.tools.common.CrossPlatform
+import android.tools.common.Timestamps
 import com.google.common.truth.Truth
 import org.junit.FixMethodOrder
 import org.junit.Test
@@ -37,15 +37,15 @@
                             id = 1,
                             wmData =
                                 WmTransitionData(
-                                    createTime = CrossPlatform.timestamp.from(10),
-                                    sendTime = CrossPlatform.timestamp.from(20),
+                                    createTime = Timestamps.from(10),
+                                    sendTime = Timestamps.from(20),
                                 ),
                         ),
                         Transition(
                             id = 1,
                             shellData =
                                 ShellTransitionData(
-                                    dispatchTime = CrossPlatform.timestamp.from(22),
+                                    dispatchTime = Timestamps.from(22),
                                     handler = "DefaultHandler"
                                 ),
                         ),
@@ -53,7 +53,7 @@
                             id = 1,
                             wmData =
                                 WmTransitionData(
-                                    finishTime = CrossPlatform.timestamp.from(40),
+                                    finishTime = Timestamps.from(40),
                                 ),
                         )
                     )
diff --git a/libraries/flicker/test/src/android/tools/common/traces/wm/WindowManagerStateTest.kt b/libraries/flicker/test/src/android/tools/common/traces/wm/WindowManagerStateTest.kt
index f933a13..7be97c9 100644
--- a/libraries/flicker/test/src/android/tools/common/traces/wm/WindowManagerStateTest.kt
+++ b/libraries/flicker/test/src/android/tools/common/traces/wm/WindowManagerStateTest.kt
@@ -16,7 +16,7 @@
 
 package android.tools.common.traces.wm
 
-import android.tools.common.CrossPlatform
+import android.tools.common.Timestamps
 import android.tools.rules.CleanFlickerEnvironmentRule
 import com.google.common.truth.Truth
 import org.junit.ClassRule
@@ -93,8 +93,7 @@
                     )
             )
         Truth.assertThat(entry.timestamp.elapsedNanos).isEqualTo(100)
-        Truth.assertThat(entry.timestamp.unixNanos)
-            .isEqualTo(CrossPlatform.timestamp.empty().unixNanos)
+        Truth.assertThat(entry.timestamp.unixNanos).isEqualTo(Timestamps.empty().unixNanos)
     }
 
     companion object {
diff --git a/libraries/flicker/test/src/android/tools/common/traces/wm/WindowManagerTraceEntryBuilderTest.kt b/libraries/flicker/test/src/android/tools/common/traces/wm/WindowManagerTraceEntryBuilderTest.kt
index e7cb46b..1aac859 100644
--- a/libraries/flicker/test/src/android/tools/common/traces/wm/WindowManagerTraceEntryBuilderTest.kt
+++ b/libraries/flicker/test/src/android/tools/common/traces/wm/WindowManagerTraceEntryBuilderTest.kt
@@ -16,7 +16,7 @@
 
 package android.tools.common.traces.wm
 
-import android.tools.common.CrossPlatform
+import android.tools.common.Timestamps
 import android.tools.rules.CleanFlickerEnvironmentRule
 import com.google.common.truth.Truth
 import org.junit.ClassRule
@@ -65,7 +65,7 @@
 
         Truth.assertThat(entry.timestamp.elapsedNanos).isEqualTo(100)
         Truth.assertThat(entry.timestamp.systemUptimeNanos)
-            .isEqualTo(CrossPlatform.timestamp.empty().systemUptimeNanos)
+            .isEqualTo(Timestamps.empty().systemUptimeNanos)
         Truth.assertThat(entry.timestamp.unixNanos).isEqualTo(600)
     }
 
@@ -88,9 +88,8 @@
 
         Truth.assertThat(entry.timestamp.elapsedNanos).isEqualTo(100)
         Truth.assertThat(entry.timestamp.systemUptimeNanos)
-            .isEqualTo(CrossPlatform.timestamp.empty().systemUptimeNanos)
-        Truth.assertThat(entry.timestamp.unixNanos)
-            .isEqualTo(CrossPlatform.timestamp.empty().unixNanos)
+            .isEqualTo(Timestamps.empty().systemUptimeNanos)
+        Truth.assertThat(entry.timestamp.unixNanos).isEqualTo(Timestamps.empty().unixNanos)
     }
 
     companion object {
diff --git a/libraries/flicker/test/src/android/tools/common/traces/wm/WindowManagerTraceTest.kt b/libraries/flicker/test/src/android/tools/common/traces/wm/WindowManagerTraceTest.kt
index c2a0b10..be008f5 100644
--- a/libraries/flicker/test/src/android/tools/common/traces/wm/WindowManagerTraceTest.kt
+++ b/libraries/flicker/test/src/android/tools/common/traces/wm/WindowManagerTraceTest.kt
@@ -17,7 +17,7 @@
 package android.tools.common.traces.wm
 
 import android.tools.common.Cache
-import android.tools.common.CrossPlatform
+import android.tools.common.Timestamps
 import android.tools.getWmTraceReaderFromAsset
 import android.tools.rules.CleanFlickerEnvironmentRule
 import com.google.common.truth.Truth.assertThat
@@ -47,9 +47,7 @@
     @Test
     fun canDetectAppWindow() {
         val appWindows =
-            trace
-                .getEntryExactlyAt(CrossPlatform.timestamp.from(elapsedNanos = 9213763541297L))
-                .appWindows
+            trace.getEntryExactlyAt(Timestamps.from(elapsedNanos = 9213763541297L)).appWindows
         assertWithMessage("Unable to detect app windows").that(appWindows.size).isEqualTo(2)
     }
 
@@ -112,8 +110,7 @@
 
     @Test
     fun canDetectValidState() {
-        val entry =
-            trace.getEntryExactlyAt(CrossPlatform.timestamp.from(elapsedNanos = 9213763541297))
+        val entry = trace.getEntryExactlyAt(Timestamps.from(elapsedNanos = 9213763541297))
         assertWithMessage("${entry.timestamp}: ${entry.getIsIncompleteReason()}")
             .that(entry.isIncomplete())
             .isFalse()
@@ -121,8 +118,7 @@
 
     @Test
     fun canDetectInvalidState() {
-        val entry =
-            trace.getEntryExactlyAt(CrossPlatform.timestamp.from(elapsedNanos = 9215511235586))
+        val entry = trace.getEntryExactlyAt(Timestamps.from(elapsedNanos = 9215511235586))
         assertWithMessage("${entry.timestamp}: ${entry.getIsIncompleteReason()}")
             .that(entry.isIncomplete())
             .isTrue()
diff --git a/libraries/flicker/test/src/android/tools/device/flicker/assertions/ArtifactAssertionRunnerTest.kt b/libraries/flicker/test/src/android/tools/device/flicker/assertions/ArtifactAssertionRunnerTest.kt
index 87db6e2..eb97514 100644
--- a/libraries/flicker/test/src/android/tools/device/flicker/assertions/ArtifactAssertionRunnerTest.kt
+++ b/libraries/flicker/test/src/android/tools/device/flicker/assertions/ArtifactAssertionRunnerTest.kt
@@ -17,11 +17,9 @@
 package android.tools.device.flicker.assertions
 
 import android.tools.assertExceptionMessage
-import android.tools.common.Tag
-import android.tools.common.flicker.assertions.AssertionDataImpl
+import android.tools.common.flicker.assertions.AssertionData
 import android.tools.common.flicker.assertions.Consts
-import android.tools.common.flicker.subject.FlickerSubject
-import android.tools.common.flicker.subject.events.EventLogSubject
+import android.tools.common.flicker.assertions.SubjectsParser
 import android.tools.common.io.RunStatus
 import android.tools.device.traces.deleteIfExists
 import android.tools.device.traces.io.IResultData
@@ -128,8 +126,13 @@
     }
 
     companion object {
-        private fun newAssertionData(assertion: (FlickerSubject) -> Unit) =
-            AssertionDataImpl(name = "", Tag.ALL, EventLogSubject::class, assertion)
+        private fun newAssertionData(assertion: () -> Unit) =
+            object : AssertionData {
+                override val name = ""
+                override fun checkAssertion(run: SubjectsParser) {
+                    assertion.invoke()
+                }
+            }
 
         private fun newResultReaderWithEmptySubject(): IResultData {
             val writer = newTestResultWriter()
diff --git a/libraries/flicker/test/src/android/tools/device/flicker/datastore/Consts.kt b/libraries/flicker/test/src/android/tools/device/flicker/datastore/Consts.kt
index 6c33db8..9847568 100644
--- a/libraries/flicker/test/src/android/tools/device/flicker/datastore/Consts.kt
+++ b/libraries/flicker/test/src/android/tools/device/flicker/datastore/Consts.kt
@@ -16,7 +16,7 @@
 
 package android.tools.device.flicker.datastore
 
-import android.tools.common.CrossPlatform
+import android.tools.common.Timestamps
 import android.tools.common.io.TransitionTimeRange
 import android.tools.device.traces.io.InMemoryArtifact
 import android.tools.device.traces.io.ResultData
@@ -27,22 +27,14 @@
     internal val TEST_RESULT =
         ResultData(
             _artifact = InMemoryArtifact("TEST_RESULT"),
-            _transitionTimeRange =
-                TransitionTimeRange(
-                    CrossPlatform.timestamp.empty(),
-                    CrossPlatform.timestamp.empty()
-                ),
+            _transitionTimeRange = TransitionTimeRange(Timestamps.empty(), Timestamps.empty()),
             _executionError = null
         )
 
     internal val RESULT_FAILURE =
         ResultData(
             _artifact = InMemoryArtifact("RESULT_FAILURE"),
-            _transitionTimeRange =
-                TransitionTimeRange(
-                    CrossPlatform.timestamp.empty(),
-                    CrossPlatform.timestamp.empty()
-                ),
+            _transitionTimeRange = TransitionTimeRange(Timestamps.empty(), Timestamps.empty()),
             _executionError = null
         )
 }
diff --git a/libraries/flicker/test/src/android/tools/device/flicker/integration/FullTestRun.kt b/libraries/flicker/test/src/android/tools/device/flicker/integration/FullTestRun.kt
index 0bda133..afd6788 100644
--- a/libraries/flicker/test/src/android/tools/device/flicker/integration/FullTestRun.kt
+++ b/libraries/flicker/test/src/android/tools/device/flicker/integration/FullTestRun.kt
@@ -31,9 +31,8 @@
 import android.tools.device.flicker.junit.FlickerBuilderProvider
 import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
 import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
 import android.tools.device.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.launcher3.tapl.LauncherInstrumentation
@@ -177,15 +176,14 @@
         /**
          * Creates the test configurations.
          *
-         * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+         * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
          * navigation modes.
          */
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): List<FlickerTest> {
-            return FlickerTestFactory.nonRotationTests(
+        fun getParams() =
+            LegacyFlickerTestFactory.nonRotationTests(
                 extraArgs = mapOf(Scenario.FAAS_BLOCKING to true)
             )
-        }
     }
 }
diff --git a/libraries/flicker/test/src/android/tools/device/flicker/junit/FlickerServiceCachedTestCaseTest.kt b/libraries/flicker/test/src/android/tools/device/flicker/junit/FlickerServiceCachedTestCaseTest.kt
index a6611fb..f546089 100644
--- a/libraries/flicker/test/src/android/tools/device/flicker/junit/FlickerServiceCachedTestCaseTest.kt
+++ b/libraries/flicker/test/src/android/tools/device/flicker/junit/FlickerServiceCachedTestCaseTest.kt
@@ -20,9 +20,13 @@
 import android.device.collectors.util.SendToInstrumentation
 import android.tools.assertThrows
 import android.tools.common.flicker.AssertionInvocationGroup
-import android.tools.common.flicker.IFlickerService
-import android.tools.common.flicker.assertors.IAssertionResult
-import android.tools.common.flicker.assertors.IFaasAssertion
+import android.tools.common.flicker.FlickerService
+import android.tools.common.flicker.ScenarioInstance
+import android.tools.common.flicker.assertions.AssertionData
+import android.tools.common.flicker.assertions.AssertionResult
+import android.tools.common.flicker.assertions.ScenarioAssertion
+import android.tools.common.flicker.assertions.SubjectsParser
+import android.tools.common.io.Reader
 import android.tools.device.flicker.FlickerServiceResultsCollector
 import android.tools.utils.KotlinMockito
 import com.google.common.truth.Truth
@@ -33,15 +37,34 @@
 class FlickerServiceCachedTestCaseTest {
     @Test
     fun reportsPassingResultMetric() {
-        val mockAssertion = Mockito.mock(IFaasAssertion::class.java)
-        val mockFlickerService = Mockito.mock(IFlickerService::class.java)
         val decorator = Mockito.mock(IFlickerJUnitDecorator::class.java)
         val mockInstrumentation = Mockito.mock(Instrumentation::class.java)
+        val mockFlickerService = Mockito.mock(FlickerService::class.java)
+        val mockScenarioInstance = Mockito.mock(ScenarioInstance::class.java)
+        val mockScenarioAssertion = Mockito.mock(ScenarioAssertion::class.java)
+        val assertionResult =
+            object : AssertionResult {
+                override val assertion =
+                    object : AssertionData {
+                        override val name = "AssertionName"
+                        override fun checkAssertion(run: SubjectsParser) {
+                            error("Unimplemented - shouldn't be called")
+                        }
+                    }
+                override val assertionError = null
+                override val stabilityGroup = AssertionInvocationGroup.BLOCKING
+                override val passed = true
+            }
+        Mockito.`when`(mockScenarioAssertion.execute()).thenReturn(assertionResult)
+        Mockito.`when`(mockScenarioInstance.generateAssertions())
+            .thenReturn(listOf(mockScenarioAssertion))
+        Mockito.`when`(mockFlickerService.detectScenarios(KotlinMockito.any(Reader::class.java)))
+            .thenReturn(listOf(mockScenarioInstance))
 
+        val mockDescription = Mockito.mock(Description::class.java)
         val test =
             FlickerServiceCachedTestCase(
-                assertion = mockAssertion,
-                flickerService = mockFlickerService,
+                assertion = mockScenarioAssertion,
                 method = InjectedTestCase::class.java.getMethod("execute", Description::class.java),
                 onlyBlocking = false,
                 isLast = false,
@@ -49,26 +72,6 @@
                 instrumentation = mockInstrumentation,
                 paramString = "",
             )
-
-        val assertionResult =
-            object : IAssertionResult {
-                override val assertion =
-                    object : IFaasAssertion {
-                        override val name = "PassingFaasAssertion"
-                        override val stabilityGroup = AssertionInvocationGroup.BLOCKING
-                        override fun evaluate(): IAssertionResult {
-                            TODO("Not implemented")
-                        }
-                    }
-                override val passed = true
-                override val assertionError = null
-            }
-        Mockito.`when`(
-                mockFlickerService.executeAssertion(KotlinMockito.any(IFaasAssertion::class.java))
-            )
-            .thenReturn(assertionResult)
-
-        val mockDescription = Mockito.mock(Description::class.java)
         test.execute(mockDescription)
 
         Mockito.verify(mockInstrumentation)
@@ -77,7 +80,7 @@
                 KotlinMockito.argThat {
                     this.getString(
                         "${FlickerServiceResultsCollector.FAAS_METRICS_PREFIX}::" +
-                            "${assertionResult.assertion.name}"
+                            assertionResult.assertion.name
                     ) == "0"
                 }
             )
@@ -85,15 +88,34 @@
 
     @Test
     fun reportsFailingResultMetric() {
-        val mockAssertion = Mockito.mock(IFaasAssertion::class.java)
-        val mockFlickerService = Mockito.mock(IFlickerService::class.java)
         val decorator = Mockito.mock(IFlickerJUnitDecorator::class.java)
         val mockInstrumentation = Mockito.mock(Instrumentation::class.java)
+        val mockFlickerService = Mockito.mock(FlickerService::class.java)
+        val mockScenarioInstance = Mockito.mock(ScenarioInstance::class.java)
+        val mockScenarioAssertion = Mockito.mock(ScenarioAssertion::class.java)
+        val assertionResult =
+            object : AssertionResult {
+                override val assertion =
+                    object : AssertionData {
+                        override val name = "AssertionName"
+                        override fun checkAssertion(run: SubjectsParser) {
+                            error("Unimplemented - shouldn't be called")
+                        }
+                    }
+                override val assertionError = Exception("EXPECTED")
+                override val stabilityGroup = AssertionInvocationGroup.BLOCKING
+                override val passed = false
+            }
+        Mockito.`when`(mockScenarioAssertion.execute()).thenReturn(assertionResult)
+        Mockito.`when`(mockScenarioInstance.generateAssertions())
+            .thenReturn(listOf(mockScenarioAssertion))
+        Mockito.`when`(mockFlickerService.detectScenarios(KotlinMockito.any(Reader::class.java)))
+            .thenReturn(listOf(mockScenarioInstance))
 
+        val mockDescription = Mockito.mock(Description::class.java)
         val test =
             FlickerServiceCachedTestCase(
-                assertion = mockAssertion,
-                flickerService = mockFlickerService,
+                assertion = mockScenarioAssertion,
                 method = InjectedTestCase::class.java.getMethod("execute", Description::class.java),
                 onlyBlocking = false,
                 isLast = false,
@@ -102,28 +124,8 @@
                 paramString = "",
             )
 
-        val assertionResult =
-            object : IAssertionResult {
-                override val assertion =
-                    object : IFaasAssertion {
-                        override val name = "PassingFaasAssertion"
-                        override val stabilityGroup = AssertionInvocationGroup.BLOCKING
-                        override fun evaluate(): IAssertionResult {
-                            TODO("Not implemented")
-                        }
-                    }
-                override val passed = false
-                override val assertionError = Throwable("Some assertion")
-            }
-        Mockito.`when`(
-                mockFlickerService.executeAssertion(KotlinMockito.any(IFaasAssertion::class.java))
-            )
-            .thenReturn(assertionResult)
-
-        val mockDescription = Mockito.mock(Description::class.java)
-
         val failure = assertThrows<Throwable> { test.execute(mockDescription) }
-        Truth.assertThat(failure).hasMessageThat().isEqualTo("Some assertion")
+        Truth.assertThat(failure).hasMessageThat().isEqualTo("EXPECTED")
 
         Mockito.verify(mockInstrumentation)
             .sendStatus(
@@ -131,7 +133,7 @@
                 KotlinMockito.argThat {
                     this.getString(
                         "${FlickerServiceResultsCollector.FAAS_METRICS_PREFIX}::" +
-                            "${assertionResult.assertion.name}"
+                            assertionResult.assertion.name
                     ) == "1"
                 }
             )
diff --git a/libraries/flicker/test/src/android/tools/device/flicker/junit/LegacyFlickerJUnit4ClassRunnerTest.kt b/libraries/flicker/test/src/android/tools/device/flicker/junit/LegacyFlickerJUnit4ClassRunnerTest.kt
index eca8233..716b103 100644
--- a/libraries/flicker/test/src/android/tools/device/flicker/junit/LegacyFlickerJUnit4ClassRunnerTest.kt
+++ b/libraries/flicker/test/src/android/tools/device/flicker/junit/LegacyFlickerJUnit4ClassRunnerTest.kt
@@ -19,14 +19,14 @@
 import android.annotation.SuppressLint
 import android.app.Instrumentation
 import android.platform.test.annotations.FlakyTest
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.device.apphelpers.BrowserAppHelper
 import android.tools.device.flicker.IS_FAAS_ENABLED
 import android.tools.device.flicker.annotation.FlickerServiceCompatible
 import android.tools.device.flicker.isShellTransitionsEnabled
 import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
 import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
 import android.tools.getScenarioTraces
 import android.tools.rules.CleanFlickerEnvironmentRule
 import androidx.test.platform.app.InstrumentationRegistry
@@ -92,7 +92,7 @@
     @Test
     fun runsWithValidFlickerTest() {
         val testClass = TestClass(SimpleFaasTest::class.java)
-        val parameters = FlickerTestFactory.nonRotationTests()
+        val parameters = LegacyFlickerTestFactory.nonRotationTests()
         val test = TestWithParameters("[PARAMS]", testClass, listOf(parameters[0]))
         val runner = createRunner(test)
         runner.run(RunNotifier())
@@ -101,7 +101,7 @@
     @Test
     fun flakyTestsRunWithNoFilter() {
         val testClass = TestClass(SimpleTestWithFlakyTest::class.java)
-        val parameters = FlickerTestFactory.nonRotationTests()
+        val parameters = LegacyFlickerTestFactory.nonRotationTests()
         val test = TestWithParameters("[PARAMS]", testClass, listOf(parameters[0]))
         val runner = createRunner(test)
         flakyTestRuns = 0
@@ -113,7 +113,7 @@
     @Test
     fun canFilterOutFlakyTests() {
         val testClass = TestClass(SimpleTestWithFlakyTest::class.java)
-        val parameters = FlickerTestFactory.nonRotationTests()
+        val parameters = LegacyFlickerTestFactory.nonRotationTests()
         val test = TestWithParameters("[PARAMS]", testClass, listOf(parameters[0]))
         val runner = createRunner(test)
         runner.filter(FLAKY_TEST_FILTER)
@@ -135,7 +135,7 @@
         Assume.assumeTrue(IS_FAAS_ENABLED)
 
         val testClass = TestClass(SimpleFaasTest::class.java)
-        val parameters = FlickerTestFactory.nonRotationTests()
+        val parameters = LegacyFlickerTestFactory.nonRotationTests()
         val test = TestWithParameters("[PARAMS]", testClass, listOf(parameters[0]))
         val runner = createRunner(test)
         val notifier = mock(RunNotifier::class.java)
@@ -205,7 +205,7 @@
 
     private fun checkTestRunReportsExecutionErrors(klass: Class<*>) {
         val testClass = TestClass(klass)
-        val parameters = FlickerTestFactory.nonRotationTests()
+        val parameters = LegacyFlickerTestFactory.nonRotationTests()
         val flickerTest = parameters.first() as LegacyFlickerTest
         val test = TestWithParameters("[PARAMS]", testClass, listOf(flickerTest))
 
@@ -305,7 +305,7 @@
 
     companion object {
         const val TRANSITION_FAILURE_MESSAGE = "Transition execution failed"
-        private val NO_SCENARIO_MESSAGE = "Unable to extract ${LegacyFlickerTest::class.simpleName}"
+        private val NO_SCENARIO_MESSAGE = "Unable to extract ${FlickerTest::class.simpleName}"
 
         val FLAKY_TEST_FILTER =
             object : Filter() {
diff --git a/libraries/flicker/test/src/android/tools/device/flicker/junit/LegacyFlickerServiceDecoratorTest.kt b/libraries/flicker/test/src/android/tools/device/flicker/junit/LegacyFlickerServiceDecoratorTest.kt
index 7c4340b..78f2fcb 100644
--- a/libraries/flicker/test/src/android/tools/device/flicker/junit/LegacyFlickerServiceDecoratorTest.kt
+++ b/libraries/flicker/test/src/android/tools/device/flicker/junit/LegacyFlickerServiceDecoratorTest.kt
@@ -18,6 +18,7 @@
 
 import android.annotation.SuppressLint
 import android.tools.TEST_SCENARIO
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.device.flicker.datastore.DataStore
 import android.tools.device.flicker.isShellTransitionsEnabled
 import android.tools.device.flicker.legacy.FlickerBuilder
@@ -182,7 +183,7 @@
             .that(failure)
             .hasMessageThat()
             .contains(
-                "Constructor should have a parameter of type ${LegacyFlickerTest::class.simpleName}"
+                "Constructor should have a parameter of type ${FlickerTest::class.simpleName}"
             )
     }
 
diff --git a/libraries/flicker/test/src/android/tools/device/flicker/junit/TestUtils.kt b/libraries/flicker/test/src/android/tools/device/flicker/junit/TestUtils.kt
index 368a0b8..53f80a1 100644
--- a/libraries/flicker/test/src/android/tools/device/flicker/junit/TestUtils.kt
+++ b/libraries/flicker/test/src/android/tools/device/flicker/junit/TestUtils.kt
@@ -18,8 +18,8 @@
 
 import android.app.Instrumentation
 import android.tools.common.ScenarioBuilder
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
 import android.tools.device.flicker.legacy.LegacyFlickerTest
 import androidx.test.platform.app.InstrumentationRegistry
 
diff --git a/libraries/flicker/test/src/android/tools/device/flicker/legacy/FlickerTestFactoryTest.kt b/libraries/flicker/test/src/android/tools/device/flicker/legacy/LegacyFlickerTestFactoryTest.kt
similarity index 86%
rename from libraries/flicker/test/src/android/tools/device/flicker/legacy/FlickerTestFactoryTest.kt
rename to libraries/flicker/test/src/android/tools/device/flicker/legacy/LegacyFlickerTestFactoryTest.kt
index 7901ecd..96d6c58 100644
--- a/libraries/flicker/test/src/android/tools/device/flicker/legacy/FlickerTestFactoryTest.kt
+++ b/libraries/flicker/test/src/android/tools/device/flicker/legacy/LegacyFlickerTestFactoryTest.kt
@@ -25,15 +25,15 @@
 import org.junit.runners.MethodSorters
 
 /**
- * Contains [FlickerTestFactory] tests.
+ * Contains [LegacyFlickerTestFactory] tests.
  *
  * To run this test: `atest FlickerLibTest:FlickerTestFactoryRunnerTest`
  */
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class FlickerTestFactoryTest {
+class LegacyFlickerTestFactoryTest {
     @Test
     fun checkBuildTest() {
-        val actual = FlickerTestFactory.nonRotationTests()
+        val actual = LegacyFlickerTestFactory.nonRotationTests()
         Truth.assertWithMessage("Flicker should create tests for 0 and 90 degrees")
             .that(actual)
             .hasSize(4)
@@ -41,7 +41,7 @@
 
     @Test
     fun checkBuildRotationTest() {
-        val actual = FlickerTestFactory.rotationTests()
+        val actual = LegacyFlickerTestFactory.rotationTests()
         Truth.assertWithMessage("Flicker should create tests for 0 and 90 degrees")
             .that(actual)
             .hasSize(4)
@@ -56,7 +56,7 @@
                 Rotation.ROTATION_180,
                 Rotation.ROTATION_270
             )
-        val actual = FlickerTestFactory.rotationTests(supportedRotations = rotations)
+        val actual = LegacyFlickerTestFactory.rotationTests(supportedRotations = rotations)
         // Should have config for each rotation pair
         Truth.assertWithMessage("Flicker should create tests for 0/90/180/270 degrees")
             .that(actual)
diff --git a/libraries/flicker/test/src/android/tools/device/flicker/legacy/FlickerTestTest.kt b/libraries/flicker/test/src/android/tools/device/flicker/legacy/LegacyFlickerTestTest.kt
similarity index 95%
rename from libraries/flicker/test/src/android/tools/device/flicker/legacy/FlickerTestTest.kt
rename to libraries/flicker/test/src/android/tools/device/flicker/legacy/LegacyFlickerTestTest.kt
index eb7ac92..14f0120 100644
--- a/libraries/flicker/test/src/android/tools/device/flicker/legacy/FlickerTestTest.kt
+++ b/libraries/flicker/test/src/android/tools/device/flicker/legacy/LegacyFlickerTestTest.kt
@@ -21,6 +21,8 @@
 import android.tools.TestTraces
 import android.tools.assertExceptionMessage
 import android.tools.assertThrows
+import android.tools.common.ScenarioBuilder
+import android.tools.common.flicker.assertions.FlickerTest
 import android.tools.common.io.TraceType
 import android.tools.device.flicker.datastore.CachedResultReader
 import android.tools.device.flicker.datastore.DataStore
@@ -30,13 +32,14 @@
 import android.tools.rules.CleanFlickerEnvironmentRule
 import com.google.common.truth.Truth
 import java.io.File
+import kotlin.io.path.name
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
 
 /** Tests for [FlickerTest] */
 @SuppressLint("VisibleForTests")
-class FlickerTestTest {
+class LegacyFlickerTestTest {
     private var executionCount = 0
     @Rule @JvmField val envCleanup = CleanFlickerEnvironmentRule()
 
@@ -187,9 +190,11 @@
     @Test
     fun doesNotExecuteEventLogWithoutEventLog() {
         val predicate: (FlickerTest) -> Unit = { it.assertEventLog { executionCount++ } }
-        newTestCachedResultWriter().write()
+        val scenarioName = kotlin.io.path.createTempFile().name
+        val scenario = ScenarioBuilder().forClass(scenarioName).build()
+        newTestCachedResultWriter(scenario).write()
         val flickerWrapper = LegacyFlickerTest()
-        flickerWrapper.initialize(TEST_SCENARIO.testClass)
+        flickerWrapper.initialize(scenarioName)
         // Each assertion is executed independently and not cached, only Flicker as a Service
         // assertions are cached
         predicate.invoke(flickerWrapper)
diff --git a/libraries/flicker/test/src/android/tools/device/flicker/legacy/runner/TestUtils.kt b/libraries/flicker/test/src/android/tools/device/flicker/legacy/runner/TestUtils.kt
index 2f50f8e..9aa0f3a 100644
--- a/libraries/flicker/test/src/android/tools/device/flicker/legacy/runner/TestUtils.kt
+++ b/libraries/flicker/test/src/android/tools/device/flicker/legacy/runner/TestUtils.kt
@@ -16,8 +16,8 @@
 
 package android.tools.device.flicker.legacy.runner
 
-import android.tools.common.CrossPlatform
 import android.tools.common.Timestamp
+import android.tools.common.Timestamps
 import android.tools.device.traces.io.IResultData
 import com.google.common.truth.Truth
 
@@ -25,16 +25,16 @@
     internal fun validateTransitionTime(result: IResultData) {
         val startTime = result.transitionTimeRange.start
         val endTime = result.transitionTimeRange.end
-        validateTimeGreaterThan(startTime, "Start time", CrossPlatform.timestamp.min())
-        validateTimeGreaterThan(endTime, "End time", CrossPlatform.timestamp.min())
-        validateTimeGreaterThan(CrossPlatform.timestamp.max(), "End time", endTime)
+        validateTimeGreaterThan(startTime, "Start time", Timestamps.min())
+        validateTimeGreaterThan(endTime, "End time", Timestamps.min())
+        validateTimeGreaterThan(Timestamps.max(), "End time", endTime)
     }
 
     internal fun validateTransitionTimeIsEmpty(result: IResultData) {
         val startTime = result.transitionTimeRange.start
         val endTime = result.transitionTimeRange.end
-        validateEqualTo(startTime, "Start time", CrossPlatform.timestamp.min())
-        validateEqualTo(endTime, "End time", CrossPlatform.timestamp.max())
+        validateEqualTo(startTime, "Start time", Timestamps.min())
+        validateEqualTo(endTime, "End time", Timestamps.max())
     }
 
     private fun validateEqualTo(time: Timestamp, name: String, expectedValue: Timestamp) {
diff --git a/libraries/flicker/test/src/android/tools/device/traces/io/BaseResultReaderTestParseTrace.kt b/libraries/flicker/test/src/android/tools/device/traces/io/BaseResultReaderTestParseTrace.kt
index 7a19a7e..4b5bfb8 100644
--- a/libraries/flicker/test/src/android/tools/device/traces/io/BaseResultReaderTestParseTrace.kt
+++ b/libraries/flicker/test/src/android/tools/device/traces/io/BaseResultReaderTestParseTrace.kt
@@ -19,9 +19,9 @@
 import android.tools.TestTraces
 import android.tools.assertExceptionMessage
 import android.tools.assertThrows
-import android.tools.common.CrossPlatform
 import android.tools.common.ITrace
 import android.tools.common.Timestamp
+import android.tools.common.Timestamps
 import android.tools.common.io.RunStatus
 import android.tools.common.io.TraceType
 import android.tools.device.traces.TRACE_CONFIG_REQUIRE_CHANGES
@@ -109,9 +109,7 @@
     @Test
     fun readTraceAndSliceTraceByTimestampAndFailInvalidSize() {
         val result =
-            setupWriter(newTestResultWriter())
-                .setTransitionEndTime(CrossPlatform.timestamp.min())
-                .write()
+            setupWriter(newTestResultWriter()).setTransitionEndTime(Timestamps.min()).write()
         val reader = ResultReader(result, TRACE_CONFIG_REQUIRE_CHANGES)
         val exception =
             assertThrows<IllegalArgumentException> {
diff --git a/libraries/flicker/test/src/android/tools/device/traces/io/ResultReaderTest.kt b/libraries/flicker/test/src/android/tools/device/traces/io/ResultReaderTest.kt
index 599efe0..5b78da3 100644
--- a/libraries/flicker/test/src/android/tools/device/traces/io/ResultReaderTest.kt
+++ b/libraries/flicker/test/src/android/tools/device/traces/io/ResultReaderTest.kt
@@ -17,7 +17,7 @@
 package android.tools.device.traces.io
 
 import android.tools.assertThrows
-import android.tools.common.CrossPlatform
+import android.tools.common.Timestamps
 import android.tools.common.io.RunStatus
 import android.tools.device.traces.TRACE_CONFIG_REQUIRE_CHANGES
 import android.tools.device.traces.deleteIfExists
@@ -55,8 +55,7 @@
     fun slicedResultKeepsStatusInSync() {
         val data = newTestResultWriter().setRunComplete().write()
         val reader = ResultReader(data, TRACE_CONFIG_REQUIRE_CHANGES)
-        val slicedReader =
-            reader.slice(CrossPlatform.timestamp.min(), CrossPlatform.timestamp.max())
+        val slicedReader = reader.slice(Timestamps.min(), Timestamps.max())
         reader.result.updateStatus(RunStatus.ASSERTION_SUCCESS)
 
         Truth.assertThat(reader.runStatus).isEqualTo(RunStatus.ASSERTION_SUCCESS)
diff --git a/libraries/flicker/test/src/android/tools/device/traces/io/ResultWriterTest.kt b/libraries/flicker/test/src/android/tools/device/traces/io/ResultWriterTest.kt
index 46af4ff..560d5a0 100644
--- a/libraries/flicker/test/src/android/tools/device/traces/io/ResultWriterTest.kt
+++ b/libraries/flicker/test/src/android/tools/device/traces/io/ResultWriterTest.kt
@@ -21,8 +21,8 @@
 import android.tools.TestTraces
 import android.tools.assertExceptionMessage
 import android.tools.assertThrows
-import android.tools.common.CrossPlatform
 import android.tools.common.ScenarioBuilder
+import android.tools.common.Timestamps
 import android.tools.common.io.RunStatus
 import android.tools.common.io.TraceType
 import android.tools.device.traces.TRACE_CONFIG_REQUIRE_CHANGES
@@ -64,10 +64,10 @@
         Truth.assertWithMessage("File exists").that(path.exists()).isTrue()
         Truth.assertWithMessage("Transition start time")
             .that(result.transitionTimeRange.start)
-            .isEqualTo(CrossPlatform.timestamp.min())
+            .isEqualTo(Timestamps.min())
         Truth.assertWithMessage("Transition end time")
             .that(result.transitionTimeRange.end)
-            .isEqualTo(CrossPlatform.timestamp.max())
+            .isEqualTo(Timestamps.max())
         val reader = ResultReader(result, TRACE_CONFIG_REQUIRE_CHANGES)
         Truth.assertWithMessage("File count").that(reader.countFiles()).isEqualTo(0)
     }
diff --git a/libraries/flicker/test/src/android/tools/device/traces/parsers/MockTraceParser.kt b/libraries/flicker/test/src/android/tools/device/traces/parsers/MockTraceParser.kt
index ae65b86..9e21d7b 100644
--- a/libraries/flicker/test/src/android/tools/device/traces/parsers/MockTraceParser.kt
+++ b/libraries/flicker/test/src/android/tools/device/traces/parsers/MockTraceParser.kt
@@ -16,8 +16,8 @@
 
 package android.tools.device.traces.parsers
 
-import android.tools.common.CrossPlatform
 import android.tools.common.Timestamp
+import android.tools.common.Timestamps
 import android.tools.common.parsers.AbstractTraceParser
 import android.tools.common.traces.wm.WindowManagerState
 import android.tools.common.traces.wm.WindowManagerTrace
@@ -36,6 +36,6 @@
     override fun getEntries(input: WindowManagerTrace): List<WindowManagerState> =
         input.entries.toList()
     override fun getTimestamp(entry: WindowManagerState): Timestamp =
-        CrossPlatform.timestamp.from(elapsedNanos = entry.elapsedTimestamp)
+        Timestamps.from(elapsedNanos = entry.elapsedTimestamp)
     override fun onBeforeParse(input: WindowManagerTrace) {}
 }
diff --git a/libraries/flicker/test/src/android/tools/device/traces/parsers/TraceParserTest.kt b/libraries/flicker/test/src/android/tools/device/traces/parsers/TraceParserTest.kt
index 89eb90e..d77004f 100644
--- a/libraries/flicker/test/src/android/tools/device/traces/parsers/TraceParserTest.kt
+++ b/libraries/flicker/test/src/android/tools/device/traces/parsers/TraceParserTest.kt
@@ -16,8 +16,8 @@
 
 package android.tools.device.traces.parsers
 
-import android.tools.common.CrossPlatform
 import android.tools.common.Timestamp
+import android.tools.common.Timestamps
 import android.tools.common.parsers.AbstractTraceParser
 import android.tools.rules.CleanFlickerEnvironmentRule
 import android.tools.utils.MockWindowManagerTraceBuilder
@@ -31,7 +31,7 @@
     @Test
     fun canSliceWithAllBefore() {
         testSliceUsingElapsedTimestamp(
-            CrossPlatform.timestamp.min().elapsedNanos,
+            Timestamps.min().elapsedNanos,
             mockTraceForSliceTests.entries.first().timestamp.elapsedNanos - 1,
             listOf<Long>()
         )
@@ -45,8 +45,8 @@
             MockTraceParser(mockTraceForSliceTests)
                 .parse(
                     mockTraceForSliceTests,
-                    CrossPlatform.timestamp.from(elapsedNanos = from),
-                    CrossPlatform.timestamp.from(elapsedNanos = to),
+                    Timestamps.from(elapsedNanos = from),
+                    Timestamps.from(elapsedNanos = to),
                     addInitialEntry = false
                 )
         Truth.assertThat(splitLayersTraceWithoutInitialEntry.entries).isEmpty()
@@ -55,8 +55,8 @@
             MockTraceParser(mockTraceForSliceTests)
                 .parse(
                     mockTraceForSliceTests,
-                    CrossPlatform.timestamp.from(elapsedNanos = from),
-                    CrossPlatform.timestamp.from(elapsedNanos = to),
+                    Timestamps.from(elapsedNanos = from),
+                    Timestamps.from(elapsedNanos = to),
                     addInitialEntry = true
                 )
         Truth.assertThat(splitLayersTraceWithInitialEntry.entries).asList().hasSize(1)
@@ -247,8 +247,8 @@
             MockTraceParser(mockTraceForSliceTests)
                 .parse(
                     mockTraceForSliceTests,
-                    CrossPlatform.timestamp.from(elapsedNanos = from),
-                    CrossPlatform.timestamp.from(elapsedNanos = to),
+                    Timestamps.from(elapsedNanos = from),
+                    Timestamps.from(elapsedNanos = to),
                     addInitialEntry = false
                 )
         Truth.assertThat(splitLayersTrace.entries.map { it.timestamp.elapsedNanos })
@@ -260,8 +260,8 @@
             MockTraceParser(mockTraceForSliceTests)
                 .parse(
                     mockTraceForSliceTests,
-                    CrossPlatform.timestamp.from(elapsedNanos = from),
-                    CrossPlatform.timestamp.from(elapsedNanos = to),
+                    Timestamps.from(elapsedNanos = from),
+                    Timestamps.from(elapsedNanos = to),
                     addInitialEntry = true
                 )
         Truth.assertThat(splitLayersTraceWithStartEntry.entries.map { it.timestamp.elapsedNanos })
diff --git a/libraries/flicker/test/src/android/tools/device/traces/parsers/WindowManagerStateHelperTest.kt b/libraries/flicker/test/src/android/tools/device/traces/parsers/WindowManagerStateHelperTest.kt
index 54d5e13..dc4fc69 100644
--- a/libraries/flicker/test/src/android/tools/device/traces/parsers/WindowManagerStateHelperTest.kt
+++ b/libraries/flicker/test/src/android/tools/device/traces/parsers/WindowManagerStateHelperTest.kt
@@ -18,8 +18,8 @@
 
 import android.annotation.SuppressLint
 import android.tools.common.Cache
-import android.tools.common.CrossPlatform
 import android.tools.common.Rotation
+import android.tools.common.Timestamps
 import android.tools.common.datatypes.ActiveBuffer
 import android.tools.common.datatypes.Color
 import android.tools.common.datatypes.Matrix33
@@ -342,8 +342,7 @@
         val trace = reader.readWmTrace() ?: error("Unable to read WM trace")
         val initialTimestamp = 69443918698679
         val supplier = trace.asSupplier(startingTimestamp = initialTimestamp)
-        val initialEntry =
-            trace.getEntryExactlyAt(CrossPlatform.timestamp.from(elapsedNanos = initialTimestamp))
+        val initialEntry = trace.getEntryExactlyAt(Timestamps.from(elapsedNanos = initialTimestamp))
         val helper =
             TestWindowManagerStateHelper(
                 initialEntry,
diff --git a/libraries/flicker/test/src/android/tools/rules/InitializeCrossPlatformRule.kt b/libraries/flicker/test/src/android/tools/rules/InitializeCrossPlatformRule.kt
index 24ce067..fbcdae9 100644
--- a/libraries/flicker/test/src/android/tools/rules/InitializeCrossPlatformRule.kt
+++ b/libraries/flicker/test/src/android/tools/rules/InitializeCrossPlatformRule.kt
@@ -18,7 +18,7 @@
 
 import android.tools.common.CrossPlatform
 import android.tools.common.TimestampFactory
-import android.tools.device.traces.ANDROID_LOGGER
+import android.tools.device.AndroidLogger
 import android.tools.device.traces.formatRealTimestamp
 import org.junit.rules.TestRule
 import org.junit.runner.Description
@@ -28,7 +28,7 @@
     override fun apply(base: Statement?, description: Description?): Statement {
         return object : Statement() {
             override fun evaluate() {
-                CrossPlatform.setLogger(ANDROID_LOGGER)
+                CrossPlatform.setLogger(AndroidLogger())
                     .setTimestampFactory(TimestampFactory { formatRealTimestamp(it) })
 
                 base?.evaluate()