Add CrossfadeBenchmark

Bug: 322882983
Test: N/A
Change-Id: Ia3318b33840c3c1d5c9e94fdc40fec27efc2fb6c
diff --git a/compose/integration-tests/macrobenchmark-target/src/main/AndroidManifest.xml b/compose/integration-tests/macrobenchmark-target/src/main/AndroidManifest.xml
index 1873374..a905398 100644
--- a/compose/integration-tests/macrobenchmark-target/src/main/AndroidManifest.xml
+++ b/compose/integration-tests/macrobenchmark-target/src/main/AndroidManifest.xml
@@ -241,5 +241,19 @@
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
         </activity>
+
+        <activity
+            android:name=".CrossfadeActivity"
+            android:label="Compose Crossfade Benchmark"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+            <intent-filter>
+                <action android:name="androidx.compose.integration.macrobenchmark.target.CROSSFADE_ACTIVITY" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
     </application>
 </manifest>
diff --git a/compose/integration-tests/macrobenchmark-target/src/main/java/androidx/compose/integration/macrobenchmark/target/CrossfadeActivity.kt b/compose/integration-tests/macrobenchmark-target/src/main/java/androidx/compose/integration/macrobenchmark/target/CrossfadeActivity.kt
new file mode 100644
index 0000000..eed8a8d
--- /dev/null
+++ b/compose/integration-tests/macrobenchmark-target/src/main/java/androidx/compose/integration/macrobenchmark/target/CrossfadeActivity.kt
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2024 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 androidx.compose.integration.macrobenchmark.target
+
+import android.os.Bundle
+import androidx.activity.ComponentActivity
+import androidx.activity.compose.setContent
+import androidx.compose.animation.Crossfade
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.size
+import androidx.compose.material3.Button
+import androidx.compose.material3.Text
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.key
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.semantics.contentDescription
+import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.unit.dp
+
+class CrossfadeActivity : ComponentActivity() {
+
+    @Suppress("UnusedCrossfadeTargetStateParameter")
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+
+        setContent {
+            Column {
+                var toggled by remember { mutableStateOf(false) }
+                var targetState by remember { mutableStateOf(false) }
+                key(toggled) {
+                    Crossfade(
+                        modifier = Modifier.size(150.dp),
+                        label = "Crossfade",
+                        targetState = targetState
+                    ) {
+                    }
+                }
+                Button(
+                    modifier = Modifier.semantics { contentDescription = "toggle-crossfade" },
+                    onClick = { toggled = !toggled }) {
+                    Text(toggled.toString())
+                }
+                Button(
+                    modifier = Modifier.semantics { contentDescription = "toggle-target" },
+                    onClick = { targetState = !targetState }) {
+                    Text(targetState.toString())
+                }
+            }
+            launchIdlenessTracking()
+        }
+    }
+}
diff --git a/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/CrossfadeBenchmark.kt b/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/CrossfadeBenchmark.kt
new file mode 100644
index 0000000..2152b67a
--- /dev/null
+++ b/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/CrossfadeBenchmark.kt
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2024 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 androidx.compose.integration.macrobenchmark
+
+import android.content.Intent
+import androidx.benchmark.macro.CompilationMode
+import androidx.benchmark.macro.FrameTimingMetric
+import androidx.benchmark.macro.junit4.MacrobenchmarkRule
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.Until
+import androidx.testutils.createCompilationParams
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+@RunWith(Parameterized::class)
+class CrossfadeBenchmark(private val compilationMode: CompilationMode) {
+
+    @get:Rule
+    val benchmarkRule = MacrobenchmarkRule()
+
+    @Test
+    fun crossfadeBenchmarkInitialComposition() {
+        benchmarkRule.measureRepeated(
+            packageName = PackageName,
+            metrics = listOf(FrameTimingMetric()),
+            compilationMode = compilationMode,
+            iterations = 10,
+            setupBlock = {
+                val intent = Intent().apply { action = Action }
+                startActivityAndWait(intent)
+            }
+        ) {
+            repeat(2) {
+                device.findObject(By.desc(ToggleCrossfadeDescription)).click()
+                device.wait(Until.findObject(By.desc(ComposeIdle)), 3000)
+            }
+        }
+    }
+
+    @Test
+    fun crossfadeBenchmarkTargetStateChange() {
+        benchmarkRule.measureRepeated(
+            packageName = PackageName,
+            metrics = listOf(FrameTimingMetric()),
+            compilationMode = compilationMode,
+            iterations = 10,
+            setupBlock = {
+                val intent = Intent().apply { action = Action }
+                startActivityAndWait(intent)
+            }
+        ) {
+            repeat(2) {
+                device.findObject(By.desc(ToggleTargetStateDescription)).click()
+                device.wait(Until.findObject(By.desc(ComposeIdle)), 3000)
+            }
+        }
+    }
+
+    companion object {
+        private const val PackageName = "androidx.compose.integration.macrobenchmark.target"
+        private const val Action =
+            "androidx.compose.integration.macrobenchmark.target.CROSSFADE_ACTIVITY"
+        const val ToggleCrossfadeDescription = "toggle-crossfade"
+        const val ToggleTargetStateDescription = "toggle-target"
+        const val ComposeIdle = "COMPOSE-IDLE"
+
+        @Parameterized.Parameters(name = "compilationMode={0}")
+        @JvmStatic
+        fun parameters() = createCompilationParams()
+    }
+}