Add FaaS assertions

Bug: 270949117
Test: atest FlickerLibTest
Change-Id: I1bc0b1b2a0b25b1ad5f9c2d6c07571ba3970d696
diff --git a/libraries/flicker/src/android/tools/common/datatypes/component/ComponentName.kt b/libraries/flicker/src/android/tools/common/datatypes/component/ComponentName.kt
index d75185c..de61c71 100644
--- a/libraries/flicker/src/android/tools/common/datatypes/component/ComponentName.kt
+++ b/libraries/flicker/src/android/tools/common/datatypes/component/ComponentName.kt
@@ -123,4 +123,22 @@
     fun toLayerNameRegex(): Regex = Regex(".*${Regex.escape(this.toLayerName())}.*")
 
     override fun toString(): String = toShortWindowName()
+
+    companion object {
+        fun fromLayerName(name: String): IComponentName {
+            var packageName = ""
+            var className = ""
+            if (name.contains("/")) {
+                if (name.contains("#")) {
+                    name.removeSuffix("#")
+                }
+                val splitString = name.split('/')
+                packageName = splitString[0]
+                className = splitString[1]
+            } else {
+                className = name
+            }
+            return ComponentName(packageName, className)
+        }
+    }
 }
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 99c9d54..df3a380 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
@@ -24,7 +24,7 @@
  * Checks that the app layer doesn't exist or is invisible at the start of the transition, but is
  * created and/or becomes visible during the transition.
  */
-class AppLayerBecomesInvisible(component: ComponentTemplate) :
+class AppLayerBecomesInvisible(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
     override fun doEvaluate(scenarioInstance: IScenarioInstance, layerSubject: LayersTraceSubject) {
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 7467760..460d410 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
@@ -25,7 +25,7 @@
  * Checks that the app layer doesn't exist or is invisible at the start of the transition, but is
  * created and/or becomes visible during the transition.
  */
-class AppLayerBecomesVisible(component: ComponentTemplate) :
+class AppLayerBecomesVisible(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
     override fun doEvaluate(scenarioInstance: IScenarioInstance, layerSubject: LayersTraceSubject) {
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 6472c2f..c505f76 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
@@ -20,7 +20,7 @@
 import android.tools.common.flicker.assertors.ComponentTemplate
 import android.tools.common.flicker.subject.layers.LayersTraceSubject
 
-class AppLayerCoversFullScreenAtEnd(component: ComponentTemplate) :
+class AppLayerCoversFullScreenAtEnd(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
     override fun doEvaluate(scenarioInstance: IScenarioInstance, layerSubject: LayersTraceSubject) {
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 2b9de3f..da04c0f 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
@@ -20,7 +20,7 @@
 import android.tools.common.flicker.assertors.ComponentTemplate
 import android.tools.common.flicker.subject.layers.LayersTraceSubject
 
-class AppLayerCoversFullScreenAtStart(component: ComponentTemplate) :
+class AppLayerCoversFullScreenAtStart(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
     override fun doEvaluate(scenarioInstance: IScenarioInstance, layerSubject: LayersTraceSubject) {
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 0d812ee..ea5de16 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
@@ -21,7 +21,7 @@
 import android.tools.common.flicker.subject.layers.LayersTraceSubject
 
 /** Checks if the [component] layer is invisible at the end of the transition */
-class AppLayerIsInvisibleAtEnd(component: ComponentTemplate) :
+class AppLayerIsInvisibleAtEnd(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
     override fun doEvaluate(scenarioInstance: IScenarioInstance, layerSubject: LayersTraceSubject) {
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 9a69c44..ceabb0c 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
@@ -21,7 +21,7 @@
 import android.tools.common.flicker.subject.layers.LayersTraceSubject
 
 /** Checks if the [component] layer is invisible at the start of the transition */
-class AppLayerIsInvisibleAtStart(component: ComponentTemplate) :
+class AppLayerIsInvisibleAtStart(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
     override fun doEvaluate(scenarioInstance: IScenarioInstance, layerSubject: LayersTraceSubject) {
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 8ee49da..101b7b1 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
@@ -21,7 +21,7 @@
 import android.tools.common.flicker.subject.layers.LayersTraceSubject
 
 /** Checks if the [component] layer is visible throughout the animation */
-class AppLayerIsVisibleAlways(component: ComponentTemplate) :
+class AppLayerIsVisibleAlways(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
     override fun doEvaluate(scenarioInstance: IScenarioInstance, layerSubject: LayersTraceSubject) {
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 508e42a..d0bc377 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
@@ -21,7 +21,7 @@
 import android.tools.common.flicker.subject.layers.LayersTraceSubject
 
 /** Checks if the [component] layer is visible at the end of the transition */
-class AppLayerIsVisibleAtEnd(component: ComponentTemplate) :
+class AppLayerIsVisibleAtEnd(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
     override fun doEvaluate(scenarioInstance: IScenarioInstance, layerSubject: LayersTraceSubject) {
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 d72db81..3c98abe 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
@@ -21,7 +21,7 @@
 import android.tools.common.flicker.subject.layers.LayersTraceSubject
 
 /** Checks if the [component] layer is visible at the start of the transition */
-class AppLayerIsVisibleAtStart(component: ComponentTemplate) :
+class AppLayerIsVisibleAtStart(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
     override fun doEvaluate(scenarioInstance: IScenarioInstance, layerSubject: LayersTraceSubject) {
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 cd4e679..fd09710 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
@@ -21,7 +21,8 @@
 import android.tools.common.flicker.subject.layers.LayersTraceSubject
 
 /** Checks that the visible region of [component] always reduces during the animation */
-class AppLayerReduces(component: ComponentTemplate) : AssertionTemplateWithComponent(component) {
+class AppLayerReduces(private val component: ComponentTemplate) :
+    AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
     override fun doEvaluate(scenarioInstance: IScenarioInstance, layerSubject: LayersTraceSubject) {
         val layerMatcher = component.build(scenarioInstance)
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 5c87616..abcea88 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
@@ -23,7 +23,7 @@
 /**
  * Checks if the [component] layer remains inside the display bounds throughout the whole animation
  */
-class AppLayerRemainInsideDisplayBounds(component: ComponentTemplate) :
+class AppLayerRemainInsideDisplayBounds(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
     override fun doEvaluate(scenarioInstance: IScenarioInstance, layerSubject: LayersTraceSubject) {
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 d64c81f..57f4e23 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
@@ -30,7 +30,7 @@
  *     [component] remains visible until the end of the trace
  * ```
  */
-class AppLayerReplacesLauncher(component: ComponentTemplate) :
+class AppLayerReplacesLauncher(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
     override fun doEvaluate(scenarioInstance: IScenarioInstance, layerSubject: LayersTraceSubject) {
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 2d79b5e..d5caf91 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
@@ -24,7 +24,7 @@
  * Checks that the app layer doesn't exist or is invisible at the start of the transition, but is
  * created and/or becomes visible during the transition.
  */
-class AppWindowBecomesInvisible(component: ComponentTemplate) :
+class AppWindowBecomesInvisible(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
     override fun doEvaluate(
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 ef65d4a..d7baa08 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
@@ -21,7 +21,7 @@
 import android.tools.common.flicker.subject.wm.WindowManagerTraceSubject
 
 /** Checks that [component] window becomes pinned */
-class AppWindowBecomesPinned(component: ComponentTemplate) :
+class AppWindowBecomesPinned(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
     override fun doEvaluate(
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 35d428a..cb98ed5 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
@@ -25,7 +25,7 @@
  * Checks that the app layer doesn't exist or is invisible at the start of the transition, but is
  * created and/or becomes visible during the transition.
  */
-class AppWindowBecomesTopWindow(component: ComponentTemplate) :
+class AppWindowBecomesTopWindow(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
     override fun doEvaluate(
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 7f88616..e495edd 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
@@ -25,7 +25,7 @@
  * Checks that the app layer doesn't exist or is invisible at the start of the transition, but is
  * created and/or becomes visible during the transition.
  */
-class AppWindowBecomesVisible(component: ComponentTemplate) :
+class AppWindowBecomesVisible(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
     override fun doEvaluate(
@@ -40,5 +40,7 @@
             .isAppWindowVisible(ComponentNameMatcher.SPLASH_SCREEN, isOptional = true)
             .then()
             .isAppWindowVisible(component.build(scenarioInstance))
+            .forAllEntries()
+        // TODO: Check everywhere we are missing this!
     }
 }
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 353a185..986dbd3 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
@@ -20,7 +20,7 @@
 import android.tools.common.flicker.assertors.ComponentTemplate
 import android.tools.common.flicker.subject.wm.WindowManagerTraceSubject
 
-class AppWindowCoversFullScreenAtEnd(component: ComponentTemplate) :
+class AppWindowCoversFullScreenAtEnd(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
     override fun doEvaluate(
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 0e20a5b..b964a95 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
@@ -20,7 +20,7 @@
 import android.tools.common.flicker.assertors.ComponentTemplate
 import android.tools.common.flicker.subject.wm.WindowManagerTraceSubject
 
-class AppWindowCoversFullScreenAtStart(component: ComponentTemplate) :
+class AppWindowCoversFullScreenAtStart(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
     override fun doEvaluate(
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 91fd914..6d111d8 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
@@ -21,7 +21,7 @@
 import android.tools.common.flicker.subject.wm.WindowManagerTraceSubject
 
 /** Checks if the [getWindowState] layer is invisible at the end of the transition */
-class AppWindowIsInvisibleAtEnd(component: ComponentTemplate) :
+class AppWindowIsInvisibleAtEnd(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
     override fun doEvaluate(
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 bd25849..e5e092e 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
@@ -20,7 +20,7 @@
 import android.tools.common.flicker.assertors.ComponentTemplate
 import android.tools.common.flicker.subject.wm.WindowManagerTraceSubject
 
-class AppWindowIsInvisibleAtStart(component: ComponentTemplate) :
+class AppWindowIsInvisibleAtStart(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
     override fun doEvaluate(
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 a52a4d9..e0cc080 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
@@ -20,7 +20,7 @@
 import android.tools.common.flicker.assertors.ComponentTemplate
 import android.tools.common.flicker.subject.wm.WindowManagerTraceSubject
 
-class AppWindowIsTopWindowAtStart(component: ComponentTemplate) :
+class AppWindowIsTopWindowAtStart(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
     override fun doEvaluate(
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 9402a0c..83e54de 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
@@ -21,7 +21,7 @@
 import android.tools.common.flicker.subject.wm.WindowManagerTraceSubject
 
 /** Checks that [component] window remains visible throughout the transition */
-class AppWindowIsVisibleAlways(component: ComponentTemplate) :
+class AppWindowIsVisibleAlways(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
     override fun doEvaluate(
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 f7f65bd..bd1c1e7 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
@@ -20,7 +20,7 @@
 import android.tools.common.flicker.assertors.ComponentTemplate
 import android.tools.common.flicker.subject.wm.WindowManagerTraceSubject
 
-class AppWindowIsVisibleAtEnd(component: ComponentTemplate) :
+class AppWindowIsVisibleAtEnd(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
     override fun doEvaluate(
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 2d432a3..6baecfe 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
@@ -20,7 +20,7 @@
 import android.tools.common.flicker.assertors.ComponentTemplate
 import android.tools.common.flicker.subject.wm.WindowManagerTraceSubject
 
-class AppWindowIsVisibleAtStart(component: ComponentTemplate) :
+class AppWindowIsVisibleAtStart(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
     override fun doEvaluate(
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 b572e3b..9bbcaec 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
@@ -20,7 +20,7 @@
 import android.tools.common.flicker.assertors.ComponentTemplate
 import android.tools.common.flicker.subject.wm.WindowManagerTraceSubject
 
-class AppWindowOnTopAtEnd(component: ComponentTemplate) :
+class AppWindowOnTopAtEnd(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
     override fun doEvaluate(
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 3a7fe4e..9cbd815 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
@@ -20,7 +20,7 @@
 import android.tools.common.flicker.assertors.ComponentTemplate
 import android.tools.common.flicker.subject.wm.WindowManagerTraceSubject
 
-class AppWindowOnTopAtStart(component: ComponentTemplate) :
+class AppWindowOnTopAtStart(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
     override fun doEvaluate(
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 3b6fd22..e3cadb9 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
@@ -23,7 +23,7 @@
 /**
  * Checks that [component] window remains inside the display bounds throughout the whole animation
  */
-class AppWindowRemainInsideDisplayBounds(component: ComponentTemplate) :
+class AppWindowRemainInsideDisplayBounds(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
     override fun doEvaluate(
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 adcd80a..86e8573 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
@@ -26,7 +26,7 @@
  * Checks that [Components.LAUNCHER] is the top visible app window at the start of the transition
  * and that it is replaced by [component] during the transition
  */
-class AppWindowReplacesLauncherAsTopWindow(component: ComponentTemplate) :
+class AppWindowReplacesLauncherAsTopWindow(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
     override fun doEvaluate(
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 0e2b595..0fa2e0a 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
@@ -20,10 +20,11 @@
 import android.tools.common.flicker.assertors.ComponentTemplate
 
 /** Base class for tests that require a [component] named window name */
-abstract class AssertionTemplateWithComponent(val component: ComponentTemplate) :
+abstract class AssertionTemplateWithComponent(vararg val components: ComponentTemplate) :
     AssertionTemplate() {
 
-    override val assertionName = "${this::class.simpleName}(${component.name})"
+    override val assertionName =
+        "${this::class.java.simpleName}(${components.joinToString { it.name }})"
 
     override fun equals(other: Any?): Boolean {
         if (other !is AssertionTemplateWithComponent) {
@@ -31,17 +32,22 @@
         }
 
         // Check both assertions are instances of the same class.
-        if (this::class != component::class) {
+        if (this::class != other::class) {
+            return false
+        }
+
+        if (components.size != other.components.size) {
             return false
         }
 
         // TODO: Make sure equality is properly defined on the component
-        return other.component == component
+        // Order of components matters
+        return components.zip(other.components).all { it.first == it.second }
     }
 
     override fun hashCode(): Int {
         var result = super.hashCode()
-        result = 31 * result + component.hashCode()
+        result = 31 * result + components.hashCode()
         result = 31 * result + assertionName.hashCode()
         return result
     }
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
new file mode 100644
index 0000000..e0bc9b7
--- /dev/null
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/FocusChanges.kt
@@ -0,0 +1,62 @@
+/*
+ * 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.assertors.assertions
+
+import com.android.server.wm.flicker.service.IScenarioInstance
+import com.android.server.wm.flicker.service.assertors.ComponentTemplate
+import com.android.server.wm.flicker.traces.eventlog.EventLogSubject
+import com.android.server.wm.traces.common.component.matchers.ComponentNameMatcher
+import com.android.server.wm.traces.common.component.matchers.IComponentNameMatcher
+
+val ANY_MATCH_COMPONENT = ComponentTemplate("ANY") { _ -> ComponentNameMatcher("", "") }
+
+class FocusChanges(
+    private val fromComponent: ComponentTemplate = ANY_MATCH_COMPONENT,
+    private val toComponent: ComponentTemplate = ANY_MATCH_COMPONENT
+) : AssertionTemplateWithComponent(fromComponent, toComponent) {
+
+    // TODO: Make parent call this when appropriate
+    override fun doEvaluate(scenarioInstance: IScenarioInstance, eventLog: EventLogSubject) {
+        val layersTrace = scenarioInstance.reader.readLayersTrace()
+        val fromComponent = fromComponent.build(scenarioInstance)
+        val toComponent = toComponent.build(scenarioInstance)
+
+        val fromPackage =
+            if (fromComponent is IComponentNameMatcher) {
+                fromComponent.packageName
+            } else {
+                requireNotNull(layersTrace) { "Missing layers trace" }
+                layersTrace.entries
+                    .flatMap { it.flattenedLayers.asList() }
+                    .first { fromComponent.layerMatchesAnyOf(it) }
+                    .packageName
+            }
+
+        val toPackage =
+            if (toComponent is IComponentNameMatcher) {
+                toComponent.packageName
+            } else {
+                requireNotNull(layersTrace) { "Missing layers trace" }
+                layersTrace.entries
+                    .flatMap { it.flattenedLayers.asList() }
+                    .first { toComponent.layerMatchesAnyOf(it) }
+                    .packageName
+            }
+
+        eventLog.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
new file mode 100644
index 0000000..a1d95e7
--- /dev/null
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/HasAtMostOneWindowMatching.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 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.assertors.assertions
+
+import com.android.server.wm.flicker.service.IScenarioInstance
+import com.android.server.wm.flicker.service.assertors.ComponentTemplate
+import com.android.server.wm.flicker.traces.windowmanager.WindowManagerTraceSubject
+import com.google.common.truth.Truth
+
+/**
+ * Checks that the app layer doesn't exist or is invisible at the start of the transition, but is
+ * created and/or becomes visible during the transition.
+ */
+class HasAtMostOneWindowMatching(private val component: ComponentTemplate) :
+    AssertionTemplateWithComponent(component) {
+    /** {@inheritDoc} */
+    override fun doEvaluate(
+        scenarioInstance: IScenarioInstance,
+        wmSubject: WindowManagerTraceSubject
+    ) {
+        wmSubject
+            .invoke("HasAtMostOneWindowMatching") {
+                val windowCount =
+                    it.wmState.windowStates.count { window ->
+                        component.build(scenarioInstance).windowMatchesAnyOf(window)
+                    }
+                Truth.assertThat(windowCount).isAtMost(1)
+            }
+            .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 9704431..99ac3eb 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
@@ -29,7 +29,7 @@
  *     [Components.LAUNCHER] becomes visible
  * ```
  */
-class LauncherReplacesAppLayer(component: ComponentTemplate) :
+class LauncherReplacesAppLayer(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
     override fun doEvaluate(scenarioInstance: IScenarioInstance, layerSubject: LayersTraceSubject) {
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 f785b52..ce9dd85 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
@@ -26,7 +26,7 @@
  * Checks that [component] is the top visible app window at the start of the transition and that it
  * is replaced by [Components.LAUNCHER] during the transition
  */
-class LauncherWindowReplacesAppAsTopWindow(component: ComponentTemplate) :
+class LauncherWindowReplacesAppAsTopWindow(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     override fun doEvaluate(
         scenarioInstance: IScenarioInstance,
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 40eb900..47632ad 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
@@ -24,7 +24,7 @@
  * Checks if the [componentMatcher] layer is visible at the start of the transition and becomes
  * invisible
  */
-class LayerBecomesInvisible(component: ComponentTemplate) :
+class LayerBecomesInvisible(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
     override fun doEvaluate(scenarioInstance: IScenarioInstance, layerSubject: LayersTraceSubject) {
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 6712cad..f5f0fe9 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
@@ -24,7 +24,7 @@
  * Checks if the [componentMatcher] layer is invisible at the start of the transition and becomes
  * visible
  */
-class LayerBecomesVisible(component: ComponentTemplate) :
+class LayerBecomesVisible(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
     override fun doEvaluate(scenarioInstance: IScenarioInstance, layerSubject: LayersTraceSubject) {
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 9979a90..116813d 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
@@ -21,7 +21,7 @@
 import android.tools.common.flicker.subject.layers.LayersTraceSubject
 
 /** Checks if the [componentMatcher] layer is invisible during the entire transition */
-class LayerIsInvisibleAlways(component: ComponentTemplate) :
+class LayerIsInvisibleAlways(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
     override fun doEvaluate(scenarioInstance: IScenarioInstance, layerSubject: LayersTraceSubject) {
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 55aab05..34d6d1f 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
@@ -21,7 +21,7 @@
 import android.tools.common.flicker.subject.layers.LayersTraceSubject
 
 /** Checks if the [componentMatcher] layer is invisible at the end of the transition */
-class LayerIsInvisibleAtEnd(component: ComponentTemplate) :
+class LayerIsInvisibleAtEnd(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
     override fun doEvaluate(scenarioInstance: IScenarioInstance, layerSubject: LayersTraceSubject) {
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 1fa1792..e9ffa80 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
@@ -21,7 +21,7 @@
 import android.tools.common.flicker.subject.layers.LayersTraceSubject
 
 /** Checks if the [componentMatcher] layer is invisible at the start of the transition */
-class LayerIsInvisibleAtStart(component: ComponentTemplate) :
+class LayerIsInvisibleAtStart(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
     override fun doEvaluate(scenarioInstance: IScenarioInstance, layerSubject: LayersTraceSubject) {
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 717fd00..6a4923a 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
@@ -21,7 +21,7 @@
 import android.tools.common.flicker.subject.layers.LayersTraceSubject
 
 /** Checks if the [componentMatcher] layer is visible during the entire transition */
-class LayerIsVisibleAlways(component: ComponentTemplate) :
+class LayerIsVisibleAlways(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
     override fun doEvaluate(scenarioInstance: IScenarioInstance, layerSubject: LayersTraceSubject) {
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 a5cec29..2be3989 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
@@ -21,7 +21,7 @@
 import android.tools.common.flicker.subject.layers.LayersTraceSubject
 
 /** Checks if the [component] layer is visible at the end of the transition */
-class LayerIsVisibleAtEnd(component: ComponentTemplate) :
+class LayerIsVisibleAtEnd(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
     override fun doEvaluate(scenarioInstance: IScenarioInstance, layerSubject: LayersTraceSubject) {
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 0a43fbd..6f34cdb 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
@@ -21,7 +21,7 @@
 import android.tools.common.flicker.subject.layers.LayersTraceSubject
 
 /** Checks if the [component] layer is visible at the start of the transition */
-class LayerIsVisibleAtStart(component: ComponentTemplate) :
+class LayerIsVisibleAtStart(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
     override fun doEvaluate(scenarioInstance: IScenarioInstance, layerSubject: LayersTraceSubject) {
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
new file mode 100644
index 0000000..6cd2a2a
--- /dev/null
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/LayerReduces.kt
@@ -0,0 +1,34 @@
+/*
+ * 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 com.android.server.wm.flicker.service.assertors.assertions
+
+import com.android.server.wm.flicker.service.IScenarioInstance
+import com.android.server.wm.flicker.service.assertors.ComponentTemplate
+import com.android.server.wm.flicker.traces.layers.LayersTraceSubject
+
+class LayerReduces(private val component: ComponentTemplate) :
+    AssertionTemplateWithComponent(component) {
+    override fun doEvaluate(scenarioInstance: IScenarioInstance, layersTrace: LayersTraceSubject) {
+        val pipLayerList =
+            layersTrace.layers {
+                component.build(scenarioInstance).layerMatchesAnyOf(it) && it.isVisible
+            }
+        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
new file mode 100644
index 0000000..41261a3
--- /dev/null
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/LayerRemainInsideVisibleBounds.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 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 com.android.server.wm.flicker.service.assertors.assertions
+
+import com.android.server.wm.flicker.service.IScenarioInstance
+import com.android.server.wm.flicker.service.assertors.ComponentTemplate
+import com.android.server.wm.flicker.traces.layers.LayersTraceSubject
+import com.android.server.wm.traces.common.Rect
+
+/**
+ * Checks that the app layer doesn't exist or is invisible at the start of the transition, but is
+ * created and/or becomes visible during the transition.
+ */
+class LayerRemainInsideVisibleBounds(private val component: ComponentTemplate) :
+    AssertionTemplateWithComponent(component) {
+    /** {@inheritDoc} */
+    override fun doEvaluate(
+        scenarioInstance: IScenarioInstance,
+        layersTraceSubject: LayersTraceSubject
+    ) {
+        val displayBounds = Rect.EMPTY // TODO: Get display bounds from subject
+        layersTraceSubject
+            .visibleRegion(component.build(scenarioInstance))
+            .coversAtMost(displayBounds)
+            .forAllEntries()
+    }
+}
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 c3b66d7..8fca7a7 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
@@ -24,7 +24,7 @@
  * Checks that non-app window [component] is visible at the start of the transition and becomes
  * invisible
  */
-open class NonAppWindowBecomesInvisible(component: ComponentTemplate) :
+open class NonAppWindowBecomesInvisible(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
     override fun doEvaluate(
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 c7355ff..ea632a5 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
@@ -24,7 +24,7 @@
  * Checks that non-app window [component] is invisible at the start of the transition and becomes
  * visible
  */
-class NonAppWindowBecomesVisible(component: ComponentTemplate) :
+class NonAppWindowBecomesVisible(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
     override fun doEvaluate(
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 2cffd43..420b6ce 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
@@ -21,7 +21,7 @@
 import android.tools.common.flicker.subject.wm.WindowManagerTraceSubject
 
 /** Checks if the [component] window is invisible during the entire transition */
-class NonAppWindowIsInvisibleAlways(component: ComponentTemplate) :
+class NonAppWindowIsInvisibleAlways(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
     override fun doEvaluate(
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 19d6b7a..95eba33 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
@@ -21,7 +21,7 @@
 import android.tools.common.flicker.subject.wm.WindowManagerTraceSubject
 
 /** Checks if the [component] window is visible during the entire transition */
-class NonAppWindowIsVisibleAlways(component: ComponentTemplate) :
+class NonAppWindowIsVisibleAlways(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
     override fun doEvaluate(
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 f5c1dd9..49d5948 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
@@ -21,7 +21,7 @@
 import android.tools.common.flicker.subject.wm.WindowManagerTraceSubject
 
 /** Checks if the [component] window is visible at the end of the transition */
-class NonAppWindowIsVisibleAtEnd(component: ComponentTemplate) :
+class NonAppWindowIsVisibleAtEnd(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
     override fun doEvaluate(
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 04f8a05..29f83f9 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
@@ -21,7 +21,7 @@
 import android.tools.common.flicker.subject.wm.WindowManagerTraceSubject
 
 /** Checks if the [component] window is visible at the end of the transition */
-class NonAppWindowIsVisibleAtStart(component: ComponentTemplate) :
+class NonAppWindowIsVisibleAtStart(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
     override fun doEvaluate(
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 aa4ae9c..6ef66da 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
@@ -24,7 +24,7 @@
  * Checks that [component] window is pinned and visible at the start and then becomes unpinned and
  * invisible at the same moment, and remains unpinned and invisible until the end of the transition
  */
-class PipWindowBecomesInvisible(component: ComponentTemplate) :
+class PipWindowBecomesInvisible(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
     override fun doEvaluate(
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 cc541a9..bd1831c 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
@@ -25,7 +25,7 @@
  * Checks that the [ComponentNameMatcher.ROTATION] layer appears during the transition, doesn't
  * flicker, and disappears before the transition is complete.
  */
-class RotationLayerAppearsAndVanishes(component: ComponentTemplate) :
+class RotationLayerAppearsAndVanishes(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
     override fun doEvaluate(scenarioInstance: IScenarioInstance, layerSubject: LayersTraceSubject) {
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
new file mode 100644
index 0000000..d50e2eb
--- /dev/null
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/ScreenLockedAtStart.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 com.android.server.wm.flicker.service.assertors.assertions
+
+import com.android.server.wm.flicker.service.IScenarioInstance
+import com.android.server.wm.flicker.service.assertors.AssertionTemplate
+import com.android.server.wm.flicker.traces.layers.LayersTraceSubject
+
+class ScreenLockedAtStart : AssertionTemplate() {
+
+    override fun doEvaluate(scenarioInstance: IScenarioInstance, layersTrace: LayersTraceSubject) {
+        layersTrace.first().isEmpty()
+    }
+}
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
new file mode 100644
index 0000000..6b7e6cb
--- /dev/null
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/SplitAppLayerBoundsSnapToDivider.kt
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2021 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.assertors.assertions
+
+import android.tools.common.datatypes.Region
+import android.tools.common.flicker.IScenarioInstance
+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
+
+class SplitAppLayerBoundsSnapToDivider(private val component: ComponentTemplate) :
+    AssertionTemplateWithComponent(component) {
+    /** {@inheritDoc} */
+    override fun doEvaluate(
+        scenarioInstance: IScenarioInstance,
+        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
+
+        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")
+
+                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
+                                )
+                            }
+                        }
+                    )
+            }
+            .forAllEntries()
+    }
+}
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
new file mode 100644
index 0000000..dd095b0
--- /dev/null
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/WindowBecomesPinned.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2022 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 com.android.server.wm.flicker.service.assertors.assertions
+
+import com.android.server.wm.flicker.service.IScenarioInstance
+import com.android.server.wm.flicker.service.assertors.ComponentTemplate
+import com.android.server.wm.flicker.traces.windowmanager.WindowManagerTraceSubject
+
+/**
+ * Checks that the app layer doesn't exist or is invisible at the start of the transition, but is
+ * created and/or becomes visible during the transition.
+ */
+class WindowBecomesPinned(private val component: ComponentTemplate) :
+    AssertionTemplateWithComponent(component) {
+    /** {@inheritDoc} */
+    override fun doEvaluate(
+        scenarioInstance: IScenarioInstance,
+        wmSubject: WindowManagerTraceSubject
+    ) {
+        val component = component.build(scenarioInstance)
+        wmSubject.isNotPinned(component).then().isPinned(component).forAllEntries()
+    }
+}
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 db5c279..f115503 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
@@ -21,7 +21,7 @@
 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(component: ComponentTemplate) :
+open class WindowMovesOutOfTop(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
     override fun doEvaluate(
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 ca2568b..678c556 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
@@ -21,7 +21,7 @@
 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(component: ComponentTemplate) :
+open class WindowMovesToTop(private val component: ComponentTemplate) :
     AssertionTemplateWithComponent(component) {
     /** {@inheritDoc} */
     override fun doEvaluate(
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
new file mode 100644
index 0000000..6422b69
--- /dev/null
+++ b/libraries/flicker/src/android/tools/common/flicker/assertors/assertions/WindowRemainInsideVisibleBounds.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 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 com.android.server.wm.flicker.service.assertors.assertions
+
+import com.android.server.wm.flicker.service.IScenarioInstance
+import com.android.server.wm.flicker.service.assertors.ComponentTemplate
+import com.android.server.wm.flicker.traces.windowmanager.WindowManagerTraceSubject
+import com.android.server.wm.traces.common.Rect
+
+/**
+ * Checks that the app layer doesn't exist or is invisible at the start of the transition, but is
+ * created and/or becomes visible during the transition.
+ */
+class WindowRemainInsideVisibleBounds(private val component: ComponentTemplate) :
+    AssertionTemplateWithComponent(component) {
+    /** {@inheritDoc} */
+    override fun doEvaluate(
+        scenarioInstance: IScenarioInstance,
+        wmSubject: WindowManagerTraceSubject
+    ) {
+        val displayBounds = Rect.EMPTY // TODO: Get display bounds from wmSubject
+        wmSubject
+            .visibleRegion(component.build(scenarioInstance))
+            .coversAtMost(displayBounds)
+            .forAllEntries()
+    }
+}
diff --git a/libraries/flicker/src/android/tools/common/traces/surfaceflinger/Layer.kt b/libraries/flicker/src/android/tools/common/traces/surfaceflinger/Layer.kt
index 28c5c7d..31b57ba 100644
--- a/libraries/flicker/src/android/tools/common/traces/surfaceflinger/Layer.kt
+++ b/libraries/flicker/src/android/tools/common/traces/surfaceflinger/Layer.kt
@@ -21,6 +21,7 @@
 import android.tools.common.datatypes.Rect
 import android.tools.common.datatypes.RectF
 import android.tools.common.datatypes.Region
+import android.tools.common.datatypes.component.ComponentName
 import kotlin.js.JsExport
 import kotlin.js.JsName
 
@@ -44,6 +45,7 @@
     var parent: Layer? = null
     var zOrderRelativeOf: Layer? = null
     var zOrderRelativeParentOf: Int = 0
+    val packageName = ComponentName.fromLayerName(name).packageName
 
     /**
      * Checks if the [Layer] is a root layer in the hierarchy
diff --git a/libraries/flicker/src/android/tools/device/flicker/Utils.kt b/libraries/flicker/src/android/tools/device/flicker/Utils.kt
index 92f9e0a..915ed79 100644
--- a/libraries/flicker/src/android/tools/device/flicker/Utils.kt
+++ b/libraries/flicker/src/android/tools/device/flicker/Utils.kt
@@ -17,7 +17,18 @@
 package android.tools.device.flicker
 
 import android.app.Instrumentation
+import android.tools.common.IScenario
 import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.device.traces.DEFAULT_TRACE_CONFIG
+import android.tools.device.traces.getDefaultFlickerOutputDir
+import android.tools.device.traces.io.ResultReader
+import android.tools.device.traces.io.ResultWriter
+import android.tools.device.traces.monitors.ScreenRecorder
+import android.tools.device.traces.monitors.events.EventLogMonitor
+import android.tools.device.traces.monitors.surfaceflinger.LayersTraceMonitor
+import android.tools.device.traces.monitors.surfaceflinger.TransactionsTraceMonitor
+import android.tools.device.traces.monitors.wm.TransitionsTraceMonitor
+import android.tools.device.traces.monitors.wm.WindowManagerTraceMonitor
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.server.wm.flicker.io.ResultReader
 import com.android.server.wm.flicker.io.ResultWriter
@@ -31,22 +42,6 @@
 import com.android.server.wm.traces.common.component.matchers.ComponentNameMatcher
 
 object Utils {
-    fun componentMatcherParamsFromName(name: String): Pair<String, String> {
-        var packageName = ""
-        var className = ""
-        if (name.contains("/")) {
-            if (name.contains("#")) {
-                name.removeSuffix("#")
-            }
-            val splitString = name.split('/')
-            packageName = splitString[0]
-            className = splitString[1]
-        } else {
-            className = name
-        }
-        return Pair(packageName, className)
-    }
-
     fun componentNameMatcherHardcoded(str: String): ComponentNameMatcher? {
         return when (true) {
             str.contains("NavigationBar0") -> ComponentNameMatcher.NAV_BAR