diff --git a/benchmarks/src/main/java/com/google/samples/apps/nowinandroid/Utils.kt b/benchmarks/src/main/java/com/google/samples/apps/nowinandroid/Utils.kt index 494e451d0..9ece991c4 100644 --- a/benchmarks/src/main/java/com/google/samples/apps/nowinandroid/Utils.kt +++ b/benchmarks/src/main/java/com/google/samples/apps/nowinandroid/Utils.kt @@ -16,10 +16,13 @@ package com.google.samples.apps.nowinandroid +import androidx.test.uiautomator.BySelector import androidx.test.uiautomator.Direction import androidx.test.uiautomator.UiDevice import androidx.test.uiautomator.UiObject2 +import androidx.test.uiautomator.Until import com.google.samples.apps.nowinandroid.benchmarks.BuildConfig +import java.io.ByteArrayOutputStream /** * Convenience parameter to use proper package name with regards to build type and build flavor. @@ -38,3 +41,24 @@ fun UiDevice.flingElementDownUp(element: UiObject2) { waitForIdle() element.fling(Direction.UP) } + +/** + * Waits until an object with [selector] if visible on screen and returns the object. + * If the element is not available in [timeout], throws [AssertionError] + */ +fun UiDevice.waitAndFindObject(selector: BySelector, timeout: Long): UiObject2 { + if (!wait(Until.hasObject(selector), timeout)) { + throw AssertionError("Element not found on screen in ${timeout}ms (selector=$selector)") + } + + return findObject(selector) +} + +/** + * Helper to dump window hierarchy into a string. + */ +fun UiDevice.dumpWindowHierarchy(): String { + val buffer = ByteArrayOutputStream() + dumpWindowHierarchy(buffer) + return buffer.toString() +} diff --git a/benchmarks/src/main/java/com/google/samples/apps/nowinandroid/baselineprofile/BaselineProfileGenerator.kt b/benchmarks/src/main/java/com/google/samples/apps/nowinandroid/baselineprofile/BaselineProfileGenerator.kt index 3dfafd647..9286b2bef 100644 --- a/benchmarks/src/main/java/com/google/samples/apps/nowinandroid/baselineprofile/BaselineProfileGenerator.kt +++ b/benchmarks/src/main/java/com/google/samples/apps/nowinandroid/baselineprofile/BaselineProfileGenerator.kt @@ -19,6 +19,7 @@ package com.google.samples.apps.nowinandroid.baselineprofile import androidx.benchmark.macro.ExperimentalBaselineProfilesApi import androidx.benchmark.macro.junit4.BaselineProfileRule import com.google.samples.apps.nowinandroid.PACKAGE_NAME +import com.google.samples.apps.nowinandroid.allowNotifications import com.google.samples.apps.nowinandroid.bookmarks.goToBookmarksScreen import com.google.samples.apps.nowinandroid.foryou.forYouScrollFeedDownUp import com.google.samples.apps.nowinandroid.foryou.forYouSelectTopics @@ -41,7 +42,7 @@ class BaselineProfileGenerator { // This block defines the app's critical user journey. Here we are interested in // optimizing for app startup. But you can also navigate and scroll // through your most important UI. - + allowNotifications() pressHome() startActivityAndWait() diff --git a/benchmarks/src/main/java/com/google/samples/apps/nowinandroid/foryou/ForYouActions.kt b/benchmarks/src/main/java/com/google/samples/apps/nowinandroid/foryou/ForYouActions.kt index 5e4952fbb..9dea9dc4a 100644 --- a/benchmarks/src/main/java/com/google/samples/apps/nowinandroid/foryou/ForYouActions.kt +++ b/benchmarks/src/main/java/com/google/samples/apps/nowinandroid/foryou/ForYouActions.kt @@ -21,13 +21,14 @@ import androidx.test.uiautomator.By import androidx.test.uiautomator.Until import androidx.test.uiautomator.untilHasChildren import com.google.samples.apps.nowinandroid.flingElementDownUp +import com.google.samples.apps.nowinandroid.waitAndFindObject fun MacrobenchmarkScope.forYouWaitForContent() { // Wait until content is loaded by checking if topics are loaded device.wait(Until.gone(By.res("loadingWheel")), 5_000) // Sometimes, the loading wheel is gone, but the content is not loaded yet // So we'll wait here for topics to be sure - val obj = device.findObject(By.res("forYou:topicSelection")) + val obj = device.waitAndFindObject(By.res("forYou:topicSelection"), 10_000) // Timeout here is quite big, because sometimes data loading takes a long time! obj.wait(untilHasChildren(), 60_000) } diff --git a/benchmarks/src/main/java/com/google/samples/apps/nowinandroid/foryou/ScrollForYouFeedBenchmark.kt b/benchmarks/src/main/java/com/google/samples/apps/nowinandroid/foryou/ScrollForYouFeedBenchmark.kt index 3008fdc0d..18a7a717b 100644 --- a/benchmarks/src/main/java/com/google/samples/apps/nowinandroid/foryou/ScrollForYouFeedBenchmark.kt +++ b/benchmarks/src/main/java/com/google/samples/apps/nowinandroid/foryou/ScrollForYouFeedBenchmark.kt @@ -43,7 +43,7 @@ class ScrollForYouFeedBenchmark { metrics = listOf(FrameTimingMetric()), compilationMode = compilationMode, iterations = 10, - startupMode = StartupMode.COLD, + startupMode = StartupMode.WARM, setupBlock = { // Start the app pressHome() diff --git a/benchmarks/src/main/java/com/google/samples/apps/nowinandroid/startup/StartupBenchmark.kt b/benchmarks/src/main/java/com/google/samples/apps/nowinandroid/startup/StartupBenchmark.kt index 8e396eda3..678102f78 100644 --- a/benchmarks/src/main/java/com/google/samples/apps/nowinandroid/startup/StartupBenchmark.kt +++ b/benchmarks/src/main/java/com/google/samples/apps/nowinandroid/startup/StartupBenchmark.kt @@ -19,45 +19,24 @@ package com.google.samples.apps.nowinandroid.startup import androidx.benchmark.macro.BaselineProfileMode.Disable import androidx.benchmark.macro.BaselineProfileMode.Require import androidx.benchmark.macro.CompilationMode -import androidx.benchmark.macro.StartupMode import androidx.benchmark.macro.StartupMode.COLD -import androidx.benchmark.macro.StartupMode.HOT -import androidx.benchmark.macro.StartupMode.WARM import androidx.benchmark.macro.StartupTimingMetric import androidx.benchmark.macro.junit4.MacrobenchmarkRule import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner import com.google.samples.apps.nowinandroid.PACKAGE_NAME +import com.google.samples.apps.nowinandroid.allowNotifications import com.google.samples.apps.nowinandroid.foryou.forYouWaitForContent import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith /** + * Enables app startups from various states of baseline profile or [CompilationMode]s. * Run this benchmark from Studio to see startup measurements, and captured system traces * for investigating your app's performance from a cold state. */ @RunWith(AndroidJUnit4ClassRunner::class) -class ColdStartupBenchmark : AbstractStartupBenchmark(COLD) - -/** - * Run this benchmark from Studio to see startup measurements, and captured system traces - * for investigating your app's performance from a warm state. - */ -@RunWith(AndroidJUnit4ClassRunner::class) -class WarmStartupBenchmark : AbstractStartupBenchmark(WARM) - -/** - * Run this benchmark from Studio to see startup measurements, and captured system traces - * for investigating your app's performance from a hot state. - */ -@RunWith(AndroidJUnit4ClassRunner::class) -class HotStartupBenchmark : AbstractStartupBenchmark(HOT) - -/** - * Base class for benchmarks with different startup modes. - * Enables app startups from various states of baseline profile or [CompilationMode]s. - */ -abstract class AbstractStartupBenchmark(private val startupMode: StartupMode) { +class StartupBenchmark { @get:Rule val benchmarkRule = MacrobenchmarkRule() @@ -80,9 +59,10 @@ abstract class AbstractStartupBenchmark(private val startupMode: StartupMode) { metrics = listOf(StartupTimingMetric()), compilationMode = compilationMode, iterations = 10, - startupMode = startupMode, + startupMode = COLD, setupBlock = { pressHome() + allowNotifications() }, ) { startActivityAndWait()