Add lazy scrolling jank benchmark.

And move RecyclerView benchmark to drag gesture. This makes both
benchmarks fairly aligned on distance, speed and amout of work done.

Bug: 182320524
Test: Run from AS after installing target app
Change-Id: I9429a33d3c4b0f334149ce4509164c4d06bab14c
diff --git a/benchmark/integration-tests/macrobenchmark-target/src/main/java/androidx/benchmark/integration/macrobenchmark/target/RecyclerViewActivity.kt b/benchmark/integration-tests/macrobenchmark-target/src/main/java/androidx/benchmark/integration/macrobenchmark/target/RecyclerViewActivity.kt
index f5d6a2a..98a5770 100644
--- a/benchmark/integration-tests/macrobenchmark-target/src/main/java/androidx/benchmark/integration/macrobenchmark/target/RecyclerViewActivity.kt
+++ b/benchmark/integration-tests/macrobenchmark-target/src/main/java/androidx/benchmark/integration/macrobenchmark/target/RecyclerViewActivity.kt
@@ -27,7 +27,7 @@
         title = "RecyclerView Sample"
         setContentView(R.layout.activity_recycler_view)
         val recycler = findViewById<RecyclerView>(R.id.recycler)
-        val itemCount = intent.getIntExtra(EXTRA_ITEM_COUNT, 1000)
+        val itemCount = intent.getIntExtra(EXTRA_ITEM_COUNT, 3000)
         val adapter = EntryAdapter(entries(itemCount))
         recycler.layoutManager = LinearLayoutManager(this)
         recycler.adapter = adapter
diff --git a/benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/benchmark/integration/macrobenchmark/FrameTimingMetricValidation.kt b/benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/benchmark/integration/macrobenchmark/FrameTimingMetricValidation.kt
index c3c7319..b9ce5d4 100644
--- a/benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/benchmark/integration/macrobenchmark/FrameTimingMetricValidation.kt
+++ b/benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/benchmark/integration/macrobenchmark/FrameTimingMetricValidation.kt
@@ -17,6 +17,7 @@
 package androidx.benchmark.integration.macrobenchmark
 
 import android.content.Intent
+import android.graphics.Point
 import androidx.benchmark.macro.CompilationMode
 import androidx.benchmark.macro.FrameTimingMetric
 import androidx.benchmark.macro.junit4.MacrobenchmarkRule
@@ -24,7 +25,6 @@
 import androidx.test.filters.SdkSuppress
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.By
-import androidx.test.uiautomator.Direction
 import androidx.test.uiautomator.UiDevice
 import org.junit.Before
 import org.junit.Rule
@@ -66,7 +66,8 @@
             // Setting a gesture margin is important otherwise gesture nav is triggered.
             recycler.setGestureMargin(device.displayWidth / 5)
             for (i in 1..10) {
-                recycler.scroll(Direction.DOWN, 2f)
+                // From center we scroll 2/3 of it which is 1/3 of the screen.
+                recycler.drag(Point(0, recycler.visibleCenter.y / 3))
                 device.waitForIdle()
             }
         }
diff --git a/compose/integration-tests/macrobenchmark-target/src/main/java/androidx/compose/integration/macrobenchmark/target/LazyColumnActivity.kt b/compose/integration-tests/macrobenchmark-target/src/main/java/androidx/compose/integration/macrobenchmark/target/LazyColumnActivity.kt
index 9abea652..a8dc146 100644
--- a/compose/integration-tests/macrobenchmark-target/src/main/java/androidx/compose/integration/macrobenchmark/target/LazyColumnActivity.kt
+++ b/compose/integration-tests/macrobenchmark-target/src/main/java/androidx/compose/integration/macrobenchmark/target/LazyColumnActivity.kt
@@ -17,6 +17,8 @@
 package androidx.compose.integration.macrobenchmark.target
 
 import android.os.Bundle
+import android.view.Choreographer
+import android.view.View
 import androidx.activity.ComponentActivity
 import androidx.activity.compose.setContent
 import androidx.compose.foundation.layout.Row
@@ -29,22 +31,29 @@
 import androidx.compose.material.Checkbox
 import androidx.compose.material.Text
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.Recomposer
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.semantics.contentDescription
+import androidx.compose.ui.semantics.semantics
 import androidx.compose.ui.unit.dp
 
 class LazyColumnActivity : ComponentActivity() {
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
 
-        val itemCount = intent.getIntExtra(EXTRA_ITEM_COUNT, 1000)
+        val itemCount = intent.getIntExtra(EXTRA_ITEM_COUNT, 3000)
 
         setContent {
-            LazyColumn(modifier = Modifier.fillMaxWidth()) {
+            LazyColumn(
+                modifier = Modifier.fillMaxWidth().semantics { contentDescription = "IamLazy" }
+            ) {
                 items(List(itemCount) { Entry("Item $it") }) {
                     ListRow(it)
                 }
             }
         }
+
+        launchIdlenessTracking()
     }
 
     companion object {
@@ -52,6 +61,21 @@
     }
 }
 
+private fun ComponentActivity.launchIdlenessTracking() {
+    val contentView: View = findViewById(android.R.id.content)
+    val callback: Choreographer.FrameCallback = object : Choreographer.FrameCallback {
+        override fun doFrame(frameTimeNanos: Long) {
+            if (Recomposer.runningRecomposers.value.any { it.hasPendingWork }) {
+                contentView.contentDescription = "COMPOSE-BUSY"
+            } else {
+                contentView.contentDescription = "COMPOSE-IDLE"
+            }
+            Choreographer.getInstance().postFrameCallback(this)
+        }
+    }
+    Choreographer.getInstance().postFrameCallback(callback)
+}
+
 @Composable
 private fun ListRow(entry: Entry) {
     Card(modifier = Modifier.padding(8.dp)) {
diff --git a/compose/integration-tests/macrobenchmark/build.gradle b/compose/integration-tests/macrobenchmark/build.gradle
index c67b044..6568c2a 100644
--- a/compose/integration-tests/macrobenchmark/build.gradle
+++ b/compose/integration-tests/macrobenchmark/build.gradle
@@ -39,6 +39,7 @@
     androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
     androidTestImplementation(ANDROIDX_TEST_CORE)
     androidTestImplementation(ANDROIDX_TEST_RUNNER)
+    androidTestImplementation(ANDROIDX_TEST_UIAUTOMATOR)
 }
 
 // Define a task dependency so the app is installed before we run macro benchmarks.
diff --git a/compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/compose/integration/macrobenchmark/FrameTimingMetricValidation.kt b/compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/compose/integration/macrobenchmark/FrameTimingMetricValidation.kt
new file mode 100644
index 0000000..bf96acd
--- /dev/null
+++ b/compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/compose/integration/macrobenchmark/FrameTimingMetricValidation.kt
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2020 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 android.graphics.Point
+import androidx.benchmark.macro.CompilationMode
+import androidx.benchmark.macro.FrameTimingMetric
+import androidx.benchmark.macro.junit4.MacrobenchmarkRule
+import androidx.test.filters.LargeTest
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.UiDevice
+import androidx.test.uiautomator.Until
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+@LargeTest
+@RunWith(Parameterized::class)
+class FrameTimingMetricValidation(private val compilationMode: CompilationMode) {
+    @get:Rule
+    val benchmarkRule = MacrobenchmarkRule()
+
+    private lateinit var device: UiDevice
+
+    @Before
+    fun setUp() {
+        val instrumentation = InstrumentationRegistry.getInstrumentation()
+        device = UiDevice.getInstance(instrumentation)
+    }
+
+    @Test
+    fun start() {
+        benchmarkRule.measureRepeated(
+            packageName = PACKAGE_NAME,
+            metrics = listOf(FrameTimingMetric()),
+            compilationMode = compilationMode,
+            iterations = 10,
+            setupBlock = {
+                val intent = Intent()
+                intent.action = ACTION
+                startActivityAndWait(intent)
+            }
+        ) {
+            val lazyColumn = device.findObject(By.desc(CONTENT_DESCRIPTION))
+            // Setting a gesture margin is important otherwise gesture nav is triggered.
+            lazyColumn.setGestureMargin(device.displayWidth / 5)
+            for (i in 1..10) {
+                // From center we scroll 2/3 of it which is 1/3 of the screen.
+                lazyColumn.drag(Point(0, lazyColumn.visibleCenter.y / 3))
+                device.wait(Until.findObject(By.desc(COMPOSE_IDLE)), 3000)
+            }
+        }
+    }
+
+    companion object {
+        private const val PACKAGE_NAME = "androidx.compose.integration.macrobenchmark.target"
+        private const val ACTION =
+            "androidx.compose.integration.macrobenchmark.target.LAZY_COLUMN_ACTIVITY"
+        private const val CONTENT_DESCRIPTION = "IamLazy"
+
+        private const val COMPOSE_IDLE = "COMPOSE-IDLE"
+
+        @Parameterized.Parameters(name = "compilation_mode={0}")
+        @JvmStatic
+        fun jankParameters(): List<Array<Any>> {
+            return listOf(
+                CompilationMode.None,
+                CompilationMode.SpeedProfile(warmupIterations = 3)
+            ).map { arrayOf(it) }
+        }
+    }
+}