Update Transitions trace parse function to only include transition that have full executed in the trace range

Bug: 406453297

Test: atest FlickerLibTests
Change-Id: I4374a963eb83389cb8d752ae53a05dddde4152b4
diff --git a/libraries/flicker/utils/src/android/tools/traces/parsers/perfetto/TransitionsTraceParser.kt b/libraries/flicker/utils/src/android/tools/traces/parsers/perfetto/TransitionsTraceParser.kt
index f2de431..8b30494 100644
--- a/libraries/flicker/utils/src/android/tools/traces/parsers/perfetto/TransitionsTraceParser.kt
+++ b/libraries/flicker/utils/src/android/tools/traces/parsers/perfetto/TransitionsTraceParser.kt
@@ -26,7 +26,7 @@
 import android.tools.traces.wm.TransitionsTrace
 import android.tools.traces.wm.WmTransitionData
 
-class TransitionsTraceParser :
+open class TransitionsTraceParser :
     AbstractTraceParser<TraceProcessorSession, Transition, Transition, TransitionsTrace>() {
 
     override val traceName = "Transitions Trace"
@@ -71,6 +71,25 @@
 
     override fun onBeforeParse(input: TraceProcessorSession) {}
 
+    override fun doParse(
+        input: TraceProcessorSession,
+        from: Timestamp,
+        to: Timestamp,
+        addInitialEntry: Boolean,
+    ): TransitionsTrace {
+        val sliceEntries =
+            getEntries(input).filter {
+                (it.wmData.sendTime ?: it.shellData.dispatchTime ?: Timestamps.min()) >= from &&
+                    (it.wmData.finishTime
+                        ?: it.wmData.abortTime
+                        ?: it.shellData.abortTime
+                        ?: it.shellData.mergeTime
+                        ?: Timestamps.max()) <= to
+            }
+
+        return createTrace(sliceEntries)
+    }
+
     override fun doParseEntry(entry: Transition) = entry
 
     companion object {
diff --git a/libraries/flicker/utils/src/android/tools/traces/wm/Transition.kt b/libraries/flicker/utils/src/android/tools/traces/wm/Transition.kt
index c473218..36627b9 100644
--- a/libraries/flicker/utils/src/android/tools/traces/wm/Transition.kt
+++ b/libraries/flicker/utils/src/android/tools/traces/wm/Transition.kt
@@ -44,6 +44,8 @@
         }
     }
 
+    // TODO: Rethink the timestamp assigned to transitions, conceptually these are not discrete
+    //  entries but continuous time ranges over which a transition lives.
     override val timestamp =
         wmData.createTime
             ?: wmData.sendTime
diff --git a/libraries/flicker/utils/test/src/android/tools/parsers/wm/TransitionsTraceParserTest.kt b/libraries/flicker/utils/test/src/android/tools/parsers/wm/TransitionsTraceParserTest.kt
index af20edc..68e7dea 100644
--- a/libraries/flicker/utils/test/src/android/tools/parsers/wm/TransitionsTraceParserTest.kt
+++ b/libraries/flicker/utils/test/src/android/tools/parsers/wm/TransitionsTraceParserTest.kt
@@ -17,10 +17,16 @@
 package android.tools.parsers.wm
 
 import android.tools.Cache
+import android.tools.Timestamp
+import android.tools.Timestamps
 import android.tools.testutils.CleanFlickerEnvironmentRule
 import android.tools.testutils.readAsset
+import android.tools.traces.parsers.perfetto.Row
 import android.tools.traces.parsers.perfetto.TraceProcessorSession
 import android.tools.traces.parsers.perfetto.TransitionsTraceParser
+import android.tools.traces.wm.ShellTransitionData
+import android.tools.traces.wm.Transition
+import android.tools.traces.wm.WmTransitionData
 import com.google.common.truth.Truth
 import org.junit.Assume
 import org.junit.Before
@@ -64,6 +70,148 @@
         }
     }
 
+    @Test
+    fun filtersTransitionWithDispatchTimeBeforeFrom() {
+        val from = Timestamps.from(elapsedNanos = 100)
+        val to = Timestamps.from(elapsedNanos = 200)
+        val transition =
+            createMockTransition(
+                id = 1,
+                dispatchTime = Timestamps.from(elapsedNanos = 99), // Before 'from'
+                finishTime = Timestamps.from(elapsedNanos = 150),
+            )
+        val parser = MockableTransitionsTraceParser(listOf(transition))
+        val trace = parser.parse(MockTraceProcessorSession(), from, to)
+        Truth.assertThat(trace.entries).isEmpty()
+    }
+
+    @Test
+    fun filtersTransitionWithSendTimeBeforeFrom() {
+        val from = Timestamps.from(elapsedNanos = 100)
+        val to = Timestamps.from(elapsedNanos = 200)
+        val transition =
+            createMockTransition(
+                id = 1,
+                sendTime = Timestamps.from(elapsedNanos = 99), // Before 'from'
+                finishTime = Timestamps.from(elapsedNanos = 150),
+            )
+        val parser = MockableTransitionsTraceParser(listOf(transition))
+        val trace = parser.parse(MockTraceProcessorSession(), from, to)
+        Truth.assertThat(trace.entries).isEmpty()
+    }
+
+    @Test
+    fun filtersTransitionWithFinishTimeAfterTo() {
+        val from = Timestamps.from(elapsedNanos = 100)
+        val to = Timestamps.from(elapsedNanos = 200)
+        val transition =
+            createMockTransition(
+                id = 1,
+                dispatchTime = Timestamps.from(elapsedNanos = 110),
+                finishTime = Timestamps.from(elapsedNanos = 201), // After 'to'
+            )
+        val parser = MockableTransitionsTraceParser(listOf(transition))
+        val trace = parser.parse(MockTraceProcessorSession(), from, to)
+        Truth.assertThat(trace.entries).isEmpty()
+    }
+
+    @Test
+    fun filtersTransitionWithWmAbortTimeAfterTo() {
+        val from = Timestamps.from(elapsedNanos = 100)
+        val to = Timestamps.from(elapsedNanos = 200)
+        val transition =
+            createMockTransition(
+                id = 1,
+                dispatchTime = Timestamps.from(elapsedNanos = 110),
+                wmAbortTime = Timestamps.from(elapsedNanos = 201), // After 'to'
+            )
+        val parser = MockableTransitionsTraceParser(listOf(transition))
+        val trace = parser.parse(MockTraceProcessorSession(), from, to)
+        Truth.assertThat(trace.entries).isEmpty()
+    }
+
+    @Test
+    fun filtersTransitionWithShellAbortTimeAfterTo() {
+        val from = Timestamps.from(elapsedNanos = 100)
+        val to = Timestamps.from(elapsedNanos = 200)
+        val transition =
+            createMockTransition(
+                id = 1,
+                dispatchTime = Timestamps.from(elapsedNanos = 110),
+                shellAbortTime = Timestamps.from(elapsedNanos = 201), // After 'to'
+            )
+        val parser = MockableTransitionsTraceParser(listOf(transition))
+        val trace = parser.parse(MockTraceProcessorSession(), from, to)
+        Truth.assertThat(trace.entries).isEmpty()
+    }
+
+    @Test
+    fun filtersTransitionWithMergeTimeAfterTo() {
+        val from = Timestamps.from(elapsedNanos = 100)
+        val to = Timestamps.from(elapsedNanos = 200)
+        val transition =
+            createMockTransition(
+                id = 1,
+                dispatchTime = Timestamps.from(elapsedNanos = 110),
+                mergeTime = Timestamps.from(elapsedNanos = 201), // After 'to'
+            )
+        val parser = MockableTransitionsTraceParser(listOf(transition))
+        val trace = parser.parse(MockTraceProcessorSession(), from, to)
+        Truth.assertThat(trace.entries).isEmpty()
+    }
+
+    @Test
+    fun includesValidTransition() {
+        val from = Timestamps.from(elapsedNanos = 100)
+        val to = Timestamps.from(elapsedNanos = 200)
+        val transition = createMockTransition(id = 1, dispatchTime = from, finishTime = to)
+        val parser = MockableTransitionsTraceParser(listOf(transition))
+        val trace = parser.parse(MockTraceProcessorSession(), from, to)
+        Truth.assertThat(trace.entries).containsExactly(transition)
+    }
+
+    private class MockTraceProcessorSession : TraceProcessorSession {
+        override fun <T> query(sql: String, predicate: (List<Row>) -> T): T {
+            // Not used in tests
+            error("Not implemented")
+        }
+    }
+
+    // Simple mock implementation for testing purposes
+    private class MockableTransitionsTraceParser(private val mockEntries: List<Transition>) :
+        TransitionsTraceParser() {
+        // Override getEntries to return the mocked list directly
+        override fun getEntries(input: TraceProcessorSession): List<Transition> {
+            return mockEntries
+        }
+    }
+
+    private fun createMockTransition(
+        id: Int,
+        sendTime: Timestamp? = null,
+        dispatchTime: Timestamp? = null,
+        finishTime: Timestamp? = null,
+        wmAbortTime: Timestamp? = null,
+        shellAbortTime: Timestamp? = null,
+        mergeTime: Timestamp? = null,
+    ): Transition {
+        return Transition(
+            id = id,
+            wmData =
+                WmTransitionData(
+                    sendTime = sendTime,
+                    finishTime = finishTime,
+                    abortTime = wmAbortTime,
+                ),
+            shellData =
+                ShellTransitionData(
+                    dispatchTime = dispatchTime,
+                    abortTime = shellAbortTime,
+                    mergeTime = mergeTime,
+                ),
+        )
+    }
+
     companion object {
         @ClassRule @JvmField val ENV_CLEANUP = CleanFlickerEnvironmentRule()
     }
diff --git a/libraries/flicker/utils/test/src/android/tools/testutils/TestTraces.kt b/libraries/flicker/utils/test/src/android/tools/testutils/TestTraces.kt
index 2e57e50..9f61c79 100644
--- a/libraries/flicker/utils/test/src/android/tools/testutils/TestTraces.kt
+++ b/libraries/flicker/utils/test/src/android/tools/testutils/TestTraces.kt
@@ -101,11 +101,7 @@
         val START_TIME =
             Timestamps.from(elapsedNanos = 479583450794, systemUptimeNanos = 0, unixNanos = 0)
         val VALID_SLICE_TIME =
-            Timestamps.from(
-                elapsedNanos = 479583450794 + 5000,
-                systemUptimeNanos = 0,
-                unixNanos = 0,
-            )
+            Timestamps.from(elapsedNanos = 480124777862, systemUptimeNanos = 0, unixNanos = 0)
         val INVALID_SLICE_TIME =
             Timestamps.from(elapsedNanos = 487330863192 + 1, systemUptimeNanos = 0, unixNanos = 0)
         val END_TIME =