From e986cd2a78d4e88d9489b6db0855df7e63942155 Mon Sep 17 00:00:00 2001 From: Ben Weiss Date: Mon, 7 Jul 2025 13:34:02 +0200 Subject: [PATCH] Move from SNAPSHOT to alpha / rc Change-Id: I75c04745b3641ad4cabd5df1e3c8b4518e9db9a6 --- benchmarks/build.gradle.kts | 1 + .../apps/nowinandroid/GeneralActions.kt | 6 +- .../bookmarks/BookmarksActions.kt | 2 +- .../apps/nowinandroid/foryou/ForYouActions.kt | 12 +-- .../interests/InterestsActions.kt | 10 +-- .../interests/ScrollTopicListBenchmark.kt | 8 +- .../ScrollTopicListPowerMetricsBenchmark.kt | 2 +- .../TopicsScreenRecompositionBenchmark.kt | 6 +- .../userjourney/NewUserJourneyBenchmark.kt | 84 +++++++++++++++++++ gradle/libs.versions.toml | 5 +- 10 files changed, 114 insertions(+), 22 deletions(-) create mode 100644 benchmarks/src/main/kotlin/com/google/samples/apps/nowinandroid/userjourney/NewUserJourneyBenchmark.kt diff --git a/benchmarks/build.gradle.kts b/benchmarks/build.gradle.kts index e36f021b0..d32db8d6d 100644 --- a/benchmarks/build.gradle.kts +++ b/benchmarks/build.gradle.kts @@ -69,6 +69,7 @@ baselineProfile { dependencies { implementation(libs.androidx.benchmark.macro) + implementation(libs.androidx.benchmark.traceprocessor) implementation(libs.androidx.test.core) implementation(libs.androidx.test.espresso.core) implementation(libs.androidx.test.ext) diff --git a/benchmarks/src/main/kotlin/com/google/samples/apps/nowinandroid/GeneralActions.kt b/benchmarks/src/main/kotlin/com/google/samples/apps/nowinandroid/GeneralActions.kt index 21bd5f22d..9c6beb5a5 100644 --- a/benchmarks/src/main/kotlin/com/google/samples/apps/nowinandroid/GeneralActions.kt +++ b/benchmarks/src/main/kotlin/com/google/samples/apps/nowinandroid/GeneralActions.kt @@ -18,7 +18,7 @@ package com.google.samples.apps.nowinandroid import android.view.accessibility.AccessibilityNodeInfo import androidx.test.uiautomator.UiAutomatorTestScope -import androidx.test.uiautomator.onView +import androidx.test.uiautomator.onElement import androidx.test.uiautomator.textAsString import androidx.test.uiautomator.watcher.PermissionDialog @@ -34,12 +34,12 @@ fun UiAutomatorTestScope.startAppAndAllowPermission() { } fun UiAutomatorTestScope.textVisibleOnTopAppBar(text: String) = - onTopAppBar { textAsString == text && isVisibleToUser } + onTopAppBar { textAsString() == text && isVisibleToUser } fun UiAutomatorTestScope.onTopAppBar( timeoutMs: Long = 10000, pollIntervalMs: Long = 100, block: AccessibilityNodeInfo.() -> (Boolean), ) { - onView { viewIdResourceName == "niaTopAppBar" }.onView(timeoutMs, pollIntervalMs, block) + onElement { viewIdResourceName == "niaTopAppBar" }.onElement(timeoutMs, pollIntervalMs, block) } diff --git a/benchmarks/src/main/kotlin/com/google/samples/apps/nowinandroid/bookmarks/BookmarksActions.kt b/benchmarks/src/main/kotlin/com/google/samples/apps/nowinandroid/bookmarks/BookmarksActions.kt index 2a9440067..308583df0 100644 --- a/benchmarks/src/main/kotlin/com/google/samples/apps/nowinandroid/bookmarks/BookmarksActions.kt +++ b/benchmarks/src/main/kotlin/com/google/samples/apps/nowinandroid/bookmarks/BookmarksActions.kt @@ -21,6 +21,6 @@ import androidx.test.uiautomator.textAsString import com.google.samples.apps.nowinandroid.textVisibleOnTopAppBar fun UiAutomatorTestScope.goToBookmarksScreen() { - onView { textAsString == "Saved" }.click() + onElement { textAsString == "Saved" }.click() textVisibleOnTopAppBar("Saved") } diff --git a/benchmarks/src/main/kotlin/com/google/samples/apps/nowinandroid/foryou/ForYouActions.kt b/benchmarks/src/main/kotlin/com/google/samples/apps/nowinandroid/foryou/ForYouActions.kt index a982fd01a..691b7db55 100644 --- a/benchmarks/src/main/kotlin/com/google/samples/apps/nowinandroid/foryou/ForYouActions.kt +++ b/benchmarks/src/main/kotlin/com/google/samples/apps/nowinandroid/foryou/ForYouActions.kt @@ -23,11 +23,11 @@ import com.google.samples.apps.nowinandroid.textVisibleOnTopAppBar import org.junit.Assert.fail fun UiAutomatorTestScope.forYouWaitForContent() { - onViewOrNull(timeoutMs = 500) { viewIdResourceName == "loadingWheel" && !isVisibleToUser } + onElementOrNull(timeoutMs = 500) { viewIdResourceName == "loadingWheel" && !isVisibleToUser } // Sometimes, the loading wheel is gone, but the content is not loaded yet // So we'll wait here for topics to be sure // Timeout here is quite big, because sometimes data loading takes a long time! - onView(timeoutMs = 30_000) { + onElement(timeoutMs = 30_000) { viewIdResourceName == "forYou:topicSelection" && childCount > 0 && isVisibleToUser } } @@ -37,7 +37,7 @@ fun UiAutomatorTestScope.forYouWaitForContent() { * [recheckTopicsIfChecked] Topics may be already checked from the previous iteration. */ fun UiAutomatorTestScope.forYouSelectTopics(recheckTopicsIfChecked: Boolean = false) { - onView { viewIdResourceName == "forYou:topicSelection" }.run { + onElement { viewIdResourceName == "forYou:topicSelection" }.run { if (children.isEmpty()) { fail("No topics found, can't generate profile for ForYou page.") } @@ -59,14 +59,14 @@ fun UiAutomatorTestScope.forYouSelectTopics(recheckTopicsIfChecked: Boolean = fa } fun UiAutomatorTestScope.forYouScrollFeedDownUp() { - onView { viewIdResourceName == "forYou:feed" }.run { + onElement { viewIdResourceName == "forYou:feed" }.run { fling(Direction.DOWN) fling(Direction.UP) } } fun UiAutomatorTestScope.setAppTheme(isDark: Boolean) { - onView { textAsString == if (isDark) "Dark" else "Light" }.click() - onView { textAsString == "OK" }.click() + onElement { textAsString() == if (isDark) "Dark" else "Light" }.click() + onElement { textAsString() == "OK" }.click() textVisibleOnTopAppBar("Now in Android") } diff --git a/benchmarks/src/main/kotlin/com/google/samples/apps/nowinandroid/interests/InterestsActions.kt b/benchmarks/src/main/kotlin/com/google/samples/apps/nowinandroid/interests/InterestsActions.kt index 2fd2f011a..6312d0cf9 100644 --- a/benchmarks/src/main/kotlin/com/google/samples/apps/nowinandroid/interests/InterestsActions.kt +++ b/benchmarks/src/main/kotlin/com/google/samples/apps/nowinandroid/interests/InterestsActions.kt @@ -22,21 +22,21 @@ import androidx.test.uiautomator.textAsString import com.google.samples.apps.nowinandroid.textVisibleOnTopAppBar fun UiAutomatorTestScope.goToInterestsScreen() { - onView { textAsString == "Interests" }.click() + onElement { textAsString() == "Interests" }.click() textVisibleOnTopAppBar("Interests") // Wait until content is loaded by checking if interests are loaded - assert(onViewOrNull { viewIdResourceName == "loadingWheel" && !isVisibleToUser } == null) + assert(onElementOrNull { viewIdResourceName == "loadingWheel" && !isVisibleToUser } == null) } fun UiAutomatorTestScope.interestsScrollTopicsDownUp() { - onView { viewIdResourceName == "interests:topics" }.run { + onElement { viewIdResourceName == "interests:topics" }.run { // Set some margin from the sides to prevent triggering system navigation - setGestureMargin(uiDevice.displayWidth / 5) + setGestureMargin(device.displayWidth / 5) fling(Direction.DOWN) fling(Direction.UP) } } fun UiAutomatorTestScope.interestsWaitForTopics() { - onView(30_000) { textAsString == "Accessibility" } + onElement(30_000) { textAsString() == "Accessibility" } } diff --git a/benchmarks/src/main/kotlin/com/google/samples/apps/nowinandroid/interests/ScrollTopicListBenchmark.kt b/benchmarks/src/main/kotlin/com/google/samples/apps/nowinandroid/interests/ScrollTopicListBenchmark.kt index cf27f7517..9397206b5 100644 --- a/benchmarks/src/main/kotlin/com/google/samples/apps/nowinandroid/interests/ScrollTopicListBenchmark.kt +++ b/benchmarks/src/main/kotlin/com/google/samples/apps/nowinandroid/interests/ScrollTopicListBenchmark.kt @@ -16,10 +16,14 @@ package com.google.samples.apps.nowinandroid.interests +import androidx.benchmark.ExperimentalBenchmarkConfigApi +import androidx.benchmark.ExperimentalConfig +import androidx.benchmark.StartupInsightsConfig import androidx.benchmark.macro.CompilationMode import androidx.benchmark.macro.FrameTimingMetric import androidx.benchmark.macro.StartupMode import androidx.benchmark.macro.junit4.MacrobenchmarkRule +import androidx.benchmark.perfetto.ExperimentalPerfettoCaptureApi import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.uiautomator.textAsString import androidx.test.uiautomator.uiAutomator @@ -30,6 +34,7 @@ import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith +@OptIn(ExperimentalBenchmarkConfigApi::class, ExperimentalPerfettoCaptureApi::class) @RunWith(AndroidJUnit4::class) class ScrollTopicListBenchmark { @get:Rule @@ -46,13 +51,14 @@ class ScrollTopicListBenchmark { compilationMode = compilationMode, iterations = ITERATIONS, startupMode = StartupMode.WARM, + experimentalConfig = ExperimentalConfig(startupInsightsConfig = StartupInsightsConfig(true)), setupBlock = { uiAutomator { // Start the app pressHome() startAppAndAllowPermission() // Navigate to interests screen - onView { textAsString == "Interests" }.click() + onElement { textAsString() == "Interests" }.click() } }, ) { diff --git a/benchmarks/src/main/kotlin/com/google/samples/apps/nowinandroid/interests/ScrollTopicListPowerMetricsBenchmark.kt b/benchmarks/src/main/kotlin/com/google/samples/apps/nowinandroid/interests/ScrollTopicListPowerMetricsBenchmark.kt index 07e3f06cc..aa9235bc4 100644 --- a/benchmarks/src/main/kotlin/com/google/samples/apps/nowinandroid/interests/ScrollTopicListPowerMetricsBenchmark.kt +++ b/benchmarks/src/main/kotlin/com/google/samples/apps/nowinandroid/interests/ScrollTopicListPowerMetricsBenchmark.kt @@ -68,7 +68,7 @@ class ScrollTopicListPowerMetricsBenchmark { uiAutomator { pressHome() startAppAndAllowPermission() - onView { contentDescription == "Settings" }.click() + onElement { contentDescription == "Settings" }.click() setAppTheme(isDark) } }, diff --git a/benchmarks/src/main/kotlin/com/google/samples/apps/nowinandroid/interests/TopicsScreenRecompositionBenchmark.kt b/benchmarks/src/main/kotlin/com/google/samples/apps/nowinandroid/interests/TopicsScreenRecompositionBenchmark.kt index 3375bbf6b..e0eb412a4 100644 --- a/benchmarks/src/main/kotlin/com/google/samples/apps/nowinandroid/interests/TopicsScreenRecompositionBenchmark.kt +++ b/benchmarks/src/main/kotlin/com/google/samples/apps/nowinandroid/interests/TopicsScreenRecompositionBenchmark.kt @@ -21,7 +21,7 @@ import androidx.benchmark.macro.FrameTimingMetric import androidx.benchmark.macro.StartupMode import androidx.benchmark.macro.junit4.MacrobenchmarkRule import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.uiautomator.onView +import androidx.test.uiautomator.onElement import androidx.test.uiautomator.textAsString import androidx.test.uiautomator.uiAutomator import com.google.samples.apps.nowinandroid.ITERATIONS @@ -53,7 +53,7 @@ class TopicsScreenRecompositionBenchmark { pressHome() startAppAndAllowPermission() // Navigate to interests screen - onView { textAsString == "Interests" }.click() + onElement { textAsString() == "Interests" }.click() } }, ) { @@ -61,7 +61,7 @@ class TopicsScreenRecompositionBenchmark { interestsWaitForTopics() repeat(3) { // Toggle bookmarked - onView { viewIdResourceName == "interests:topics" }.onView { isCheckable } + onElement { viewIdResourceName == "interests:topics" }.onElement { isCheckable } .click() } } diff --git a/benchmarks/src/main/kotlin/com/google/samples/apps/nowinandroid/userjourney/NewUserJourneyBenchmark.kt b/benchmarks/src/main/kotlin/com/google/samples/apps/nowinandroid/userjourney/NewUserJourneyBenchmark.kt new file mode 100644 index 000000000..ae7217ac9 --- /dev/null +++ b/benchmarks/src/main/kotlin/com/google/samples/apps/nowinandroid/userjourney/NewUserJourneyBenchmark.kt @@ -0,0 +1,84 @@ +/* + * Copyright 2025 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 + * + * https://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.google.samples.apps.nowinandroid.userjourney + +import androidx.benchmark.macro.CompilationMode +import androidx.benchmark.macro.StartupMode +import androidx.benchmark.macro.junit4.MacrobenchmarkRule +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.uiautomator.Direction +import androidx.test.uiautomator.scrollToElement +import androidx.test.uiautomator.textAsString +import androidx.test.uiautomator.uiAutomator +import androidx.test.uiautomator.waitForStable +import androidx.test.uiautomator.watcher.PermissionDialog +import com.google.samples.apps.nowinandroid.BaselineProfileMetrics +import com.google.samples.apps.nowinandroid.ITERATIONS +import com.google.samples.apps.nowinandroid.PACKAGE_NAME +import com.google.samples.apps.nowinandroid.foryou.forYouSelectTopics +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class NewUserJourneyBenchmark { + + @get:Rule + val benchmarkRule = MacrobenchmarkRule() + + @Test + fun measureJourney() = benchmarkRule.measureRepeated( + packageName = PACKAGE_NAME, + metrics = BaselineProfileMetrics.allMetrics, + compilationMode = CompilationMode.DEFAULT, + startupMode = StartupMode.COLD, + iterations = ITERATIONS, + ) { + uiAutomator { + startApp(PACKAGE_NAME) + watchFor(PermissionDialog) { + clickAllow() + } + // Select some topics + forYouSelectTopics() + onElement { textAsString() == "Done" }.click() + onElement { isScrollable }.scroll(Direction.DOWN, 0.25f) + onElement { textAsString() == "Interests" }.click() + + activeWindowRoot().waitForStable() + + onElement { isScrollable }.scrollToElement( + direction = Direction.DOWN, + block = { + textAsString() == "Performance" + }, + ).click() + + // Enable dynamic color in settings + onElement { contentDescription == "Settings" }.click() + onElement { textAsString() == "Yes" }.click() + pressBack() + + // Search for "AndroidX releases" + onElement { contentDescription == "Search" }.click() + // Wait for animations to finish + activeWindowRoot().waitForStable() + type("AndroidX releases") + pressEnter() + } + } +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 468c4b3b0..aea65cba8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -18,7 +18,7 @@ androidxEspresso = "3.6.1" androidxHiltNavigationCompose = "1.2.0" androidxLifecycle = "2.8.7" androidxLintGradle = "1.0.0-alpha03" -androidxMacroBenchmark = "1.4.0-alpha11" +androidxMacroBenchmark = "1.4.0-rc01" androidxMetrics = "1.0.0-beta01" androidxNavigation = "2.8.5" androidxProfileinstaller = "1.4.1" @@ -27,7 +27,7 @@ androidxTestExt = "1.2.1" androidxTestRules = "1.6.1" androidxTestRunner = "1.6.2" androidxTracing = "1.3.0-alpha02" -androidxUiAutomator = "2.4.0-SNAPSHOT" +androidxUiAutomator = "2.4.0-alpha05" androidxWindowManager = "1.3.0" androidxWork = "2.10.0" coil = "2.7.0" @@ -69,6 +69,7 @@ android-desugarJdkLibs = { group = "com.android.tools", name = "desugar_jdk_libs androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "androidxActivity" } androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "androidxAppCompat" } androidx-benchmark-macro = { group = "androidx.benchmark", name = "benchmark-macro-junit4", version.ref = "androidxMacroBenchmark" } +androidx-benchmark-traceprocessor = { group = "androidx.benchmark", name = "benchmark-traceprocessor", version.ref = "androidxMacroBenchmark" } androidx-browser = { group = "androidx.browser", name = "browser", version.ref = "androidxBrowser" } androidx-compose-bom = { group = "androidx.compose", name = "compose-bom-alpha", version.ref = "androidxComposeBom" } androidx-compose-foundation = { group = "androidx.compose.foundation", name = "foundation", version.ref = "androidxComposeFoundation" }