Merge "Added configuration to explicit dependency on agp in baseline profile gradle plugin tests" into androidx-main
diff --git a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/task/impl/TaskCapabilityImplTest.kt b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/task/TaskCapabilityImplTest.kt
similarity index 100%
rename from appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/task/impl/TaskCapabilityImplTest.kt
rename to appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/task/TaskCapabilityImplTest.kt
diff --git a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/task/impl/TaskCapabilityUtilsTest.kt b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/task/TaskCapabilityUtilsTest.kt
similarity index 100%
rename from appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/task/impl/TaskCapabilityUtilsTest.kt
rename to appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/task/TaskCapabilityUtilsTest.kt
diff --git a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/task/impl/TaskSlotProcessorTest.kt b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/task/TaskSlotProcessorTest.kt
similarity index 100%
rename from appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/task/impl/TaskSlotProcessorTest.kt
rename to appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/task/TaskSlotProcessorTest.kt
diff --git a/benchmark/benchmark-macro/build.gradle b/benchmark/benchmark-macro/build.gradle
index 0bb6d0b..538d68d 100644
--- a/benchmark/benchmark-macro/build.gradle
+++ b/benchmark/benchmark-macro/build.gradle
@@ -158,6 +158,13 @@
}
}
+androidx {
+ deviceTests {
+ targetAppProject = project(":benchmark:integration-tests:macrobenchmark-target")
+ targetAppVariant = "release"
+ }
+}
+
// Define a task dependency so the app is installed before we run macro benchmarks.
afterEvaluate {
// `:benchmark:integration-tests:macrobenchmark-target:installRelease` is not in the compose
diff --git a/benchmark/integration-tests/baselineprofile-flavors-producer/build.gradle b/benchmark/integration-tests/baselineprofile-flavors-producer/build.gradle
index 0634f31..05d1c99 100644
--- a/benchmark/integration-tests/baselineprofile-flavors-producer/build.gradle
+++ b/benchmark/integration-tests/baselineprofile-flavors-producer/build.gradle
@@ -61,5 +61,7 @@
}
androidx {
- disableDeviceTests = true
+ deviceTests {
+ enabled = false
+ }
}
diff --git a/benchmark/integration-tests/baselineprofile-library-producer/build.gradle b/benchmark/integration-tests/baselineprofile-library-producer/build.gradle
index b6cee42..44b3bda 100644
--- a/benchmark/integration-tests/baselineprofile-library-producer/build.gradle
+++ b/benchmark/integration-tests/baselineprofile-library-producer/build.gradle
@@ -56,5 +56,7 @@
}
androidx {
- disableDeviceTests = true
+ deviceTests {
+ enabled = false
+ }
}
diff --git a/benchmark/integration-tests/baselineprofile-producer/build.gradle b/benchmark/integration-tests/baselineprofile-producer/build.gradle
index a696a90..e04a270 100644
--- a/benchmark/integration-tests/baselineprofile-producer/build.gradle
+++ b/benchmark/integration-tests/baselineprofile-producer/build.gradle
@@ -56,5 +56,7 @@
}
androidx {
- disableDeviceTests = true
+ deviceTests {
+ enabled = false
+ }
}
diff --git a/benchmark/integration-tests/macrobenchmark/build.gradle b/benchmark/integration-tests/macrobenchmark/build.gradle
index a62c063..58d7ee0 100644
--- a/benchmark/integration-tests/macrobenchmark/build.gradle
+++ b/benchmark/integration-tests/macrobenchmark/build.gradle
@@ -19,7 +19,7 @@
plugins {
id("AndroidXPlugin")
- id("com.android.library")
+ id("com.android.test")
id("kotlin-android")
}
@@ -28,34 +28,31 @@
minSdkVersion 23
}
sourceSets {
- androidTest.assets.srcDirs += new File(
+ main.assets.srcDirs += new File(
SupportConfigKt.getPrebuiltsRoot(project),
"androidx/traceprocessor/testdata"
)
}
namespace "androidx.benchmark.integration.macrobenchmark"
+ targetProjectPath = ":benchmark:integration-tests:macrobenchmark-target"
+ experimentalProperties["android.experimental.self-instrumenting"] = true
}
+// Create a release build type and make sure it's the only one enabled.
+// This is needed because we benchmark the release build type only.
+android.buildTypes { release {} }
+androidComponents { beforeVariants(selector().all()) { enabled = buildType == 'release' } }
+
dependencies {
- androidTestImplementation(project(":benchmark:benchmark-junit4"))
- androidTestImplementation(project(":benchmark:benchmark-macro-junit4"))
- androidTestImplementation(project(":internal-testutils-macrobenchmark"))
- androidTestImplementation(project(":tracing:tracing-ktx"))
- androidTestImplementation(libs.kotlinTest)
- androidTestImplementation(libs.testRules)
- androidTestImplementation(libs.testExtJunit)
- androidTestImplementation(libs.testCore)
- androidTestImplementation(libs.testRunner)
- androidTestImplementation(libs.testUiautomator)
- androidTestImplementation(libs.testExtTruth)
-}
-
-// Define a task dependency so the app is installed before we run macro benchmarks.
-afterEvaluate {
- tasks.getByPath(":benchmark:integration-tests:macrobenchmark:connectedDebugAndroidTest")
- .dependsOn(
- tasks.getByPath(
- ":benchmark:integration-tests:macrobenchmark-target:installRelease"
- )
- )
+ implementation(project(":benchmark:benchmark-junit4"))
+ implementation(project(":benchmark:benchmark-macro-junit4"))
+ implementation(project(":internal-testutils-macrobenchmark"))
+ implementation(project(":tracing:tracing-ktx"))
+ implementation(libs.kotlinTest)
+ implementation(libs.testRules)
+ implementation(libs.testExtJunit)
+ implementation(libs.testCore)
+ implementation(libs.testRunner)
+ implementation(libs.testUiautomator)
+ implementation(libs.testExtTruth)
}
diff --git a/benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/benchmark/integration/macrobenchmark/AudioUnderrunBenchmark.kt b/benchmark/integration-tests/macrobenchmark/src/main/java/androidx/benchmark/integration/macrobenchmark/AudioUnderrunBenchmark.kt
similarity index 100%
rename from benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/benchmark/integration/macrobenchmark/AudioUnderrunBenchmark.kt
rename to benchmark/integration-tests/macrobenchmark/src/main/java/androidx/benchmark/integration/macrobenchmark/AudioUnderrunBenchmark.kt
diff --git a/benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/benchmark/integration/macrobenchmark/BaselineProfileRuleTest.kt b/benchmark/integration-tests/macrobenchmark/src/main/java/androidx/benchmark/integration/macrobenchmark/BaselineProfileRuleTest.kt
similarity index 100%
rename from benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/benchmark/integration/macrobenchmark/BaselineProfileRuleTest.kt
rename to benchmark/integration-tests/macrobenchmark/src/main/java/androidx/benchmark/integration/macrobenchmark/BaselineProfileRuleTest.kt
diff --git a/benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/benchmark/integration/macrobenchmark/CompilationModeTest.kt b/benchmark/integration-tests/macrobenchmark/src/main/java/androidx/benchmark/integration/macrobenchmark/CompilationModeTest.kt
similarity index 100%
rename from benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/benchmark/integration/macrobenchmark/CompilationModeTest.kt
rename to benchmark/integration-tests/macrobenchmark/src/main/java/androidx/benchmark/integration/macrobenchmark/CompilationModeTest.kt
diff --git a/benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/benchmark/integration/macrobenchmark/GithubBrowserBaselineProfile.kt b/benchmark/integration-tests/macrobenchmark/src/main/java/androidx/benchmark/integration/macrobenchmark/GithubBrowserBaselineProfile.kt
similarity index 100%
rename from benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/benchmark/integration/macrobenchmark/GithubBrowserBaselineProfile.kt
rename to benchmark/integration-tests/macrobenchmark/src/main/java/androidx/benchmark/integration/macrobenchmark/GithubBrowserBaselineProfile.kt
diff --git a/benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/benchmark/integration/macrobenchmark/GridBenchmark.kt b/benchmark/integration-tests/macrobenchmark/src/main/java/androidx/benchmark/integration/macrobenchmark/GridBenchmark.kt
similarity index 100%
rename from benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/benchmark/integration/macrobenchmark/GridBenchmark.kt
rename to benchmark/integration-tests/macrobenchmark/src/main/java/androidx/benchmark/integration/macrobenchmark/GridBenchmark.kt
diff --git a/benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/benchmark/integration/macrobenchmark/PerfettoTraceProcessorBenchmark.kt b/benchmark/integration-tests/macrobenchmark/src/main/java/androidx/benchmark/integration/macrobenchmark/PerfettoTraceProcessorBenchmark.kt
similarity index 100%
rename from benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/benchmark/integration/macrobenchmark/PerfettoTraceProcessorBenchmark.kt
rename to benchmark/integration-tests/macrobenchmark/src/main/java/androidx/benchmark/integration/macrobenchmark/PerfettoTraceProcessorBenchmark.kt
diff --git a/benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/benchmark/integration/macrobenchmark/SeparateProcessBenchmark.kt b/benchmark/integration-tests/macrobenchmark/src/main/java/androidx/benchmark/integration/macrobenchmark/SeparateProcessBenchmark.kt
similarity index 100%
rename from benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/benchmark/integration/macrobenchmark/SeparateProcessBenchmark.kt
rename to benchmark/integration-tests/macrobenchmark/src/main/java/androidx/benchmark/integration/macrobenchmark/SeparateProcessBenchmark.kt
diff --git a/benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/benchmark/integration/macrobenchmark/SingleColorPowerBenchmark.kt b/benchmark/integration-tests/macrobenchmark/src/main/java/androidx/benchmark/integration/macrobenchmark/SingleColorPowerBenchmark.kt
similarity index 100%
rename from benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/benchmark/integration/macrobenchmark/SingleColorPowerBenchmark.kt
rename to benchmark/integration-tests/macrobenchmark/src/main/java/androidx/benchmark/integration/macrobenchmark/SingleColorPowerBenchmark.kt
diff --git a/benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/benchmark/integration/macrobenchmark/SmallListStartupBenchmark.kt b/benchmark/integration-tests/macrobenchmark/src/main/java/androidx/benchmark/integration/macrobenchmark/SmallListStartupBenchmark.kt
similarity index 100%
rename from benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/benchmark/integration/macrobenchmark/SmallListStartupBenchmark.kt
rename to benchmark/integration-tests/macrobenchmark/src/main/java/androidx/benchmark/integration/macrobenchmark/SmallListStartupBenchmark.kt
diff --git a/benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/benchmark/integration/macrobenchmark/StartupPressHomeBenchmark.kt b/benchmark/integration-tests/macrobenchmark/src/main/java/androidx/benchmark/integration/macrobenchmark/StartupPressHomeBenchmark.kt
similarity index 100%
rename from benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/benchmark/integration/macrobenchmark/StartupPressHomeBenchmark.kt
rename to benchmark/integration-tests/macrobenchmark/src/main/java/androidx/benchmark/integration/macrobenchmark/StartupPressHomeBenchmark.kt
diff --git a/benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/benchmark/integration/macrobenchmark/SystemUiBenchmark.kt b/benchmark/integration-tests/macrobenchmark/src/main/java/androidx/benchmark/integration/macrobenchmark/SystemUiBenchmark.kt
similarity index 100%
rename from benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/benchmark/integration/macrobenchmark/SystemUiBenchmark.kt
rename to benchmark/integration-tests/macrobenchmark/src/main/java/androidx/benchmark/integration/macrobenchmark/SystemUiBenchmark.kt
diff --git a/benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/benchmark/integration/macrobenchmark/TrivialListScrollBaselineProfile.kt b/benchmark/integration-tests/macrobenchmark/src/main/java/androidx/benchmark/integration/macrobenchmark/TrivialListScrollBaselineProfile.kt
similarity index 100%
rename from benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/benchmark/integration/macrobenchmark/TrivialListScrollBaselineProfile.kt
rename to benchmark/integration-tests/macrobenchmark/src/main/java/androidx/benchmark/integration/macrobenchmark/TrivialListScrollBaselineProfile.kt
diff --git a/benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/benchmark/integration/macrobenchmark/TrivialListScrollBenchmark.kt b/benchmark/integration-tests/macrobenchmark/src/main/java/androidx/benchmark/integration/macrobenchmark/TrivialListScrollBenchmark.kt
similarity index 100%
rename from benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/benchmark/integration/macrobenchmark/TrivialListScrollBenchmark.kt
rename to benchmark/integration-tests/macrobenchmark/src/main/java/androidx/benchmark/integration/macrobenchmark/TrivialListScrollBenchmark.kt
diff --git a/benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/benchmark/integration/macrobenchmark/TrivialPowerBenchmark.kt b/benchmark/integration-tests/macrobenchmark/src/main/java/androidx/benchmark/integration/macrobenchmark/TrivialPowerBenchmark.kt
similarity index 100%
rename from benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/benchmark/integration/macrobenchmark/TrivialPowerBenchmark.kt
rename to benchmark/integration-tests/macrobenchmark/src/main/java/androidx/benchmark/integration/macrobenchmark/TrivialPowerBenchmark.kt
diff --git a/benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/benchmark/integration/macrobenchmark/TrivialStartupBaselineProfile.kt b/benchmark/integration-tests/macrobenchmark/src/main/java/androidx/benchmark/integration/macrobenchmark/TrivialStartupBaselineProfile.kt
similarity index 100%
rename from benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/benchmark/integration/macrobenchmark/TrivialStartupBaselineProfile.kt
rename to benchmark/integration-tests/macrobenchmark/src/main/java/androidx/benchmark/integration/macrobenchmark/TrivialStartupBaselineProfile.kt
diff --git a/benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/benchmark/integration/macrobenchmark/TrivialStartupBenchmark.kt b/benchmark/integration-tests/macrobenchmark/src/main/java/androidx/benchmark/integration/macrobenchmark/TrivialStartupBenchmark.kt
similarity index 100%
rename from benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/benchmark/integration/macrobenchmark/TrivialStartupBenchmark.kt
rename to benchmark/integration-tests/macrobenchmark/src/main/java/androidx/benchmark/integration/macrobenchmark/TrivialStartupBenchmark.kt
diff --git a/benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/benchmark/integration/macrobenchmark/TrivialStartupFullyDrawnBenchmark.kt b/benchmark/integration-tests/macrobenchmark/src/main/java/androidx/benchmark/integration/macrobenchmark/TrivialStartupFullyDrawnBenchmark.kt
similarity index 100%
rename from benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/benchmark/integration/macrobenchmark/TrivialStartupFullyDrawnBenchmark.kt
rename to benchmark/integration-tests/macrobenchmark/src/main/java/androidx/benchmark/integration/macrobenchmark/TrivialStartupFullyDrawnBenchmark.kt
diff --git a/benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/benchmark/integration/macrobenchmark/TrivialStartupJavaBenchmark.java b/benchmark/integration-tests/macrobenchmark/src/main/java/androidx/benchmark/integration/macrobenchmark/TrivialStartupJavaBenchmark.java
similarity index 92%
rename from benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/benchmark/integration/macrobenchmark/TrivialStartupJavaBenchmark.java
rename to benchmark/integration-tests/macrobenchmark/src/main/java/androidx/benchmark/integration/macrobenchmark/TrivialStartupJavaBenchmark.java
index 2e75f3a..8090aa3 100644
--- a/benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/benchmark/integration/macrobenchmark/TrivialStartupJavaBenchmark.java
+++ b/benchmark/integration-tests/macrobenchmark/src/main/java/androidx/benchmark/integration/macrobenchmark/TrivialStartupJavaBenchmark.java
@@ -20,19 +20,27 @@
import androidx.benchmark.macro.StartupMode;
import androidx.benchmark.macro.StartupTimingMetric;
import androidx.benchmark.macro.junit4.MacrobenchmarkRule;
+import androidx.test.filters.LargeTest;
import androidx.test.filters.SdkSuppress;
+import kotlin.Unit;
+
import org.junit.Rule;
import org.junit.Test;
import java.util.Collections;
-import kotlin.Unit;
-
+/**
+ * Simple benchmark for startup in java.
+ */
+@LargeTest
public class TrivialStartupJavaBenchmark {
@Rule
public MacrobenchmarkRule mBenchmarkRule = new MacrobenchmarkRule();
+ /**
+ * Benchmark for startup.
+ */
@Test
@SdkSuppress(minSdkVersion = 29)
public void startup() {
diff --git a/benchmark/integration-tests/test-module-sample/build.gradle b/benchmark/integration-tests/test-module-sample/build.gradle
deleted file mode 100644
index 5351938..0000000
--- a/benchmark/integration-tests/test-module-sample/build.gradle
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2021 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.
- */
-
-plugins {
- id("AndroidXPlugin")
- id("com.android.test")
- id("kotlin-android")
-}
-
-android {
- targetProjectPath = ":benchmark:integration-tests:macrobenchmark-target"
- experimentalProperties["android.experimental.self-instrumenting"] = true
-
- // note: below is optional, mimicing eventual benchmark module setup
- buildTypes {
- release {
- debuggable = true
- }
- }
-
- defaultConfig {
- minSdkVersion 28
- }
- namespace "androidx.benchmark.integration.testmodulesample"
-}
-
-// note: below is optional, mimicing eventual benchmark module setup
-androidComponents {
- beforeVariants(selector().all()) {
- // Enable only the release buildType, since we only want to measure
- // release build performance
- getLogger().info("setting enable for variant" + name + ", buildType " + buildType)
- enabled = buildType == 'release'
- }
-}
-
-dependencies {
- implementation(libs.kotlinStdlib)
- implementation(libs.testRules)
- implementation(libs.testExtJunit)
- implementation(libs.testCore)
- implementation(libs.testRunner)
-}
diff --git a/benchmark/integration-tests/test-module-sample/src/main/java/androidx/benchmark/integration/macrobenchmark/TrivialTestModuleTest.kt b/benchmark/integration-tests/test-module-sample/src/main/java/androidx/benchmark/integration/macrobenchmark/TrivialTestModuleTest.kt
deleted file mode 100644
index aac7497..0000000
--- a/benchmark/integration-tests/test-module-sample/src/main/java/androidx/benchmark/integration/macrobenchmark/TrivialTestModuleTest.kt
+++ /dev/null
@@ -1,69 +0,0 @@
-
-/*
- * 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.benchmark.integration.macrobenchmark
-
-import android.content.pm.PackageManager
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.LargeTest
-import androidx.test.platform.app.InstrumentationRegistry
-import org.junit.Assert.assertEquals
-import org.junit.Ignore
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@LargeTest
-@RunWith(AndroidJUnit4::class)
-class TrivialTestModuleTest {
- @Test
- fun targetPackage() {
- // if self-instrumenting wasn't used, this would instrument the target app,
- // and we'd see TargetPackage instead
- assertEquals(
- TestPackage,
- InstrumentationRegistry.getInstrumentation().targetContext.packageName
- )
- }
-
- @Test
- fun testPackage() {
- assertEquals(
- TestPackage,
- InstrumentationRegistry.getInstrumentation().context.packageName
- )
- }
-
- @Ignore // b/202321897
- @Test
- @Suppress("DEPRECATION")
- fun targetPackageInstalled() {
- val pm = InstrumentationRegistry.getInstrumentation().context.packageManager
- try {
- pm.getApplicationInfo(TargetPackage, 0)
- } catch (notFoundException: PackageManager.NameNotFoundException) {
- throw AssertionError(
- "Unable to find target package $TargetPackage, is it installed?",
- notFoundException
- )
- }
- }
-
- companion object {
- const val TargetPackage = "androidx.benchmark.integration.macrobenchmark.target"
- const val TestPackage = "androidx.benchmark.integration.testmodulesample"
- }
-}
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXExtension.kt b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXExtension.kt
index 8c0a117..242b964 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXExtension.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXExtension.kt
@@ -23,13 +23,16 @@
import java.io.File
import org.gradle.api.GradleException
import org.gradle.api.Project
+import org.gradle.api.plugins.ExtensionAware
+import org.gradle.api.plugins.ExtensionContainer
import org.gradle.api.provider.Property
import org.gradle.api.provider.Provider
/**
* Extension for [AndroidXImplPlugin] that's responsible for holding configuration options.
*/
-open class AndroidXExtension(val project: Project) {
+abstract class AndroidXExtension(val project: Project) : ExtensionAware {
+
@JvmField
val LibraryVersions: Map<String, Version>
@@ -45,6 +48,8 @@
private val versionService: LibraryVersionsService
+ val deviceTests = DeviceTests.register(project.extensions)
+
init {
val tomlFileName = "libraryversions.toml"
val toml = lazyReadFile(tomlFileName)
@@ -376,8 +381,6 @@
var metalavaK2UastEnabled = false
- var disableDeviceTests = false
-
val additionalDeviceTestApkKeys = mutableListOf<String>()
val additionalDeviceTestTags: MutableList<String> by lazy {
@@ -422,3 +425,18 @@
var name: String? = null
var url: String? = null
}
+
+abstract class DeviceTests {
+
+ companion object {
+ private const val EXTENSION_NAME = "deviceTests"
+ internal fun register(extensions: ExtensionContainer): DeviceTests {
+ return extensions.findByType(DeviceTests::class.java)
+ ?: extensions.create(EXTENSION_NAME, DeviceTests::class.java)
+ }
+ }
+
+ var enabled = true
+ var targetAppProject: Project? = null
+ var targetAppVariant = "debug"
+}
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt
index 3fae48c..b8b224c 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt
@@ -323,7 +323,7 @@
private fun configureWithAppPlugin(project: Project, androidXExtension: AndroidXExtension) {
project.extensions.getByType<AppExtension>().apply {
configureAndroidBaseOptions(project, androidXExtension)
- configureAndroidApplicationOptions(project)
+ configureAndroidApplicationOptions(project, androidXExtension)
}
project.extensions.getByType<ApplicationAndroidComponentsExtension>().apply {
@@ -347,6 +347,7 @@
) {
project.extensions.getByType<TestExtension>().apply {
configureAndroidBaseOptions(project, androidXExtension)
+ project.addAppApkToTestConfigGeneration(androidXExtension)
}
project.configureJavaCompilationWarnings(androidXExtension)
@@ -410,6 +411,7 @@
) {
val libraryExtension = project.extensions.getByType<LibraryExtension>().apply {
configureAndroidBaseOptions(project, androidXExtension)
+ project.addAppApkToTestConfigGeneration(androidXExtension)
configureAndroidLibraryOptions(project, androidXExtension)
// Make sure the main Kotlin source set doesn't contain anything under src/main/kotlin.
@@ -808,13 +810,16 @@
}
}
- private fun AppExtension.configureAndroidApplicationOptions(project: Project) {
+ private fun AppExtension.configureAndroidApplicationOptions(
+ project: Project,
+ androidXExtension: AndroidXExtension
+ ) {
defaultConfig.apply {
versionCode = 1
versionName = "1.0"
}
- project.addAppApkToTestConfigGeneration()
+ project.addAppApkToTestConfigGeneration(androidXExtension)
project.addAppApkToFtlRunner()
}
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/testConfiguration/GenerateTestConfigurationTask.kt b/buildSrc/private/src/main/kotlin/androidx/build/testConfiguration/GenerateTestConfigurationTask.kt
index 1960148..3f8005e 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/testConfiguration/GenerateTestConfigurationTask.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/testConfiguration/GenerateTestConfigurationTask.kt
@@ -19,10 +19,13 @@
import androidx.build.dependencyTracker.ProjectSubset
import com.android.build.api.variant.BuiltArtifactsLoader
import java.io.File
+import javax.inject.Inject
import org.gradle.api.DefaultTask
import org.gradle.api.GradleException
+import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.RegularFileProperty
+import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.ListProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
@@ -42,13 +45,19 @@
* This config gets ingested by Tradefed.
*/
@DisableCachingByDefault(because = "Doesn't benefit from caching")
-abstract class GenerateTestConfigurationTask : DefaultTask() {
+abstract class GenerateTestConfigurationTask @Inject constructor(
+ private val objects: ObjectFactory
+) : DefaultTask() {
@get:InputFiles
@get:Optional
@get:PathSensitive(PathSensitivity.RELATIVE)
abstract val appFolder: DirectoryProperty
+ @get:InputFiles
+ @get:PathSensitive(PathSensitivity.RELATIVE)
+ abstract val appFileCollection: ConfigurableFileCollection
+
@get:Internal
abstract val appLoader: Property<BuiltArtifactsLoader>
@@ -129,7 +138,20 @@
val configBuilder = ConfigBuilder()
configBuilder.configName = outputFile.asFile.get().name
if (appLoader.isPresent) {
- val appApk = appLoader.get().load(appFolder.get())
+
+ // Decides where to load the app apk from, depending on whether appFolder or
+ // appFileCollection has been set.
+ val appDir = if (appFolder.isPresent && appFileCollection.files.isEmpty()) {
+ appFolder.get()
+ } else if (!appFolder.isPresent && appFileCollection.files.size == 1) {
+ objects.directoryProperty().also { it.set(appFileCollection.files.first()) }.get()
+ } else {
+ throw IllegalStateException("""
+ App apk not specified or both appFileCollection and appFolder specified.
+ """.trimIndent())
+ }
+
+ val appApk = appLoader.get().load(appDir)
?: throw RuntimeException("Cannot load required APK for task: $name")
// We don't need to check hasBenchmarkPlugin because benchmarks shouldn't have test apps
val appApkBuiltArtifact = appApk.elements.single()
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/testConfiguration/TestSuiteConfiguration.kt b/buildSrc/private/src/main/kotlin/androidx/build/testConfiguration/TestSuiteConfiguration.kt
index 8ca7eb7..152b49a 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/testConfiguration/TestSuiteConfiguration.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/testConfiguration/TestSuiteConfiguration.kt
@@ -35,27 +35,31 @@
import com.android.build.api.variant.AndroidComponentsExtension
import com.android.build.api.variant.ApplicationAndroidComponentsExtension
import com.android.build.api.variant.HasAndroidTest
+import com.android.build.api.variant.LibraryAndroidComponentsExtension
+import com.android.build.api.variant.TestAndroidComponentsExtension
+import com.android.build.api.variant.Variant
import com.android.build.gradle.BaseExtension
import java.io.File
import org.gradle.api.Project
-import org.gradle.api.UnknownTaskException
+import com.android.build.gradle.TestExtension
+import com.android.build.gradle.internal.attributes.VariantAttr
+import com.android.build.gradle.internal.publishing.AndroidArtifacts
+import com.android.build.gradle.internal.publishing.AndroidArtifacts.ArtifactType
+import org.gradle.api.attributes.Usage
import org.gradle.api.tasks.TaskProvider
import org.gradle.kotlin.dsl.getByType
+import org.gradle.kotlin.dsl.named
/**
* Creates and configures the test config generation task for a project. Configuration includes
* populating the task with relevant data from the first 4 params, and setting whether the task
* is enabled.
- *
- * @param overrideProject Allows the config task for one project to get registered to an
- * alternative project. Default is for the project to register the new config task to itself
*/
fun Project.createTestConfigurationGenerationTask(
variantName: String,
artifacts: Artifacts,
minSdk: Int,
testRunner: String,
- overrideProject: Project = this
) {
val xmlName = "${path.asFilenamePrefix()}$variantName.xml"
val jsonName = "_${path.asFilenamePrefix()}$variantName.json"
@@ -68,7 +72,7 @@
)
)
}
- val generateTestConfigurationTask = overrideProject.tasks.register(
+ val generateTestConfigurationTask = tasks.register(
"${AndroidXImplPlugin.GENERATE_TEST_CONFIGURATION_TASK}$variantName",
GenerateTestConfigurationTask::class.java
) { task ->
@@ -114,7 +118,7 @@
afterEvaluate {
val androidXExtension = extensions.getByType<AndroidXExtension>()
generateTestConfigurationTask.configure {
- it.enabled = hasAndroidTestSourceCode() && !androidXExtension.disableDeviceTests
+ it.enabled = androidXExtension.deviceTests.enabled && hasAndroidTestSourceCode()
}
}
this.rootProject.tasks.findByName(ZIP_TEST_CONFIGS_WITH_APKS_TASK)!!
@@ -128,76 +132,143 @@
* there is a test app in addition to the instrumentation app, and the only thing it configures is
* the location of the testapp.
*/
-fun Project.addAppApkToTestConfigGeneration() {
- if (isMacrobenchmarkTarget()) {
- extensions.getByType<ApplicationAndroidComponentsExtension>().apply {
- onVariants(selector().withBuildType("release")) { appVariant ->
- getOrCreateMacrobenchmarkConfigTask().configure { configTask ->
- configTask.appFolder.set(appVariant.artifacts.get(SingleArtifact.APK))
- configTask.appLoader.set(appVariant.artifacts.getBuiltArtifactsLoader())
- configTask.outputAppApk.set(
- File(
- getTestConfigDirectory(),
- "${path.asFilenamePrefix()}-${appVariant.name}.apk"
- )
- )
- configTask.constrainedOutputAppApk.set(
- File(
- getConstrainedTestConfigDirectory(),
- "${path.asFilenamePrefix()}-${appVariant.name}.apk"
- )
- )
- }
- if (path == ":benchmark:integration-tests:macrobenchmark-target") {
- // Ugly workaround for b/188699825 where we hardcode that
- // :benchmark:integration-tests:macrobenchmark-target needs to be installed
- // for :benchmark:benchmark-macro tests to work.
- project(MACRO_PROJECT).tasks.withType(
- GenerateTestConfigurationTask::class.java
- ).named(
- "${AndroidXImplPlugin.GENERATE_TEST_CONFIGURATION_TASK}debugAndroidTest"
- ).configure { configTask ->
- configTask.appFolder.set(appVariant.artifacts.get(SingleArtifact.APK))
- configTask.appLoader.set(appVariant.artifacts.getBuiltArtifactsLoader())
- configTask.outputAppApk.set(
- File(
- getTestConfigDirectory(),
- "${MACRO_PROJECT.asFilenamePrefix()}-${appVariant.name}.apk"
- )
- )
- configTask.constrainedOutputAppApk.set(
- File(
- getConstrainedTestConfigDirectory(),
- "${MACRO_PROJECT.asFilenamePrefix()}-${appVariant.name}.apk"
- )
- )
- }
- }
- }
+fun Project.addAppApkToTestConfigGeneration(androidXExtension: AndroidXExtension) {
+
+ fun outputAppApkFile(
+ variant: Variant,
+ appProjectPath: String,
+ instrumentationProjectPath: String?
+ ): File {
+ var filename = appProjectPath.asFilenamePrefix()
+ if (instrumentationProjectPath != null) {
+ filename += "_for_${instrumentationProjectPath.asFilenamePrefix()}"
}
- return
+ filename += "-${variant.name}.apk"
+ return File(getTestConfigDirectory(), filename)
+ }
+ fun constrainedOutputAppApkFile(
+ variant: Variant,
+ path: String,
+ instrumentationPath: String?
+ ): File {
+ var filename = path.asFilenamePrefix()
+ if (instrumentationPath != null) {
+ filename += "-for-${instrumentationPath.asFilenamePrefix()}"
+ }
+ filename += "-${variant.name}.apk"
+ return File(getConstrainedTestConfigDirectory(), filename)
}
- extensions.getByType<ApplicationAndroidComponentsExtension>().apply {
- onVariants(selector().withBuildType("debug")) { appVariant ->
+ // For application modules, the instrumentation apk is generated in the module itself
+ extensions.findByType(ApplicationAndroidComponentsExtension::class.java)?.apply {
+ onVariants(selector().withBuildType("debug")) { variant ->
tasks.named(
- AndroidXImplPlugin.GENERATE_TEST_CONFIGURATION_TASK +
- "${appVariant.name}AndroidTest"
- ) { configTask ->
- configTask as GenerateTestConfigurationTask
- configTask.appFolder.set(appVariant.artifacts.get(SingleArtifact.APK))
- configTask.appLoader.set(appVariant.artifacts.getBuiltArtifactsLoader())
- configTask.outputAppApk.set(
- File(
- getTestConfigDirectory(),
- "${path.asFilenamePrefix()}-${appVariant.name}.apk"
- )
+ "${AndroidXImplPlugin.GENERATE_TEST_CONFIGURATION_TASK}${variant.name}AndroidTest",
+ GenerateTestConfigurationTask::class.java
+ ) { task ->
+ task.appFolder.set(variant.artifacts.get(SingleArtifact.APK))
+ task.appLoader.set(variant.artifacts.getBuiltArtifactsLoader())
+
+ // The target project is the same being evaluated
+ task.outputAppApk.set(outputAppApkFile(variant, path, null))
+ task.constrainedOutputAppApk.set(constrainedOutputAppApkFile(variant, path, null))
+ }
+ }
+ }
+
+ // For tests modules, the instrumentation apk is pulled from the <variant>TestedApks
+ // configuration. Note that also the associated test configuration task name is different
+ // from the application one.
+ extensions.findByType(TestAndroidComponentsExtension::class.java)?.apply {
+ onVariants(selector().all()) { variant ->
+ tasks.named(
+ "${AndroidXImplPlugin.GENERATE_TEST_CONFIGURATION_TASK}${variant.name}",
+ GenerateTestConfigurationTask::class.java
+ ) { task ->
+ task.appLoader.set(
+ variant.artifacts.getBuiltArtifactsLoader()
)
- configTask.constrainedOutputAppApk.set(
- File(
- getConstrainedTestConfigDirectory(),
- "${path.asFilenamePrefix()}-${appVariant.name}.apk"
- )
+
+ // The target app path is defined in the targetProjectPath field in the android
+ // extension of the test module
+ val targetProjectPath = project
+ .extensions
+ .getByType(TestExtension::class.java)
+ .targetProjectPath
+ ?: throw IllegalStateException("""
+ Module `$path` does not have a targetProjectPath defined.
+ """.trimIndent())
+ task.outputAppApk.set(
+ outputAppApkFile(variant, targetProjectPath, path)
+ )
+ task.constrainedOutputAppApk.set(
+ constrainedOutputAppApkFile(variant, targetProjectPath, path)
+ )
+
+ task.appFileCollection.from(
+ configurations
+ .named("${variant.name}TestedApks")
+ .get()
+ .incoming
+ .artifactView {
+ it.attributes { container ->
+ container.attribute(
+ AndroidArtifacts.ARTIFACT_TYPE,
+ ArtifactType.APK.type
+ )
+ }
+ }
+ .files
+ )
+ }
+ }
+ }
+
+ // For library modules we only look at the build type debug. The target app project can be
+ // specified through the androidX extension, through: targetAppProjectForInstrumentationTest
+ // and targetAppProjectVariantForInstrumentationTest.
+ extensions.findByType(LibraryAndroidComponentsExtension::class.java)?.apply {
+ onVariants(selector().withBuildType("debug")) { variant ->
+
+ val targetAppProject =
+ androidXExtension.deviceTests.targetAppProject ?: return@onVariants
+ val targetAppProjectVariant =
+ androidXExtension.deviceTests.targetAppVariant
+
+ // Recreate the same configuration existing for test modules to pull the artifact
+ // from the application module specified in the deviceTests extension.
+ val configuration = configurations.create("${variant.name}TestedApks") { config ->
+ config.isCanBeResolved = true
+ config.isCanBeConsumed = false
+ config.attributes {
+ it.attribute(VariantAttr.ATTRIBUTE, objects.named(targetAppProjectVariant))
+ it.attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.JAVA_RUNTIME))
+ }
+ config
+ .dependencies
+ .add(project.dependencyFactory.create(targetAppProject))
+ }
+
+ tasks.named(
+ "${AndroidXImplPlugin.GENERATE_TEST_CONFIGURATION_TASK}${variant.name}AndroidTest",
+ GenerateTestConfigurationTask::class.java
+ ) { task ->
+ task.appLoader.set(variant.artifacts.getBuiltArtifactsLoader())
+
+ // The target app path is defined in the androidx extension
+ task.outputAppApk.set(
+ outputAppApkFile(variant, targetAppProject.path, path)
+ )
+ task.constrainedOutputAppApk.set(
+ constrainedOutputAppApkFile(variant, targetAppProject.path, path)
+ )
+
+ task.appFileCollection.from(
+ configuration.incoming.artifactView { view ->
+ view.attributes {
+ it.attribute(AndroidArtifacts.ARTIFACT_TYPE, ArtifactType.APK.type)
+ }
+ }.files
)
}
}
@@ -329,94 +400,7 @@
}
}
-private fun Project.getOrCreateMacrobenchmarkConfigTask():
- TaskProvider<GenerateTestConfigurationTask> {
- val parentProject = this.parent!!
- return try {
- parentProject.tasks.withType(GenerateTestConfigurationTask::class.java)
- .named(AndroidXImplPlugin.GENERATE_TEST_CONFIGURATION_TASK)
- } catch (e: UnknownTaskException) {
- parentProject.tasks.register(
- AndroidXImplPlugin.GENERATE_TEST_CONFIGURATION_TASK,
- GenerateTestConfigurationTask::class.java
- )
- }
-}
-
-private fun Project.configureMacrobenchmarkConfigTask(
- variantName: String,
- artifacts: Artifacts,
- minSdk: Int,
- testRunner: String
-) {
- val configTask = getOrCreateMacrobenchmarkConfigTask()
- configTask.configure { task ->
- val androidXExtension = extensions.getByType<AndroidXExtension>()
- val fileNamePrefix = path.asFilenamePrefix()
- task.testFolder.set(artifacts.get(SingleArtifact.APK))
- task.testLoader.set(artifacts.getBuiltArtifactsLoader())
- task.outputTestApk.set(
- File(getTestConfigDirectory(), "${path.asFilenamePrefix()}-$variantName.apk")
- )
- task.constrainedOutputTestApk.set(
- File(
- getConstrainedTestConfigDirectory(),
- "${path.asFilenamePrefix()}-$variantName.apk"
- )
- )
- task.additionalApkKeys.set(androidXExtension.additionalDeviceTestApkKeys)
- task.additionalTags.set(androidXExtension.additionalDeviceTestTags)
- task.outputXml.fileValue(
- File(getTestConfigDirectory(), "$fileNamePrefix$variantName.xml")
- )
- task.outputJson.fileValue(
- File(getTestConfigDirectory(), "_$fileNamePrefix$variantName.json")
- )
- task.constrainedOutputXml.fileValue(
- File(
- getTestConfigDirectory(),
- "${path.asFilenamePrefix()}$variantName.xml"
- )
- )
- task.minSdk.set(minSdk)
- task.hasBenchmarkPlugin.set(hasBenchmarkPlugin())
- task.testRunner.set(testRunner)
- task.testProjectPath.set(path)
- task.presubmit.set(isPresubmitBuild())
- val detector = AffectedModuleDetector.getInstance(project)
- task.affectedModuleDetectorSubset.set(
- project.provider {
- detector.getSubset(task)
- }
- )
-
- AffectedModuleDetector.configureTaskGuard(task)
- }
- // Disable xml generation for projects that have no test sources
- afterEvaluate {
- val androidXExtension = extensions.getByType<AndroidXExtension>()
- configTask.configure {
- it.enabled = hasAndroidTestSourceCode() && !androidXExtension.disableDeviceTests
- }
- }
- rootProject.tasks.findByName(ZIP_TEST_CONFIGS_WITH_APKS_TASK)!!
- .dependsOn(configTask)
- rootProject.tasks.findByName(ZIP_CONSTRAINED_TEST_CONFIGS_WITH_APKS_TASK)!!
- .dependsOn(configTask)
-}
-
-/**
- * Tells whether this project is the macrobenchmark-target project
- */
-fun Project.isMacrobenchmarkTarget(): Boolean {
- return path.endsWith("macrobenchmark-target")
-}
-
fun Project.configureTestConfigGeneration(baseExtension: BaseExtension) {
- if (isMacrobenchmarkTarget()) {
- // macrobenchmark target projects use special setup. See addAppApkToTestConfigGeneration
- return
- }
extensions.getByType(AndroidComponentsExtension::class.java).apply {
onVariants { variant ->
var name: String? = null
@@ -453,14 +437,6 @@
isMedia2 = false
)
}
- path.endsWith("macrobenchmark") -> {
- configureMacrobenchmarkConfigTask(
- name,
- artifacts,
- baseExtension.defaultConfig.minSdk!!,
- baseExtension.defaultConfig.testInstrumentationRunner!!
- )
- }
else -> {
createTestConfigurationGenerationTask(
name,
@@ -473,5 +449,3 @@
}
}
}
-
-private const val MACRO_PROJECT = ":benchmark:benchmark-macro"
\ No newline at end of file
diff --git a/compose/integration-tests/macrobenchmark/build.gradle b/compose/integration-tests/macrobenchmark/build.gradle
index 5cb3474..7739110 100644
--- a/compose/integration-tests/macrobenchmark/build.gradle
+++ b/compose/integration-tests/macrobenchmark/build.gradle
@@ -14,11 +14,9 @@
* limitations under the License.
*/
-import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
-
plugins {
id("AndroidXPlugin")
- id("com.android.library")
+ id("com.android.test")
id("kotlin-android")
}
@@ -27,25 +25,22 @@
minSdkVersion 23
}
namespace "androidx.compose.integration.macrobenchmark"
+ targetProjectPath = ":compose:integration-tests:macrobenchmark-target"
+ experimentalProperties["android.experimental.self-instrumenting"] = true
}
+// Create a release build type and make sure it's the only one enabled.
+// This is needed because we benchmark the release build type only.
+android.buildTypes { release {} }
+androidComponents { beforeVariants(selector().all()) { enabled = buildType == 'release' } }
+
dependencies {
- androidTestImplementation(project(":benchmark:benchmark-junit4"))
- androidTestImplementation(project(":benchmark:benchmark-macro-junit4"))
- androidTestImplementation(project(":internal-testutils-macrobenchmark"))
- androidTestImplementation(libs.testRules)
- androidTestImplementation(libs.testExtJunit)
- androidTestImplementation(libs.testCore)
- androidTestImplementation(libs.testRunner)
- androidTestImplementation(libs.testUiautomator)
-}
-
-// Define a task dependency so the app is installed before we run macro benchmarks.
-afterEvaluate {
- tasks.getByPath(":compose:integration-tests:macrobenchmark:connectedDebugAndroidTest")
- .dependsOn(
- tasks.getByPath(
- ":compose:integration-tests:macrobenchmark-target:installRelease"
- )
- )
+ implementation(project(":benchmark:benchmark-junit4"))
+ implementation(project(":benchmark:benchmark-macro-junit4"))
+ implementation(project(":internal-testutils-macrobenchmark"))
+ implementation(libs.testRules)
+ implementation(libs.testExtJunit)
+ implementation(libs.testCore)
+ implementation(libs.testRunner)
+ implementation(libs.testUiautomator)
}
diff --git a/compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/compose/integration/macrobenchmark/AndroidViewListScrollBenchmark.kt b/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/AndroidViewListScrollBenchmark.kt
similarity index 100%
rename from compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/compose/integration/macrobenchmark/AndroidViewListScrollBenchmark.kt
rename to compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/AndroidViewListScrollBenchmark.kt
diff --git a/compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/compose/integration/macrobenchmark/AndroidViewPagerBenchmark.kt b/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/AndroidViewPagerBenchmark.kt
similarity index 100%
rename from compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/compose/integration/macrobenchmark/AndroidViewPagerBenchmark.kt
rename to compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/AndroidViewPagerBenchmark.kt
diff --git a/compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/compose/integration/macrobenchmark/DifferentTypesListScrollBenchmark.kt b/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/DifferentTypesListScrollBenchmark.kt
similarity index 100%
rename from compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/compose/integration/macrobenchmark/DifferentTypesListScrollBenchmark.kt
rename to compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/DifferentTypesListScrollBenchmark.kt
diff --git a/compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/compose/integration/macrobenchmark/FullyDrawnStartupBenchmark.kt b/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/FullyDrawnStartupBenchmark.kt
similarity index 100%
rename from compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/compose/integration/macrobenchmark/FullyDrawnStartupBenchmark.kt
rename to compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/FullyDrawnStartupBenchmark.kt
diff --git a/compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/compose/integration/macrobenchmark/GridBenchmark.kt b/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/GridBenchmark.kt
similarity index 100%
rename from compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/compose/integration/macrobenchmark/GridBenchmark.kt
rename to compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/GridBenchmark.kt
diff --git a/compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/compose/integration/macrobenchmark/IoSettingsStartupBenchmark.kt b/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/IoSettingsStartupBenchmark.kt
similarity index 100%
rename from compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/compose/integration/macrobenchmark/IoSettingsStartupBenchmark.kt
rename to compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/IoSettingsStartupBenchmark.kt
diff --git a/compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/compose/integration/macrobenchmark/LazyBoxWithConstraintsScrollBenchmark.kt b/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/LazyBoxWithConstraintsScrollBenchmark.kt
similarity index 100%
rename from compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/compose/integration/macrobenchmark/LazyBoxWithConstraintsScrollBenchmark.kt
rename to compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/LazyBoxWithConstraintsScrollBenchmark.kt
diff --git a/compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/compose/integration/macrobenchmark/NestedListsScrollBenchmark.kt b/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/NestedListsScrollBenchmark.kt
similarity index 100%
rename from compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/compose/integration/macrobenchmark/NestedListsScrollBenchmark.kt
rename to compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/NestedListsScrollBenchmark.kt
diff --git a/compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/compose/integration/macrobenchmark/PagerAsCarouselBenchmark.kt b/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/PagerAsCarouselBenchmark.kt
similarity index 100%
rename from compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/compose/integration/macrobenchmark/PagerAsCarouselBenchmark.kt
rename to compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/PagerAsCarouselBenchmark.kt
diff --git a/compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/compose/integration/macrobenchmark/PagerBenchmark.kt b/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/PagerBenchmark.kt
similarity index 100%
rename from compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/compose/integration/macrobenchmark/PagerBenchmark.kt
rename to compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/PagerBenchmark.kt
diff --git a/compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/compose/integration/macrobenchmark/RecyclerViewAsCarouselBenchmark.kt b/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/RecyclerViewAsCarouselBenchmark.kt
similarity index 100%
rename from compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/compose/integration/macrobenchmark/RecyclerViewAsCarouselBenchmark.kt
rename to compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/RecyclerViewAsCarouselBenchmark.kt
diff --git a/compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/compose/integration/macrobenchmark/RecyclerViewListScrollBenchmark.kt b/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/RecyclerViewListScrollBenchmark.kt
similarity index 100%
rename from compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/compose/integration/macrobenchmark/RecyclerViewListScrollBenchmark.kt
rename to compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/RecyclerViewListScrollBenchmark.kt
diff --git a/compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/compose/integration/macrobenchmark/SmallListBaselineProfile.kt b/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/SmallListBaselineProfile.kt
similarity index 100%
rename from compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/compose/integration/macrobenchmark/SmallListBaselineProfile.kt
rename to compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/SmallListBaselineProfile.kt
diff --git a/compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/compose/integration/macrobenchmark/SmallListStartupBenchmark.kt b/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/SmallListStartupBenchmark.kt
similarity index 100%
rename from compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/compose/integration/macrobenchmark/SmallListStartupBenchmark.kt
rename to compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/SmallListStartupBenchmark.kt
diff --git a/compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/compose/integration/macrobenchmark/TrivialListScrollBenchmark.kt b/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/TrivialListScrollBenchmark.kt
similarity index 100%
rename from compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/compose/integration/macrobenchmark/TrivialListScrollBenchmark.kt
rename to compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/TrivialListScrollBenchmark.kt
diff --git a/compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/compose/integration/macrobenchmark/TrivialStartupBenchmark.kt b/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/TrivialStartupBenchmark.kt
similarity index 100%
rename from compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/compose/integration/macrobenchmark/TrivialStartupBenchmark.kt
rename to compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/TrivialStartupBenchmark.kt
diff --git a/compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/compose/integration/macrobenchmark/TrivialTracingBenchmark.kt b/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/TrivialTracingBenchmark.kt
similarity index 100%
rename from compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/compose/integration/macrobenchmark/TrivialTracingBenchmark.kt
rename to compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/TrivialTracingBenchmark.kt
diff --git a/compose/material3/material3/api/current.txt b/compose/material3/material3/api/current.txt
index 1f5b379..b6e6d45 100644
--- a/compose/material3/material3/api/current.txt
+++ b/compose/material3/material3/api/current.txt
@@ -758,16 +758,20 @@
}
@androidx.compose.runtime.Immutable public final class TabPosition {
+ method public float getContentWidth();
method public float getLeft();
method public float getRight();
method public float getWidth();
+ property public final float contentWidth;
property public final float left;
property public final float right;
property public final float width;
}
public final class TabRowDefaults {
- method @androidx.compose.runtime.Composable public void Indicator(optional androidx.compose.ui.Modifier modifier, optional float height, optional long color);
+ method @Deprecated @androidx.compose.runtime.Composable public void Indicator(optional androidx.compose.ui.Modifier modifier, optional float height, optional long color);
+ method @androidx.compose.runtime.Composable public void PrimaryIndicator(optional androidx.compose.ui.Modifier modifier, optional float width, optional float height, optional long color, optional androidx.compose.ui.graphics.Shape shape);
+ method @androidx.compose.runtime.Composable public void SecondaryIndicator(optional androidx.compose.ui.Modifier modifier, optional float height, optional long color);
method @androidx.compose.runtime.Composable public long getContainerColor();
method @androidx.compose.runtime.Composable public long getContentColor();
method public androidx.compose.ui.Modifier tabIndicatorOffset(androidx.compose.ui.Modifier, androidx.compose.material3.TabPosition currentTabPosition);
diff --git a/compose/material3/material3/api/public_plus_experimental_current.txt b/compose/material3/material3/api/public_plus_experimental_current.txt
index b2471cb..a2231ee 100644
--- a/compose/material3/material3/api/public_plus_experimental_current.txt
+++ b/compose/material3/material3/api/public_plus_experimental_current.txt
@@ -1145,16 +1145,20 @@
}
@androidx.compose.runtime.Immutable public final class TabPosition {
+ method public float getContentWidth();
method public float getLeft();
method public float getRight();
method public float getWidth();
+ property public final float contentWidth;
property public final float left;
property public final float right;
property public final float width;
}
public final class TabRowDefaults {
- method @androidx.compose.runtime.Composable public void Indicator(optional androidx.compose.ui.Modifier modifier, optional float height, optional long color);
+ method @Deprecated @androidx.compose.runtime.Composable public void Indicator(optional androidx.compose.ui.Modifier modifier, optional float height, optional long color);
+ method @androidx.compose.runtime.Composable public void PrimaryIndicator(optional androidx.compose.ui.Modifier modifier, optional float width, optional float height, optional long color, optional androidx.compose.ui.graphics.Shape shape);
+ method @androidx.compose.runtime.Composable public void SecondaryIndicator(optional androidx.compose.ui.Modifier modifier, optional float height, optional long color);
method @androidx.compose.runtime.Composable public long getContainerColor();
method @androidx.compose.runtime.Composable public long getContentColor();
method public androidx.compose.ui.Modifier tabIndicatorOffset(androidx.compose.ui.Modifier, androidx.compose.material3.TabPosition currentTabPosition);
diff --git a/compose/material3/material3/api/restricted_current.txt b/compose/material3/material3/api/restricted_current.txt
index 1f5b379..b6e6d45 100644
--- a/compose/material3/material3/api/restricted_current.txt
+++ b/compose/material3/material3/api/restricted_current.txt
@@ -758,16 +758,20 @@
}
@androidx.compose.runtime.Immutable public final class TabPosition {
+ method public float getContentWidth();
method public float getLeft();
method public float getRight();
method public float getWidth();
+ property public final float contentWidth;
property public final float left;
property public final float right;
property public final float width;
}
public final class TabRowDefaults {
- method @androidx.compose.runtime.Composable public void Indicator(optional androidx.compose.ui.Modifier modifier, optional float height, optional long color);
+ method @Deprecated @androidx.compose.runtime.Composable public void Indicator(optional androidx.compose.ui.Modifier modifier, optional float height, optional long color);
+ method @androidx.compose.runtime.Composable public void PrimaryIndicator(optional androidx.compose.ui.Modifier modifier, optional float width, optional float height, optional long color, optional androidx.compose.ui.graphics.Shape shape);
+ method @androidx.compose.runtime.Composable public void SecondaryIndicator(optional androidx.compose.ui.Modifier modifier, optional float height, optional long color);
method @androidx.compose.runtime.Composable public long getContainerColor();
method @androidx.compose.runtime.Composable public long getContentColor();
method public androidx.compose.ui.Modifier tabIndicatorOffset(androidx.compose.ui.Modifier, androidx.compose.material3.TabPosition currentTabPosition);
diff --git a/compose/material3/material3/integration-tests/material3-catalog/src/main/java/androidx/compose/material3/catalog/library/model/Examples.kt b/compose/material3/material3/integration-tests/material3-catalog/src/main/java/androidx/compose/material3/catalog/library/model/Examples.kt
index 1d6480b..aef2f9c 100644
--- a/compose/material3/material3/integration-tests/material3-catalog/src/main/java/androidx/compose/material3/catalog/library/model/Examples.kt
+++ b/compose/material3/material3/integration-tests/material3-catalog/src/main/java/androidx/compose/material3/catalog/library/model/Examples.kt
@@ -101,6 +101,7 @@
import androidx.compose.material3.samples.PinnedTopAppBar
import androidx.compose.material3.samples.PlainTooltipSample
import androidx.compose.material3.samples.PlainTooltipWithManualInvocationSample
+import androidx.compose.material3.samples.PrimaryTabs
import androidx.compose.material3.samples.RadioButtonSample
import androidx.compose.material3.samples.RadioGroupSample
import androidx.compose.material3.samples.RangeSliderSample
@@ -113,8 +114,11 @@
import androidx.compose.material3.samples.ScaffoldWithMultilineSnackbar
import androidx.compose.material3.samples.ScaffoldWithSimpleSnackbar
import androidx.compose.material3.samples.ScrollingFancyIndicatorContainerTabs
+import androidx.compose.material3.samples.ScrollingPrimaryTabs
+import androidx.compose.material3.samples.ScrollingSecondaryTabs
import androidx.compose.material3.samples.ScrollingTextTabs
import androidx.compose.material3.samples.SearchBarSample
+import androidx.compose.material3.samples.SecondaryTabs
import androidx.compose.material3.samples.SimpleBottomAppBar
import androidx.compose.material3.samples.SimpleBottomSheetScaffoldSample
import androidx.compose.material3.samples.SimpleCenterAlignedTopAppBar
@@ -894,6 +898,20 @@
private const val TabsExampleSourceUrl = "$SampleSourceUrl/TabSamples.kt"
val TabsExamples = listOf(
Example(
+ name = ::PrimaryTabs.name,
+ description = TabsExampleDescription,
+ sourceUrl = TabsExampleSourceUrl
+ ) {
+ PrimaryTabs()
+ },
+ Example(
+ name = ::SecondaryTabs.name,
+ description = TabsExampleDescription,
+ sourceUrl = TabsExampleSourceUrl
+ ) {
+ SecondaryTabs()
+ },
+ Example(
name = ::TextTabs.name,
description = TabsExampleDescription,
sourceUrl = TabsExampleSourceUrl
@@ -922,6 +940,20 @@
LeadingIconTabs()
},
Example(
+ name = ::ScrollingPrimaryTabs.name,
+ description = TabsExampleDescription,
+ sourceUrl = TabsExampleSourceUrl
+ ) {
+ ScrollingPrimaryTabs()
+ },
+ Example(
+ name = ::ScrollingSecondaryTabs.name,
+ description = TabsExampleDescription,
+ sourceUrl = TabsExampleSourceUrl
+ ) {
+ ScrollingSecondaryTabs()
+ },
+ Example(
name = ::ScrollingTextTabs.name,
description = TabsExampleDescription,
sourceUrl = TabsExampleSourceUrl
diff --git a/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/TabSamples.kt b/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/TabSamples.kt
index bbeb8b3..c19a692 100644
--- a/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/TabSamples.kt
+++ b/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/TabSamples.kt
@@ -19,6 +19,7 @@
import androidx.annotation.Sampled
import androidx.compose.animation.animateColor
import androidx.compose.animation.core.animateDp
+import androidx.compose.animation.core.animateDpAsState
import androidx.compose.animation.core.spring
import androidx.compose.animation.core.updateTransition
import androidx.compose.foundation.BorderStroke
@@ -29,24 +30,25 @@
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Favorite
import androidx.compose.material3.Icon
+import androidx.compose.material3.LeadingIconTab
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ScrollableTabRow
import androidx.compose.material3.Tab
-import androidx.compose.material3.TabRowDefaults.tabIndicatorOffset
import androidx.compose.material3.TabPosition
import androidx.compose.material3.TabRow
-import androidx.compose.material3.LeadingIconTab
+import androidx.compose.material3.TabRowDefaults
+import androidx.compose.material3.TabRowDefaults.tabIndicatorOffset
import androidx.compose.material3.Text
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.filled.Favorite
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@@ -59,6 +61,58 @@
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
+@Composable
+fun PrimaryTabs() {
+ var state by remember { mutableStateOf(0) }
+ val titles = listOf("Tab 1", "Tab 2", "Tab 3 with lots of text")
+ Column {
+ TabRow(selectedTabIndex = state, indicator = @Composable { tabPositions ->
+ if (state < tabPositions.size) {
+ val width by animateDpAsState(targetValue = tabPositions[state].contentWidth)
+ TabRowDefaults.PrimaryIndicator(
+ modifier = Modifier.tabIndicatorOffset(tabPositions[state]),
+ width = width
+ )
+ }
+ }) {
+ titles.forEachIndexed { index, title ->
+ Tab(
+ selected = state == index,
+ onClick = { state = index },
+ text = { Text(text = title, maxLines = 2, overflow = TextOverflow.Ellipsis) }
+ )
+ }
+ }
+ Text(
+ modifier = Modifier.align(Alignment.CenterHorizontally),
+ text = "Primary tab ${state + 1} selected",
+ style = MaterialTheme.typography.bodyLarge
+ )
+ }
+}
+
+@Composable
+fun SecondaryTabs() {
+ var state by remember { mutableStateOf(0) }
+ val titles = listOf("Tab 1", "Tab 2", "Tab 3 with lots of text")
+ Column {
+ TabRow(selectedTabIndex = state) {
+ titles.forEachIndexed { index, title ->
+ Tab(
+ selected = state == index,
+ onClick = { state = index },
+ text = { Text(text = title, maxLines = 2, overflow = TextOverflow.Ellipsis) }
+ )
+ }
+ }
+ Text(
+ modifier = Modifier.align(Alignment.CenterHorizontally),
+ text = "Secondary tab ${state + 1} selected",
+ style = MaterialTheme.typography.bodyLarge
+ )
+ }
+}
+
@Preview
@Sampled
@Composable
@@ -160,6 +214,80 @@
}
@Composable
+fun ScrollingPrimaryTabs() {
+ var state by remember { mutableStateOf(0) }
+ val titles = listOf(
+ "Tab 1",
+ "Tab 2",
+ "Tab 3 with lots of text",
+ "Tab 4",
+ "Tab 5",
+ "Tab 6 with lots of text",
+ "Tab 7",
+ "Tab 8",
+ "Tab 9 with lots of text",
+ "Tab 10"
+ )
+ Column {
+ ScrollableTabRow(selectedTabIndex = state, indicator = @Composable { tabPositions ->
+ if (state < tabPositions.size) {
+ val width by animateDpAsState(targetValue = tabPositions[state].contentWidth)
+ TabRowDefaults.PrimaryIndicator(
+ modifier = Modifier.tabIndicatorOffset(tabPositions[state]),
+ width = width
+ )
+ }
+ }) {
+ titles.forEachIndexed { index, title ->
+ Tab(
+ selected = state == index,
+ onClick = { state = index },
+ text = { Text(title) }
+ )
+ }
+ }
+ Text(
+ modifier = Modifier.align(Alignment.CenterHorizontally),
+ text = "Scrolling primary tab ${state + 1} selected",
+ style = MaterialTheme.typography.bodyLarge
+ )
+ }
+}
+
+@Composable
+fun ScrollingSecondaryTabs() {
+ var state by remember { mutableStateOf(0) }
+ val titles = listOf(
+ "Tab 1",
+ "Tab 2",
+ "Tab 3 with lots of text",
+ "Tab 4",
+ "Tab 5",
+ "Tab 6 with lots of text",
+ "Tab 7",
+ "Tab 8",
+ "Tab 9 with lots of text",
+ "Tab 10"
+ )
+ Column {
+ ScrollableTabRow(selectedTabIndex = state) {
+ titles.forEachIndexed { index, title ->
+ Tab(
+ selected = state == index,
+ onClick = { state = index },
+ text = { Text(title) }
+ )
+ }
+ }
+ Text(
+ modifier = Modifier.align(Alignment.CenterHorizontally),
+ text = "Scrolling secondary tab ${state + 1} selected",
+ style = MaterialTheme.typography.bodyLarge
+ )
+ }
+}
+
+@Composable
fun ScrollingTextTabs() {
var state by remember { mutableStateOf(0) }
val titles = listOf(
@@ -201,7 +329,11 @@
Column {
TabRow(selectedTabIndex = state) {
titles.forEachIndexed { index, title ->
- FancyTab(title = title, onClick = { state = index }, selected = (index == state))
+ FancyTab(
+ title = title,
+ onClick = { state = index },
+ selected = (index == state)
+ )
}
}
Text(
@@ -334,7 +466,8 @@
.align(Alignment.CenterHorizontally)
.background(
color = if (selected) MaterialTheme.colorScheme.primary
- else MaterialTheme.colorScheme.background)
+ else MaterialTheme.colorScheme.background
+ )
)
Text(
text = title,
diff --git a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/TabScreenshotTest.kt b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/TabScreenshotTest.kt
index cced64f..318b5c0 100644
--- a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/TabScreenshotTest.kt
+++ b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/TabScreenshotTest.kt
@@ -59,7 +59,7 @@
val screenshotRule = AndroidXScreenshotTestRule(GOLDEN_MATERIAL3)
@Test
- fun lightTheme() {
+ fun lightTheme_primary() {
val interactionSource = MutableInteractionSource()
var scope: CoroutineScope? = null
@@ -67,7 +67,7 @@
composeTestRule.setContent {
scope = rememberCoroutineScope()
MaterialTheme(lightColorScheme()) {
- DefaultTabs(interactionSource)
+ DefaultPrimaryTabs(interactionSource)
}
}
@@ -75,12 +75,12 @@
scope = scope!!,
interactionSource = interactionSource,
interaction = null,
- goldenIdentifier = "tabs_lightTheme"
+ goldenIdentifier = "tabs_lightTheme_primary"
)
}
@Test
- fun lightTheme_pressed() {
+ fun lightTheme_secondary() {
val interactionSource = MutableInteractionSource()
var scope: CoroutineScope? = null
@@ -88,7 +88,28 @@
composeTestRule.setContent {
scope = rememberCoroutineScope()
MaterialTheme(lightColorScheme()) {
- DefaultTabs(interactionSource)
+ DefaultSecondaryTabs(interactionSource)
+ }
+ }
+
+ assertTabsMatch(
+ scope = scope!!,
+ interactionSource = interactionSource,
+ interaction = null,
+ goldenIdentifier = "tabs_lightTheme_secondary"
+ )
+ }
+
+ @Test
+ fun lightTheme_primary_pressed() {
+ val interactionSource = MutableInteractionSource()
+
+ var scope: CoroutineScope? = null
+
+ composeTestRule.setContent {
+ scope = rememberCoroutineScope()
+ MaterialTheme(lightColorScheme()) {
+ DefaultPrimaryTabs(interactionSource)
}
}
@@ -96,54 +117,12 @@
scope = scope!!,
interactionSource = interactionSource,
interaction = PressInteraction.Press(Offset(10f, 10f)),
- goldenIdentifier = "tabs_lightTheme_pressed"
+ goldenIdentifier = "tabs_lightTheme_primary_pressed"
)
}
@Test
- fun darkTheme() {
- val interactionSource = MutableInteractionSource()
-
- var scope: CoroutineScope? = null
-
- composeTestRule.setContent {
- scope = rememberCoroutineScope()
- MaterialTheme(darkColorScheme()) {
- DefaultTabs(interactionSource)
- }
- }
-
- assertTabsMatch(
- scope = scope!!,
- interactionSource = interactionSource,
- interaction = null,
- goldenIdentifier = "tabs_darkTheme"
- )
- }
-
- @Test
- fun darkTheme_pressed() {
- val interactionSource = MutableInteractionSource()
-
- var scope: CoroutineScope? = null
-
- composeTestRule.setContent {
- scope = rememberCoroutineScope()
- MaterialTheme(darkColorScheme()) {
- DefaultTabs(interactionSource)
- }
- }
-
- assertTabsMatch(
- scope = scope!!,
- interactionSource = interactionSource,
- interaction = PressInteraction.Press(Offset(10f, 10f)),
- goldenIdentifier = "tabs_darkTheme_pressed"
- )
- }
-
- @Test
- fun leadingIconTabs_lightTheme() {
+ fun lightTheme_secondary_pressed() {
val interactionSource = MutableInteractionSource()
var scope: CoroutineScope? = null
@@ -151,20 +130,20 @@
composeTestRule.setContent {
scope = rememberCoroutineScope()
MaterialTheme(lightColorScheme()) {
- DefaultLeadingIconTabs(interactionSource)
+ DefaultSecondaryTabs(interactionSource)
}
}
assertTabsMatch(
scope = scope!!,
interactionSource = interactionSource,
- interaction = null,
- goldenIdentifier = "leadingIconTabs_lightTheme"
+ interaction = PressInteraction.Press(Offset(10f, 10f)),
+ goldenIdentifier = "tabs_lightTheme_secondary_pressed"
)
}
@Test
- fun leadingIconTabs_darkTheme() {
+ fun darkTheme_primary() {
val interactionSource = MutableInteractionSource()
var scope: CoroutineScope? = null
@@ -172,7 +151,7 @@
composeTestRule.setContent {
scope = rememberCoroutineScope()
MaterialTheme(darkColorScheme()) {
- DefaultLeadingIconTabs(interactionSource)
+ DefaultPrimaryTabs(interactionSource)
}
}
@@ -180,7 +159,342 @@
scope = scope!!,
interactionSource = interactionSource,
interaction = null,
- goldenIdentifier = "leadingIconTabs_darkTheme"
+ goldenIdentifier = "tabs_darkTheme_primary"
+ )
+ }
+
+ @Test
+ fun darkTheme_secondary() {
+ val interactionSource = MutableInteractionSource()
+
+ var scope: CoroutineScope? = null
+
+ composeTestRule.setContent {
+ scope = rememberCoroutineScope()
+ MaterialTheme(darkColorScheme()) {
+ DefaultSecondaryTabs(interactionSource)
+ }
+ }
+
+ assertTabsMatch(
+ scope = scope!!,
+ interactionSource = interactionSource,
+ interaction = null,
+ goldenIdentifier = "tabs_darkTheme_secondary"
+ )
+ }
+
+ @Test
+ fun darkTheme_primary_pressed() {
+ val interactionSource = MutableInteractionSource()
+
+ var scope: CoroutineScope? = null
+
+ composeTestRule.setContent {
+ scope = rememberCoroutineScope()
+ MaterialTheme(darkColorScheme()) {
+ DefaultPrimaryTabs(interactionSource)
+ }
+ }
+
+ assertTabsMatch(
+ scope = scope!!,
+ interactionSource = interactionSource,
+ interaction = PressInteraction.Press(Offset(10f, 10f)),
+ goldenIdentifier = "tabs_darkTheme_primary_pressed"
+ )
+ }
+
+ @Test
+ fun darkTheme_secondary_pressed() {
+ val interactionSource = MutableInteractionSource()
+
+ var scope: CoroutineScope? = null
+
+ composeTestRule.setContent {
+ scope = rememberCoroutineScope()
+ MaterialTheme(darkColorScheme()) {
+ DefaultSecondaryTabs(interactionSource)
+ }
+ }
+
+ assertTabsMatch(
+ scope = scope!!,
+ interactionSource = interactionSource,
+ interaction = PressInteraction.Press(Offset(10f, 10f)),
+ goldenIdentifier = "tabs_darkTheme_secondary_pressed"
+ )
+ }
+
+ @Test
+ fun customTabs_lightTheme_primary() {
+ val interactionSource = MutableInteractionSource()
+
+ var scope: CoroutineScope? = null
+
+ composeTestRule.setContent {
+ scope = rememberCoroutineScope()
+ MaterialTheme(lightColorScheme()) {
+ CustomPrimaryTabs(
+ interactionSource,
+ containerColor = MaterialTheme.colorScheme.tertiaryContainer,
+ selectedContentColor = MaterialTheme.colorScheme.onTertiary,
+ unselectedContentColor = Color.Black
+ )
+ }
+ }
+
+ assertTabsMatch(
+ scope = scope!!,
+ interactionSource = interactionSource,
+ interaction = null,
+ goldenIdentifier = "customTabs_lightTheme_primary"
+ )
+ }
+
+ @Test
+ fun customTabs_lightTheme_secondary() {
+ val interactionSource = MutableInteractionSource()
+
+ var scope: CoroutineScope? = null
+
+ composeTestRule.setContent {
+ scope = rememberCoroutineScope()
+ MaterialTheme(lightColorScheme()) {
+ CustomSecondaryTabs(
+ interactionSource,
+ containerColor = MaterialTheme.colorScheme.tertiaryContainer,
+ selectedContentColor = MaterialTheme.colorScheme.onTertiary,
+ unselectedContentColor = Color.Black
+ )
+ }
+ }
+
+ assertTabsMatch(
+ scope = scope!!,
+ interactionSource = interactionSource,
+ interaction = null,
+ goldenIdentifier = "customTabs_lightTheme_secondary"
+ )
+ }
+
+ @Test
+ fun customTabs_darkTheme_primary() {
+ val interactionSource = MutableInteractionSource()
+
+ var scope: CoroutineScope? = null
+
+ composeTestRule.setContent {
+ scope = rememberCoroutineScope()
+ MaterialTheme(darkColorScheme()) {
+ CustomPrimaryTabs(
+ interactionSource,
+ containerColor = MaterialTheme.colorScheme.tertiaryContainer,
+ selectedContentColor = MaterialTheme.colorScheme.onTertiary,
+ unselectedContentColor = Color.Black
+ )
+ }
+ }
+
+ assertTabsMatch(
+ scope = scope!!,
+ interactionSource = interactionSource,
+ interaction = null,
+ goldenIdentifier = "customTabs_darkTheme_primary"
+ )
+ }
+
+ @Test
+ fun customTabs_darkTheme_secondary() {
+ val interactionSource = MutableInteractionSource()
+
+ var scope: CoroutineScope? = null
+
+ composeTestRule.setContent {
+ scope = rememberCoroutineScope()
+ MaterialTheme(darkColorScheme()) {
+ CustomSecondaryTabs(
+ interactionSource,
+ containerColor = MaterialTheme.colorScheme.tertiaryContainer,
+ selectedContentColor = MaterialTheme.colorScheme.onTertiary,
+ unselectedContentColor = Color.Black
+ )
+ }
+ }
+
+ assertTabsMatch(
+ scope = scope!!,
+ interactionSource = interactionSource,
+ interaction = null,
+ goldenIdentifier = "customTabs_darkTheme_secondary"
+ )
+ }
+
+ @Test
+ fun leadingIconTabs_lightTheme_primary() {
+ val interactionSource = MutableInteractionSource()
+
+ var scope: CoroutineScope? = null
+
+ composeTestRule.setContent {
+ scope = rememberCoroutineScope()
+ MaterialTheme(lightColorScheme()) {
+ DefaultPrimaryLeadingIconTabs(interactionSource)
+ }
+ }
+
+ assertTabsMatch(
+ scope = scope!!,
+ interactionSource = interactionSource,
+ interaction = null,
+ goldenIdentifier = "leadingIconTabs_lightTheme_primary"
+ )
+ }
+
+ @Test
+ fun leadingIconTabs_lightTheme_secondary() {
+ val interactionSource = MutableInteractionSource()
+
+ var scope: CoroutineScope? = null
+
+ composeTestRule.setContent {
+ scope = rememberCoroutineScope()
+ MaterialTheme(lightColorScheme()) {
+ DefaultSecondaryLeadingIconTabs(interactionSource)
+ }
+ }
+
+ assertTabsMatch(
+ scope = scope!!,
+ interactionSource = interactionSource,
+ interaction = null,
+ goldenIdentifier = "leadingIconTabs_lightTheme_secondary"
+ )
+ }
+
+ @Test
+ fun leadingIconTabs_darkTheme_primary() {
+ val interactionSource = MutableInteractionSource()
+
+ var scope: CoroutineScope? = null
+
+ composeTestRule.setContent {
+ scope = rememberCoroutineScope()
+ MaterialTheme(darkColorScheme()) {
+ DefaultPrimaryLeadingIconTabs(interactionSource)
+ }
+ }
+
+ assertTabsMatch(
+ scope = scope!!,
+ interactionSource = interactionSource,
+ interaction = null,
+ goldenIdentifier = "leadingIconTabs_darkTheme_primary"
+ )
+ }
+
+ @Test
+ fun leadingIconTabs_darkTheme_secondary() {
+ val interactionSource = MutableInteractionSource()
+
+ var scope: CoroutineScope? = null
+
+ composeTestRule.setContent {
+ scope = rememberCoroutineScope()
+ MaterialTheme(darkColorScheme()) {
+ DefaultSecondaryLeadingIconTabs(interactionSource)
+ }
+ }
+
+ assertTabsMatch(
+ scope = scope!!,
+ interactionSource = interactionSource,
+ interaction = null,
+ goldenIdentifier = "leadingIconTabs_darkTheme_secondary"
+ )
+ }
+
+ @Test
+ fun lightTheme_primary_scrollable() {
+ val interactionSource = MutableInteractionSource()
+
+ var scope: CoroutineScope? = null
+
+ composeTestRule.setContent {
+ scope = rememberCoroutineScope()
+ MaterialTheme(lightColorScheme()) {
+ DefaultPrimaryScrollableTabs(interactionSource)
+ }
+ }
+
+ assertTabsMatch(
+ scope = scope!!,
+ interactionSource = interactionSource,
+ interaction = null,
+ goldenIdentifier = "tabs_lightTheme_primary_scrollable"
+ )
+ }
+
+ @Test
+ fun lightTheme_secondary_scrollable() {
+ val interactionSource = MutableInteractionSource()
+
+ var scope: CoroutineScope? = null
+
+ composeTestRule.setContent {
+ scope = rememberCoroutineScope()
+ MaterialTheme(lightColorScheme()) {
+ DefaultSecondaryScrollableTabs(interactionSource)
+ }
+ }
+
+ assertTabsMatch(
+ scope = scope!!,
+ interactionSource = interactionSource,
+ interaction = null,
+ goldenIdentifier = "tabs_lightTheme_secondary_scrollable"
+ )
+ }
+
+ @Test
+ fun darkTheme_primary_scrollable() {
+ val interactionSource = MutableInteractionSource()
+
+ var scope: CoroutineScope? = null
+
+ composeTestRule.setContent {
+ scope = rememberCoroutineScope()
+ MaterialTheme(darkColorScheme()) {
+ DefaultPrimaryScrollableTabs(interactionSource)
+ }
+ }
+
+ assertTabsMatch(
+ scope = scope!!,
+ interactionSource = interactionSource,
+ interaction = null,
+ goldenIdentifier = "tabs_darkTheme_primary_scrollable"
+ )
+ }
+
+ @Test
+ fun darkTheme_secondary_scrollable() {
+ val interactionSource = MutableInteractionSource()
+
+ var scope: CoroutineScope? = null
+
+ composeTestRule.setContent {
+ scope = rememberCoroutineScope()
+ MaterialTheme(darkColorScheme()) {
+ DefaultSecondaryScrollableTabs(interactionSource)
+ }
+ }
+
+ assertTabsMatch(
+ scope = scope!!,
+ interactionSource = interactionSource,
+ interaction = null,
+ goldenIdentifier = "tabs_darkTheme_secondary_scrollable"
)
}
@@ -213,23 +527,66 @@
}
// Capture and compare screenshots
- composeTestRule.onNodeWithTag(Tag)
+ composeTestRule.onNodeWithTag(TAG)
.captureToImage()
.assertAgainstGolden(screenshotRule, goldenIdentifier)
}
}
/**
- * Default colored [TabRow] with three [Tab]s. The first [Tab] is selected, and the rest are not.
+ * Default primary colored [TabRow] with three [Tab]s. The first [Tab] is selected, and the rest are not.
*
* @param interactionSource the [MutableInteractionSource] for the first [Tab], to control its
* visual state.
*/
@Composable
-private fun DefaultTabs(
+private fun DefaultPrimaryTabs(
interactionSource: MutableInteractionSource
) {
- Box(Modifier.semantics(mergeDescendants = true) {}.testTag(Tag)) {
+ Box(
+ Modifier
+ .semantics(mergeDescendants = true) {}
+ .testTag(TAG)) {
+ TabRow(selectedTabIndex = 0, indicator = @Composable { tabPositions ->
+ TabRowDefaults.PrimaryIndicator(
+ modifier = Modifier.tabIndicatorOffset(tabPositions[0]),
+ width = tabPositions[0].contentWidth
+ )
+ }) {
+ Tab(
+ selected = true,
+ onClick = {},
+ text = { Text("TAB") },
+ interactionSource = interactionSource
+ )
+ Tab(
+ selected = false,
+ onClick = {},
+ text = { Text("TAB") }
+ )
+ Tab(
+ selected = false,
+ onClick = {},
+ text = { Text("TAB") }
+ )
+ }
+ }
+}
+
+/**
+ * Default secondary colored [TabRow] with three [Tab]s. The first [Tab] is selected, and the rest are not.
+ *
+ * @param interactionSource the [MutableInteractionSource] for the first [Tab], to control its
+ * visual state.
+ */
+@Composable
+private fun DefaultSecondaryTabs(
+ interactionSource: MutableInteractionSource
+) {
+ Box(
+ Modifier
+ .semantics(mergeDescendants = true) {}
+ .testTag(TAG)) {
TabRow(selectedTabIndex = 0) {
Tab(
selected = true,
@@ -252,7 +609,7 @@
}
/**
- * Custom colored [TabRow] with three [Tab]s. The first [Tab] is selected, and the rest are not.
+ * Custom primary colored [TabRow] with three [Tab]s. The first [Tab] is selected, and the rest are not.
*
* @param interactionSource the [MutableInteractionSource] for the first [Tab], to control its
* visual state.
@@ -261,17 +618,75 @@
* @param unselectedContentColor the content color for an unselected [Tab] (second and third tabs)
*/
@Composable
-private fun CustomTabs(
+private fun CustomPrimaryTabs(
interactionSource: MutableInteractionSource,
containerColor: Color,
selectedContentColor: Color,
unselectedContentColor: Color
) {
- Box(Modifier.semantics(mergeDescendants = true) {}.testTag(Tag)) {
+ Box(
+ Modifier
+ .semantics(mergeDescendants = true) {}
+ .testTag(TAG)) {
TabRow(selectedTabIndex = 0,
containerColor = containerColor,
indicator = @Composable { tabPositions ->
- TabRowDefaults.Indicator(
+ TabRowDefaults.PrimaryIndicator(
+ modifier = Modifier.tabIndicatorOffset(tabPositions[0]),
+ width = tabPositions[0].contentWidth,
+ color = selectedContentColor
+ )
+ }) {
+ Tab(
+ selected = true,
+ onClick = {},
+ text = { Text("TAB") },
+ selectedContentColor = selectedContentColor,
+ unselectedContentColor = unselectedContentColor,
+ interactionSource = interactionSource
+ )
+ Tab(
+ selected = false,
+ onClick = {},
+ text = { Text("TAB") },
+ selectedContentColor = selectedContentColor,
+ unselectedContentColor = unselectedContentColor
+ )
+ Tab(
+ selected = false,
+ onClick = {},
+ text = { Text("TAB") },
+ selectedContentColor = selectedContentColor,
+ unselectedContentColor = unselectedContentColor
+ )
+ }
+ }
+}
+
+/**
+ * Custom secondary colored [TabRow] with three [Tab]s. The first [Tab] is selected, and the rest are not.
+ *
+ * @param interactionSource the [MutableInteractionSource] for the first [Tab], to control its
+ * visual state.
+ * @param containerColor the containerColor of the [TabRow]
+ * @param selectedContentColor the content color for a selected [Tab] (first tab)
+ * @param unselectedContentColor the content color for an unselected [Tab] (second and third tabs)
+ */
+@Composable
+private fun CustomSecondaryTabs(
+ interactionSource: MutableInteractionSource,
+ containerColor: Color,
+ selectedContentColor: Color,
+ unselectedContentColor: Color
+) {
+ Box(
+ Modifier
+ .semantics(mergeDescendants = true) {}
+ .testTag(TAG)) {
+ TabRow(selectedTabIndex = 0,
+ containerColor = containerColor,
+ indicator = @Composable { tabPositions ->
+ TabRowDefaults.SecondaryIndicator(
modifier = Modifier.tabIndicatorOffset(tabPositions[0]),
color = selectedContentColor
)
@@ -303,17 +718,64 @@
}
/**
- * Default colored [TabRow] with three [LeadingIconTab]s. The first [LeadingIconTab] is selected,
+ * Default primary colored [TabRow] with three [LeadingIconTab]s. The first [LeadingIconTab] is selected,
* and the rest are not.
*
* @param interactionSource the [MutableInteractionSource] for the first [LeadingIconTab], to control its
* visual state.
*/
@Composable
-private fun DefaultLeadingIconTabs(
+private fun DefaultPrimaryLeadingIconTabs(
interactionSource: MutableInteractionSource
) {
- Box(Modifier.semantics(mergeDescendants = true) {}.testTag(Tag)) {
+ Box(
+ Modifier
+ .semantics(mergeDescendants = true) {}
+ .testTag(TAG)) {
+ TabRow(selectedTabIndex = 0, indicator = @Composable { tabPositions ->
+ TabRowDefaults.PrimaryIndicator(
+ modifier = Modifier.tabIndicatorOffset(tabPositions[0]),
+ width = tabPositions[0].contentWidth
+ )
+ }) {
+ LeadingIconTab(
+ selected = true,
+ onClick = {},
+ text = { Text("TAB") },
+ icon = { Icon(Icons.Filled.Favorite, contentDescription = "Favorite") },
+ interactionSource = interactionSource
+ )
+ LeadingIconTab(
+ selected = false,
+ onClick = {},
+ text = { Text("TAB") },
+ icon = { Icon(Icons.Filled.Favorite, contentDescription = "Favorite") }
+ )
+ LeadingIconTab(
+ selected = false,
+ onClick = {},
+ text = { Text("TAB") },
+ icon = { Icon(Icons.Filled.Favorite, contentDescription = "Favorite") }
+ )
+ }
+ }
+}
+
+/**
+ * Default secondary colored [TabRow] with three [LeadingIconTab]s. The first [LeadingIconTab] is selected,
+ * and the rest are not.
+ *
+ * @param interactionSource the [MutableInteractionSource] for the first [LeadingIconTab], to control its
+ * visual state.
+ */
+@Composable
+private fun DefaultSecondaryLeadingIconTabs(
+ interactionSource: MutableInteractionSource
+) {
+ Box(
+ Modifier
+ .semantics(mergeDescendants = true) {}
+ .testTag(TAG)) {
TabRow(selectedTabIndex = 0) {
LeadingIconTab(
selected = true,
@@ -338,4 +800,79 @@
}
}
-private const val Tag = "Tab"
+/**
+ * Default primary colored [ScrollableTabRow] with three [Tab]s. The first [Tab] is selected, and the rest are not.
+ *
+ * @param interactionSource the [MutableInteractionSource] for the first [Tab], to control its
+ * visual state.
+ */
+@Composable
+private fun DefaultPrimaryScrollableTabs(
+ interactionSource: MutableInteractionSource
+) {
+ Box(
+ Modifier
+ .semantics(mergeDescendants = true) {}
+ .testTag(TAG)) {
+ ScrollableTabRow(selectedTabIndex = 0, indicator = @Composable { tabPositions ->
+ TabRowDefaults.PrimaryIndicator(
+ modifier = Modifier.tabIndicatorOffset(tabPositions[0]),
+ width = tabPositions[0].contentWidth
+ )
+ }) {
+ Tab(
+ selected = true,
+ onClick = {},
+ text = { Text("TAB") },
+ interactionSource = interactionSource
+ )
+ Tab(
+ selected = false,
+ onClick = {},
+ text = { Text("TAB") }
+ )
+ Tab(
+ selected = false,
+ onClick = {},
+ text = { Text("TAB") }
+ )
+ }
+ }
+}
+
+/**
+ * Default secondary colored [ScrollableTabRow] with three [Tab]s. The first [Tab] is selected, and the rest are not.
+ *
+ * @param interactionSource the [MutableInteractionSource] for the first [Tab], to control its
+ * visual state.
+ */
+@Composable
+private fun DefaultSecondaryScrollableTabs(
+ interactionSource: MutableInteractionSource
+) {
+ Box(
+ Modifier
+ .semantics(mergeDescendants = true) {}
+ .testTag(TAG)) {
+ ScrollableTabRow(selectedTabIndex = 0) {
+ Tab(
+ selected = true,
+ onClick = {},
+ text = { Text("TAB") },
+ interactionSource = interactionSource
+ )
+ Tab(
+ selected = false,
+ onClick = {},
+ text = { Text("TAB") }
+ )
+ Tab(
+ selected = false,
+ onClick = {},
+ text = { Text("TAB") }
+ )
+ }
+ }
+}
+
+private const val TAG = "Tab"
diff --git a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/TabTest.kt b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/TabTest.kt
index 4ff880a..7b9ed6e 100644
--- a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/TabTest.kt
+++ b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/TabTest.kt
@@ -27,7 +27,7 @@
import androidx.compose.material3.samples.LeadingIconTabs
import androidx.compose.material3.samples.ScrollingTextTabs
import androidx.compose.material3.samples.TextTabs
-import androidx.compose.material3.tokens.PrimaryNavigationTabTokens
+import androidx.compose.material3.tokens.DividerTokens
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue
@@ -326,9 +326,9 @@
rule.onNodeWithTag("divider", true)
.assertPositionInRootIsEqualTo(
expectedLeft = 0.dp,
- expectedTop = tabRowBounds.height - PrimaryNavigationTabTokens.DividerHeight
+ expectedTop = tabRowBounds.height - DividerTokens.Thickness
)
- .assertHeightIsEqualTo(PrimaryNavigationTabTokens.DividerHeight)
+ .assertHeightIsEqualTo(DividerTokens.Thickness)
}
@Test
@@ -435,7 +435,7 @@
}
@Test
- fun LeadingIconTab_textAndIconPosition() {
+ fun leadingIconTab_textAndIconPosition() {
rule.setMaterialContent(lightColorScheme()) {
Box {
TabRow(
@@ -564,9 +564,9 @@
rule.onNodeWithTag("divider", true)
.assertPositionInRootIsEqualTo(
expectedLeft = 0.dp,
- expectedTop = tabRowBounds.height - PrimaryNavigationTabTokens.DividerHeight,
+ expectedTop = tabRowBounds.height - DividerTokens.Thickness,
)
- .assertHeightIsEqualTo(PrimaryNavigationTabTokens.DividerHeight)
+ .assertHeightIsEqualTo(DividerTokens.Thickness)
}
@Test
@@ -593,8 +593,10 @@
TextTabs()
}
+ val nodes = rule.onAllNodes(isSelectable())
+
// Only the first tab should be selected
- rule.onAllNodes(isSelectable())
+ nodes
.assertCountEquals(3)
.apply {
get(0).assertIsSelected()
@@ -603,10 +605,10 @@
}
// Click the last tab
- rule.onAllNodes(isSelectable())[2].performClick()
+ nodes[2].performClick()
// Now only the last tab should be selected
- rule.onAllNodes(isSelectable())
+ nodes
.assertCountEquals(3)
.apply {
get(0).assertIsNotSelected()
@@ -747,7 +749,7 @@
val titles = listOf("TAB 1", "TAB 2", "TAB 3 WITH LOTS OF TEXT")
val indicator = @Composable { tabPositions: List<TabPosition> ->
- TabRowDefaults.Indicator(
+ TabRowDefaults.SecondaryIndicator(
Modifier
.tabIndicatorOffset(tabPositions[state])
.testTag("indicator")
@@ -791,7 +793,7 @@
@Test
fun testInspectorValue() {
- val pos = TabPosition(10.0.dp, 200.0.dp)
+ val pos = TabPosition(10.0.dp, 200.0.dp, 0.dp)
rule.setContent {
val modifier = Modifier.tabIndicatorOffset(pos) as InspectableValue
assertThat(modifier.nameFallback).isEqualTo("tabIndicatorOffset")
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Tab.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Tab.kt
index d726302..31ab35e 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Tab.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Tab.kt
@@ -315,7 +315,11 @@
) { text() }
}
if (icon != null) {
- Box(Modifier.layoutId("icon")) { icon() }
+ Box(
+ Modifier
+ .layoutId("icon")
+ .padding(horizontal = HorizontalTextPadding)
+ ) { icon() }
}
}
) { measurables, constraints ->
@@ -430,7 +434,7 @@
private const val TabFadeOutAnimationDuration = 100
// The horizontal padding on the left and right of text
-private val HorizontalTextPadding = 16.dp
+internal val HorizontalTextPadding = 16.dp
// Distance from the top of the indicator to the text baseline when there is one line of text and an
// icon
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TabRow.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TabRow.kt
index 6480116..82d1d85 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TabRow.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TabRow.kt
@@ -24,9 +24,11 @@
import androidx.compose.foundation.background
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.offset
+import androidx.compose.foundation.layout.requiredSize
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.rememberScrollState
@@ -43,6 +45,8 @@
import androidx.compose.ui.composed
import androidx.compose.ui.draw.clipToBounds
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.Shape
+import androidx.compose.ui.layout.Placeable
import androidx.compose.ui.layout.SubcomposeLayout
import androidx.compose.ui.platform.debugInspectorInfo
import androidx.compose.ui.unit.Constraints
@@ -52,8 +56,9 @@
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
-// TODO: Provide M3 tab row asset and docs when available.
/**
+ * <a href="https://m3.material.io/components/tabs/overview" class="external" target="_blank">Material Design tabs</a>
+ *
* Material Design fixed tabs.
*
* Fixed tabs display all tabs in a set simultaneously. They are best for switching between related
@@ -113,7 +118,7 @@
* matching content color for [containerColor], or to the current [LocalContentColor] if
* [containerColor] is not a color from the theme.
* @param indicator the indicator that represents which tab is currently selected. By default this
- * will be a [TabRowDefaults.Indicator], using a [TabRowDefaults.tabIndicatorOffset] modifier to
+ * will be a [TabRowDefaults.SecondaryIndicator], using a [TabRowDefaults.tabIndicatorOffset] modifier to
* animate its position. Note that this indicator will be forced to fill up the entire tab row, so
* you should use [TabRowDefaults.tabIndicatorOffset] or similar to animate the actual drawn
* indicator inside this space, and provide an offset from the start.
@@ -130,7 +135,7 @@
contentColor: Color = TabRowDefaults.contentColor,
indicator: @Composable (tabPositions: List<TabPosition>) -> Unit = @Composable { tabPositions ->
if (selectedTabIndex < tabPositions.size) {
- TabRowDefaults.Indicator(
+ TabRowDefaults.SecondaryIndicator(
Modifier.tabIndicatorOffset(tabPositions[selectedTabIndex])
)
}
@@ -140,6 +145,18 @@
},
tabs: @Composable () -> Unit
) {
+ TabRowImpl(modifier, containerColor, contentColor, indicator, divider, tabs)
+}
+
+@Composable
+private fun TabRowImpl(
+ modifier: Modifier,
+ containerColor: Color,
+ contentColor: Color,
+ indicator: @Composable (tabPositions: List<TabPosition>) -> Unit,
+ divider: @Composable () -> Unit,
+ tabs: @Composable () -> Unit
+) {
Surface(
modifier = modifier.selectableGroup(),
color = containerColor,
@@ -169,7 +186,10 @@
}
val tabPositions = List(tabCount) { index ->
- TabPosition(tabWidth.toDp() * index, tabWidth.toDp())
+ var contentWidth =
+ minOf(tabMeasurables[index].maxIntrinsicWidth(tabRowHeight), tabWidth).toDp()
+ contentWidth -= HorizontalTextPadding * 2
+ TabPosition(tabWidth.toDp() * index, tabWidth.toDp(), contentWidth)
}
layout(tabRowWidth, tabRowHeight) {
@@ -192,8 +212,9 @@
}
}
-// TODO: Provide M3 tab row asset and docs when available.
/**
+ * <a href="https://m3.material.io/components/tabs/overview" class="external" target="_blank">Material Design tabs</a>
+ *
* Material Design scrollable tabs.
*
* When a set of tabs cannot fit on screen, use scrollable tabs. Scrollable tabs can use longer text
@@ -215,7 +236,7 @@
* and the tabs inside the row. This padding helps inform the user that this tab row can be
* scrolled, unlike a [TabRow].
* @param indicator the indicator that represents which tab is currently selected. By default this
- * will be a [TabRowDefaults.Indicator], using a [TabRowDefaults.tabIndicatorOffset] modifier to
+ * will be a [TabRowDefaults.SecondaryIndicator], using a [TabRowDefaults.tabIndicatorOffset] modifier to
* animate its position. Note that this indicator will be forced to fill up the entire tab row, so
* you should use [TabRowDefaults.tabIndicatorOffset] or similar to animate the actual drawn
* indicator inside this space, and provide an offset from the start.
@@ -232,7 +253,7 @@
contentColor: Color = TabRowDefaults.contentColor,
edgePadding: Dp = ScrollableTabRowPadding,
indicator: @Composable (tabPositions: List<TabPosition>) -> Unit = @Composable { tabPositions ->
- TabRowDefaults.Indicator(
+ TabRowDefaults.SecondaryIndicator(
Modifier.tabIndicatorOffset(tabPositions[selectedTabIndex])
)
},
@@ -276,8 +297,20 @@
minHeight = layoutHeight,
maxHeight = layoutHeight,
)
- val tabPlaceables = tabMeasurables
- .map { it.measure(tabConstraints) }
+
+ val tabPlaceables = mutableListOf<Placeable>()
+ val tabContentWidths = mutableListOf<Dp>()
+ tabMeasurables.forEach {
+ val placeable = it.measure(tabConstraints)
+ var contentWidth =
+ minOf(
+ it.maxIntrinsicWidth(placeable.height),
+ placeable.width
+ ).toDp()
+ contentWidth -= HorizontalTextPadding * 2
+ tabPlaceables.add(placeable)
+ tabContentWidths.add(contentWidth)
+ }
val layoutWidth = tabPlaceables.fold(initial = padding * 2) { curr, measurable ->
curr + measurable.width
@@ -288,10 +321,16 @@
// Place the tabs
val tabPositions = mutableListOf<TabPosition>()
var left = padding
- tabPlaceables.forEach {
- it.placeRelative(left, 0)
- tabPositions.add(TabPosition(left = left.toDp(), width = it.width.toDp()))
- left += it.width
+ tabPlaceables.forEachIndexed { index, placeable ->
+ placeable.placeRelative(left, 0)
+ tabPositions.add(
+ TabPosition(
+ left = left.toDp(),
+ width = placeable.width.toDp(),
+ contentWidth = tabContentWidths[index]
+ )
+ )
+ left += placeable.width
}
// The divider is measured with its own height, and width equal to the total width
@@ -333,9 +372,11 @@
* @property left the left edge's x position from the start of the [TabRow]
* @property right the right edge's x position from the start of the [TabRow]
* @property width the width of this tab
+ * @property contentWidth the content width of this tab
*/
@Immutable
-class TabPosition internal constructor(val left: Dp, val width: Dp) {
+class TabPosition internal constructor(val left: Dp, val width: Dp, val contentWidth: Dp) {
+
val right: Dp get() = left + width
override fun equals(other: Any?): Boolean {
@@ -344,6 +385,7 @@
if (left != other.left) return false
if (width != other.width) return false
+ if (contentWidth != other.contentWidth) return false
return true
}
@@ -351,11 +393,12 @@
override fun hashCode(): Int {
var result = left.hashCode()
result = 31 * result + width.hashCode()
+ result = 31 * result + contentWidth.hashCode()
return result
}
override fun toString(): String {
- return "TabPosition(left=$left, right=$right, width=$width)"
+ return "TabPosition(left=$left, right=$right, width=$width, contentWidth=$contentWidth)"
}
}
@@ -364,12 +407,14 @@
*/
object TabRowDefaults {
/** Default container color of a tab row. */
- val containerColor: Color @Composable get() =
- PrimaryNavigationTabTokens.ContainerColor.toColor()
+ val containerColor: Color
+ @Composable get() =
+ PrimaryNavigationTabTokens.ContainerColor.toColor()
/** Default content color of a tab row. */
- val contentColor: Color @Composable get() =
- PrimaryNavigationTabTokens.ActiveLabelTextColor.toColor()
+ val contentColor: Color
+ @Composable get() =
+ PrimaryNavigationTabTokens.ActiveLabelTextColor.toColor()
/**
* Default indicator, which will be positioned at the bottom of the [TabRow], on top of the
@@ -380,6 +425,12 @@
* @param color color of the indicator
*/
@Composable
+ @Deprecated(
+ message = "Use SecondaryIndicator instead.",
+ replaceWith = ReplaceWith(
+ "SecondaryIndicator(modifier, height, color)"
+ )
+ )
fun Indicator(
modifier: Modifier = Modifier,
height: Dp = PrimaryNavigationTabTokens.ActiveIndicatorHeight,
@@ -395,6 +446,54 @@
}
/**
+ * Primary indicator, which will be positioned at the bottom of the [TabRow], on top of the
+ * divider.
+ *
+ * @param modifier modifier for the indicator's layout
+ * @param width width of the indicator
+ * @param height height of the indicator
+ * @param color color of the indicator
+ * @param shape shape of the indicator
+ */
+ @Composable
+ fun PrimaryIndicator(
+ modifier: Modifier = Modifier,
+ width: Dp = 0.dp,
+ height: Dp = PrimaryNavigationTabTokens.ActiveIndicatorHeight,
+ color: Color = PrimaryNavigationTabTokens.ActiveIndicatorColor.toColor(),
+ shape: Shape = PrimaryNavigationTabTokens.ActiveIndicatorShape
+ ) {
+ Spacer(
+ modifier
+ .requiredSize(width, height)
+ .background(color = color, shape = shape)
+ )
+ }
+
+ /**
+ * Secondary indicator, which will be positioned at the bottom of the [TabRow], on top of the
+ * divider.
+ *
+ * @param modifier modifier for the indicator's layout
+ * @param height height of the indicator
+ * @param color color of the indicator
+ */
+ @Composable
+ fun SecondaryIndicator(
+ modifier: Modifier = Modifier,
+ height: Dp = PrimaryNavigationTabTokens.ActiveIndicatorHeight,
+ color: Color =
+ MaterialTheme.colorScheme.fromToken(PrimaryNavigationTabTokens.ActiveIndicatorColor)
+ ) {
+ Box(
+ modifier
+ .fillMaxWidth()
+ .height(height)
+ .background(color = color)
+ )
+ }
+
+ /**
* [Modifier] that takes up all the available width inside the [TabRow], and then animates
* the offset of the indicator it is applied to, depending on the [currentTabPosition].
*
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/PrimaryNavigationTabTokens.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/PrimaryNavigationTabTokens.kt
index 3fd0e91..4622e75 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/PrimaryNavigationTabTokens.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/PrimaryNavigationTabTokens.kt
@@ -13,7 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-// VERSION: v0_103
+
+// VERSION: v0_162
// GENERATED CODE - DO NOT MODIFY BY HAND
package androidx.compose.material3.tokens
@@ -29,8 +30,6 @@
val ContainerElevation = ElevationTokens.Level0
val ContainerHeight = 48.0.dp
val ContainerShape = ShapeKeyTokens.CornerNone
- val DividerColor = ColorSchemeKeyTokens.SurfaceVariant
- val DividerHeight = 1.0.dp
val ActiveFocusIconColor = ColorSchemeKeyTokens.Primary
val ActiveHoverIconColor = ColorSchemeKeyTokens.Primary
val ActiveIconColor = ColorSchemeKeyTokens.Primary
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/SecondaryNavigationTabTokens.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/SecondaryNavigationTabTokens.kt
new file mode 100644
index 0000000..6d34a48
--- /dev/null
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/SecondaryNavigationTabTokens.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2023 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.
+ */
+
+// VERSION: v0_162
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+package androidx.compose.material3.tokens
+
+import androidx.compose.ui.unit.dp
+
+internal object SecondaryNavigationTabTokens {
+ val ActiveLabelTextColor = ColorSchemeKeyTokens.OnSurface
+ val ContainerColor = ColorSchemeKeyTokens.Surface
+ val ContainerElevation = ElevationTokens.Level0
+ val ContainerHeight = 48.0.dp
+ val ContainerShape = ShapeKeyTokens.CornerNone
+ val DividerColor = ColorSchemeKeyTokens.SurfaceVariant
+ val DividerHeight = 1.0.dp
+ val FocusLabelTextColor = ColorSchemeKeyTokens.OnSurface
+ val HoverLabelTextColor = ColorSchemeKeyTokens.OnSurface
+ val InactiveLabelTextColor = ColorSchemeKeyTokens.OnSurfaceVariant
+ val LabelTextFont = TypographyKeyTokens.TitleSmall
+ val PressedLabelTextColor = ColorSchemeKeyTokens.OnSurface
+ val ActiveIconColor = ColorSchemeKeyTokens.OnSurface
+ val FocusIconColor = ColorSchemeKeyTokens.OnSurface
+ val HoverIconColor = ColorSchemeKeyTokens.OnSurface
+ val IconSize = 24.0.dp
+ val InactiveIconColor = ColorSchemeKeyTokens.OnSurfaceVariant
+ val PressedIconColor = ColorSchemeKeyTokens.OnSurface
+}
\ No newline at end of file
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Effects.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Effects.kt
index 1254875..9efcc11 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Effects.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Effects.kt
@@ -22,6 +22,7 @@
import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch
import kotlin.coroutines.EmptyCoroutineContext
+import kotlinx.coroutines.CancellationException
/**
* Schedule [effect] to run when the current composition completes successfully and applies
@@ -284,17 +285,18 @@
private var job: Job? = null
override fun onRemembered() {
+ // This should never happen but is left here for safety
job?.cancel("Old job was still running!")
job = scope.launch(block = task)
}
override fun onForgotten() {
- job?.cancel()
+ job?.cancel(LeftCompositionCancellationException())
job = null
}
override fun onAbandoned() {
- job?.cancel()
+ job?.cancel(LeftCompositionCancellationException())
job = null
}
}
@@ -384,6 +386,12 @@
remember(key1, key2, key3) { LaunchedEffectImpl(applyContext, block) }
}
+private class LeftCompositionCancellationException : CancellationException(
+ "The coroutine scope left the composition"
+) {
+ override fun fillInStackTrace(): Throwable = this
+}
+
/**
* When [LaunchedEffect] enters the composition it will launch [block] into the composition's
* [CoroutineContext]. The coroutine will be [cancelled][Job.cancel] and **re-launched** when
@@ -416,11 +424,11 @@
}
override fun onForgotten() {
- coroutineScope.cancel()
+ coroutineScope.cancel(LeftCompositionCancellationException())
}
override fun onAbandoned() {
- coroutineScope.cancel()
+ coroutineScope.cancel(LeftCompositionCancellationException())
}
}
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Recomposer.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Recomposer.kt
index b66eab9..faf8739 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Recomposer.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Recomposer.kt
@@ -614,7 +614,7 @@
try {
// We could do toComplete += toApply but doing it like below
// avoids unncessary allocations since toApply is a mutable list
- toComplete += toApply
+ // toComplete += toApply
toApply.fastForEach { composition ->
toComplete.add(composition)
}
diff --git a/constraintlayout/constraintlayout-compose/integration-tests/macrobenchmark/build.gradle b/constraintlayout/constraintlayout-compose/integration-tests/macrobenchmark/build.gradle
index 5824041..488e08f 100644
--- a/constraintlayout/constraintlayout-compose/integration-tests/macrobenchmark/build.gradle
+++ b/constraintlayout/constraintlayout-compose/integration-tests/macrobenchmark/build.gradle
@@ -14,11 +14,9 @@
* limitations under the License.
*/
-import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
-
plugins {
id("AndroidXPlugin")
- id("com.android.library")
+ id("com.android.test")
id("kotlin-android")
}
@@ -30,26 +28,23 @@
// We need animations to work for MotionLayout
testOptions.animationsDisabled false
+ targetProjectPath = ":constraintlayout:constraintlayout-compose:integration-tests:macrobenchmark-target"
+ experimentalProperties["android.experimental.self-instrumenting"] = true
}
+// Create a release build type and make sure it's the only one enabled.
+// This is needed because we benchmark the release build type only.
+android.buildTypes { release {} }
+androidComponents { beforeVariants(selector().all()) { enabled = buildType == 'release' } }
+
dependencies {
- androidTestImplementation(project(":benchmark:benchmark-junit4"))
- androidTestImplementation(project(":benchmark:benchmark-macro-junit4"))
- androidTestImplementation(project(":internal-testutils-macrobenchmark"))
- androidTestImplementation(project(":internal-testutils-runtime"))
- androidTestImplementation(libs.testRules)
- androidTestImplementation(libs.testExtJunit)
- androidTestImplementation(libs.testCore)
- androidTestImplementation(libs.testRunner)
- androidTestImplementation(libs.testUiautomator)
+ implementation(project(":benchmark:benchmark-junit4"))
+ implementation(project(":benchmark:benchmark-macro-junit4"))
+ implementation(project(":internal-testutils-macrobenchmark"))
+ implementation(project(":internal-testutils-runtime"))
+ implementation(libs.testRules)
+ implementation(libs.testExtJunit)
+ implementation(libs.testCore)
+ implementation(libs.testRunner)
+ implementation(libs.testUiautomator)
}
-
-// Define a task dependency so the app is installed before we run macro benchmarks.
-afterEvaluate {
- tasks.getByPath(":constraintlayout:constraintlayout-compose:integration-tests:macrobenchmark:connectedDebugAndroidTest")
- .dependsOn(
- tasks.getByPath(
- ":constraintlayout:constraintlayout-compose:integration-tests:macrobenchmark-target:installRelease"
- )
- )
-}
\ No newline at end of file
diff --git a/constraintlayout/constraintlayout-compose/integration-tests/macrobenchmark/src/main/AndroidManifest.xml b/constraintlayout/constraintlayout-compose/integration-tests/macrobenchmark/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..8e90956
--- /dev/null
+++ b/constraintlayout/constraintlayout-compose/integration-tests/macrobenchmark/src/main/AndroidManifest.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 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.
+ -->
+<manifest />
diff --git a/constraintlayout/constraintlayout-compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/constraintlayout/compose/integration/macrobenchmark/MotionLayoutBenchmark.kt b/constraintlayout/constraintlayout-compose/integration-tests/macrobenchmark/src/main/java/androidx/constraintlayout/compose/integration/macrobenchmark/MotionLayoutBenchmark.kt
similarity index 100%
rename from constraintlayout/constraintlayout-compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/constraintlayout/compose/integration/macrobenchmark/MotionLayoutBenchmark.kt
rename to constraintlayout/constraintlayout-compose/integration-tests/macrobenchmark/src/main/java/androidx/constraintlayout/compose/integration/macrobenchmark/MotionLayoutBenchmark.kt
diff --git a/emoji2/integration-tests/init-disabled-macrobenchmark/build.gradle b/emoji2/integration-tests/init-disabled-macrobenchmark/build.gradle
index 708a1b6..4a65042 100644
--- a/emoji2/integration-tests/init-disabled-macrobenchmark/build.gradle
+++ b/emoji2/integration-tests/init-disabled-macrobenchmark/build.gradle
@@ -16,7 +16,7 @@
plugins {
id("AndroidXPlugin")
- id("com.android.library")
+ id("com.android.test")
id("kotlin-android")
}
@@ -25,23 +25,20 @@
minSdkVersion 23
}
namespace "androidx.emoji2.integration.macrobenchmark.disabled"
+ targetProjectPath = ":emoji2:integration-tests:init-disabled-macrobenchmark-target"
+ experimentalProperties["android.experimental.self-instrumenting"] = true
}
+// Create a release build type and make sure it's the only one enabled.
+// This is needed because we benchmark the release build type only.
+android.buildTypes { release {} }
+androidComponents { beforeVariants(selector().all()) { enabled = buildType == 'release' } }
+
dependencies {
- androidTestImplementation(project(":benchmark:benchmark-macro-junit4"))
- androidTestImplementation(project(":internal-testutils-macrobenchmark"))
- androidTestImplementation(libs.testRules)
- androidTestImplementation(libs.testExtJunit)
- androidTestImplementation(libs.testCore)
- androidTestImplementation(libs.testRunner)
-}
-
-// Define a task dependency so the app is installed before we run macro benchmarks.
-afterEvaluate {
- tasks.getByPath(":emoji2:integration-tests:init-disabled-macrobenchmark:connectedDebugAndroidTest")
- .dependsOn(
- tasks.getByPath(
- ":emoji2:integration-tests:init-disabled-macrobenchmark-target:installRelease"
- )
- )
+ implementation(project(":benchmark:benchmark-macro-junit4"))
+ implementation(project(":internal-testutils-macrobenchmark"))
+ implementation(libs.testRules)
+ implementation(libs.testExtJunit)
+ implementation(libs.testCore)
+ implementation(libs.testRunner)
}
diff --git a/benchmark/integration-tests/test-module-sample/src/main/AndroidManifest.xml b/emoji2/integration-tests/init-disabled-macrobenchmark/src/main/AndroidManifest.xml
similarity index 60%
rename from benchmark/integration-tests/test-module-sample/src/main/AndroidManifest.xml
rename to emoji2/integration-tests/init-disabled-macrobenchmark/src/main/AndroidManifest.xml
index 37fa920..5b41847 100644
--- a/benchmark/integration-tests/test-module-sample/src/main/AndroidManifest.xml
+++ b/emoji2/integration-tests/init-disabled-macrobenchmark/src/main/AndroidManifest.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2021 The Android Open Source Project
+ ~ Copyright (C) 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.
@@ -14,12 +14,4 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android">
- <queries>
- <!--
- Enables querying application info with packageManager.getApplicationInfo, to verify
- the target package is present
- -->
- <package android:name="androidx.benchmark.integration.macrobenchmark.target" />
- </queries>
-</manifest>
+<manifest />
diff --git a/emoji2/integration-tests/init-disabled-macrobenchmark/src/androidTest/java/androidx/emoji2/integration/macrobenchmark/disabled/EmojiStartupBenchmark.kt b/emoji2/integration-tests/init-disabled-macrobenchmark/src/main/java/androidx/emoji2/integration/macrobenchmark/disabled/EmojiStartupBenchmark.kt
similarity index 100%
rename from emoji2/integration-tests/init-disabled-macrobenchmark/src/androidTest/java/androidx/emoji2/integration/macrobenchmark/disabled/EmojiStartupBenchmark.kt
rename to emoji2/integration-tests/init-disabled-macrobenchmark/src/main/java/androidx/emoji2/integration/macrobenchmark/disabled/EmojiStartupBenchmark.kt
diff --git a/emoji2/integration-tests/init-enabled-macrobenchmark/build.gradle b/emoji2/integration-tests/init-enabled-macrobenchmark/build.gradle
index 1dee7de..c1f5ed9 100644
--- a/emoji2/integration-tests/init-enabled-macrobenchmark/build.gradle
+++ b/emoji2/integration-tests/init-enabled-macrobenchmark/build.gradle
@@ -16,7 +16,7 @@
plugins {
id("AndroidXPlugin")
- id("com.android.library")
+ id("com.android.test")
id("kotlin-android")
}
@@ -25,24 +25,21 @@
minSdkVersion 23
}
namespace "androidx.emoji2.integration.macrobenchmark.enabled"
+ targetProjectPath = ":emoji2:integration-tests:init-enabled-macrobenchmark-target"
+ experimentalProperties["android.experimental.self-instrumenting"] = true
}
+// Create a release build type and make sure it's the only one enabled.
+// This is needed because we benchmark the release build type only.
+android.buildTypes { release {} }
+androidComponents { beforeVariants(selector().all()) { enabled = buildType == 'release' } }
+
dependencies {
- androidTestImplementation(project(":emoji2:emoji2"))
- androidTestImplementation(project(":benchmark:benchmark-macro-junit4"))
- androidTestImplementation(project(":internal-testutils-macrobenchmark"))
- androidTestImplementation(libs.testRules)
- androidTestImplementation(libs.testExtJunit)
- androidTestImplementation(libs.testCore)
- androidTestImplementation(libs.testRunner)
-}
-
-// Define a task dependency so the app is installed before we run macro benchmarks.
-afterEvaluate {
- tasks.getByPath(":emoji2:integration-tests:init-enabled-macrobenchmark:connectedDebugAndroidTest")
- .dependsOn(
- tasks.getByPath(
- ":emoji2:integration-tests:init-enabled-macrobenchmark-target:installRelease"
- )
- )
+ implementation(project(":emoji2:emoji2"))
+ implementation(project(":benchmark:benchmark-macro-junit4"))
+ implementation(project(":internal-testutils-macrobenchmark"))
+ implementation(libs.testRules)
+ implementation(libs.testExtJunit)
+ implementation(libs.testCore)
+ implementation(libs.testRunner)
}
diff --git a/benchmark/integration-tests/test-module-sample/src/main/AndroidManifest.xml b/emoji2/integration-tests/init-enabled-macrobenchmark/src/main/AndroidManifest.xml
similarity index 60%
copy from benchmark/integration-tests/test-module-sample/src/main/AndroidManifest.xml
copy to emoji2/integration-tests/init-enabled-macrobenchmark/src/main/AndroidManifest.xml
index 37fa920..5b41847 100644
--- a/benchmark/integration-tests/test-module-sample/src/main/AndroidManifest.xml
+++ b/emoji2/integration-tests/init-enabled-macrobenchmark/src/main/AndroidManifest.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2021 The Android Open Source Project
+ ~ Copyright (C) 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.
@@ -14,12 +14,4 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android">
- <queries>
- <!--
- Enables querying application info with packageManager.getApplicationInfo, to verify
- the target package is present
- -->
- <package android:name="androidx.benchmark.integration.macrobenchmark.target" />
- </queries>
-</manifest>
+<manifest />
diff --git a/emoji2/integration-tests/init-enabled-macrobenchmark/src/androidTest/java/androidx/emoji2/integration/macrobenchmark/enabled/EmojiStartupBenchmark.kt b/emoji2/integration-tests/init-enabled-macrobenchmark/src/main/java/androidx/emoji2/integration/macrobenchmark/enabled/EmojiStartupBenchmark.kt
similarity index 100%
rename from emoji2/integration-tests/init-enabled-macrobenchmark/src/androidTest/java/androidx/emoji2/integration/macrobenchmark/enabled/EmojiStartupBenchmark.kt
rename to emoji2/integration-tests/init-enabled-macrobenchmark/src/main/java/androidx/emoji2/integration/macrobenchmark/enabled/EmojiStartupBenchmark.kt
diff --git a/glance/glance-appwidget/integration-tests/macrobenchmark/build.gradle b/glance/glance-appwidget/integration-tests/macrobenchmark/build.gradle
index 19b0df6..cfa7f61 100644
--- a/glance/glance-appwidget/integration-tests/macrobenchmark/build.gradle
+++ b/glance/glance-appwidget/integration-tests/macrobenchmark/build.gradle
@@ -16,31 +16,37 @@
plugins {
id("AndroidXPlugin")
- id("com.android.library")
+ id("com.android.test")
id("kotlin-android")
}
android {
+ defaultConfig {
+ minSdkVersion 23
+ }
namespace "androidx.glance.appwidget.macrobenchmark"
+ targetProjectPath = ":glance:glance-appwidget:integration-tests:macrobenchmark-target"
+ experimentalProperties["android.experimental.self-instrumenting"] = true
}
-android.defaultConfig {
- minSdkVersion 23
-}
+// Create a release build type and make sure it's the only one enabled.
+// This is needed because we benchmark the release build type only.
+android.buildTypes { release {} }
+androidComponents { beforeVariants(selector().all()) { enabled = buildType == 'release' } }
dependencies {
implementation 'androidx.compose.ui:ui-unit:1.2.1'
- androidTestImplementation(project(':benchmark:benchmark-macro'))
- androidTestImplementation(project(':benchmark:benchmark-common'))
- androidTestImplementation(project(':benchmark:benchmark-macro-junit4'))
- androidTestImplementation('androidx.core:core-ktx:1.7.0')
- androidTestImplementation(project(":glance:glance"))
- androidTestImplementation(project(":glance:glance-appwidget"))
- androidTestImplementation(project(":internal-testutils-macrobenchmark"))
- androidTestImplementation(libs.kotlinTest)
- androidTestImplementation(libs.testRules)
- androidTestImplementation(libs.testExtJunit)
- androidTestImplementation(libs.testCore)
- androidTestImplementation(libs.testRunner)
- androidTestImplementation(libs.testUiautomator)
+ implementation(project(':benchmark:benchmark-macro'))
+ implementation(project(':benchmark:benchmark-common'))
+ implementation(project(':benchmark:benchmark-macro-junit4'))
+ implementation('androidx.core:core-ktx:1.7.0')
+ implementation(project(":glance:glance"))
+ implementation(project(":glance:glance-appwidget"))
+ implementation(project(":internal-testutils-macrobenchmark"))
+ implementation(libs.kotlinTest)
+ implementation(libs.testRules)
+ implementation(libs.testExtJunit)
+ implementation(libs.testCore)
+ implementation(libs.testRunner)
+ implementation(libs.testUiautomator)
}
diff --git a/glance/glance-appwidget/integration-tests/macrobenchmark/src/androidTest/AndroidManifest.xml b/glance/glance-appwidget/integration-tests/macrobenchmark/src/main/AndroidManifest.xml
similarity index 99%
rename from glance/glance-appwidget/integration-tests/macrobenchmark/src/androidTest/AndroidManifest.xml
rename to glance/glance-appwidget/integration-tests/macrobenchmark/src/main/AndroidManifest.xml
index 05a1d72..e7eaa978 100644
--- a/glance/glance-appwidget/integration-tests/macrobenchmark/src/androidTest/AndroidManifest.xml
+++ b/glance/glance-appwidget/integration-tests/macrobenchmark/src/main/AndroidManifest.xml
@@ -25,4 +25,4 @@
android:configChanges="orientation|screenLayout|screenSize"
android:exported="true"/>
</application>
-</manifest>
\ No newline at end of file
+</manifest>
diff --git a/glance/glance-appwidget/integration-tests/macrobenchmark/src/androidTest/java/androidx/glance/appwidget/macrobenchmark/AppWidgetHostRule.kt b/glance/glance-appwidget/integration-tests/macrobenchmark/src/main/java/androidx/glance/appwidget/macrobenchmark/AppWidgetHostRule.kt
similarity index 100%
rename from glance/glance-appwidget/integration-tests/macrobenchmark/src/androidTest/java/androidx/glance/appwidget/macrobenchmark/AppWidgetHostRule.kt
rename to glance/glance-appwidget/integration-tests/macrobenchmark/src/main/java/androidx/glance/appwidget/macrobenchmark/AppWidgetHostRule.kt
diff --git a/glance/glance-appwidget/integration-tests/macrobenchmark/src/androidTest/java/androidx/glance/appwidget/macrobenchmark/AppWidgetHostTestActivity.kt b/glance/glance-appwidget/integration-tests/macrobenchmark/src/main/java/androidx/glance/appwidget/macrobenchmark/AppWidgetHostTestActivity.kt
similarity index 100%
rename from glance/glance-appwidget/integration-tests/macrobenchmark/src/androidTest/java/androidx/glance/appwidget/macrobenchmark/AppWidgetHostTestActivity.kt
rename to glance/glance-appwidget/integration-tests/macrobenchmark/src/main/java/androidx/glance/appwidget/macrobenchmark/AppWidgetHostTestActivity.kt
diff --git a/glance/glance-appwidget/integration-tests/macrobenchmark/src/androidTest/java/androidx/glance/appwidget/macrobenchmark/AppWidgetUpdateBenchmark.kt b/glance/glance-appwidget/integration-tests/macrobenchmark/src/main/java/androidx/glance/appwidget/macrobenchmark/AppWidgetUpdateBenchmark.kt
similarity index 100%
rename from glance/glance-appwidget/integration-tests/macrobenchmark/src/androidTest/java/androidx/glance/appwidget/macrobenchmark/AppWidgetUpdateBenchmark.kt
rename to glance/glance-appwidget/integration-tests/macrobenchmark/src/main/java/androidx/glance/appwidget/macrobenchmark/AppWidgetUpdateBenchmark.kt
diff --git a/glance/glance-appwidget/integration-tests/macrobenchmark/src/androidTest/res/layout/app_widget_host_activity.xml b/glance/glance-appwidget/integration-tests/macrobenchmark/src/main/res/layout/app_widget_host_activity.xml
similarity index 100%
rename from glance/glance-appwidget/integration-tests/macrobenchmark/src/androidTest/res/layout/app_widget_host_activity.xml
rename to glance/glance-appwidget/integration-tests/macrobenchmark/src/main/res/layout/app_widget_host_activity.xml
diff --git a/libraryversions.toml b/libraryversions.toml
index e865369..413f3f3 100644
--- a/libraryversions.toml
+++ b/libraryversions.toml
@@ -21,7 +21,7 @@
COLLECTION = "1.3.0-alpha05"
COMPOSE = "1.5.0-alpha04"
COMPOSE_COMPILER = "1.4.7"
-COMPOSE_MATERIAL3 = "1.2.0-alpha01"
+COMPOSE_MATERIAL3 = "1.2.0-alpha02"
COMPOSE_MATERIAL3_ADAPTIVE = "1.0.0-alpha01"
COMPOSE_RUNTIME_TRACING = "1.0.0-alpha03"
CONSTRAINTLAYOUT = "2.2.0-alpha10"
diff --git a/profileinstaller/integration-tests/init-macrobenchmark/build.gradle b/profileinstaller/integration-tests/init-macrobenchmark/build.gradle
index 0d054c7..7088271 100644
--- a/profileinstaller/integration-tests/init-macrobenchmark/build.gradle
+++ b/profileinstaller/integration-tests/init-macrobenchmark/build.gradle
@@ -16,7 +16,7 @@
plugins {
id("AndroidXPlugin")
- id("com.android.library")
+ id("com.android.test")
id("kotlin-android")
}
@@ -25,24 +25,21 @@
minSdkVersion 23
}
namespace "androidx.profileinstaller.integration.macrobenchmark"
+ targetProjectPath = ":profileinstaller:integration-tests:init-macrobenchmark-target"
+ experimentalProperties["android.experimental.self-instrumenting"] = true
}
+// Create a release build type and make sure it's the only one enabled.
+// This is needed because we benchmark the release build type only.
+android.buildTypes { release {} }
+androidComponents { beforeVariants(selector().all()) { enabled = buildType == 'release' } }
+
dependencies {
- androidTestImplementation(project(":profileinstaller:profileinstaller"))
- androidTestImplementation(project(":benchmark:benchmark-macro-junit4"))
- androidTestImplementation(project(":internal-testutils-macrobenchmark"))
- androidTestImplementation(libs.testRules)
- androidTestImplementation(libs.testExtJunit)
- androidTestImplementation(libs.testCore)
- androidTestImplementation(libs.testRunner)
-}
-
-// Define a task dependency so the app is installed before we run macro benchmarks.
-afterEvaluate {
- tasks.getByPath(":profileinstaller:integration-tests:init-macrobenchmark:connectedDebugAndroidTest")
- .dependsOn(
- tasks.getByPath(
- ":profileinstaller:integration-tests:init-macrobenchmark-target:installRelease"
- )
- )
+ implementation(project(":profileinstaller:profileinstaller"))
+ implementation(project(":benchmark:benchmark-macro-junit4"))
+ implementation(project(":internal-testutils-macrobenchmark"))
+ implementation(libs.testRules)
+ implementation(libs.testExtJunit)
+ implementation(libs.testCore)
+ implementation(libs.testRunner)
}
diff --git a/benchmark/integration-tests/test-module-sample/src/main/AndroidManifest.xml b/profileinstaller/integration-tests/init-macrobenchmark/src/main/AndroidManifest.xml
similarity index 60%
copy from benchmark/integration-tests/test-module-sample/src/main/AndroidManifest.xml
copy to profileinstaller/integration-tests/init-macrobenchmark/src/main/AndroidManifest.xml
index 37fa920..5b41847 100644
--- a/benchmark/integration-tests/test-module-sample/src/main/AndroidManifest.xml
+++ b/profileinstaller/integration-tests/init-macrobenchmark/src/main/AndroidManifest.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2021 The Android Open Source Project
+ ~ Copyright (C) 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.
@@ -14,12 +14,4 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android">
- <queries>
- <!--
- Enables querying application info with packageManager.getApplicationInfo, to verify
- the target package is present
- -->
- <package android:name="androidx.benchmark.integration.macrobenchmark.target" />
- </queries>
-</manifest>
+<manifest />
diff --git a/profileinstaller/integration-tests/init-macrobenchmark/src/androidTest/java/androidx/profileinstaller/integration/macrobenchmark/ProfileinstallerStartupBenchmark.kt b/profileinstaller/integration-tests/init-macrobenchmark/src/main/java/androidx/profileinstaller/integration/macrobenchmark/ProfileinstallerStartupBenchmark.kt
similarity index 100%
rename from profileinstaller/integration-tests/init-macrobenchmark/src/androidTest/java/androidx/profileinstaller/integration/macrobenchmark/ProfileinstallerStartupBenchmark.kt
rename to profileinstaller/integration-tests/init-macrobenchmark/src/main/java/androidx/profileinstaller/integration/macrobenchmark/ProfileinstallerStartupBenchmark.kt
diff --git a/settings.gradle b/settings.gradle
index f0129a6..0f11a3a 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -472,7 +472,6 @@
includeProject(":benchmark:integration-tests:dry-run-benchmark", [BuildType.MAIN])
includeProject(":benchmark:integration-tests:macrobenchmark", [BuildType.MAIN])
includeProject(":benchmark:integration-tests:macrobenchmark-target", [BuildType.MAIN])
-includeProject(":benchmark:integration-tests:test-module-sample", [BuildType.MAIN])
includeProject(":benchmark:integration-tests:startup-benchmark", [BuildType.MAIN])
includeProject(":biometric:biometric", [BuildType.MAIN])
includeProject(":biometric:biometric-ktx", [BuildType.MAIN])
diff --git a/slice/slice-benchmark/build.gradle b/slice/slice-benchmark/build.gradle
index e353c79..1e151d0 100644
--- a/slice/slice-benchmark/build.gradle
+++ b/slice/slice-benchmark/build.gradle
@@ -42,10 +42,14 @@
androidx {
name = "Slices Benchmarks"
publish = Publish.NONE // Library is deprecated pending removal.
- disableDeviceTests = true
mavenVersion = LibraryVersions.SLICE_BENCHMARK
inceptionYear = "2018"
description = "RecyclerView Benchmarks"
+
+ deviceTests {
+ // Pending removal, don't run tests.
+ enabled = false
+ }
}
android {
diff --git a/slice/slice-builders-ktx/build.gradle b/slice/slice-builders-ktx/build.gradle
index 7ef627a..cbd1af6 100644
--- a/slice/slice-builders-ktx/build.gradle
+++ b/slice/slice-builders-ktx/build.gradle
@@ -47,11 +47,15 @@
androidx {
name = "Slice builders KTX"
publish = Publish.SNAPSHOT_ONLY // Library is deprecated pending removal.
- disableDeviceTests = true // Pending removal, don't run tests.
runApiTasks = new RunApiTasks.Yes() // Pending removal, but keep API files for now.
mavenVersion = LibraryVersions.SLICE_BUILDERS_KTX
inceptionYear = "2018"
description = "A set of Kotlin extension methods built on top of slice-builders APIs."
failOnDeprecationWarnings = false
legacyDisableKotlinStrictApiMode = true
+
+ deviceTests {
+ // Pending removal, don't run tests.
+ enabled = false
+ }
}
diff --git a/slice/slice-builders/build.gradle b/slice/slice-builders/build.gradle
index d0ba1a4..a8c0dbb 100644
--- a/slice/slice-builders/build.gradle
+++ b/slice/slice-builders/build.gradle
@@ -33,12 +33,16 @@
androidx {
name = "Slice builders"
publish = Publish.SNAPSHOT_ONLY // Library is deprecated pending removal.
- disableDeviceTests = true // Pending removal, don't run tests.
runApiTasks = new RunApiTasks.Yes() // Pending removal, but keep API files for now.
mavenVersion = LibraryVersions.SLICE
inceptionYear = "2017"
description = "A set of builders to create templates using SliceProvider APIs"
failOnDeprecationWarnings = false
+
+ deviceTests {
+ // Pending removal, don't run tests.
+ enabled = false
+ }
}
android {
diff --git a/slice/slice-core/build.gradle b/slice/slice-core/build.gradle
index 2bab0a9..03a0441 100644
--- a/slice/slice-core/build.gradle
+++ b/slice/slice-core/build.gradle
@@ -39,12 +39,16 @@
androidx {
name = "Common utilities for slices"
publish = Publish.SNAPSHOT_ONLY // Library is deprecated pending removal.
- disableDeviceTests = true // Pending removal, don't run tests.
runApiTasks = new RunApiTasks.Yes() // Pending removal, but keep API files for now.
mavenVersion = LibraryVersions.SLICE
inceptionYear = "2017"
description = "The slices core library provides utilities for the slices view and provider libraries"
failOnDeprecationWarnings = false
+
+ deviceTests {
+ // Pending removal, don't run tests.
+ enabled = false
+ }
}
android {
diff --git a/slice/slice-remotecallback/build.gradle b/slice/slice-remotecallback/build.gradle
index 56db28d..edd99ea 100644
--- a/slice/slice-remotecallback/build.gradle
+++ b/slice/slice-remotecallback/build.gradle
@@ -39,12 +39,16 @@
androidx {
name = "Slice Remote Callback"
publish = Publish.SNAPSHOT_ONLY // Library is deprecated pending removal.
- disableDeviceTests = true // Pending removal, don't run tests.
runApiTasks = new RunApiTasks.Yes() // Pending removal, but keep API files for now.
mavenVersion = LibraryVersions.SLICE_REMOTECALLBACK
inceptionYear = "2019"
description = "A library that handles PendingIntents in slices as remote callbacks"
failOnDeprecationWarnings = false
+
+ deviceTests {
+ // Pending removal, don't run tests.
+ enabled = false
+ }
}
android {
diff --git a/slice/slice-test/build.gradle b/slice/slice-test/build.gradle
index ff04df0..a7330d5 100644
--- a/slice/slice-test/build.gradle
+++ b/slice/slice-test/build.gradle
@@ -41,11 +41,15 @@
name = "Slice test code"
type = LibraryType.INTERNAL_TEST_LIBRARY
publish = Publish.NONE // Library is deprecated pending removal.
- disableDeviceTests = true
mavenVersion = LibraryVersions.SLICE
inceptionYear = "2017"
description = "A library that holds common code for testing slices"
failOnDeprecationWarnings = false
+
+ deviceTests {
+ // Pending removal, don't run tests.
+ enabled = false
+ }
}
android {
diff --git a/slice/slice-view/build.gradle b/slice/slice-view/build.gradle
index 5dc4379..8f8c858 100644
--- a/slice/slice-view/build.gradle
+++ b/slice/slice-view/build.gradle
@@ -43,12 +43,16 @@
androidx {
name = "Slice views"
publish = Publish.SNAPSHOT_ONLY // Library is deprecated pending removal.
- disableDeviceTests = true // Pending removal, don't run tests.
runApiTasks = new RunApiTasks.Yes() // Pending removal, but keep API files for now.
mavenVersion = LibraryVersions.SLICE
inceptionYear = "2017"
description = "A library that handles rendering of slice content into supported templates"
failOnDeprecationWarnings = false
+
+ deviceTests {
+ // Pending removal, don't run tests.
+ enabled = false
+ }
}
android {
diff --git a/wear/benchmark/integration-tests/macrobenchmark/build.gradle b/wear/benchmark/integration-tests/macrobenchmark/build.gradle
index 1708504..e7fc8f1 100644
--- a/wear/benchmark/integration-tests/macrobenchmark/build.gradle
+++ b/wear/benchmark/integration-tests/macrobenchmark/build.gradle
@@ -16,7 +16,7 @@
plugins {
id("AndroidXPlugin")
- id 'com.android.library'
+ id 'com.android.test'
id 'kotlin-android'
}
@@ -25,25 +25,22 @@
minSdkVersion 29
}
namespace "androidx.wear.benchmark.integration.macrobenchmark"
+ targetProjectPath = ":wear:benchmark:integration-tests:macrobenchmark-target"
+ experimentalProperties["android.experimental.self-instrumenting"] = true
}
+// Create a release build type and make sure it's the only one enabled.
+// This is needed because we benchmark the release build type only.
+android.buildTypes { release {} }
+androidComponents { beforeVariants(selector().all()) { enabled = buildType == 'release' } }
+
dependencies {
- androidTestImplementation(project(":benchmark:benchmark-junit4"))
- androidTestImplementation(project(":benchmark:benchmark-macro-junit4"))
- androidTestImplementation(project(":internal-testutils-macrobenchmark"))
- androidTestImplementation(libs.testRules)
- androidTestImplementation(libs.testExtJunit)
- androidTestImplementation(libs.testCore)
- androidTestImplementation(libs.testRunner)
- androidTestImplementation(libs.testUiautomator)
-}
-
-// Define a task dependency so the app is installed before we run macro benchmarks.
-afterEvaluate {
- tasks.getByPath(":wear:benchmark:integration-tests:macrobenchmark:connectedDebugAndroidTest")
- .dependsOn(
- tasks.getByPath(
- ":wear:benchmark:integration-tests:macrobenchmark-target:installRelease"
- )
- )
+ implementation(project(":benchmark:benchmark-junit4"))
+ implementation(project(":benchmark:benchmark-macro-junit4"))
+ implementation(project(":internal-testutils-macrobenchmark"))
+ implementation(libs.testRules)
+ implementation(libs.testExtJunit)
+ implementation(libs.testCore)
+ implementation(libs.testRunner)
+ implementation(libs.testUiautomator)
}
diff --git a/wear/benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/wear/benchmark/integration/macrobenchmark/ScrollBenchmark.kt b/wear/benchmark/integration-tests/macrobenchmark/src/main/java/androidx/wear/benchmark/integration/macrobenchmark/ScrollBenchmark.kt
similarity index 100%
rename from wear/benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/wear/benchmark/integration/macrobenchmark/ScrollBenchmark.kt
rename to wear/benchmark/integration-tests/macrobenchmark/src/main/java/androidx/wear/benchmark/integration/macrobenchmark/ScrollBenchmark.kt
diff --git a/wear/benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/wear/benchmark/integration/macrobenchmark/StartupBenchmark.kt b/wear/benchmark/integration-tests/macrobenchmark/src/main/java/androidx/wear/benchmark/integration/macrobenchmark/StartupBenchmark.kt
similarity index 100%
rename from wear/benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/wear/benchmark/integration/macrobenchmark/StartupBenchmark.kt
rename to wear/benchmark/integration-tests/macrobenchmark/src/main/java/androidx/wear/benchmark/integration/macrobenchmark/StartupBenchmark.kt
diff --git a/wear/benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/wear/benchmark/integration/macrobenchmark/SwipeBenchmark.kt b/wear/benchmark/integration-tests/macrobenchmark/src/main/java/androidx/wear/benchmark/integration/macrobenchmark/SwipeBenchmark.kt
similarity index 100%
rename from wear/benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/wear/benchmark/integration/macrobenchmark/SwipeBenchmark.kt
rename to wear/benchmark/integration-tests/macrobenchmark/src/main/java/androidx/wear/benchmark/integration/macrobenchmark/SwipeBenchmark.kt
diff --git a/wear/compose/integration-tests/macrobenchmark/build.gradle b/wear/compose/integration-tests/macrobenchmark/build.gradle
index 1e07985..414dd2b 100644
--- a/wear/compose/integration-tests/macrobenchmark/build.gradle
+++ b/wear/compose/integration-tests/macrobenchmark/build.gradle
@@ -1,5 +1,3 @@
-import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
-
/*
* Copyright 2021 The Android Open Source Project
*
@@ -18,7 +16,7 @@
plugins {
id("AndroidXPlugin")
- id("com.android.library")
+ id("com.android.test")
id("kotlin-android")
}
@@ -27,25 +25,22 @@
minSdkVersion 29
}
namespace "androidx.wear.compose.integration.macrobenchmark"
+ targetProjectPath = ":wear:compose:integration-tests:macrobenchmark-target"
+ experimentalProperties["android.experimental.self-instrumenting"] = true
}
+// Create a release build type and make sure it's the only one enabled.
+// This is needed because we benchmark the release build type only.
+android.buildTypes { release {} }
+androidComponents { beforeVariants(selector().all()) { enabled = buildType == 'release' } }
+
dependencies {
- androidTestImplementation(project(":benchmark:benchmark-junit4"))
- androidTestImplementation(project(":benchmark:benchmark-macro-junit4"))
- androidTestImplementation(project(":internal-testutils-macrobenchmark"))
- androidTestImplementation(libs.testRules)
- androidTestImplementation(libs.testExtJunit)
- androidTestImplementation(libs.testCore)
- androidTestImplementation(libs.testRunner)
- androidTestImplementation(libs.testUiautomator)
-}
-
-// Define a task dependency so the app is installed before we run macro benchmarks.
-afterEvaluate {
- tasks.getByPath(":wear:compose:integration-tests:macrobenchmark:connectedDebugAndroidTest")
- .dependsOn(
- tasks.getByPath(
- ":wear:compose:integration-tests:macrobenchmark-target:installRelease"
- )
- )
+ implementation(project(":benchmark:benchmark-junit4"))
+ implementation(project(":benchmark:benchmark-macro-junit4"))
+ implementation(project(":internal-testutils-macrobenchmark"))
+ implementation(libs.testRules)
+ implementation(libs.testExtJunit)
+ implementation(libs.testCore)
+ implementation(libs.testRunner)
+ implementation(libs.testUiautomator)
}
diff --git a/wear/compose/integration-tests/macrobenchmark/src/main/AndroidManifest.xml b/wear/compose/integration-tests/macrobenchmark/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..e0788d6
--- /dev/null
+++ b/wear/compose/integration-tests/macrobenchmark/src/main/AndroidManifest.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2021 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.
+ -->
+
+<manifest />
diff --git a/wear/compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/wear/compose/integration/macrobenchmark/BaselineProfile.kt b/wear/compose/integration-tests/macrobenchmark/src/main/java/androidx/wear/compose/integration/macrobenchmark/BaselineProfile.kt
similarity index 100%
rename from wear/compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/wear/compose/integration/macrobenchmark/BaselineProfile.kt
rename to wear/compose/integration-tests/macrobenchmark/src/main/java/androidx/wear/compose/integration/macrobenchmark/BaselineProfile.kt
diff --git a/wear/compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/wear/compose/integration/macrobenchmark/Common.kt b/wear/compose/integration-tests/macrobenchmark/src/main/java/androidx/wear/compose/integration/macrobenchmark/Common.kt
similarity index 100%
rename from wear/compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/wear/compose/integration/macrobenchmark/Common.kt
rename to wear/compose/integration-tests/macrobenchmark/src/main/java/androidx/wear/compose/integration/macrobenchmark/Common.kt
diff --git a/wear/compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/wear/compose/integration/macrobenchmark/ScrollBenchmark.kt b/wear/compose/integration-tests/macrobenchmark/src/main/java/androidx/wear/compose/integration/macrobenchmark/ScrollBenchmark.kt
similarity index 100%
rename from wear/compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/wear/compose/integration/macrobenchmark/ScrollBenchmark.kt
rename to wear/compose/integration-tests/macrobenchmark/src/main/java/androidx/wear/compose/integration/macrobenchmark/ScrollBenchmark.kt
diff --git a/wear/compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/wear/compose/integration/macrobenchmark/StartupBenchmark.kt b/wear/compose/integration-tests/macrobenchmark/src/main/java/androidx/wear/compose/integration/macrobenchmark/StartupBenchmark.kt
similarity index 100%
rename from wear/compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/wear/compose/integration/macrobenchmark/StartupBenchmark.kt
rename to wear/compose/integration-tests/macrobenchmark/src/main/java/androidx/wear/compose/integration/macrobenchmark/StartupBenchmark.kt
diff --git a/wear/compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/wear/compose/integration/macrobenchmark/SwipeBenchmark.kt b/wear/compose/integration-tests/macrobenchmark/src/main/java/androidx/wear/compose/integration/macrobenchmark/SwipeBenchmark.kt
similarity index 100%
rename from wear/compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/wear/compose/integration/macrobenchmark/SwipeBenchmark.kt
rename to wear/compose/integration-tests/macrobenchmark/src/main/java/androidx/wear/compose/integration/macrobenchmark/SwipeBenchmark.kt