Merge "Define the default constructor for ReplaceFileCorruptionHandler which can be used in common code" into androidx-main
diff --git a/annotation/annotation/build.gradle b/annotation/annotation/build.gradle
index c8681d9..dd9bd8a 100644
--- a/annotation/annotation/build.gradle
+++ b/annotation/annotation/build.gradle
@@ -17,15 +17,16 @@
androidXMultiplatform {
androidNative()
+ ios()
+ js()
jvm()
+ linux()
mac()
mingwX64()
- linux()
- ios()
- watchosDeviceArm64()
- watchos()
tvos()
wasmJs()
+ watchos()
+ watchosDeviceArm64()
defaultPlatform(PlatformIdentifier.JVM)
@@ -44,6 +45,10 @@
dependsOn(nonJvmMain)
}
+ jsMain {
+ dependsOn(nonJvmMain)
+ }
+
targets.configureEach { target ->
if (target.platformType !in [KotlinPlatformType.jvm, KotlinPlatformType.common]) {
target.compilations["main"].defaultSourceSet {
diff --git a/benchmark/baseline-profile-gradle-plugin/build.gradle b/benchmark/baseline-profile-gradle-plugin/build.gradle
index 6856063..2e6c028 100644
--- a/benchmark/baseline-profile-gradle-plugin/build.gradle
+++ b/benchmark/baseline-profile-gradle-plugin/build.gradle
@@ -49,7 +49,7 @@
compileOnly(libs.kotlinGradlePluginz)
implementation(gradleApi())
- implementation(libs.protobuf)
+ implementation("com.google.protobuf:protobuf-java:3.22.3")
implementation(libs.agpTestingPlatformCoreProto)
testImplementation(gradleTestKit())
diff --git a/binarycompatibilityvalidator/binarycompatibilityvalidator/src/main/java/androidx/binarycompatibilityvalidator/KLibDumpParser.kt b/binarycompatibilityvalidator/binarycompatibilityvalidator/src/main/java/androidx/binarycompatibilityvalidator/KLibDumpParser.kt
index be77a52..41335c3d 100644
--- a/binarycompatibilityvalidator/binarycompatibilityvalidator/src/main/java/androidx/binarycompatibilityvalidator/KLibDumpParser.kt
+++ b/binarycompatibilityvalidator/binarycompatibilityvalidator/src/main/java/androidx/binarycompatibilityvalidator/KLibDumpParser.kt
@@ -95,6 +95,7 @@
platformTargets = listOf(),
compilerVersion = "",
abiVersion = "",
+ libraryVersion = "",
irProviderName = ""
)
)
diff --git a/buildSrc-tests/src/test/java/androidx/build/KmpPlatformsTest.kt b/buildSrc-tests/src/test/java/androidx/build/KmpPlatformsTest.kt
index 23c9ff9..a50cc57 100644
--- a/buildSrc-tests/src/test/java/androidx/build/KmpPlatformsTest.kt
+++ b/buildSrc-tests/src/test/java/androidx/build/KmpPlatformsTest.kt
@@ -32,7 +32,10 @@
PlatformGroup.WINDOWS,
PlatformGroup.LINUX,
PlatformGroup.DESKTOP,
- PlatformGroup.ANDROID_NATIVE))
+ PlatformGroup.ANDROID_NATIVE,
+ PlatformGroup.JS
+ )
+ )
}
@Test
@@ -47,7 +50,9 @@
PlatformGroup.LINUX,
PlatformGroup.DESKTOP,
PlatformGroup.ANDROID_NATIVE,
- ))
+ PlatformGroup.JS,
+ )
+ )
}
@Test
@@ -62,12 +67,14 @@
PlatformGroup.LINUX,
PlatformGroup.DESKTOP,
PlatformGroup.ANDROID_NATIVE,
- ))
+ PlatformGroup.JS,
+ )
+ )
}
@Test
fun withNoPlatforms_itParsesTheFlagCorrectly() {
- assertThat(parseTargetPlatformsFlag("-jvm,-desktop,-native,-wasm"))
+ assertThat(parseTargetPlatformsFlag("-jvm,-desktop,-native,-wasm,-js"))
.isEqualTo(emptySet<PlatformGroup>())
}
@@ -84,7 +91,9 @@
PlatformGroup.LINUX,
PlatformGroup.DESKTOP,
PlatformGroup.ANDROID_NATIVE,
- ))
+ PlatformGroup.JS,
+ )
+ )
}
@Test
@@ -100,12 +109,14 @@
PlatformGroup.LINUX,
PlatformGroup.DESKTOP,
PlatformGroup.ANDROID_NATIVE,
- ))
+ PlatformGroup.JS,
+ )
+ )
}
@Test
fun withNegativeFlags_itParsesTheFlagCorrectly() {
- assertThat(parseTargetPlatformsFlag("-jvm,+mac,-wasm"))
+ assertThat(parseTargetPlatformsFlag("-jvm,+mac,-wasm,-js"))
.isEqualTo(
setOf(
PlatformGroup.MAC,
@@ -113,7 +124,8 @@
PlatformGroup.LINUX,
PlatformGroup.DESKTOP,
PlatformGroup.ANDROID_NATIVE,
- ))
+ )
+ )
}
@Test
@@ -127,7 +139,10 @@
PlatformGroup.WINDOWS,
PlatformGroup.LINUX,
PlatformGroup.DESKTOP,
- PlatformGroup.ANDROID_NATIVE))
+ PlatformGroup.ANDROID_NATIVE,
+ PlatformGroup.JS
+ )
+ )
}
@Test
@@ -140,18 +155,22 @@
PlatformGroup.WINDOWS,
PlatformGroup.LINUX,
PlatformGroup.DESKTOP,
- PlatformGroup.ANDROID_NATIVE))
+ PlatformGroup.ANDROID_NATIVE
+ )
+ )
}
@Test
fun withRedundentFlags_itParsesTheFlagCorrectly() {
- assertThat(parseTargetPlatformsFlag("-wasm,-jvm,+native,+linux,+mac,+linux,-wasm"))
+ assertThat(parseTargetPlatformsFlag("-wasm,-jvm,+native,+linux,+mac,+linux,-wasm,-js"))
.isEqualTo(
setOf(
PlatformGroup.MAC,
PlatformGroup.WINDOWS,
PlatformGroup.LINUX,
PlatformGroup.DESKTOP,
- PlatformGroup.ANDROID_NATIVE))
+ PlatformGroup.ANDROID_NATIVE
+ )
+ )
}
}
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXComposeImplPlugin.kt b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXComposeImplPlugin.kt
index 6f6e0b20..76cb02d 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXComposeImplPlugin.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXComposeImplPlugin.kt
@@ -185,7 +185,11 @@
compile.pluginClasspath.from(kotlinPluginProvider.get())
- compile.enableFeatureFlag(ComposeFeatureFlag.OptimizeNonSkippingGroups)
+ // todo(b/291587160): enable when Compose compiler 2.0.20 is merged
+ // compile.enableFeatureFlag(ComposeFeatureFlag.StrongSkipping)
+ // compile.enableFeatureFlag(ComposeFeatureFlag.OptimizeNonSkippingGroups)
+ compile.addPluginOption(ComposeCompileOptions.StrongSkipping, "true")
+ compile.addPluginOption(ComposeCompileOptions.NonSkippingGroupOptimization, "true")
if (shouldPublish) {
compile.addPluginOption(ComposeCompileOptions.SourceOption, "true")
}
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt
index 00a8c9b..29a3abd 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt
@@ -1108,9 +1108,8 @@
buildToolsVersion = project.defaultAndroidConfig.buildToolsVersion
- defaultConfig.ndk.abiFilters.addAll(
- listOf("armeabi-v7a", "arm64-v8a", "x86", "x86_64", "riscv64")
- )
+ // b/366238650
+ defaultConfig.ndk.abiFilters.addAll(listOf("armeabi-v7a", "arm64-v8a", "x86", "x86_64"))
defaultConfig.minSdk = defaultMinSdk
defaultConfig.testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXMultiplatformExtension.kt b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXMultiplatformExtension.kt
index 5b4605e..2dcaa60 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXMultiplatformExtension.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXMultiplatformExtension.kt
@@ -34,7 +34,6 @@
import org.gradle.api.plugins.ExtensionAware
import org.gradle.kotlin.dsl.findByType
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
-import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.KotlinMultiplatformPluginWrapper
@@ -45,6 +44,7 @@
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTargetWithHostTests
+import org.jetbrains.kotlin.gradle.targets.js.dsl.ExperimentalWasmDsl
import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsTargetDsl
import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinWasmTargetDsl
import org.jetbrains.kotlin.gradle.targets.js.ir.DefaultIncrementalSyncTask
@@ -658,7 +658,12 @@
fun js(block: Action<KotlinJsTargetDsl>? = null): KotlinJsTargetDsl? {
supportedPlatforms.add(PlatformIdentifier.JS)
return if (project.enableJs()) {
- kotlinExtension.js { block?.execute(this) }
+ kotlinExtension.js() {
+ block?.execute(this)
+ binaries.library()
+ browser {}
+ project.configureJs()
+ }
} else {
null
}
@@ -700,20 +705,19 @@
}
}
+private fun Project.configureJs() {
+ configureNode()
+ // Use DSL API when https://youtrack.jetbrains.com/issue/KT-70029 is closed for all tasks below
+ tasks.named("jsDevelopmentLibraryCompileSync", DefaultIncrementalSyncTask::class.java) {
+ it.destinationDirectory.set(file(layout.buildDirectory.dir("js/packages/js/dev/kotlin")))
+ }
+ tasks.named("jsProductionLibraryCompileSync", DefaultIncrementalSyncTask::class.java) {
+ it.destinationDirectory.set(file(layout.buildDirectory.dir("js/packages/js/prod/kotlin")))
+ }
+}
+
private fun Project.configureWasm() {
- rootProject.extensions.findByType<NodeJsRootExtension>()?.let {
- it.version = getVersionByName("node")
- it.downloadBaseUrl =
- File(project.getPrebuiltsRoot(), "androidx/external/org/nodejs/node").toURI().toString()
- }
-
- rootProject.extensions.findByType(YarnRootExtension::class.java)?.let {
- it.version = getVersionByName("yarn")
- it.lockFileDirectory =
- File(project.getPrebuiltsRoot(), "androidx/external/wasm/yarn-offline-mirror")
- it.yarnLockMismatchReport = YarnLockMismatchReport.WARNING
- }
-
+ configureNode()
// Use DSL API when https://youtrack.jetbrains.com/issue/KT-70029 is closed for all tasks below
tasks.named("wasmJsDevelopmentLibraryCompileSync", DefaultIncrementalSyncTask::class.java) {
it.destinationDirectory.set(
@@ -734,6 +738,21 @@
}
}
+private fun Project.configureNode() {
+ rootProject.extensions.findByType<NodeJsRootExtension>()?.let {
+ it.version = getVersionByName("node")
+ it.downloadBaseUrl =
+ File(project.getPrebuiltsRoot(), "androidx/external/org/nodejs/node").toURI().toString()
+ }
+
+ rootProject.extensions.findByType(YarnRootExtension::class.java)?.let {
+ it.version = getVersionByName("yarn")
+ it.lockFileDirectory =
+ File(project.getPrebuiltsRoot(), "androidx/external/wasm/yarn-offline-mirror")
+ it.yarnLockMismatchReport = YarnLockMismatchReport.FAIL
+ }
+}
+
fun Project.validatePublishedMultiplatformHasDefault() {
val extension = project.extensions.getByType(AndroidXMultiplatformExtension::class.java)
if (extension.defaultPlatform == null && extension.supportedPlatforms.isNotEmpty()) {
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXRepackageImplPlugin.kt b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXRepackageImplPlugin.kt
index 833f947..6a57ac1 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXRepackageImplPlugin.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXRepackageImplPlugin.kt
@@ -58,6 +58,11 @@
dropResourcesWithSuffix = ".proto"
}
)
+ task.transformers.add(
+ BundleInsideHelper.DontIncludeResourceTransformer().apply {
+ dropResourcesWithSuffix = ".proto.bin"
+ }
+ )
task.from(sourceSets.named("main").map { it.output })
relocationExtension.getRelocations().forEach {
task.relocate(it.sourcePackage, it.targetPackage)
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/ListTaskOutputsTask.kt b/buildSrc/private/src/main/kotlin/androidx/build/ListTaskOutputsTask.kt
index 96b2c68..1e77374 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/ListTaskOutputsTask.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/ListTaskOutputsTask.kt
@@ -136,12 +136,13 @@
// The following tasks have the same output configFile file:
// projectBuildDir/js/packages/projectName-wasm-js/webpack.config.js
- // Remove when https://youtrack.jetbrains.com/issue/KT-70029 is resolved
+ // Remove when https://youtrack.jetbrains.com/issue/KT-70029 / b/361319689 is resolved
// and set configFile location for each task
"wasmJsBrowserDevelopmentWebpack",
"wasmJsBrowserDevelopmentRun",
"wasmJsBrowserProductionWebpack",
"wasmJsBrowserProductionRun",
+ "jsTestTestDevelopmentExecutableCompileSync",
// Remove when https://youtrack.jetbrains.com/issue/KT-71688 is resolved and set
// destinationDirectory to the project's build directory
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/MavenUploadHelper.kt b/buildSrc/private/src/main/kotlin/androidx/build/MavenUploadHelper.kt
index fd90716..ac96f91 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/MavenUploadHelper.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/MavenUploadHelper.kt
@@ -307,7 +307,7 @@
// will not move adjacent elements, so any comments would remain in their
// original order.
element.content().replaceAll {
- val index = deps.indexOf(it)
+ val index = sortedDeps.indexOf(it)
if (index >= 0) {
sortedDeps[index]
} else {
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/clang/KonanBuildService.kt b/buildSrc/private/src/main/kotlin/androidx/build/clang/KonanBuildService.kt
index b0b2916..50f8f8ec 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/clang/KonanBuildService.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/clang/KonanBuildService.kt
@@ -35,9 +35,7 @@
import org.gradle.process.ExecSpec
import org.jetbrains.kotlin.gradle.plugin.KotlinMultiplatformPluginWrapper
import org.jetbrains.kotlin.gradle.utils.NativeCompilerDownloader
-import org.jetbrains.kotlin.konan.TempFiles
import org.jetbrains.kotlin.konan.target.Family
-import org.jetbrains.kotlin.konan.target.LinkerArguments
import org.jetbrains.kotlin.konan.target.LinkerOutputKind
import org.jetbrains.kotlin.konan.target.Platform
import org.jetbrains.kotlin.konan.target.PlatformManager
@@ -140,22 +138,18 @@
val objectFiles = parameters.objectFiles.regularFilePaths()
val linkedObjectFiles = parameters.linkedObjects.regularFilePaths()
val linkCommands =
- with(platform.linker) {
- LinkerArguments(
- TempFiles(),
- objectFiles = objectFiles,
- executable = outputFile.canonicalPath,
- libraries = linkedObjectFiles,
- linkerArgs = linkerFlags,
- optimize = true,
- debug = false,
- kind = LinkerOutputKind.DYNAMIC_LIBRARY,
- outputDsymBundle = "unused",
- mimallocEnabled = false,
- sanitizer = null
- )
- .finalLinkCommands()
- }
+ platform.linker.finalLinkCommands(
+ objectFiles = objectFiles,
+ executable = outputFile.canonicalPath,
+ libraries = linkedObjectFiles,
+ linkerArgs = linkerFlags,
+ optimize = true,
+ debug = false,
+ kind = LinkerOutputKind.DYNAMIC_LIBRARY,
+ outputDsymBundle = "unused",
+ mimallocEnabled = false,
+ sanitizer = null
+ )
linkCommands
.map { it.argsWithExecutable }
.forEach { args ->
diff --git a/buildSrc/public/src/main/kotlin/androidx/build/KmpPlatforms.kt b/buildSrc/public/src/main/kotlin/androidx/build/KmpPlatforms.kt
index ca78a94..047be08 100644
--- a/buildSrc/public/src/main/kotlin/androidx/build/KmpPlatforms.kt
+++ b/buildSrc/public/src/main/kotlin/androidx/build/KmpPlatforms.kt
@@ -46,12 +46,10 @@
val native = listOf(MAC, LINUX, WINDOWS, ANDROID_NATIVE)
/**
- * Target platform groups which are enabled by default.
- *
- * Do *not* enable [JS] unless you have read and understand this:
- * https://blog.jetbrains.com/kotlin/2021/10/important-ua-parser-js-exploit-and-kotlin-js/
+ * Target platform groups which are enabled by default. We currently enable all platforms by
+ * default.
*/
- val enabledByDefault = listOf(JVM, DESKTOP, MAC, LINUX, WINDOWS, ANDROID_NATIVE, WASM)
+ val enabledByDefault = listOf(ANDROID_NATIVE, DESKTOP, JS, JVM, LINUX, MAC, WASM, WINDOWS)
}
}
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/imagecapture/FakeTakePictureCallbackDeviceTest.kt b/camera/camera-core/src/androidTest/java/androidx/camera/core/imagecapture/FakeTakePictureCallbackDeviceTest.kt
index 1584d69..b95cdc6 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/imagecapture/FakeTakePictureCallbackDeviceTest.kt
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/imagecapture/FakeTakePictureCallbackDeviceTest.kt
@@ -16,6 +16,7 @@
package androidx.camera.core.imagecapture
+import android.graphics.ImageFormat
import androidx.camera.core.ImageCapture.OutputFileResults
import androidx.camera.testing.impl.fakes.FakeImageInfo
import androidx.camera.testing.impl.fakes.FakeImageProxy
@@ -33,7 +34,7 @@
@Test
fun onDiskResultArrivesBeforeGet_canGetResult() = runBlocking {
// Arrange.
- val onDiskResult = OutputFileResults(null)
+ val onDiskResult = OutputFileResults(null, ImageFormat.JPEG)
// Assert.
fakeTakePictureCallback.onFinalResult(onDiskResult)
// Act.
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/imagecapture/ProcessingNodeDeviceTest.kt b/camera/camera-core/src/androidTest/java/androidx/camera/core/imagecapture/ProcessingNodeDeviceTest.kt
index 065ac04..42c55dd 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/imagecapture/ProcessingNodeDeviceTest.kt
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/imagecapture/ProcessingNodeDeviceTest.kt
@@ -196,7 +196,8 @@
ProcessingRequest(
{ listOf() },
createTakePictureRequest(
- if (outputFileOptions == null) null else listOf(outputFileOptions),
+ outputFileOptions,
+ null,
CROP_RECT,
SENSOR_TO_BUFFER,
/*rotationDegrees=*/ 0, // 0 because exif does not have rotation.
@@ -231,7 +232,8 @@
ProcessingRequest(
{ listOf() },
createTakePictureRequest(
- if (outputFileOptions == null) null else listOf(outputFileOptions),
+ outputFileOptions,
+ null,
Rect(0, 0, WIDTH, HEIGHT),
SENSOR_TO_BUFFER,
/*rotationDegrees=*/ 0, // 0 because exif does not have rotation.
@@ -273,7 +275,8 @@
ProcessingRequest(
{ listOf() },
createTakePictureRequest(
- if (outputFileOptions == null) null else listOf(outputFileOptions),
+ outputFileOptions,
+ null,
Rect(0, 0, WIDTH, HEIGHT),
SENSOR_TO_BUFFER,
/*rotationDegrees=*/ 0, // 0 because exif does not have rotation.
@@ -321,7 +324,8 @@
ProcessingRequest(
{ listOf() },
createTakePictureRequest(
- if (outputFileOptions == null) null else listOf(outputFileOptions),
+ outputFileOptions,
+ null,
Rect(0, 0, WIDTH, HEIGHT),
SENSOR_TO_BUFFER,
/*rotationDegrees=*/ 0, // 0 because exif does not have rotation.
@@ -363,7 +367,8 @@
ProcessingRequest(
{ listOf() },
createTakePictureRequest(
- if (outputFileOptions == null) null else listOf(outputFileOptions),
+ outputFileOptions,
+ null,
Rect(0, 0, WIDTH, HEIGHT),
SENSOR_TO_BUFFER,
/*rotationDegrees=*/ 0, // 0 because exif does not have rotation.
@@ -407,7 +412,8 @@
ProcessingRequest(
{ listOf() },
createTakePictureRequest(
- if (outputFileOptions == null) null else listOf(outputFileOptions),
+ outputFileOptions,
+ null,
CROP_RECT,
SENSOR_TO_BUFFER,
/*rotationDegrees=*/ 0, // 0 because exif does not have rotation.
@@ -452,7 +458,8 @@
ProcessingRequest(
{ listOf() },
createTakePictureRequest(
- if (outputFileOptions == null) null else listOf(outputFileOptions),
+ outputFileOptions,
+ null,
CROP_RECT,
SENSOR_TO_BUFFER,
/*rotationDegrees=*/ 0, // 0 because exif does not have rotation.
@@ -507,6 +514,7 @@
{ listOf() },
createTakePictureRequest(
/*outputFileOptions=*/ null,
+ /*secondaryOutputFileOptions=*/ null,
Rect(0, 0, WIDTH, HEIGHT),
SENSOR_TO_BUFFER,
/*rotationDegrees=*/ 0, // 0 because exif does not have rotation.
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/imagecapture/Utils.kt b/camera/camera-core/src/androidTest/java/androidx/camera/core/imagecapture/Utils.kt
index f59512c..4991c23 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/imagecapture/Utils.kt
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/imagecapture/Utils.kt
@@ -50,7 +50,8 @@
)
fun createTakePictureRequest(
- outputFileOptions: List<ImageCapture.OutputFileOptions>?,
+ outputFileOptions: ImageCapture.OutputFileOptions?,
+ secondaryFileOption: ImageCapture.OutputFileOptions?,
cropRect: Rect,
sensorToBufferTransform: Matrix,
rotationDegrees: Int,
@@ -70,6 +71,7 @@
onMemoryCallback,
onDiskCallback,
outputFileOptions,
+ secondaryFileOption,
cropRect,
sensorToBufferTransform,
rotationDegrees,
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java b/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java
index 72c23be..3fac0e4 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java
@@ -922,7 +922,7 @@
}
takePictureInternal(executor, callback, /*onDiskCallback=*/null,
- /*outputFileOptions=*/null);
+ /*outputFileOptions=*/null, /*secondaryOutputFileOptions=*/null);
}
/**
@@ -944,7 +944,14 @@
final @NonNull OutputFileOptions outputFileOptions,
final @NonNull Executor executor,
final @NonNull OnImageSavedCallback imageSavedCallback) {
- takePicture(List.of(outputFileOptions), executor, imageSavedCallback);
+ if (Looper.getMainLooper() != Looper.myLooper()) {
+ CameraXExecutors.mainThreadExecutor().execute(() -> takePicture(
+ outputFileOptions, executor, imageSavedCallback));
+ return;
+ }
+
+ takePictureInternal(executor, /*inMemoryCallback=*/null, imageSavedCallback,
+ outputFileOptions, /*secondaryOutputFileOptions=*/null);
}
/**
@@ -956,7 +963,8 @@
* {@link ImageFormat#RAW_SENSOR} image and the second one is for {@link ImageFormat#JPEG}. The
* order in which image format is triggered first is not guaranteed.
*
- * @param outputFileOptions List of options to store the newly captured images.
+ * @param rawOutputFileOptions Options to store the newly captured raw image.
+ * @param jpegOutputFileOptions Options to store the newly captured jpeg image.
* @param executor The executor in which the callback methods will be run.
* @param imageSavedCallback Callback to be called for the newly captured image.
*
@@ -965,17 +973,18 @@
*/
@RestrictTo(Scope.LIBRARY_GROUP)
public void takePicture(
- final @NonNull List<OutputFileOptions> outputFileOptions,
+ final @NonNull OutputFileOptions rawOutputFileOptions,
+ final @NonNull OutputFileOptions jpegOutputFileOptions,
final @NonNull Executor executor,
final @NonNull OnImageSavedCallback imageSavedCallback) {
if (Looper.getMainLooper() != Looper.myLooper()) {
CameraXExecutors.mainThreadExecutor().execute(
- () -> takePicture(outputFileOptions,
+ () -> takePicture(rawOutputFileOptions, jpegOutputFileOptions,
executor, imageSavedCallback));
return;
}
takePictureInternal(executor, /*inMemoryCallback=*/null, imageSavedCallback,
- outputFileOptions);
+ rawOutputFileOptions, jpegOutputFileOptions);
}
/**
@@ -1453,8 +1462,9 @@
@MainThread
private void takePictureInternal(@NonNull Executor executor,
@Nullable OnImageCapturedCallback inMemoryCallback,
- @Nullable ImageCapture.OnImageSavedCallback onDiskCallback,
- @Nullable List<OutputFileOptions> outputFileOptions) {
+ @Nullable OnImageSavedCallback onDiskCallback,
+ @Nullable OutputFileOptions outputFileOptions,
+ @Nullable OutputFileOptions secondaryOutputFileOptions) {
checkMainThread();
if (getFlashMode() == ImageCapture.FLASH_MODE_SCREEN
&& mScreenFlashWrapper.getBaseScreenFlash() == null) {
@@ -1471,6 +1481,7 @@
inMemoryCallback,
onDiskCallback,
outputFileOptions,
+ secondaryOutputFileOptions,
getTakePictureCropRect(),
getSensorToBufferTransformMatrix(),
getRelativeRotation(camera),
@@ -2193,12 +2204,12 @@
@Nullable
private final Uri mSavedUri;
- /**
- *
- */
+ private final int mImageFormat;
+
@RestrictTo(Scope.LIBRARY_GROUP)
- public OutputFileResults(@Nullable Uri savedUri) {
+ public OutputFileResults(@Nullable Uri savedUri, int imageFormat) {
mSavedUri = savedUri;
+ mImageFormat = imageFormat;
}
/**
@@ -2212,6 +2223,14 @@
public Uri getSavedUri() {
return mSavedUri;
}
+
+ /**
+ * Returns the {@link ImageFormat} of the saved file.
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ public int getImageFormat() {
+ return mImageFormat;
+ }
}
/** Holder class for metadata that will be saved with captured images. */
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/imagecapture/DngImage2Disk.java b/camera/camera-core/src/main/java/androidx/camera/core/imagecapture/DngImage2Disk.java
index c19ed71..9f1b768 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/imagecapture/DngImage2Disk.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/imagecapture/DngImage2Disk.java
@@ -20,6 +20,7 @@
import static androidx.camera.core.imagecapture.FileUtil.createTempFile;
import static androidx.camera.core.imagecapture.FileUtil.moveFileToTarget;
+import android.graphics.ImageFormat;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.DngCreator;
@@ -63,7 +64,7 @@
File tempFile = createTempFile(options);
writeImageToFile(tempFile, in.getImageProxy(), in.getRotationDegrees());
Uri uri = moveFileToTarget(tempFile, options);
- return new ImageCapture.OutputFileResults(uri);
+ return new ImageCapture.OutputFileResults(uri, ImageFormat.RAW_SENSOR);
}
/**
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/imagecapture/JpegBytes2Disk.java b/camera/camera-core/src/main/java/androidx/camera/core/imagecapture/JpegBytes2Disk.java
index 6e32225..bfde90c 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/imagecapture/JpegBytes2Disk.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/imagecapture/JpegBytes2Disk.java
@@ -22,6 +22,7 @@
import static java.util.Objects.requireNonNull;
+import android.graphics.ImageFormat;
import android.net.Uri;
import androidx.annotation.NonNull;
@@ -55,7 +56,7 @@
updateFileExif(tempFile, requireNonNull(packet.getExif()), options,
packet.getRotationDegrees());
Uri uri = moveFileToTarget(tempFile, options);
- return new ImageCapture.OutputFileResults(uri);
+ return new ImageCapture.OutputFileResults(uri, ImageFormat.JPEG);
}
/**
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/imagecapture/ProcessingNode.java b/camera/camera-core/src/main/java/androidx/camera/core/imagecapture/ProcessingNode.java
index 5819ecd..1b46be5 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/imagecapture/ProcessingNode.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/imagecapture/ProcessingNode.java
@@ -252,30 +252,29 @@
String.format("On-disk capture only support JPEG and"
+ " JPEG/R and RAW output formats. Output format: %s", format));
ProcessingRequest request = inputPacket.getProcessingRequest();
- checkArgument(request.getOutputFileOptions() != null
- && !request.getOutputFileOptions().isEmpty(),
+ checkArgument(request.getOutputFileOptions() != null,
"OutputFileOptions cannot be empty");
Packet<ImageProxy> originalImage = mInput2Packet.apply(inputPacket);
boolean isSimultaneousCaptureEnabled = outputFormats.size() > 1;
if (isSimultaneousCaptureEnabled) {
- // If simultaneous capture RAW + JPEG, use the first output file options for JPEG and
- // the second for RAW.
+ // If simultaneous capture RAW + JPEG, use the first output file options for RAW and
+ // the second for JPEG.
checkArgument(request.getOutputFileOptions() != null
- && request.getOutputFileOptions().size() > 1,
+ && request.getSecondaryOutputFileOptions() != null,
"The number of OutputFileOptions for simultaneous capture "
+ "should be at least two");
ImageCapture.OutputFileResults outputFileResults = null;
switch (originalImage.getFormat()) {
case RAW_SENSOR:
outputFileResults = saveRawToDisk(originalImage,
- requireNonNull(request.getOutputFileOptions()).get(0));
+ requireNonNull(request.getOutputFileOptions()));
request.getTakePictureRequest()
.markFormatProcessStatusInSimultaneousCapture(RAW_SENSOR, true);
return outputFileResults;
case JPEG:
default:
outputFileResults = saveJpegToDisk(originalImage,
- requireNonNull(request.getOutputFileOptions()).get(1),
+ requireNonNull(request.getSecondaryOutputFileOptions()),
request.getJpegQuality());
request.getTakePictureRequest()
.markFormatProcessStatusInSimultaneousCapture(JPEG, true);
@@ -285,11 +284,11 @@
switch (format) {
case RAW_SENSOR:
return saveRawToDisk(originalImage,
- requireNonNull(request.getOutputFileOptions()).get(0));
+ requireNonNull(request.getOutputFileOptions()));
case JPEG:
default:
return saveJpegToDisk(originalImage,
- requireNonNull(request.getOutputFileOptions()).get(0),
+ requireNonNull(request.getOutputFileOptions()),
request.getJpegQuality());
}
}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/imagecapture/ProcessingRequest.java b/camera/camera-core/src/main/java/androidx/camera/core/imagecapture/ProcessingRequest.java
index bf70e64..0e2b5d3 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/imagecapture/ProcessingRequest.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/imagecapture/ProcessingRequest.java
@@ -43,7 +43,9 @@
private final int mRequestId;
@NonNull TakePictureRequest mTakePictureRequest;
@Nullable
- private final List<ImageCapture.OutputFileOptions> mOutputFileOptions;
+ private final ImageCapture.OutputFileOptions mOutputFileOptions;
+ @Nullable
+ private final ImageCapture.OutputFileOptions mSecondaryOutputFileOptions;
@NonNull
private final Rect mCropRect;
private final int mRotationDegrees;
@@ -77,6 +79,7 @@
mRequestId = requestId;
mTakePictureRequest = takePictureRequest;
mOutputFileOptions = takePictureRequest.getOutputFileOptions();
+ mSecondaryOutputFileOptions = takePictureRequest.getSecondaryOutputFileOptions();
mJpegQuality = takePictureRequest.getJpegQuality();
mRotationDegrees = takePictureRequest.getRotationDegrees();
mCropRect = takePictureRequest.getCropRect();
@@ -110,10 +113,15 @@
}
@Nullable
- List<ImageCapture.OutputFileOptions> getOutputFileOptions() {
+ ImageCapture.OutputFileOptions getOutputFileOptions() {
return mOutputFileOptions;
}
+ @Nullable
+ ImageCapture.OutputFileOptions getSecondaryOutputFileOptions() {
+ return mSecondaryOutputFileOptions;
+ }
+
@NonNull
Rect getCropRect() {
return mCropRect;
@@ -133,7 +141,7 @@
}
boolean isInMemoryCapture() {
- return getOutputFileOptions() == null || getOutputFileOptions().isEmpty();
+ return getOutputFileOptions() == null && getSecondaryOutputFileOptions() == null;
}
/**
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/imagecapture/TakePictureRequest.java b/camera/camera-core/src/main/java/androidx/camera/core/imagecapture/TakePictureRequest.java
index 120b23c..6ed06ba 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/imagecapture/TakePictureRequest.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/imagecapture/TakePictureRequest.java
@@ -101,7 +101,13 @@
* Gets the app provided options for on-disk capture.
*/
@Nullable
- public abstract List<ImageCapture.OutputFileOptions> getOutputFileOptions();
+ public abstract ImageCapture.OutputFileOptions getOutputFileOptions();
+
+ /**
+ * Gets the app provided options for secondary on-disk capture.
+ */
+ @Nullable
+ public abstract ImageCapture.OutputFileOptions getSecondaryOutputFileOptions();
/**
* A snapshot of {@link ImageCapture#getViewPortCropRect()} when
@@ -283,7 +289,8 @@
public static TakePictureRequest of(@NonNull Executor appExecutor,
@Nullable ImageCapture.OnImageCapturedCallback inMemoryCallback,
@Nullable ImageCapture.OnImageSavedCallback onDiskCallback,
- @Nullable List<ImageCapture.OutputFileOptions> outputFileOptions,
+ @Nullable ImageCapture.OutputFileOptions outputFileOptions,
+ @Nullable ImageCapture.OutputFileOptions secondaryOutputFileOptions,
@NonNull Rect cropRect,
@NonNull Matrix sensorToBufferTransform,
int rotationDegrees,
@@ -296,7 +303,7 @@
checkArgument((onDiskCallback == null) ^ (inMemoryCallback == null),
"One and only one on-disk or in-memory callback should be present.");
TakePictureRequest request = new AutoValue_TakePictureRequest(appExecutor, inMemoryCallback,
- onDiskCallback, outputFileOptions, cropRect,
+ onDiskCallback, outputFileOptions, secondaryOutputFileOptions, cropRect,
sensorToBufferTransform, rotationDegrees, jpegQuality, captureMode,
isSimultaneousCapture,
sessionConfigCameraCaptureCallbacks);
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/ImageCaptureExtTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/ImageCaptureExtTest.kt
index af73043..962eec1 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/ImageCaptureExtTest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/ImageCaptureExtTest.kt
@@ -18,6 +18,7 @@
import android.content.Context
import android.graphics.Bitmap
+import android.graphics.ImageFormat
import android.os.Build
import android.os.Looper
import androidx.camera.core.impl.utils.executor.CameraXExecutors
@@ -225,7 +226,7 @@
@Test
fun takePicture_onDisk_canGetResult(): Unit = runTest {
// Arrange
- val outputFileResults = ImageCapture.OutputFileResults(null)
+ val outputFileResults = ImageCapture.OutputFileResults(null, ImageFormat.JPEG)
// Arrange & Act.
val takePictureAsync =
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/FakeProcessingRequest.kt b/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/FakeProcessingRequest.kt
index 7a40e02..0d0eec8 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/FakeProcessingRequest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/FakeProcessingRequest.kt
@@ -40,9 +40,8 @@
ProcessingRequest(
captureBundle,
createTakePictureRequest(
- if (outputFileOptions == null) null
- else if (secondaryOutputFileOptions == null) listOf(outputFileOptions)
- else listOf(outputFileOptions, secondaryOutputFileOptions),
+ outputFileOptions,
+ secondaryOutputFileOptions,
cropRect,
sensorToBufferTransform,
rotationDegrees,
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/FakeTakePictureRequest.kt b/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/FakeTakePictureRequest.kt
index 7bf9c75..b99c301 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/FakeTakePictureRequest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/FakeTakePictureRequest.kt
@@ -109,8 +109,12 @@
imageSavedCallback = onDiskCallback
}
- override fun getOutputFileOptions(): List<ImageCapture.OutputFileOptions> {
- return listOfNotNull(fileOptions, secondaryFileOptions)
+ override fun getOutputFileOptions(): ImageCapture.OutputFileOptions? {
+ return fileOptions
+ }
+
+ override fun getSecondaryOutputFileOptions(): ImageCapture.OutputFileOptions? {
+ return secondaryFileOptions
}
override fun getCropRect(): Rect {
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/ImagePipelineTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/ImagePipelineTest.kt
index f6a7c82..8b2adf4f 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/ImagePipelineTest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/ImagePipelineTest.kt
@@ -67,7 +67,6 @@
import androidx.camera.testing.impl.fakes.FakeImageReaderProxy
import androidx.camera.testing.impl.fakes.GrayscaleImageEffect
import androidx.core.util.Pair
-import com.google.common.collect.ImmutableList
import com.google.common.truth.Truth.assertThat
import org.junit.After
import org.junit.Before
@@ -373,7 +372,8 @@
override fun onError(exception: ImageCaptureException) {}
},
- ImmutableList.of(OUTPUT_FILE_OPTIONS, SECONDARY_OUTPUT_FILE_OPTIONS),
+ OUTPUT_FILE_OPTIONS,
+ SECONDARY_OUTPUT_FILE_OPTIONS,
cropRect,
SENSOR_TO_BUFFER,
ROTATION_DEGREES,
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/ProcessingInput2PacketTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/ProcessingInput2PacketTest.kt
index d059a5a..ed218f1 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/ProcessingInput2PacketTest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/ProcessingInput2PacketTest.kt
@@ -139,7 +139,8 @@
ProcessingRequest(
{ listOf() },
createTakePictureRequest(
- listOf(OUTPUT_FILE_OPTIONS),
+ OUTPUT_FILE_OPTIONS,
+ null,
CROP_RECT,
SENSOR_TO_BUFFER,
/*rotationDegrees=*/ 90,
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/ProcessingNodeTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/ProcessingNodeTest.kt
index 7653d47..b5757ec 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/ProcessingNodeTest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/ProcessingNodeTest.kt
@@ -84,7 +84,8 @@
ProcessingRequest(
{ listOf() },
createTakePictureRequest(
- listOf(OUTPUT_FILE_OPTIONS),
+ OUTPUT_FILE_OPTIONS,
+ null,
Rect(0, 0, WIDTH, HEIGHT),
SENSOR_TO_BUFFER,
ROTATION_DEGREES,
@@ -113,7 +114,8 @@
ProcessingRequest(
{ listOf() },
createTakePictureRequest(
- listOf(OUTPUT_FILE_OPTIONS),
+ OUTPUT_FILE_OPTIONS,
+ null,
Rect(0, 0, WIDTH, HEIGHT),
SENSOR_TO_BUFFER,
ROTATION_DEGREES,
@@ -144,7 +146,8 @@
ProcessingRequest(
{ listOf() },
createTakePictureRequest(
- listOf(OUTPUT_FILE_OPTIONS),
+ OUTPUT_FILE_OPTIONS,
+ null,
Rect(0, 0, WIDTH, HEIGHT),
SENSOR_TO_BUFFER,
ROTATION_DEGREES,
@@ -183,7 +186,8 @@
ProcessingRequest(
{ listOf() },
createTakePictureRequest(
- listOf(OUTPUT_FILE_OPTIONS, SECONDARY_OUTPUT_FILE_OPTIONS),
+ OUTPUT_FILE_OPTIONS,
+ SECONDARY_OUTPUT_FILE_OPTIONS,
Rect(0, 0, WIDTH, HEIGHT),
SENSOR_TO_BUFFER,
ROTATION_DEGREES,
@@ -230,7 +234,8 @@
ProcessingRequest(
{ listOf() },
createTakePictureRequest(
- listOf(OUTPUT_FILE_OPTIONS),
+ OUTPUT_FILE_OPTIONS,
+ null,
Rect(0, 0, WIDTH, HEIGHT),
SENSOR_TO_BUFFER,
ROTATION_DEGREES,
@@ -258,7 +263,8 @@
ProcessingRequest(
{ listOf() },
createTakePictureRequest(
- listOf(OUTPUT_FILE_OPTIONS),
+ OUTPUT_FILE_OPTIONS,
+ null,
Rect(0, 0, WIDTH, HEIGHT),
SENSOR_TO_BUFFER,
ROTATION_DEGREES,
@@ -287,7 +293,8 @@
ProcessingRequest(
{ listOf() },
createTakePictureRequest(
- listOf(OUTPUT_FILE_OPTIONS),
+ OUTPUT_FILE_OPTIONS,
+ null,
Rect(0, 0, WIDTH, HEIGHT),
SENSOR_TO_BUFFER,
ROTATION_DEGREES,
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/RequestWithCallbackTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/RequestWithCallbackTest.kt
index 5f7324e..db3652f 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/RequestWithCallbackTest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/RequestWithCallbackTest.kt
@@ -16,6 +16,7 @@
package androidx.camera.core.imagecapture
+import android.graphics.ImageFormat
import android.os.Build
import android.os.Looper.getMainLooper
import androidx.camera.core.ImageCapture
@@ -57,7 +58,7 @@
abortError = ImageCaptureException(ERROR_CAMERA_CLOSED, "", null)
otherError = ImageCaptureException(ERROR_CAPTURE_FAILED, "", null)
imageResult = FakeImageProxy(FakeImageInfo())
- fileResult = ImageCapture.OutputFileResults(null)
+ fileResult = ImageCapture.OutputFileResults(null, ImageFormat.JPEG)
retryControl = FakeRetryControl()
captureRequestFuture = CallbackToFutureAdapter.getFuture { "captureRequestFuture" }
}
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/TakePictureManagerTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/TakePictureManagerTest.kt
index 62f161b..0d081ab 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/TakePictureManagerTest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/TakePictureManagerTest.kt
@@ -16,6 +16,7 @@
package androidx.camera.core.imagecapture
+import android.graphics.ImageFormat
import android.hardware.camera2.CameraCharacteristics
import android.os.Build
import android.os.Looper.getMainLooper
@@ -173,7 +174,7 @@
processingRequest.onImageCaptured()
// Act.
processingRequest.onFinalResult(FakeImageProxy(FakeImageInfo()))
- processingRequest.onFinalResult(OutputFileResults(null))
+ processingRequest.onFinalResult(OutputFileResults(null, ImageFormat.JPEG))
}
@Test
@@ -327,7 +328,7 @@
takePictureManager.offerRequest(request3)
shadowOf(getMainLooper()).idle()
val response1 = exception
- val response2 = OutputFileResults(null)
+ val response2 = OutputFileResults(null, ImageFormat.JPEG)
val response3 = FakeImageProxy(FakeImageInfo())
imagePipeline.getProcessingRequest(request1).onImageCaptured()
shadowOf(getMainLooper()).idle()
@@ -370,7 +371,7 @@
takePictureManager.offerRequest(request)
// Act: send OutputFileResults via ImagePipeline
- val outputFileResults = OutputFileResults(null)
+ val outputFileResults = OutputFileResults(null, ImageFormat.JPEG)
imagePipeline.getProcessingRequest(request).onImageCaptured()
imagePipeline.getProcessingRequest(request).onFinalResult(outputFileResults)
shadowOf(getMainLooper()).idle()
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/Utils.kt b/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/Utils.kt
index 3305a82..6536cdb 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/Utils.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/Utils.kt
@@ -72,7 +72,8 @@
return ProcessingRequest(
captureBundle,
createTakePictureRequest(
- listOf(OUTPUT_FILE_OPTIONS),
+ OUTPUT_FILE_OPTIONS,
+ null,
CROP_RECT,
SENSOR_TO_BUFFER,
ROTATION_DEGREES,
@@ -113,7 +114,8 @@
}
fun createTakePictureRequest(
- outputFileOptions: List<ImageCapture.OutputFileOptions>?,
+ outputFileOptions: ImageCapture.OutputFileOptions?,
+ secondaryOutputFileOptions: ImageCapture.OutputFileOptions?,
cropRect: Rect,
sensorToBufferTransform: Matrix,
rotationDegrees: Int,
@@ -133,6 +135,7 @@
onMemoryCallback,
onDiskCallback,
outputFileOptions,
+ secondaryOutputFileOptions,
cropRect,
sensorToBufferTransform,
rotationDegrees,
diff --git a/camera/camera-testing/src/main/java/androidx/camera/testing/impl/wrappers/TakePictureManagerWrapper.kt b/camera/camera-testing/src/main/java/androidx/camera/testing/impl/wrappers/TakePictureManagerWrapper.kt
index a035008..c043e29 100644
--- a/camera/camera-testing/src/main/java/androidx/camera/testing/impl/wrappers/TakePictureManagerWrapper.kt
+++ b/camera/camera-testing/src/main/java/androidx/camera/testing/impl/wrappers/TakePictureManagerWrapper.kt
@@ -167,23 +167,19 @@
// user-provided data like bitmap/image proxy and use that to complete capture.
val bitmap = takePictureRequest.createBitmap()
- val outputFileOptions =
- takePictureRequest.outputFileOptions // enables smartcast for null check
+ val outputFileOptions = takePictureRequest.outputFileOptions // enables
+ val secondaryOutputResults = takePictureRequest.secondaryOutputFileOptions
if (takePictureRequest.onDiskCallback != null && outputFileOptions != null) {
if (outputFileResultsQueue.isEmpty()) {
- if (outputFileOptions.size > 1) {
+ if (secondaryOutputResults != null) {
Logger.w(
TAG,
"Simultaneous capture not supported, outputFileOptions = $outputFileOptions"
)
}
onFinalResult(
- createOutputFileResults(
- takePictureRequest,
- outputFileOptions[0],
- bitmap
- )
+ createOutputFileResults(takePictureRequest, outputFileOptions, bitmap)
)
} else {
onFinalResult(outputFileResultsQueue.removeFirst())
diff --git a/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/CameraXActivity.java b/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/CameraXActivity.java
index b8cdb7e..8609e1b 100644
--- a/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/CameraXActivity.java
+++ b/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/CameraXActivity.java
@@ -1034,7 +1034,8 @@
ImageCapture.OutputFileOptions jpegOutputFileOptions =
createOutputFileOptions(OUTPUT_FORMAT_JPEG);
getImageCapture().takePicture(
- List.of(rawOutputFileOptions, jpegOutputFileOptions),
+ rawOutputFileOptions,
+ jpegOutputFileOptions,
mImageCaptureExecutorService,
callback);
} else {
diff --git a/collection/collection/bcv/native/current.txt b/collection/collection/bcv/native/current.txt
index 4fcb3f8..012c700f 100644
--- a/collection/collection/bcv/native/current.txt
+++ b/collection/collection/bcv/native/current.txt
@@ -981,6 +981,8 @@
}
sealed class <#A: kotlin/Any?, #B: kotlin/Any?> androidx.collection/ScatterMap { // androidx.collection/ScatterMap|null[0]
+ constructor <init>() // androidx.collection/ScatterMap.<init>|<init>(){}[0]
+
final val capacity // androidx.collection/ScatterMap.capacity|{}capacity[0]
final fun <get-capacity>(): kotlin/Int // androidx.collection/ScatterMap.capacity.<get-capacity>|<get-capacity>(){}[0]
final val size // androidx.collection/ScatterMap.size|{}size[0]
@@ -1022,6 +1024,8 @@
}
sealed class <#A: kotlin/Any?> androidx.collection/FloatObjectMap { // androidx.collection/FloatObjectMap|null[0]
+ constructor <init>() // androidx.collection/FloatObjectMap.<init>|<init>(){}[0]
+
final val capacity // androidx.collection/FloatObjectMap.capacity|{}capacity[0]
final fun <get-capacity>(): kotlin/Int // androidx.collection/FloatObjectMap.capacity.<get-capacity>|<get-capacity>(){}[0]
final val size // androidx.collection/FloatObjectMap.size|{}size[0]
@@ -1063,6 +1067,8 @@
}
sealed class <#A: kotlin/Any?> androidx.collection/IntObjectMap { // androidx.collection/IntObjectMap|null[0]
+ constructor <init>() // androidx.collection/IntObjectMap.<init>|<init>(){}[0]
+
final val capacity // androidx.collection/IntObjectMap.capacity|{}capacity[0]
final fun <get-capacity>(): kotlin/Int // androidx.collection/IntObjectMap.capacity.<get-capacity>|<get-capacity>(){}[0]
final val size // androidx.collection/IntObjectMap.size|{}size[0]
@@ -1104,6 +1110,8 @@
}
sealed class <#A: kotlin/Any?> androidx.collection/LongObjectMap { // androidx.collection/LongObjectMap|null[0]
+ constructor <init>() // androidx.collection/LongObjectMap.<init>|<init>(){}[0]
+
final val capacity // androidx.collection/LongObjectMap.capacity|{}capacity[0]
final fun <get-capacity>(): kotlin/Int // androidx.collection/LongObjectMap.capacity.<get-capacity>|<get-capacity>(){}[0]
final val size // androidx.collection/LongObjectMap.size|{}size[0]
@@ -1145,6 +1153,8 @@
}
sealed class <#A: kotlin/Any?> androidx.collection/ObjectFloatMap { // androidx.collection/ObjectFloatMap|null[0]
+ constructor <init>() // androidx.collection/ObjectFloatMap.<init>|<init>(){}[0]
+
final val capacity // androidx.collection/ObjectFloatMap.capacity|{}capacity[0]
final fun <get-capacity>(): kotlin/Int // androidx.collection/ObjectFloatMap.capacity.<get-capacity>|<get-capacity>(){}[0]
final val size // androidx.collection/ObjectFloatMap.size|{}size[0]
@@ -1187,6 +1197,8 @@
}
sealed class <#A: kotlin/Any?> androidx.collection/ObjectIntMap { // androidx.collection/ObjectIntMap|null[0]
+ constructor <init>() // androidx.collection/ObjectIntMap.<init>|<init>(){}[0]
+
final val capacity // androidx.collection/ObjectIntMap.capacity|{}capacity[0]
final fun <get-capacity>(): kotlin/Int // androidx.collection/ObjectIntMap.capacity.<get-capacity>|<get-capacity>(){}[0]
final val size // androidx.collection/ObjectIntMap.size|{}size[0]
@@ -1229,6 +1241,8 @@
}
sealed class <#A: kotlin/Any?> androidx.collection/ObjectList { // androidx.collection/ObjectList|null[0]
+ constructor <init>(kotlin/Int) // androidx.collection/ObjectList.<init>|<init>(kotlin.Int){}[0]
+
final val indices // androidx.collection/ObjectList.indices|{}indices[0]
final inline fun <get-indices>(): kotlin.ranges/IntRange // androidx.collection/ObjectList.indices.<get-indices>|<get-indices>(){}[0]
final val lastIndex // androidx.collection/ObjectList.lastIndex|{}lastIndex[0]
@@ -1287,6 +1301,8 @@
}
sealed class <#A: kotlin/Any?> androidx.collection/ObjectLongMap { // androidx.collection/ObjectLongMap|null[0]
+ constructor <init>() // androidx.collection/ObjectLongMap.<init>|<init>(){}[0]
+
final val capacity // androidx.collection/ObjectLongMap.capacity|{}capacity[0]
final fun <get-capacity>(): kotlin/Int // androidx.collection/ObjectLongMap.capacity.<get-capacity>|<get-capacity>(){}[0]
final val size // androidx.collection/ObjectLongMap.size|{}size[0]
@@ -1329,6 +1345,8 @@
}
sealed class <#A: kotlin/Any?> androidx.collection/OrderedScatterSet { // androidx.collection/OrderedScatterSet|null[0]
+ constructor <init>() // androidx.collection/OrderedScatterSet.<init>|<init>(){}[0]
+
final val capacity // androidx.collection/OrderedScatterSet.capacity|{}capacity[0]
final fun <get-capacity>(): kotlin/Int // androidx.collection/OrderedScatterSet.capacity.<get-capacity>|<get-capacity>(){}[0]
final val size // androidx.collection/OrderedScatterSet.size|{}size[0]
@@ -1378,6 +1396,8 @@
}
sealed class <#A: kotlin/Any?> androidx.collection/ScatterSet { // androidx.collection/ScatterSet|null[0]
+ constructor <init>() // androidx.collection/ScatterSet.<init>|<init>(){}[0]
+
final val capacity // androidx.collection/ScatterSet.capacity|{}capacity[0]
final fun <get-capacity>(): kotlin/Int // androidx.collection/ScatterSet.capacity.<get-capacity>|<get-capacity>(){}[0]
final val size // androidx.collection/ScatterSet.size|{}size[0]
@@ -1412,6 +1432,8 @@
}
sealed class androidx.collection/DoubleList { // androidx.collection/DoubleList|null[0]
+ constructor <init>(kotlin/Int) // androidx.collection/DoubleList.<init>|<init>(kotlin.Int){}[0]
+
final val indices // androidx.collection/DoubleList.indices|{}indices[0]
final inline fun <get-indices>(): kotlin.ranges/IntRange // androidx.collection/DoubleList.indices.<get-indices>|<get-indices>(){}[0]
final val lastIndex // androidx.collection/DoubleList.lastIndex|{}lastIndex[0]
@@ -1464,6 +1486,8 @@
}
sealed class androidx.collection/FloatFloatMap { // androidx.collection/FloatFloatMap|null[0]
+ constructor <init>() // androidx.collection/FloatFloatMap.<init>|<init>(){}[0]
+
final val capacity // androidx.collection/FloatFloatMap.capacity|{}capacity[0]
final fun <get-capacity>(): kotlin/Int // androidx.collection/FloatFloatMap.capacity.<get-capacity>|<get-capacity>(){}[0]
final val size // androidx.collection/FloatFloatMap.size|{}size[0]
@@ -1506,6 +1530,8 @@
}
sealed class androidx.collection/FloatIntMap { // androidx.collection/FloatIntMap|null[0]
+ constructor <init>() // androidx.collection/FloatIntMap.<init>|<init>(){}[0]
+
final val capacity // androidx.collection/FloatIntMap.capacity|{}capacity[0]
final fun <get-capacity>(): kotlin/Int // androidx.collection/FloatIntMap.capacity.<get-capacity>|<get-capacity>(){}[0]
final val size // androidx.collection/FloatIntMap.size|{}size[0]
@@ -1548,6 +1574,8 @@
}
sealed class androidx.collection/FloatList { // androidx.collection/FloatList|null[0]
+ constructor <init>(kotlin/Int) // androidx.collection/FloatList.<init>|<init>(kotlin.Int){}[0]
+
final val indices // androidx.collection/FloatList.indices|{}indices[0]
final inline fun <get-indices>(): kotlin.ranges/IntRange // androidx.collection/FloatList.indices.<get-indices>|<get-indices>(){}[0]
final val lastIndex // androidx.collection/FloatList.lastIndex|{}lastIndex[0]
@@ -1600,6 +1628,8 @@
}
sealed class androidx.collection/FloatLongMap { // androidx.collection/FloatLongMap|null[0]
+ constructor <init>() // androidx.collection/FloatLongMap.<init>|<init>(){}[0]
+
final val capacity // androidx.collection/FloatLongMap.capacity|{}capacity[0]
final fun <get-capacity>(): kotlin/Int // androidx.collection/FloatLongMap.capacity.<get-capacity>|<get-capacity>(){}[0]
final val size // androidx.collection/FloatLongMap.size|{}size[0]
@@ -1642,6 +1672,8 @@
}
sealed class androidx.collection/FloatSet { // androidx.collection/FloatSet|null[0]
+ constructor <init>() // androidx.collection/FloatSet.<init>|<init>(){}[0]
+
final val capacity // androidx.collection/FloatSet.capacity|{}capacity[0]
final fun <get-capacity>(): kotlin/Int // androidx.collection/FloatSet.capacity.<get-capacity>|<get-capacity>(){}[0]
final val size // androidx.collection/FloatSet.size|{}size[0]
@@ -1675,6 +1707,8 @@
}
sealed class androidx.collection/IntFloatMap { // androidx.collection/IntFloatMap|null[0]
+ constructor <init>() // androidx.collection/IntFloatMap.<init>|<init>(){}[0]
+
final val capacity // androidx.collection/IntFloatMap.capacity|{}capacity[0]
final fun <get-capacity>(): kotlin/Int // androidx.collection/IntFloatMap.capacity.<get-capacity>|<get-capacity>(){}[0]
final val size // androidx.collection/IntFloatMap.size|{}size[0]
@@ -1717,6 +1751,8 @@
}
sealed class androidx.collection/IntIntMap { // androidx.collection/IntIntMap|null[0]
+ constructor <init>() // androidx.collection/IntIntMap.<init>|<init>(){}[0]
+
final val capacity // androidx.collection/IntIntMap.capacity|{}capacity[0]
final fun <get-capacity>(): kotlin/Int // androidx.collection/IntIntMap.capacity.<get-capacity>|<get-capacity>(){}[0]
final val size // androidx.collection/IntIntMap.size|{}size[0]
@@ -1759,6 +1795,8 @@
}
sealed class androidx.collection/IntList { // androidx.collection/IntList|null[0]
+ constructor <init>(kotlin/Int) // androidx.collection/IntList.<init>|<init>(kotlin.Int){}[0]
+
final val indices // androidx.collection/IntList.indices|{}indices[0]
final inline fun <get-indices>(): kotlin.ranges/IntRange // androidx.collection/IntList.indices.<get-indices>|<get-indices>(){}[0]
final val lastIndex // androidx.collection/IntList.lastIndex|{}lastIndex[0]
@@ -1811,6 +1849,8 @@
}
sealed class androidx.collection/IntLongMap { // androidx.collection/IntLongMap|null[0]
+ constructor <init>() // androidx.collection/IntLongMap.<init>|<init>(){}[0]
+
final val capacity // androidx.collection/IntLongMap.capacity|{}capacity[0]
final fun <get-capacity>(): kotlin/Int // androidx.collection/IntLongMap.capacity.<get-capacity>|<get-capacity>(){}[0]
final val size // androidx.collection/IntLongMap.size|{}size[0]
@@ -1853,6 +1893,8 @@
}
sealed class androidx.collection/IntSet { // androidx.collection/IntSet|null[0]
+ constructor <init>() // androidx.collection/IntSet.<init>|<init>(){}[0]
+
final val capacity // androidx.collection/IntSet.capacity|{}capacity[0]
final fun <get-capacity>(): kotlin/Int // androidx.collection/IntSet.capacity.<get-capacity>|<get-capacity>(){}[0]
final val size // androidx.collection/IntSet.size|{}size[0]
@@ -1886,6 +1928,8 @@
}
sealed class androidx.collection/LongFloatMap { // androidx.collection/LongFloatMap|null[0]
+ constructor <init>() // androidx.collection/LongFloatMap.<init>|<init>(){}[0]
+
final val capacity // androidx.collection/LongFloatMap.capacity|{}capacity[0]
final fun <get-capacity>(): kotlin/Int // androidx.collection/LongFloatMap.capacity.<get-capacity>|<get-capacity>(){}[0]
final val size // androidx.collection/LongFloatMap.size|{}size[0]
@@ -1928,6 +1972,8 @@
}
sealed class androidx.collection/LongIntMap { // androidx.collection/LongIntMap|null[0]
+ constructor <init>() // androidx.collection/LongIntMap.<init>|<init>(){}[0]
+
final val capacity // androidx.collection/LongIntMap.capacity|{}capacity[0]
final fun <get-capacity>(): kotlin/Int // androidx.collection/LongIntMap.capacity.<get-capacity>|<get-capacity>(){}[0]
final val size // androidx.collection/LongIntMap.size|{}size[0]
@@ -1970,6 +2016,8 @@
}
sealed class androidx.collection/LongList { // androidx.collection/LongList|null[0]
+ constructor <init>(kotlin/Int) // androidx.collection/LongList.<init>|<init>(kotlin.Int){}[0]
+
final val indices // androidx.collection/LongList.indices|{}indices[0]
final inline fun <get-indices>(): kotlin.ranges/IntRange // androidx.collection/LongList.indices.<get-indices>|<get-indices>(){}[0]
final val lastIndex // androidx.collection/LongList.lastIndex|{}lastIndex[0]
@@ -2022,6 +2070,8 @@
}
sealed class androidx.collection/LongLongMap { // androidx.collection/LongLongMap|null[0]
+ constructor <init>() // androidx.collection/LongLongMap.<init>|<init>(){}[0]
+
final val capacity // androidx.collection/LongLongMap.capacity|{}capacity[0]
final fun <get-capacity>(): kotlin/Int // androidx.collection/LongLongMap.capacity.<get-capacity>|<get-capacity>(){}[0]
final val size // androidx.collection/LongLongMap.size|{}size[0]
@@ -2064,6 +2114,8 @@
}
sealed class androidx.collection/LongSet { // androidx.collection/LongSet|null[0]
+ constructor <init>() // androidx.collection/LongSet.<init>|<init>(){}[0]
+
final val capacity // androidx.collection/LongSet.capacity|{}capacity[0]
final fun <get-capacity>(): kotlin/Int // androidx.collection/LongSet.capacity.<get-capacity>|<get-capacity>(){}[0]
final val size // androidx.collection/LongSet.size|{}size[0]
diff --git a/compose/animation/animation-core/build.gradle b/compose/animation/animation-core/build.gradle
index 62e0b08..fac6444 100644
--- a/compose/animation/animation-core/build.gradle
+++ b/compose/animation/animation-core/build.gradle
@@ -135,4 +135,7 @@
android {
compileSdk 35
namespace "androidx.compose.animation.core"
+ buildTypes.configureEach {
+ consumerProguardFiles("proguard-rules.pro")
+ }
}
diff --git a/compose/animation/animation-core/proguard-rules.pro b/compose/animation/animation-core/proguard-rules.pro
new file mode 100644
index 0000000..67d118b
--- /dev/null
+++ b/compose/animation/animation-core/proguard-rules.pro
@@ -0,0 +1,24 @@
+# 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.
+# 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.
+
+# Keep all the functions created to throw an exception. We don't want these functions to be
+# inlined in any way, which R8 will do by default. The whole point of these functions is to
+# reduce the amount of code generated at the call site.
+-keep,allowshrinking,allowobfuscation class androidx.compose.**.* {
+ static void throw*Exception(...);
+ static void throw*ExceptionForNullCheck(...);
+ # For methods returning Nothing
+ static java.lang.Void throw*Exception(...);
+ static java.lang.Void throw*ExceptionForNullCheck(...);
+}
diff --git a/compose/animation/animation-core/src/androidUnitTest/kotlin/androidx/compose/animation/core/EasingTest.android.kt b/compose/animation/animation-core/src/androidUnitTest/kotlin/androidx/compose/animation/core/EasingTest.android.kt
index 03417725..05381b5 100644
--- a/compose/animation/animation-core/src/androidUnitTest/kotlin/androidx/compose/animation/core/EasingTest.android.kt
+++ b/compose/animation/animation-core/src/androidUnitTest/kotlin/androidx/compose/animation/core/EasingTest.android.kt
@@ -25,11 +25,11 @@
// This test can't be in commonTest because
// Float.ulp is jvm only: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.math/ulp.html
class EasingTestAndroid {
- private val ZeroEpsilon = -(1.0f.ulp * 2.0f)
+ private val ZeroEpsilon = 1.0f.ulp * 2.0f
private val OneEpsilon = 1.0f + 1.0f.ulp * 2.0f
@Test
- fun canSolveCubicForFractionsCloseToOne() {
+ fun canSolveCubicForFractionsCloseToZeroOrOne() {
// Only test curves defined in [0..1]
// For instance, EaseInOutBack is defined in a larger domain, so exclude it from the list
val curves =
@@ -67,7 +67,6 @@
)
for (curve in curves) {
- // Test the last 16 ulps until 1.0f
for (i in 0x3f7f9d99..0x3f7fffff) {
val fraction = floatFromBits(i)
val t = curve.transform(fraction)
@@ -76,6 +75,23 @@
"f($fraction) = $t out of range for $curve | ${-ZeroEpsilon}..${OneEpsilon}"
)
}
+
+ for (i in 0x0..0x6266) {
+ val fraction = floatFromBits(i)
+ val t = curve.transform(fraction)
+ assertTrue(
+ t in -ZeroEpsilon..OneEpsilon,
+ "f($fraction) = $t out of range for $curve | ${-ZeroEpsilon}..${OneEpsilon}"
+ )
+ }
+
+ // Test at 1.5058824E-7, small value but not too close to 0.0 either
+ val fraction = floatFromBits(0x3421b161)
+ val t = curve.transform(fraction)
+ assertTrue(
+ t in -ZeroEpsilon..OneEpsilon,
+ "f($fraction) = $t out of range for $curve | ${-ZeroEpsilon}..${OneEpsilon}"
+ )
}
}
diff --git a/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/Easing.kt b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/Easing.kt
index 9ff5f0f..80bdfb9 100644
--- a/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/Easing.kt
+++ b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/Easing.kt
@@ -22,6 +22,7 @@
import androidx.compose.ui.graphics.evaluateCubic
import androidx.compose.ui.graphics.findFirstCubicRoot
import androidx.compose.ui.util.fastCoerceIn
+import kotlin.math.max
/**
* Easing is a way to adjust an animation’s fraction. Easing allows transitioning elements to speed
@@ -70,6 +71,10 @@
*/
public val LinearEasing: Easing = Easing { fraction -> fraction }
+// This is equal to 1f.ulp or 1f.nextUp() - 1f, but neither ulp nor nextUp() are part of all KMP
+// targets, only JVM and native
+private const val OneUlpAt1 = 1.1920929e-7f
+
/**
* A cubic polynomial easing.
*
@@ -125,12 +130,16 @@
*/
override fun transform(fraction: Float): Float {
return if (fraction > 0f && fraction < 1f) {
+ // We translate the coordinates by the fraction when calling findFirstCubicRoot,
+ // but we need to make sure the translation can be done at 1.0f so we take at
+ // least 1 ulp at 1.0f
+ val f = max(fraction, OneUlpAt1)
val t =
findFirstCubicRoot(
- 0.0f - fraction,
- a - fraction,
- c - fraction,
- 1.0f - fraction,
+ 0.0f - f,
+ a - f,
+ c - f,
+ 1.0f - f,
)
// No root, the cubic curve has no solution
diff --git a/compose/foundation/foundation-layout/api/current.txt b/compose/foundation/foundation-layout/api/current.txt
index 45e5e44..185b73a 100644
--- a/compose/foundation/foundation-layout/api/current.txt
+++ b/compose/foundation/foundation-layout/api/current.txt
@@ -231,12 +231,6 @@
method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.ui.Modifier fillMaxRowHeight(androidx.compose.ui.Modifier, optional @FloatRange(from=0.0, to=1.0) float fraction);
}
- public final class InsetsHelper_androidKt {
- method @androidx.compose.runtime.Composable public static androidx.core.graphics.Insets roundToAndroidXInsets(androidx.compose.ui.unit.DpRect);
- method public static androidx.core.graphics.Insets toAndroidXInsets(androidx.compose.ui.unit.IntRect);
- method public static androidx.compose.ui.unit.IntRect toComposeIntRect(androidx.core.graphics.Insets);
- }
-
public final class IntrinsicKt {
method @androidx.compose.runtime.Stable public static androidx.compose.ui.Modifier height(androidx.compose.ui.Modifier, androidx.compose.foundation.layout.IntrinsicSize intrinsicSize);
method @androidx.compose.runtime.Stable public static androidx.compose.ui.Modifier requiredHeight(androidx.compose.ui.Modifier, androidx.compose.foundation.layout.IntrinsicSize intrinsicSize);
diff --git a/compose/foundation/foundation-layout/api/restricted_current.txt b/compose/foundation/foundation-layout/api/restricted_current.txt
index 0d70ee8..fbd6f49 100644
--- a/compose/foundation/foundation-layout/api/restricted_current.txt
+++ b/compose/foundation/foundation-layout/api/restricted_current.txt
@@ -237,12 +237,6 @@
method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.ui.Modifier fillMaxRowHeight(androidx.compose.ui.Modifier, optional @FloatRange(from=0.0, to=1.0) float fraction);
}
- public final class InsetsHelper_androidKt {
- method @androidx.compose.runtime.Composable public static androidx.core.graphics.Insets roundToAndroidXInsets(androidx.compose.ui.unit.DpRect);
- method public static androidx.core.graphics.Insets toAndroidXInsets(androidx.compose.ui.unit.IntRect);
- method public static androidx.compose.ui.unit.IntRect toComposeIntRect(androidx.core.graphics.Insets);
- }
-
public final class IntrinsicKt {
method @androidx.compose.runtime.Stable public static androidx.compose.ui.Modifier height(androidx.compose.ui.Modifier, androidx.compose.foundation.layout.IntrinsicSize intrinsicSize);
method @androidx.compose.runtime.Stable public static androidx.compose.ui.Modifier requiredHeight(androidx.compose.ui.Modifier, androidx.compose.foundation.layout.IntrinsicSize intrinsicSize);
diff --git a/compose/foundation/foundation-layout/proguard-rules.pro b/compose/foundation/foundation-layout/proguard-rules.pro
index d07663a..67d118b 100644
--- a/compose/foundation/foundation-layout/proguard-rules.pro
+++ b/compose/foundation/foundation-layout/proguard-rules.pro
@@ -17,6 +17,8 @@
# reduce the amount of code generated at the call site.
-keep,allowshrinking,allowobfuscation class androidx.compose.**.* {
static void throw*Exception(...);
+ static void throw*ExceptionForNullCheck(...);
# For methods returning Nothing
static java.lang.Void throw*Exception(...);
+ static java.lang.Void throw*ExceptionForNullCheck(...);
}
diff --git a/compose/foundation/foundation-layout/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/layout/InsetsHelper.kt b/compose/foundation/foundation-layout/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/layout/InsetsHelper.kt
deleted file mode 100644
index a5e3a11..0000000
--- a/compose/foundation/foundation-layout/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/layout/InsetsHelper.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.compose.foundation.layout
-
-import androidx.compose.ui.platform.LocalDensity
-import androidx.compose.ui.test.junit4.createComposeRule
-import androidx.compose.ui.unit.Density
-import androidx.compose.ui.unit.DpRect
-import androidx.compose.ui.unit.dp
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
-import org.junit.Assert.assertEquals
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@SmallTest
-@RunWith(AndroidJUnit4::class)
-class InsetsHelperTest {
- @get:Rule val rule = createComposeRule()
-
- @Test
- fun dpRectToAndroidXInsetsConverts() {
- lateinit var androidXInsets: androidx.core.graphics.Insets
- lateinit var density: Density
-
- rule.setContent {
- androidXInsets = DpRect(5.dp, 6.dp, 7.dp, 8.dp).roundToAndroidXInsets()
- density = LocalDensity.current
- }
-
- assertEquals(with(density) { 5.dp.roundToPx() }, androidXInsets.left)
- assertEquals(with(density) { 6.dp.roundToPx() }, androidXInsets.top)
- assertEquals(with(density) { 7.dp.roundToPx() }, androidXInsets.right)
- assertEquals(with(density) { 8.dp.roundToPx() }, androidXInsets.bottom)
- }
-}
diff --git a/compose/foundation/foundation-layout/src/androidMain/kotlin/androidx/compose/foundation/layout/InsetsHelper.android.kt b/compose/foundation/foundation-layout/src/androidMain/kotlin/androidx/compose/foundation/layout/InsetsHelper.android.kt
deleted file mode 100644
index 079d267..0000000
--- a/compose/foundation/foundation-layout/src/androidMain/kotlin/androidx/compose/foundation/layout/InsetsHelper.android.kt
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.compose.foundation.layout
-
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.platform.LocalDensity
-import androidx.compose.ui.unit.DpRect
-import androidx.compose.ui.unit.IntRect
-import androidx.compose.ui.unit.roundToIntRect
-
-/**
- * Creates a new instance of [androidx.core.graphics.Insets] with the same bounds specified in the
- * given [IntRect].
- */
-fun IntRect.toAndroidXInsets(): androidx.core.graphics.Insets =
- androidx.core.graphics.Insets.of(left, top, right, bottom)
-
-/**
- * Creates a new instance of [IntRect] with the same bounds specified in the given
- * [androidx.core.graphics.Insets].
- */
-fun androidx.core.graphics.Insets.toComposeIntRect(): IntRect = IntRect(left, top, right, bottom)
-
-/**
- * Converts the [DpRect] to [androidx.core.graphics.Insets] by using the [LocalDensity] and rounding
- * to the nearest pixel values in each dimension.
- */
-@Composable
-fun DpRect.roundToAndroidXInsets(): androidx.core.graphics.Insets =
- with(LocalDensity.current) { toRect() }.roundToIntRect().toAndroidXInsets()
diff --git a/compose/foundation/foundation-layout/src/androidUnitTest/kotlin/androidx/compose/foundation/layout/InsetsHelperTest.kt b/compose/foundation/foundation-layout/src/androidUnitTest/kotlin/androidx/compose/foundation/layout/InsetsHelperTest.kt
deleted file mode 100644
index 8c1ebbb..0000000
--- a/compose/foundation/foundation-layout/src/androidUnitTest/kotlin/androidx/compose/foundation/layout/InsetsHelperTest.kt
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.compose.foundation.layout
-
-import androidx.compose.ui.unit.IntRect
-import org.junit.Assert.assertEquals
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-
-@RunWith(JUnit4::class)
-class InsetsHelperTest {
- @Test
- fun intRectToAndroidXInsetsConverts() {
- assertEquals(
- androidx.core.graphics.Insets.of(5, 6, 7, 8),
- IntRect(5, 6, 7, 8).toAndroidXInsets(),
- )
- }
-
- @Test
- fun androidXInsetsToOntRectConverts() {
- assertEquals(
- IntRect(5, 6, 7, 8),
- androidx.core.graphics.Insets.of(5, 6, 7, 8).toComposeIntRect(),
- )
- }
-}
diff --git a/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/ScrollableTest.kt b/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/ScrollableTest.kt
index fb71215..4e75878 100644
--- a/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/ScrollableTest.kt
+++ b/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/ScrollableTest.kt
@@ -55,7 +55,6 @@
import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.currentComposer
import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
@@ -130,7 +129,6 @@
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertWithMessage
import kotlin.math.abs
-import kotlin.math.absoluteValue
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
@@ -143,6 +141,7 @@
import org.junit.After
import org.junit.Assert
import org.junit.Before
+import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -1850,66 +1849,6 @@
}
@Test
- fun scrollable_nestedFling_parentShouldFlingWithVelocityLeft_whenInnerDisappears() {
- var postFlingCalled = false
- var postFlingAvailableVelocity = Velocity.Zero
- var postFlingConsumedVelocity = Velocity.Zero
- var flingDelta by mutableFloatStateOf(0.0f)
- var preFlingVelocity = Velocity.Zero
-
- val topConnection =
- object : NestedScrollConnection {
- override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
- // accumulate deltas for second fling only
- if (source == NestedScrollSource.SideEffect) {
- flingDelta += available.y
- }
- return super.onPreScroll(available, source)
- }
-
- override suspend fun onPreFling(available: Velocity): Velocity {
- preFlingVelocity = available
- return super.onPreFling(available)
- }
-
- override suspend fun onPostFling(
- consumed: Velocity,
- available: Velocity
- ): Velocity {
- postFlingCalled = true
- postFlingAvailableVelocity = available
- postFlingConsumedVelocity = consumed
- return super.onPostFling(consumed, available)
- }
- }
-
- val columnState = ScrollState(with(rule.density) { (50 * 200.dp).roundToPx() })
-
- rule.setContent {
- Box(Modifier.nestedScroll(topConnection)) {
- if (flingDelta.absoluteValue < 100) {
- Column(Modifier.testTag("column").verticalScroll(columnState)) {
- repeat(100) { Box(Modifier.size(200.dp)) }
- }
- }
- }
- }
-
- rule.onNodeWithTag("column").performTouchInput { swipeUp() }
- rule.waitForIdle()
- // removed scrollable
- rule.onNodeWithTag("column").assertDoesNotExist()
- rule.runOnIdle {
- // we fired a post fling call after the disappearance
- assertThat(postFlingCalled).isTrue()
-
- // fling velocity in onPostFling is correctly propagated
- assertThat(postFlingConsumedVelocity + postFlingAvailableVelocity)
- .isEqualTo(preFlingVelocity)
- }
- }
-
- @Test
fun scrollable_bothOrientations_proxiesPostFling() {
val velocityFlung = 5000f
val outerState = ScrollableState(consumeScrollDelta = { 0f })
@@ -2582,6 +2521,77 @@
}
@Test
+ @Ignore("b/175010956") // re-enable when we come back to fling continuation fix
+ fun nestedScrollable_shouldImmediateScrollIfChildIsFlinging() {
+ var innerDelta = 0f
+ var middleDelta = 0f
+ var outerDelta = 0f
+ var touchSlop = 0f
+
+ val outerStateController = ScrollableState {
+ outerDelta += it
+ 0f
+ }
+
+ val middleController = ScrollableState {
+ middleDelta += it
+ 0f
+ }
+
+ val innerController = ScrollableState {
+ innerDelta += it
+ it / 2f
+ }
+
+ rule.setContentAndGetScope {
+ touchSlop = LocalViewConfiguration.current.touchSlop
+ Box(
+ modifier =
+ Modifier.testTag("outerScrollable")
+ .size(600.dp)
+ .background(Color.Red)
+ .scrollable(outerStateController, orientation = Orientation.Vertical),
+ contentAlignment = Alignment.BottomStart
+ ) {
+ Box(
+ modifier =
+ Modifier.testTag("middleScrollable")
+ .size(300.dp)
+ .background(Color.Blue)
+ .scrollable(middleController, orientation = Orientation.Vertical),
+ contentAlignment = Alignment.BottomStart
+ ) {
+ Box(
+ modifier =
+ Modifier.testTag("innerScrollable")
+ .size(50.dp)
+ .background(Color.Yellow)
+ .scrollable(innerController, orientation = Orientation.Vertical)
+ )
+ }
+ }
+ }
+
+ rule.mainClock.autoAdvance = false
+ rule.onNodeWithTag("innerScrollable").performTouchInput { swipeUp() }
+
+ rule.mainClock.advanceTimeByFrame()
+ rule.mainClock.advanceTimeByFrame()
+
+ val previousOuter = outerDelta
+
+ rule.onNodeWithTag("outerScrollable").performTouchInput {
+ down(topCenter)
+ // Move less than touch slop, should start immediately
+ moveBy(Offset(0f, touchSlop / 2))
+ }
+
+ rule.mainClock.autoAdvance = true
+
+ rule.runOnIdle { assertThat(outerDelta).isEqualTo(previousOuter + touchSlop / 2) }
+ }
+
+ @Test
fun nestedScrollable_noFlingContinuationInCrossAxis_shouldAllowClicksOnCrossAxis_scrollable() {
var clicked = 0
rule.setContentAndGetScope {
diff --git a/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/text/input/internal/selection/TextFieldCursorHandleTest.kt b/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/text/input/internal/selection/TextFieldCursorHandleTest.kt
index 9fd4053..425cd33 100644
--- a/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/text/input/internal/selection/TextFieldCursorHandleTest.kt
+++ b/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/text/input/internal/selection/TextFieldCursorHandleTest.kt
@@ -30,13 +30,17 @@
import androidx.compose.foundation.text.TEST_FONT_FAMILY
import androidx.compose.foundation.text.input.TextFieldLineLimits
import androidx.compose.foundation.text.input.TextFieldState
+import androidx.compose.foundation.text.input.internal.CodepointTransformation
+import androidx.compose.foundation.text.input.internal.mask
import androidx.compose.foundation.text.input.placeCursorAtEnd
import androidx.compose.foundation.text.input.setTextAndPlaceCursorAtEnd
import androidx.compose.foundation.text.selection.assertHandlePositionMatches
import androidx.compose.foundation.text.selection.isSelectionHandle
import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.layout.onSizeChanged
@@ -46,6 +50,7 @@
import androidx.compose.ui.platform.WindowInfo
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.assertIsNotDisplayed
import androidx.compose.ui.test.click
import androidx.compose.ui.test.hasPerformImeAction
import androidx.compose.ui.test.isDisplayed
@@ -587,6 +592,32 @@
}
@Test
+ fun cursorHandle_disappears_whenCodepointTransformationChanges() {
+ state = TextFieldState("hello")
+
+ var codepointTransformation: CodepointTransformation? by mutableStateOf(null)
+
+ rule.setContent {
+ BasicTextField(
+ state,
+ textStyle = TextStyle(fontSize = fontSize, fontFamily = TEST_FONT_FAMILY),
+ modifier = Modifier.testTag(TAG),
+ codepointTransformation = codepointTransformation,
+ )
+ }
+
+ focusAndWait()
+
+ rule.onNodeWithTag(TAG).performClick()
+ rule.onNode(isSelectionHandle(Handle.Cursor)).assertIsDisplayed()
+
+ codepointTransformation = CodepointTransformation.mask('c')
+
+ rule.waitForIdle()
+ rule.onNode(isSelectionHandle(Handle.Cursor)).assertIsNotDisplayed()
+ }
+
+ @Test
fun cursorHandleDrag_getsFiltered() {
state = TextFieldState("abc abc")
rule.setTextFieldTestContent {
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/Scrollable.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/Scrollable.kt
index 5d6a2da..f81e6db 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/Scrollable.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/Scrollable.kt
@@ -298,16 +298,6 @@
reverseDirection = reverseDirection,
flingBehavior = flingBehavior ?: defaultFlingBehavior,
nestedScrollDispatcher = nestedScrollDispatcher,
- shouldCancelFling = { flingPixels ->
- // fling should be cancelled if we try to scroll more than we can or if this node
- // is detached during a fling.
- // tries to scroll forward but cannot.
- (flingPixels > 0.0f && !state.canScrollForward) ||
- // tries to scroll backward but cannot.
- (flingPixels < 0.0f && !state.canScrollBackward) ||
- // node is detached.
- !isAttached
- }
)
private val nestedScrollConnection =
@@ -350,7 +340,12 @@
@OptIn(ExperimentalFoundationApi::class)
override fun onDragStopped(velocity: Velocity) {
- nestedScrollDispatcher.coroutineScope.launch { scrollingLogic.onDragStopped(velocity) }
+ if (NewNestedFlingPropagationEnabled) {
+ if (!isAttached) return
+ coroutineScope.launch { scrollingLogic.onDragStopped(velocity) }
+ } else {
+ nestedScrollDispatcher.coroutineScope.launch { scrollingLogic.onDragStopped(velocity) }
+ }
}
override fun startDragImmediately(): Boolean {
@@ -602,7 +597,6 @@
private var orientation: Orientation,
private var reverseDirection: Boolean,
private var nestedScrollDispatcher: NestedScrollDispatcher,
- private val shouldCancelFling: (Float) -> Boolean
) {
fun Float.toOffset(): Offset =
@@ -723,14 +717,20 @@
val reverseScope =
object : ScrollScope {
override fun scrollBy(pixels: Float): Float {
- // Fling has hit the bounds or node left composition,
- // cancel it to allow continuation. This will conclude this node's fling,
- // allowing the onPostFling signal to be called
+ // Fling has hit the bounds, cancel it to allow continuation. This will
+ // conclude this node's fling, allowing the onPostFling signal to be called
// with the leftover velocity from the fling animation. Any nested scroll
// node above will be able to pick up the left over velocity and continue
// the fling.
- if (NewNestedFlingPropagationEnabled && shouldCancelFling(pixels)) {
- throw FlingCancellationException()
+ if (NewNestedFlingPropagationEnabled) {
+ if (
+ pixels > 0.0f && !scrollableState.canScrollForward ||
+ pixels < 0.0f && !scrollableState.canScrollBackward
+ ) {
+ throw kotlin.coroutines.cancellation.CancellationException(
+ "The fling was cancelled"
+ )
+ }
}
return nestedScrollScope
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/BasicTextField.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/BasicTextField.kt
index 5d15ac5..36da905 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/BasicTextField.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/BasicTextField.kt
@@ -414,9 +414,10 @@
@Composable
internal fun TextFieldCursorHandle(selectionState: TextFieldSelectionState) {
// Does not recompose if only position of the handle changes.
- val cursorHandleState by remember {
- derivedStateOf { selectionState.getCursorHandleState(includePosition = false) }
- }
+ val cursorHandleState by
+ remember(selectionState) {
+ derivedStateOf { selectionState.getCursorHandleState(includePosition = false) }
+ }
if (cursorHandleState.visible) {
CursorHandle(
offsetProvider = {
diff --git a/compose/material/material-navigation/api/restricted_current.txt b/compose/material/material-navigation/api/restricted_current.txt
index dd70def..1dbe896 100644
--- a/compose/material/material-navigation/api/restricted_current.txt
+++ b/compose/material/material-navigation/api/restricted_current.txt
@@ -39,6 +39,7 @@
public final class NavGraphBuilderKt {
method public static void bottomSheet(androidx.navigation.NavGraphBuilder, String route, optional java.util.List<androidx.navigation.NamedNavArgument> arguments, optional java.util.List<androidx.navigation.NavDeepLink> deepLinks, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.layout.ColumnScope,? super androidx.navigation.NavBackStackEntry,kotlin.Unit> content);
method public static inline <reified T> void bottomSheet(androidx.navigation.NavGraphBuilder, optional java.util.Map<kotlin.reflect.KType,androidx.navigation.NavType<? extends java.lang.Object?>> typeMap, optional java.util.List<androidx.navigation.NamedNavArgument> arguments, optional java.util.List<androidx.navigation.NavDeepLink> deepLinks, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.layout.ColumnScope,? super androidx.navigation.NavBackStackEntry,kotlin.Unit> content);
+ method @kotlin.PublishedApi internal static void bottomSheet(androidx.navigation.NavGraphBuilder, kotlin.reflect.KClass<? extends java.lang.Object?> route, java.util.Map<kotlin.reflect.KType,androidx.navigation.NavType<? extends java.lang.Object?>> typeMap, java.util.List<androidx.navigation.NamedNavArgument> arguments, optional java.util.List<androidx.navigation.NavDeepLink> deepLinks, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.layout.ColumnScope,? super androidx.navigation.NavBackStackEntry,kotlin.Unit> content);
}
}
diff --git a/compose/material/material-navigation/src/main/java/androidx/compose/material/navigation/NavGraphBuilder.kt b/compose/material/material-navigation/src/main/java/androidx/compose/material/navigation/NavGraphBuilder.kt
index 9ecaa4b..f802f25 100644
--- a/compose/material/material-navigation/src/main/java/androidx/compose/material/navigation/NavGraphBuilder.kt
+++ b/compose/material/material-navigation/src/main/java/androidx/compose/material/navigation/NavGraphBuilder.kt
@@ -73,10 +73,21 @@
deepLinks: List<NavDeepLink> = emptyList(),
noinline content: @Composable ColumnScope.(backstackEntry: NavBackStackEntry) -> Unit
) {
+ bottomSheet(T::class, typeMap, arguments, deepLinks, content)
+}
+
+@PublishedApi
+internal fun NavGraphBuilder.bottomSheet(
+ route: KClass<*>,
+ typeMap: Map<KType, @JvmSuppressWildcards NavType<*>>,
+ arguments: List<NamedNavArgument>,
+ deepLinks: List<NavDeepLink> = emptyList(),
+ content: @Composable ColumnScope.(backstackEntry: NavBackStackEntry) -> Unit
+) {
destination(
BottomSheetNavigatorDestinationBuilder(
provider[BottomSheetNavigator::class],
- T::class,
+ route,
typeMap,
content
)
diff --git a/compose/material3/adaptive/adaptive-layout/src/commonMain/kotlin/androidx/compose/material3/adaptive/layout/AnimateBoundsModifier.kt b/compose/material3/adaptive/adaptive-layout/src/commonMain/kotlin/androidx/compose/material3/adaptive/layout/AnimateBoundsModifier.kt
index b055339..a90ff91 100644
--- a/compose/material3/adaptive/adaptive-layout/src/commonMain/kotlin/androidx/compose/material3/adaptive/layout/AnimateBoundsModifier.kt
+++ b/compose/material3/adaptive/adaptive-layout/src/commonMain/kotlin/androidx/compose/material3/adaptive/layout/AnimateBoundsModifier.kt
@@ -169,7 +169,6 @@
newSize
}
target.size = newSize
- createBoundsAnimationIfPossible()
}
fun updateTargetOffset(newOffset: IntOffset) {
@@ -185,26 +184,31 @@
newOffset
}
target.topLeft = newOffset
- createBoundsAnimationIfPossible()
}
fun updateAndGetCurrentBounds(fraction: Float): IntRect {
current =
- if (fraction == 0f) {
- origin.rect
- } else if (fraction == 1f) {
- target.rect
- } else if (boundsAnimation != null) {
- boundsAnimation!!.valueAtProgress(fraction)
- } else {
- InvalidIntRect
+ when (fraction) {
+ 0f -> origin.rect
+ 1f -> target.rect
+ else -> {
+ updateBoundsAnimationIfNeeded()
+ boundsAnimation?.valueAtProgress(fraction) ?: InvalidIntRect
+ }
}
return current
}
- private fun createBoundsAnimationIfPossible() {
- if (origin.isValid && target.isValid) {
+ private fun updateBoundsAnimationIfNeeded() {
+ if (!origin.isValid || !target.isValid) {
+ return
+ }
+ if (
+ boundsAnimation == null ||
+ boundsAnimation!!.initialValue != origin.rect ||
+ boundsAnimation!!.targetValue != target.rect
+ ) {
boundsAnimation =
TargetBasedAnimation(animationSpec, IntRectToVector, origin.rect, target.rect)
}
diff --git a/compose/material3/benchmark/src/androidTest/java/androidx/compose/material3/benchmark/SplitButtonBenchmark.kt b/compose/material3/benchmark/src/androidTest/java/androidx/compose/material3/benchmark/SplitButtonBenchmark.kt
index 8f3d4a6..9c1865c 100644
--- a/compose/material3/benchmark/src/androidTest/java/androidx/compose/material3/benchmark/SplitButtonBenchmark.kt
+++ b/compose/material3/benchmark/src/androidTest/java/androidx/compose/material3/benchmark/SplitButtonBenchmark.kt
@@ -21,18 +21,13 @@
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Edit
import androidx.compose.material.icons.outlined.KeyboardArrowDown
-import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
-import androidx.compose.material3.ElevatedSplitButton
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
-import androidx.compose.material3.FilledSplitButton
import androidx.compose.material3.Icon
-import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.OutlinedSplitButton
-import androidx.compose.material3.SplitButton
+import androidx.compose.material3.SplitButtonDefaults
+import androidx.compose.material3.SplitButtonLayout
import androidx.compose.material3.Text
-import androidx.compose.material3.TonalSplitButton
import androidx.compose.runtime.Composable
import androidx.compose.testutils.LayeredComposeTestCase
import androidx.compose.testutils.benchmark.ComposeBenchmarkRule
@@ -97,51 +92,77 @@
@Composable
override fun MeasuredContent() {
when (type) {
- SplitButtonType.SplitButton ->
- SplitButton(
+ SplitButtonType.Filled ->
+ SplitButtonLayout(
leadingButton = {
- Button(onClick = { /* Do something! */ }) { Text("Button") }
+ SplitButtonDefaults.LeadingButton(
+ onClick = { /* Do Nothing */ },
+ ) {
+ leadingContent()
+ }
},
trailingButton = {
- IconButton(onClick = { /* doSomething() */ }) {
- Icon(
- Icons.Outlined.Edit,
- contentDescription = "Localized description",
- )
+ SplitButtonDefaults.TrailingButton(
+ checked = false,
+ onCheckedChange = { /* Do Nothing */ },
+ ) {
+ trailingContent()
}
}
)
- SplitButtonType.Filled ->
- FilledSplitButton(
- onLeadingButtonClick = {},
- checked = false,
- onTrailingButtonClick = { /* Do Nothing */ },
- leadingContent = { leadingContent() },
- trailingContent = { trailingContent() },
- )
SplitButtonType.Tonal ->
- TonalSplitButton(
- onLeadingButtonClick = {},
- checked = false,
- onTrailingButtonClick = { /* Do Nothing */ },
- leadingContent = { leadingContent() },
- trailingContent = { trailingContent() },
+ SplitButtonLayout(
+ leadingButton = {
+ SplitButtonDefaults.TonalLeadingButton(
+ onClick = { /* Do Nothing */ },
+ ) {
+ leadingContent()
+ }
+ },
+ trailingButton = {
+ SplitButtonDefaults.TonalTrailingButton(
+ checked = false,
+ onCheckedChange = { /* Do Nothing */ },
+ ) {
+ trailingContent()
+ }
+ }
)
SplitButtonType.Elevated ->
- ElevatedSplitButton(
- onLeadingButtonClick = {},
- checked = false,
- onTrailingButtonClick = { /* Do Nothing */ },
- leadingContent = { leadingContent() },
- trailingContent = { trailingContent() },
+ SplitButtonLayout(
+ leadingButton = {
+ SplitButtonDefaults.ElevatedLeadingButton(
+ onClick = { /* Do Nothing */ },
+ ) {
+ leadingContent()
+ }
+ },
+ trailingButton = {
+ SplitButtonDefaults.ElevatedTrailingButton(
+ checked = false,
+ onCheckedChange = { /* Do Nothing */ },
+ ) {
+ trailingContent()
+ }
+ }
)
SplitButtonType.Outlined ->
- OutlinedSplitButton(
- onLeadingButtonClick = {},
- checked = false,
- onTrailingButtonClick = { /* Do Nothing */ },
- leadingContent = { leadingContent() },
- trailingContent = { trailingContent() },
+ SplitButtonLayout(
+ leadingButton = {
+ SplitButtonDefaults.OutlinedLeadingButton(
+ onClick = { /* Do Nothing */ },
+ ) {
+ leadingContent()
+ }
+ },
+ trailingButton = {
+ SplitButtonDefaults.OutlinedTrailingButton(
+ checked = false,
+ onCheckedChange = { /* Do Nothing */ },
+ ) {
+ trailingContent()
+ }
+ }
)
}
}
@@ -168,7 +189,6 @@
}
enum class SplitButtonType {
- SplitButton,
Filled,
Tonal,
Elevated,
diff --git a/compose/material3/material3/api/current.txt b/compose/material3/material3/api/current.txt
index f131965..dd78059 100644
--- a/compose/material3/material3/api/current.txt
+++ b/compose/material3/material3/api/current.txt
@@ -2119,8 +2119,15 @@
}
@SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi public final class SplitButtonDefaults {
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi @androidx.compose.runtime.Composable public void ElevatedLeadingButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.SplitButtonShapes shapes, optional androidx.compose.material3.ButtonColors colors, optional androidx.compose.material3.ButtonElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi @androidx.compose.runtime.Composable public void ElevatedTrailingButton(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.SplitButtonShapes shapes, optional androidx.compose.material3.ButtonColors colors, optional androidx.compose.material3.ButtonElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi @androidx.compose.runtime.Composable public void LeadingButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.SplitButtonShapes shapes, optional androidx.compose.material3.ButtonColors colors, optional androidx.compose.material3.ButtonElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
- method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi @androidx.compose.runtime.Composable public void TrailingButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, boolean checked, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.SplitButtonShapes shapes, optional androidx.compose.material3.ButtonColors colors, optional androidx.compose.material3.ButtonElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi @androidx.compose.runtime.Composable public void OutlinedLeadingButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.SplitButtonShapes shapes, optional androidx.compose.material3.ButtonColors colors, optional androidx.compose.material3.ButtonElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi @androidx.compose.runtime.Composable public void OutlinedTrailingButton(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.SplitButtonShapes shapes, optional androidx.compose.material3.ButtonColors colors, optional androidx.compose.material3.ButtonElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi @androidx.compose.runtime.Composable public void TonalLeadingButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.SplitButtonShapes shapes, optional androidx.compose.material3.ButtonColors colors, optional androidx.compose.material3.ButtonElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi @androidx.compose.runtime.Composable public void TonalTrailingButton(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.SplitButtonShapes shapes, optional androidx.compose.material3.ButtonColors colors, optional androidx.compose.material3.ButtonElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi @androidx.compose.runtime.Composable public void TrailingButton(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.SplitButtonShapes shapes, optional androidx.compose.material3.ButtonColors colors, optional androidx.compose.material3.ButtonElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi @androidx.compose.runtime.Composable public void TrailingButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.SplitButtonShapes shapes, optional androidx.compose.material3.ButtonColors colors, optional androidx.compose.material3.ButtonElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
method public androidx.compose.foundation.shape.CornerSize getInnerCornerSize();
method public androidx.compose.foundation.layout.PaddingValues getLeadingButtonContentPadding();
method public float getLeadingIconSize();
@@ -2141,11 +2148,7 @@
}
public final class SplitButtonKt {
- method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi @androidx.compose.runtime.Composable public static void ElevatedSplitButton(kotlin.jvm.functions.Function0<kotlin.Unit> onLeadingButtonClick, kotlin.jvm.functions.Function0<kotlin.Unit> onTrailingButtonClick, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> leadingContent, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> trailingContent, boolean checked, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.shape.CornerSize innerCornerSize, optional float spacing);
- method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi @androidx.compose.runtime.Composable public static void FilledSplitButton(kotlin.jvm.functions.Function0<kotlin.Unit> onLeadingButtonClick, kotlin.jvm.functions.Function0<kotlin.Unit> onTrailingButtonClick, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> leadingContent, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> trailingContent, boolean checked, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.shape.CornerSize innerCornerSize, optional float spacing);
- method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi @androidx.compose.runtime.Composable public static void OutlinedSplitButton(kotlin.jvm.functions.Function0<kotlin.Unit> onLeadingButtonClick, kotlin.jvm.functions.Function0<kotlin.Unit> onTrailingButtonClick, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> leadingContent, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> trailingContent, boolean checked, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.shape.CornerSize innerCornerSize, optional float spacing);
- method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi @androidx.compose.runtime.Composable public static void SplitButton(kotlin.jvm.functions.Function0<kotlin.Unit> leadingButton, kotlin.jvm.functions.Function0<kotlin.Unit> trailingButton, optional androidx.compose.ui.Modifier modifier, optional float spacing);
- method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi @androidx.compose.runtime.Composable public static void TonalSplitButton(kotlin.jvm.functions.Function0<kotlin.Unit> onLeadingButtonClick, kotlin.jvm.functions.Function0<kotlin.Unit> onTrailingButtonClick, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> leadingContent, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> trailingContent, boolean checked, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.shape.CornerSize innerCornerSize, optional float spacing);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi @androidx.compose.runtime.Composable public static void SplitButtonLayout(kotlin.jvm.functions.Function0<kotlin.Unit> leadingButton, kotlin.jvm.functions.Function0<kotlin.Unit> trailingButton, optional androidx.compose.ui.Modifier modifier, optional float spacing);
}
public final class SplitButtonShapes {
diff --git a/compose/material3/material3/api/restricted_current.txt b/compose/material3/material3/api/restricted_current.txt
index f131965..dd78059 100644
--- a/compose/material3/material3/api/restricted_current.txt
+++ b/compose/material3/material3/api/restricted_current.txt
@@ -2119,8 +2119,15 @@
}
@SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi public final class SplitButtonDefaults {
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi @androidx.compose.runtime.Composable public void ElevatedLeadingButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.SplitButtonShapes shapes, optional androidx.compose.material3.ButtonColors colors, optional androidx.compose.material3.ButtonElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi @androidx.compose.runtime.Composable public void ElevatedTrailingButton(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.SplitButtonShapes shapes, optional androidx.compose.material3.ButtonColors colors, optional androidx.compose.material3.ButtonElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi @androidx.compose.runtime.Composable public void LeadingButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.SplitButtonShapes shapes, optional androidx.compose.material3.ButtonColors colors, optional androidx.compose.material3.ButtonElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
- method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi @androidx.compose.runtime.Composable public void TrailingButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, boolean checked, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.SplitButtonShapes shapes, optional androidx.compose.material3.ButtonColors colors, optional androidx.compose.material3.ButtonElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi @androidx.compose.runtime.Composable public void OutlinedLeadingButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.SplitButtonShapes shapes, optional androidx.compose.material3.ButtonColors colors, optional androidx.compose.material3.ButtonElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi @androidx.compose.runtime.Composable public void OutlinedTrailingButton(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.SplitButtonShapes shapes, optional androidx.compose.material3.ButtonColors colors, optional androidx.compose.material3.ButtonElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi @androidx.compose.runtime.Composable public void TonalLeadingButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.SplitButtonShapes shapes, optional androidx.compose.material3.ButtonColors colors, optional androidx.compose.material3.ButtonElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi @androidx.compose.runtime.Composable public void TonalTrailingButton(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.SplitButtonShapes shapes, optional androidx.compose.material3.ButtonColors colors, optional androidx.compose.material3.ButtonElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi @androidx.compose.runtime.Composable public void TrailingButton(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.SplitButtonShapes shapes, optional androidx.compose.material3.ButtonColors colors, optional androidx.compose.material3.ButtonElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi @androidx.compose.runtime.Composable public void TrailingButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.SplitButtonShapes shapes, optional androidx.compose.material3.ButtonColors colors, optional androidx.compose.material3.ButtonElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
method public androidx.compose.foundation.shape.CornerSize getInnerCornerSize();
method public androidx.compose.foundation.layout.PaddingValues getLeadingButtonContentPadding();
method public float getLeadingIconSize();
@@ -2141,11 +2148,7 @@
}
public final class SplitButtonKt {
- method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi @androidx.compose.runtime.Composable public static void ElevatedSplitButton(kotlin.jvm.functions.Function0<kotlin.Unit> onLeadingButtonClick, kotlin.jvm.functions.Function0<kotlin.Unit> onTrailingButtonClick, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> leadingContent, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> trailingContent, boolean checked, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.shape.CornerSize innerCornerSize, optional float spacing);
- method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi @androidx.compose.runtime.Composable public static void FilledSplitButton(kotlin.jvm.functions.Function0<kotlin.Unit> onLeadingButtonClick, kotlin.jvm.functions.Function0<kotlin.Unit> onTrailingButtonClick, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> leadingContent, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> trailingContent, boolean checked, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.shape.CornerSize innerCornerSize, optional float spacing);
- method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi @androidx.compose.runtime.Composable public static void OutlinedSplitButton(kotlin.jvm.functions.Function0<kotlin.Unit> onLeadingButtonClick, kotlin.jvm.functions.Function0<kotlin.Unit> onTrailingButtonClick, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> leadingContent, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> trailingContent, boolean checked, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.shape.CornerSize innerCornerSize, optional float spacing);
- method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi @androidx.compose.runtime.Composable public static void SplitButton(kotlin.jvm.functions.Function0<kotlin.Unit> leadingButton, kotlin.jvm.functions.Function0<kotlin.Unit> trailingButton, optional androidx.compose.ui.Modifier modifier, optional float spacing);
- method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi @androidx.compose.runtime.Composable public static void TonalSplitButton(kotlin.jvm.functions.Function0<kotlin.Unit> onLeadingButtonClick, kotlin.jvm.functions.Function0<kotlin.Unit> onTrailingButtonClick, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> leadingContent, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> trailingContent, boolean checked, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.shape.CornerSize innerCornerSize, optional float spacing);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi @androidx.compose.runtime.Composable public static void SplitButtonLayout(kotlin.jvm.functions.Function0<kotlin.Unit> leadingButton, kotlin.jvm.functions.Function0<kotlin.Unit> trailingButton, optional androidx.compose.ui.Modifier modifier, optional float spacing);
}
public final class SplitButtonShapes {
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 d5987aa..2d8c46a 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
@@ -203,9 +203,9 @@
import androidx.compose.material3.samples.SmallExtendedFloatingActionButtonSample
import androidx.compose.material3.samples.SmallExtendedFloatingActionButtonTextSample
import androidx.compose.material3.samples.SmallFloatingActionButtonSample
-import androidx.compose.material3.samples.SplitButtonSample
import androidx.compose.material3.samples.SplitButtonWithIconSample
import androidx.compose.material3.samples.SplitButtonWithTextSample
+import androidx.compose.material3.samples.SplitButtonWithUnCheckableTrailingButtonSample
import androidx.compose.material3.samples.SquareButtonSample
import androidx.compose.material3.samples.StepRangeSliderSample
import androidx.compose.material3.samples.StepsSliderSample
@@ -1664,13 +1664,6 @@
val SplitButtonExamples =
listOf(
Example(
- name = "SplitButtonSample",
- description = SplitButtonExampleDescription,
- sourceUrl = SplitButtonSourceUrl
- ) {
- SplitButtonSample()
- },
- Example(
name = "FilledSplitButtonSample",
description = SplitButtonExampleDescription,
sourceUrl = SplitButtonSourceUrl
@@ -1678,6 +1671,13 @@
FilledSplitButtonSample()
},
Example(
+ name = "SplitButtonWithUnCheckableTrailingButtonSample",
+ description = SplitButtonExampleDescription,
+ sourceUrl = SplitButtonSourceUrl
+ ) {
+ SplitButtonWithUnCheckableTrailingButtonSample()
+ },
+ Example(
name = "TonalSplitButtonSample",
description = SplitButtonExampleDescription,
sourceUrl = SplitButtonSourceUrl
diff --git a/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/SplitButtonSamples.kt b/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/SplitButtonSamples.kt
index 3342355..0a7af3f 100644
--- a/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/SplitButtonSamples.kt
+++ b/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/SplitButtonSamples.kt
@@ -24,15 +24,11 @@
import androidx.compose.material.icons.filled.Edit
import androidx.compose.material.icons.filled.KeyboardArrowDown
import androidx.compose.material3.ButtonDefaults
-import androidx.compose.material3.ElevatedSplitButton
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
-import androidx.compose.material3.FilledSplitButton
import androidx.compose.material3.Icon
-import androidx.compose.material3.OutlinedSplitButton
-import androidx.compose.material3.SplitButton
import androidx.compose.material3.SplitButtonDefaults
+import androidx.compose.material3.SplitButtonLayout
import androidx.compose.material3.Text
-import androidx.compose.material3.TonalSplitButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@@ -49,10 +45,10 @@
@Sampled
@Composable
@Preview
-fun SplitButtonSample() {
+fun FilledSplitButtonSample() {
var checked by remember { mutableStateOf(false) }
- SplitButton(
+ SplitButtonLayout(
leadingButton = {
SplitButtonDefaults.LeadingButton(
onClick = { /* Do Nothing */ },
@@ -68,8 +64,8 @@
},
trailingButton = {
SplitButtonDefaults.TrailingButton(
- onClick = { checked = !checked },
checked = checked,
+ onCheckedChange = { checked = it },
modifier =
Modifier.semantics {
stateDescription = if (checked) "Checked" else "Unchecked"
@@ -98,36 +94,31 @@
@Sampled
@Composable
@Preview
-fun FilledSplitButtonSample() {
- var checked by remember { mutableStateOf(false) }
-
- FilledSplitButton(
- onLeadingButtonClick = {},
- checked = checked,
- onTrailingButtonClick = { checked = !checked },
- leadingContent = {
- Icon(
- Icons.Filled.Edit,
- modifier = Modifier.size(SplitButtonDefaults.LeadingIconSize),
- contentDescription = "Localized description"
- )
- Spacer(Modifier.size(ButtonDefaults.IconSpacing))
- Text("My Button")
- },
- trailingContent = {
- val rotation: Float by
- animateFloatAsState(
- targetValue = if (checked) 180f else 0f,
- label = "Trailing Icon Rotation"
+fun SplitButtonWithUnCheckableTrailingButtonSample() {
+ SplitButtonLayout(
+ leadingButton = {
+ SplitButtonDefaults.LeadingButton(
+ onClick = { /* Do Nothing */ },
+ ) {
+ Icon(
+ Icons.Filled.Edit,
+ modifier = Modifier.size(SplitButtonDefaults.LeadingIconSize),
+ contentDescription = "Localized description",
)
- Icon(
- Icons.Filled.KeyboardArrowDown,
- modifier =
- Modifier.size(SplitButtonDefaults.TrailingIconSize).graphicsLayer {
- this.rotationZ = rotation
- },
- contentDescription = "Localized description"
- )
+ Spacer(Modifier.size(ButtonDefaults.IconSpacing))
+ Text("My Button")
+ }
+ },
+ trailingButton = {
+ SplitButtonDefaults.TrailingButton(
+ onClick = { /* Do Nothing */ },
+ ) {
+ Icon(
+ Icons.Filled.KeyboardArrowDown,
+ modifier = Modifier.size(SplitButtonDefaults.TrailingIconSize),
+ contentDescription = "Localized description"
+ )
+ }
}
)
}
@@ -139,33 +130,44 @@
fun TonalSplitButtonSample() {
var checked by remember { mutableStateOf(false) }
- TonalSplitButton(
- onLeadingButtonClick = {},
- checked = checked,
- onTrailingButtonClick = { checked = !checked },
- leadingContent = {
- Icon(
- Icons.Filled.Edit,
- modifier = Modifier.size(SplitButtonDefaults.LeadingIconSize),
- contentDescription = "Localized description"
- )
- Spacer(Modifier.size(ButtonDefaults.IconSpacing))
- Text("My Button")
- },
- trailingContent = {
- val rotation: Float by
- animateFloatAsState(
- targetValue = if (checked) 180f else 0f,
- label = "Trailing Icon Rotation"
+ SplitButtonLayout(
+ leadingButton = {
+ SplitButtonDefaults.TonalLeadingButton(
+ onClick = { /* Do Nothing */ },
+ ) {
+ Icon(
+ Icons.Filled.Edit,
+ modifier = Modifier.size(SplitButtonDefaults.LeadingIconSize),
+ contentDescription = "Localized description",
)
- Icon(
- Icons.Filled.KeyboardArrowDown,
- modifier =
- Modifier.size(SplitButtonDefaults.TrailingIconSize).graphicsLayer {
- this.rotationZ = rotation
- },
- contentDescription = "Localized description"
- )
+ Spacer(Modifier.size(ButtonDefaults.IconSpacing))
+ Text("My Button")
+ }
+ },
+ trailingButton = {
+ SplitButtonDefaults.TonalTrailingButton(
+ checked = checked,
+ onCheckedChange = { checked = it },
+ // modifier =
+ // Modifier.semantics {
+ // stateDescription = if (checked) "Checked" else "Unchecked"
+ // contentDescription = "Toggle Button"
+ // },
+ ) {
+ val rotation: Float by
+ animateFloatAsState(
+ targetValue = if (checked) 180f else 0f,
+ label = "Trailing Icon Rotation"
+ )
+ Icon(
+ Icons.Filled.KeyboardArrowDown,
+ modifier =
+ Modifier.size(SplitButtonDefaults.TrailingIconSize).graphicsLayer {
+ this.rotationZ = rotation
+ },
+ contentDescription = "Localized description"
+ )
+ }
}
)
}
@@ -177,33 +179,44 @@
fun ElevatedSplitButtonSample() {
var checked by remember { mutableStateOf(false) }
- ElevatedSplitButton(
- onLeadingButtonClick = {},
- checked = checked,
- onTrailingButtonClick = { checked = !checked },
- leadingContent = {
- Icon(
- Icons.Filled.Edit,
- modifier = Modifier.size(SplitButtonDefaults.LeadingIconSize),
- contentDescription = "Localized description"
- )
- Spacer(Modifier.size(ButtonDefaults.IconSpacing))
- Text("My Button")
- },
- trailingContent = {
- val rotation: Float by
- animateFloatAsState(
- targetValue = if (checked) 180f else 0f,
- label = "Trailing Icon Rotation"
+ SplitButtonLayout(
+ leadingButton = {
+ SplitButtonDefaults.ElevatedLeadingButton(
+ onClick = { /* Do Nothing */ },
+ ) {
+ Icon(
+ Icons.Filled.Edit,
+ modifier = Modifier.size(SplitButtonDefaults.LeadingIconSize),
+ contentDescription = "Localized description",
)
- Icon(
- Icons.Filled.KeyboardArrowDown,
+ Spacer(Modifier.size(ButtonDefaults.IconSpacing))
+ Text("My Button")
+ }
+ },
+ trailingButton = {
+ SplitButtonDefaults.ElevatedTrailingButton(
+ checked = checked,
+ onCheckedChange = { checked = it },
modifier =
- Modifier.size(SplitButtonDefaults.TrailingIconSize).graphicsLayer {
- this.rotationZ = rotation
+ Modifier.semantics {
+ stateDescription = if (checked) "Checked" else "Unchecked"
+ contentDescription = "Toggle Button"
},
- contentDescription = "Localized description"
- )
+ ) {
+ val rotation: Float by
+ animateFloatAsState(
+ targetValue = if (checked) 180f else 0f,
+ label = "Trailing Icon Rotation"
+ )
+ Icon(
+ Icons.Filled.KeyboardArrowDown,
+ modifier =
+ Modifier.size(SplitButtonDefaults.TrailingIconSize).graphicsLayer {
+ this.rotationZ = rotation
+ },
+ contentDescription = "Localized description"
+ )
+ }
}
)
}
@@ -215,33 +228,44 @@
fun OutlinedSplitButtonSample() {
var checked by remember { mutableStateOf(false) }
- OutlinedSplitButton(
- onLeadingButtonClick = {},
- checked = checked,
- onTrailingButtonClick = { checked = !checked },
- leadingContent = {
- Icon(
- Icons.Filled.Edit,
- modifier = Modifier.size(SplitButtonDefaults.LeadingIconSize),
- contentDescription = "Localized description"
- )
- Spacer(Modifier.size(ButtonDefaults.IconSpacing))
- Text("My Button")
- },
- trailingContent = {
- val rotation: Float by
- animateFloatAsState(
- targetValue = if (checked) 180f else 0f,
- label = "Trailing Icon Rotation"
+ SplitButtonLayout(
+ leadingButton = {
+ SplitButtonDefaults.OutlinedLeadingButton(
+ onClick = { /* Do Nothing */ },
+ ) {
+ Icon(
+ Icons.Filled.Edit,
+ modifier = Modifier.size(SplitButtonDefaults.LeadingIconSize),
+ contentDescription = "Localized description",
)
- Icon(
- Icons.Filled.KeyboardArrowDown,
+ Spacer(Modifier.size(ButtonDefaults.IconSpacing))
+ Text("My Button")
+ }
+ },
+ trailingButton = {
+ SplitButtonDefaults.OutlinedTrailingButton(
+ checked = checked,
+ onCheckedChange = { checked = it },
modifier =
- Modifier.size(SplitButtonDefaults.TrailingIconSize).graphicsLayer {
- this.rotationZ = rotation
+ Modifier.semantics {
+ stateDescription = if (checked) "Checked" else "Unchecked"
+ contentDescription = "Toggle Button"
},
- contentDescription = "Localized description"
- )
+ ) {
+ val rotation: Float by
+ animateFloatAsState(
+ targetValue = if (checked) 180f else 0f,
+ label = "Trailing Icon Rotation"
+ )
+ Icon(
+ Icons.Filled.KeyboardArrowDown,
+ modifier =
+ Modifier.size(SplitButtonDefaults.TrailingIconSize).graphicsLayer {
+ this.rotationZ = rotation
+ },
+ contentDescription = "Localized description"
+ )
+ }
}
)
}
@@ -253,7 +277,7 @@
fun SplitButtonWithTextSample() {
var checked by remember { mutableStateOf(false) }
- SplitButton(
+ SplitButtonLayout(
leadingButton = {
SplitButtonDefaults.LeadingButton(
onClick = { /* Do Nothing */ },
@@ -263,8 +287,8 @@
},
trailingButton = {
SplitButtonDefaults.TrailingButton(
- onClick = { checked = !checked },
checked = checked,
+ onCheckedChange = { checked = it }
) {
val rotation: Float by
animateFloatAsState(
@@ -291,7 +315,7 @@
fun SplitButtonWithIconSample() {
var checked by remember { mutableStateOf(false) }
- SplitButton(
+ SplitButtonLayout(
leadingButton = {
SplitButtonDefaults.LeadingButton(
onClick = { /* Do Nothing */ },
@@ -305,8 +329,8 @@
},
trailingButton = {
SplitButtonDefaults.TrailingButton(
- onClick = { checked = !checked },
checked = checked,
+ onCheckedChange = { checked = it }
) {
val rotation: Float by
animateFloatAsState(
diff --git a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/SplitButtonScreenshotTest.kt b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/SplitButtonScreenshotTest.kt
index bfe9fa0..3fb8f8d 100644
--- a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/SplitButtonScreenshotTest.kt
+++ b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/SplitButtonScreenshotTest.kt
@@ -19,12 +19,10 @@
import android.os.Build
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Spacer
-import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Edit
-import androidx.compose.material.icons.filled.KeyboardArrowDown
import androidx.compose.material.icons.outlined.KeyboardArrowDown
import androidx.compose.testutils.assertAgainstGolden
import androidx.compose.ui.Alignment
@@ -58,10 +56,10 @@
private val trailingButtonTag = "trailingButton"
@Test
- fun splitButton() {
+ fun filledSplitButton() {
rule.setMaterialContent(scheme.colorScheme) {
Box(wrap.testTag(wrapperTestTag)) {
- SplitButton(
+ SplitButtonLayout(
leadingButton = {
SplitButtonDefaults.LeadingButton(
onClick = { /* Do Nothing */ },
@@ -77,8 +75,8 @@
},
trailingButton = {
SplitButtonDefaults.TrailingButton(
- onClick = {},
checked = false,
+ onCheckedChange = {},
) {
Icon(
Icons.Outlined.KeyboardArrowDown,
@@ -95,67 +93,36 @@
}
@Test
- fun filledSplitButton() {
+ fun filledSplitButtonChecked() {
rule.setMaterialContent(scheme.colorScheme) {
Box(wrap.testTag(wrapperTestTag)) {
- FilledSplitButton(
- onLeadingButtonClick = {},
- onTrailingButtonClick = {},
- checked = false,
- leadingContent = {
- Icon(
- Icons.Filled.Edit,
- contentDescription = "Localized description",
- Modifier.size(SplitButtonDefaults.LeadingIconSize)
- )
- Spacer(Modifier.size(ButtonDefaults.IconSpacing))
- Text("My Button")
+ SplitButtonLayout(
+ leadingButton = {
+ SplitButtonDefaults.LeadingButton(
+ onClick = { /* Do Nothing */ },
+ ) {
+ Icon(
+ Icons.Filled.Edit,
+ modifier = Modifier.size(SplitButtonDefaults.LeadingIconSize),
+ contentDescription = "Localized description",
+ )
+ Spacer(Modifier.size(ButtonDefaults.IconSpacing))
+ Text("My Button")
+ }
},
- trailingContent = {
- Box(
- modifier = Modifier.fillMaxHeight(),
- contentAlignment = Alignment.Center
+ trailingButton = {
+ SplitButtonDefaults.TrailingButton(
+ checked = true,
+ onCheckedChange = {},
) {
Icon(
Icons.Outlined.KeyboardArrowDown,
contentDescription = "Localized description",
- Modifier.size(SplitButtonDefaults.TrailingIconSize)
- )
- }
- }
- )
- }
- }
-
- assertAgainstGolden("filledSplitButton_${scheme.name}")
- }
-
- @Test
- fun filledSplitButtonChecked() {
- rule.setMaterialContent(scheme.colorScheme) {
- Box(wrap.testTag(wrapperTestTag)) {
- FilledSplitButton(
- onLeadingButtonClick = {},
- checked = true,
- onTrailingButtonClick = {},
- leadingContent = {
- Icon(
- Icons.Filled.Edit,
- contentDescription = "Localized description",
- Modifier.size(SplitButtonDefaults.LeadingIconSize)
- )
- Spacer(Modifier.size(ButtonDefaults.IconSpacing))
- Text("My Button")
- },
- trailingContent = {
- Icon(
- Icons.Filled.KeyboardArrowDown,
- modifier =
Modifier.size(SplitButtonDefaults.TrailingIconSize).graphicsLayer {
this.rotationZ = 180f
},
- contentDescription = "Localized description"
- )
+ )
+ }
}
)
}
@@ -168,21 +135,25 @@
fun tonalSplitButton() {
rule.setMaterialContent(scheme.colorScheme) {
Box(wrap.testTag(wrapperTestTag)) {
- TonalSplitButton(
- onLeadingButtonClick = {},
- onTrailingButtonClick = {},
- checked = false,
- leadingContent = {
- Icon(
- Icons.Filled.Edit,
- contentDescription = "Localized description",
- Modifier.size(SplitButtonDefaults.LeadingIconSize)
- )
- Spacer(Modifier.size(ButtonDefaults.IconSpacing))
- Text("My Button")
+ SplitButtonLayout(
+ leadingButton = {
+ SplitButtonDefaults.TonalLeadingButton(
+ onClick = { /* Do Nothing */ },
+ ) {
+ Icon(
+ Icons.Filled.Edit,
+ modifier = Modifier.size(SplitButtonDefaults.LeadingIconSize),
+ contentDescription = "Localized description",
+ )
+ Spacer(Modifier.size(ButtonDefaults.IconSpacing))
+ Text("My Button")
+ }
},
- trailingContent = {
- Box(Modifier.fillMaxHeight(), contentAlignment = Alignment.Center) {
+ trailingButton = {
+ SplitButtonDefaults.TonalTrailingButton(
+ checked = false,
+ onCheckedChange = {},
+ ) {
Icon(
Icons.Outlined.KeyboardArrowDown,
contentDescription = "Localized description",
@@ -201,21 +172,25 @@
fun elevatedSplitButton() {
rule.setMaterialContent(scheme.colorScheme) {
Box(wrap.testTag(wrapperTestTag)) {
- ElevatedSplitButton(
- onLeadingButtonClick = {},
- onTrailingButtonClick = {},
- checked = false,
- leadingContent = {
- Icon(
- Icons.Filled.Edit,
- contentDescription = "Localized description",
- Modifier.size(SplitButtonDefaults.LeadingIconSize)
- )
- Spacer(Modifier.size(ButtonDefaults.IconSpacing))
- Text("My Button")
+ SplitButtonLayout(
+ leadingButton = {
+ SplitButtonDefaults.ElevatedLeadingButton(
+ onClick = { /* Do Nothing */ },
+ ) {
+ Icon(
+ Icons.Filled.Edit,
+ modifier = Modifier.size(SplitButtonDefaults.LeadingIconSize),
+ contentDescription = "Localized description",
+ )
+ Spacer(Modifier.size(ButtonDefaults.IconSpacing))
+ Text("My Button")
+ }
},
- trailingContent = {
- Box(Modifier.fillMaxHeight(), contentAlignment = Alignment.Center) {
+ trailingButton = {
+ SplitButtonDefaults.ElevatedTrailingButton(
+ checked = false,
+ onCheckedChange = {},
+ ) {
Icon(
Icons.Outlined.KeyboardArrowDown,
contentDescription = "Localized description",
@@ -234,21 +209,25 @@
fun outlinedSplitButton() {
rule.setMaterialContent(scheme.colorScheme) {
Box(wrap.testTag(wrapperTestTag)) {
- OutlinedSplitButton(
- onLeadingButtonClick = {},
- onTrailingButtonClick = {},
- checked = false,
- leadingContent = {
- Icon(
- Icons.Filled.Edit,
- contentDescription = "Localized description",
- Modifier.size(SplitButtonDefaults.LeadingIconSize)
- )
- Spacer(Modifier.size(ButtonDefaults.IconSpacing))
- Text("My Button")
+ SplitButtonLayout(
+ leadingButton = {
+ SplitButtonDefaults.OutlinedLeadingButton(
+ onClick = { /* Do Nothing */ },
+ ) {
+ Icon(
+ Icons.Filled.Edit,
+ modifier = Modifier.size(SplitButtonDefaults.LeadingIconSize),
+ contentDescription = "Localized description",
+ )
+ Spacer(Modifier.size(ButtonDefaults.IconSpacing))
+ Text("My Button")
+ }
},
- trailingContent = {
- Box(Modifier.fillMaxHeight(), contentAlignment = Alignment.Center) {
+ trailingButton = {
+ SplitButtonDefaults.OutlinedTrailingButton(
+ checked = false,
+ onCheckedChange = {},
+ ) {
Icon(
Icons.Outlined.KeyboardArrowDown,
contentDescription = "Localized description",
@@ -267,7 +246,7 @@
fun splitButton_iconLeadingButton() {
rule.setMaterialContent(scheme.colorScheme) {
Box(wrap.testTag(wrapperTestTag)) {
- SplitButton(
+ SplitButtonLayout(
leadingButton = {
SplitButtonDefaults.LeadingButton(
onClick = { /* Do Nothing */ },
@@ -281,8 +260,8 @@
},
trailingButton = {
SplitButtonDefaults.TrailingButton(
- onClick = {},
checked = false,
+ onCheckedChange = {},
) {
Icon(
Icons.Outlined.KeyboardArrowDown,
@@ -302,7 +281,7 @@
fun splitButton_textLeadingButton() {
rule.setMaterialContent(scheme.colorScheme) {
Box(wrap.testTag(wrapperTestTag)) {
- SplitButton(
+ SplitButtonLayout(
leadingButton = {
SplitButtonDefaults.LeadingButton(
onClick = { /* Do Nothing */ },
@@ -311,7 +290,7 @@
}
},
trailingButton = {
- SplitButtonDefaults.TrailingButton(onClick = {}, checked = false) {
+ SplitButtonDefaults.TrailingButton(checked = false, onCheckedChange = {}) {
Icon(
Icons.Outlined.KeyboardArrowDown,
contentDescription = "Localized description",
@@ -330,7 +309,7 @@
fun splitButton_leadingButton_pressed() {
rule.setMaterialContent(scheme.colorScheme) {
Box(wrap.testTag(wrapperTestTag)) {
- SplitButton(
+ SplitButtonLayout(
leadingButton = {
SplitButtonDefaults.LeadingButton(
onClick = { /* Do Nothing */ },
@@ -347,8 +326,8 @@
},
trailingButton = {
SplitButtonDefaults.TrailingButton(
- onClick = {},
checked = false,
+ onCheckedChange = {},
) {
Icon(
Icons.Outlined.KeyboardArrowDown,
@@ -368,7 +347,7 @@
fun splitButton_trailingButton_pressed() {
rule.setMaterialContent(scheme.colorScheme) {
Box(wrap.testTag(wrapperTestTag)) {
- SplitButton(
+ SplitButtonLayout(
leadingButton = {
SplitButtonDefaults.LeadingButton(
onClick = { /* Do Nothing */ },
@@ -384,8 +363,8 @@
},
trailingButton = {
SplitButtonDefaults.TrailingButton(
- onClick = {},
checked = false,
+ onCheckedChange = {},
modifier = Modifier.testTag(trailingButtonTag),
) {
Icon(
diff --git a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/SplitButtonTest.kt b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/SplitButtonTest.kt
index bb8c0ba..0a9014c 100644
--- a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/SplitButtonTest.kt
+++ b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/SplitButtonTest.kt
@@ -35,7 +35,6 @@
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.unit.dp
-import androidx.compose.ui.unit.sp
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest
import org.junit.Rule
@@ -45,14 +44,14 @@
@MediumTest
@RunWith(AndroidJUnit4::class)
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
+// TODO: b/370605854 - Add test case for checked trailing button
class SplitButtonTest {
-
@get:Rule val rule = createComposeRule()
@Test
- fun basicSplitButton_contentDisplay() {
+ fun filledSplitButton_contentDisplay() {
rule.setMaterialContent(lightColorScheme()) {
- SplitButton(
+ SplitButtonLayout(
leadingButton = {
SplitButtonDefaults.LeadingButton(
onClick = { /* Do Nothing */ },
@@ -70,7 +69,7 @@
SplitButtonDefaults.TrailingButton(
modifier = Modifier.size(34.dp).testTag("trailingButton"),
checked = false,
- onClick = {},
+ onCheckedChange = {},
) {
Icon(Icons.Outlined.KeyboardArrowDown, contentDescription = "Trailing Icon")
}
@@ -86,9 +85,9 @@
}
@Test
- fun basicSplitButton_defaultSemantics() {
+ fun filledSplitButton_defaultSemantics() {
rule.setMaterialContent(lightColorScheme()) {
- SplitButton(
+ SplitButtonLayout(
leadingButton = {
SplitButtonDefaults.LeadingButton(
onClick = { /* Do Nothing */ },
@@ -99,7 +98,7 @@
},
trailingButton = {
SplitButtonDefaults.TrailingButton(
- onClick = {},
+ onCheckedChange = {},
checked = false,
modifier = Modifier.size(34.dp).testTag("trailing button"),
) {
@@ -114,15 +113,15 @@
assertIsEnabled()
}
rule.onNodeWithTag("trailing button").apply {
- assert(SemanticsMatcher.expectValue(SemanticsProperties.Role, Role.Button))
+ assert(SemanticsMatcher.expectValue(SemanticsProperties.Role, Role.Checkbox))
assertIsEnabled()
}
}
@Test
- fun basicSplitButton_disabledSemantics() {
+ fun filledSplitButton_disabledSemantics() {
rule.setMaterialContent(lightColorScheme()) {
- SplitButton(
+ SplitButtonLayout(
leadingButton = {
SplitButtonDefaults.LeadingButton(
onClick = { /* Do Nothing */ },
@@ -134,7 +133,7 @@
},
trailingButton = {
SplitButtonDefaults.TrailingButton(
- onClick = {},
+ onCheckedChange = {},
checked = false,
modifier = Modifier.size(34.dp).testTag("trailing button"),
enabled = false,
@@ -150,56 +149,36 @@
assertIsNotEnabled()
}
rule.onNodeWithTag("trailing button").apply {
- assert(SemanticsMatcher.expectValue(SemanticsProperties.Role, Role.Button))
+ assert(SemanticsMatcher.expectValue(SemanticsProperties.Role, Role.Checkbox))
assertIsNotEnabled()
}
}
@Test
- fun FilledSplitButton_contentDisplay() {
- rule.setMaterialContent(lightColorScheme()) {
- FilledSplitButton(
- onLeadingButtonClick = {},
- checked = false,
- onTrailingButtonClick = {},
- leadingContent = {
- Icon(
- Icons.Outlined.Edit,
- contentDescription = "Leading Icon",
- modifier = Modifier.size(48.dp)
- )
- Spacer(Modifier.size(ButtonDefaults.IconSpacing))
- Text("My Button", fontSize = 15.sp)
- },
- trailingContent = {
- Icon(Icons.Outlined.KeyboardArrowDown, contentDescription = "Trailing Icon")
- }
- )
- }
-
- rule.onNodeWithText("My Button").assertIsDisplayed()
- rule.onNodeWithContentDescription("Leading Icon").assertIsDisplayed()
- rule.onNodeWithContentDescription("Trailing Icon").assertIsDisplayed()
- }
-
- @Test
fun TonalSplitButton_contentDisplay() {
rule.setMaterialContent(lightColorScheme()) {
- TonalSplitButton(
- onLeadingButtonClick = {},
- checked = false,
- onTrailingButtonClick = {},
- leadingContent = {
- Icon(
- Icons.Outlined.Edit,
- contentDescription = "Leading Icon",
- modifier = Modifier.size(48.dp)
- )
- Spacer(Modifier.size(ButtonDefaults.IconSpacing))
- Text("My Button", fontSize = 15.sp)
+ SplitButtonLayout(
+ leadingButton = {
+ SplitButtonDefaults.TonalLeadingButton(
+ onClick = { /* Do Nothing */ },
+ modifier = Modifier.testTag("leadingButton")
+ ) {
+ Icon(
+ Icons.Outlined.Edit,
+ contentDescription = "Leading Icon",
+ )
+ Spacer(Modifier.size(ButtonDefaults.IconSpacing))
+ Text("My Button")
+ }
},
- trailingContent = {
- Icon(Icons.Outlined.KeyboardArrowDown, contentDescription = "Trailing Icon")
+ trailingButton = {
+ SplitButtonDefaults.TonalTrailingButton(
+ modifier = Modifier.size(34.dp).testTag("trailingButton"),
+ checked = false,
+ onCheckedChange = {},
+ ) {
+ Icon(Icons.Outlined.KeyboardArrowDown, contentDescription = "Trailing Icon")
+ }
}
)
}
@@ -212,21 +191,28 @@
@Test
fun ElevatedSplitButton_contentDisplay() {
rule.setMaterialContent(lightColorScheme()) {
- ElevatedSplitButton(
- onLeadingButtonClick = {},
- checked = false,
- onTrailingButtonClick = {},
- leadingContent = {
- Icon(
- Icons.Outlined.Edit,
- contentDescription = "Leading Icon",
- modifier = Modifier.size(48.dp)
- )
- Spacer(Modifier.size(ButtonDefaults.IconSpacing))
- Text("My Button", fontSize = 15.sp)
+ SplitButtonLayout(
+ leadingButton = {
+ SplitButtonDefaults.ElevatedLeadingButton(
+ onClick = { /* Do Nothing */ },
+ modifier = Modifier.testTag("leadingButton")
+ ) {
+ Icon(
+ Icons.Outlined.Edit,
+ contentDescription = "Leading Icon",
+ )
+ Spacer(Modifier.size(ButtonDefaults.IconSpacing))
+ Text("My Button")
+ }
},
- trailingContent = {
- Icon(Icons.Outlined.KeyboardArrowDown, contentDescription = "Trailing Icon")
+ trailingButton = {
+ SplitButtonDefaults.ElevatedTrailingButton(
+ modifier = Modifier.size(34.dp).testTag("trailingButton"),
+ checked = false,
+ onCheckedChange = {},
+ ) {
+ Icon(Icons.Outlined.KeyboardArrowDown, contentDescription = "Trailing Icon")
+ }
}
)
}
@@ -239,21 +225,28 @@
@Test
fun OutlinedSplitButton_contentDisplay() {
rule.setMaterialContent(lightColorScheme()) {
- OutlinedSplitButton(
- onLeadingButtonClick = {},
- checked = false,
- onTrailingButtonClick = {},
- leadingContent = {
- Icon(
- Icons.Outlined.Edit,
- contentDescription = "Leading Icon",
- modifier = Modifier.size(48.dp)
- )
- Spacer(Modifier.size(ButtonDefaults.IconSpacing))
- Text("My Button", fontSize = 15.sp)
+ SplitButtonLayout(
+ leadingButton = {
+ SplitButtonDefaults.OutlinedLeadingButton(
+ onClick = { /* Do Nothing */ },
+ modifier = Modifier.testTag("leadingButton")
+ ) {
+ Icon(
+ Icons.Outlined.Edit,
+ contentDescription = "Leading Icon",
+ )
+ Spacer(Modifier.size(ButtonDefaults.IconSpacing))
+ Text("My Button")
+ }
},
- trailingContent = {
- Icon(Icons.Outlined.KeyboardArrowDown, contentDescription = "Trailing Icon")
+ trailingButton = {
+ SplitButtonDefaults.OutlinedTrailingButton(
+ modifier = Modifier.size(34.dp).testTag("trailingButton"),
+ checked = false,
+ onCheckedChange = {},
+ ) {
+ Icon(Icons.Outlined.KeyboardArrowDown, contentDescription = "Trailing Icon")
+ }
}
)
}
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/SplitButton.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/SplitButton.kt
index e2e3cae..2bf0c6d 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/SplitButton.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/SplitButton.kt
@@ -63,346 +63,54 @@
import androidx.compose.ui.util.fastSumBy
/**
- * A [SplitButton] let user define a button group consisting of 2 buttons. The leading button
+ * A [SplitButtonLayout] let user define a button group consisting of 2 buttons. The leading button
* performs a primary action, and the trailing button performs a secondary action that is
* contextually related to the primary action.
*
- * @sample androidx.compose.material3.samples.SplitButtonSample
+ * @sample androidx.compose.material3.samples.FilledSplitButtonSample
+ * @sample androidx.compose.material3.samples.TonalSplitButtonSample
+ * @sample androidx.compose.material3.samples.ElevatedSplitButtonSample
+ * @sample androidx.compose.material3.samples.OutlinedSplitButtonSample
+ * @sample androidx.compose.material3.samples.SplitButtonWithUnCheckableTrailingButtonSample
* @sample androidx.compose.material3.samples.SplitButtonWithTextSample
* @sample androidx.compose.material3.samples.SplitButtonWithIconSample
*
* Choose the best split button for an action based on the amount of emphasis it needs. The more
* important an action is, the higher emphasis its button should be.
*
+ * Use [SplitButtonDefaults.LeadingButton] and [SplitButtonDefaults.TrailingButton] to construct a
+ * `FilledSplitButton`. Filled split button is the high-emphasis version of split button. It should
+ * be used for emphasizing important or final actions.
+ *
+ * Use [SplitButtonDefaults.TonalLeadingButton] and [SplitButtonDefaults.TonalTrailingButton] to
+ * construct a `tonal SplitButton`. Tonal split button is the medium-emphasis version of split
+ * buttons. It's a middle ground between `filled SplitButton` and `outlined SplitButton`
+ *
+ * Use [SplitButtonDefaults.ElevatedLeadingButton] and [SplitButtonDefaults.ElevatedTrailingButton]
+ * to construct a `elevated SplitButton`. Elevated split buttons are essentially `tonal
+ * SplitButton`s with a shadow. To prevent shadow creep, only use them when absolutely necessary,
+ * such as when the button requires visual separation from patterned container.
+ *
+ * Use [SplitButtonDefaults.OutlinedLeadingButton] and [SplitButtonDefaults.OutlinedTrailingButton]
+ * to construct a `outlined SplitButton`. Outlined split buttons are medium-emphasis buttons. They
+ * contain actions that are important, but are not the primary action in an app. Outlined buttons
+ * pair well with `filled SplitButton`s to indicate an alternative, secondary action.
+ *
* @param leadingButton the leading button. You can specify your own composable or construct a
* [SplitButtonDefaults.LeadingButton]
* @param trailingButton the trailing button.You can specify your own composable or construct a
* [SplitButtonDefaults.TrailingButton]
* @param modifier the [Modifier] to be applied to this split button.
* @param spacing The spacing between the [leadingButton] and [trailingButton]
- * @see FilledSplitButton for a high-emphasis split button without a shadow.
- * @see OutlinedSplitButton for a medium-emphasis split button with a border.
- * @see TonalSplitButton for a middle ground between [OutlinedSplitButton] and [FilledSplitButton].
- * @see ElevatedSplitButton for an [TonalSplitButton] with a shadow.
*/
@ExperimentalMaterial3ExpressiveApi
@Composable
-fun SplitButton(
+fun SplitButtonLayout(
leadingButton: @Composable () -> Unit,
trailingButton: @Composable () -> Unit,
modifier: Modifier = Modifier,
spacing: Dp = SplitButtonDefaults.Spacing,
) {
- SplitButtonLayout(
- leadingButton,
- trailingButton,
- spacing,
- modifier.minimumInteractiveComponentSize()
- )
-}
-
-/**
- * A [SplitButton] let user define a button group consisting of 2 buttons. The leading button
- * performs a primary action, and the trailing button performs a secondary action that is
- * contextually related to the primary action.
- *
- * Filled split button is the high-emphasis version of split button. It should be used for
- * emphasizing important or final actions.
- *
- * @sample androidx.compose.material3.samples.FilledSplitButtonSample
- *
- * Choose the best split button for an action based on the amount of emphasis it needs. The more
- * important an action is, the higher emphasis its button should be.
- *
- * @param onLeadingButtonClick called when the leading button is clicked
- * @param onTrailingButtonClick called when the trailing button is clicked
- * @param leadingContent the content to be placed inside the leading button. A container will be
- * provided internally to offer the standard design and style for a [FilledSplitButton].
- * @param trailingContent the content to be placed inside the trailing button. A container is
- * provided internally to ensure the standard design and style of a [FilledSplitButton]. The
- * container corner radius morphs to `full` when the [checked] state changes to `true`.
- * @param checked indicates if the trailing button is toggled. This can be used to indicate a new
- * state that's a result of [onTrailingButtonClick]. For example, a drop down menu or pop up.
- * @param modifier the [Modifier] to be applied to this this split button.
- * @param enabled controls the enabled state of the split button. When `false`, this component will
- * not respond to user input, and it will appear visually disabled and disabled to accessibility
- * services.
- * @param innerCornerSize The size for leading button's end corners and trailing button's start
- * corners
- * @param spacing The spacing between the leading and trailing buttons
- * @see OutlinedSplitButton for a medium-emphasis split button with a border.
- * @see TonalSplitButton for a middle ground between [OutlinedSplitButton] and [FilledSplitButton].
- * @see ElevatedSplitButton for an [TonalSplitButton] with a shadow.
- *
- * The default text style for internal [Text] components will be set to [Typography.labelLarge].
- */
-@ExperimentalMaterial3ExpressiveApi
-@Composable
-fun FilledSplitButton(
- onLeadingButtonClick: () -> Unit,
- onTrailingButtonClick: () -> Unit,
- leadingContent: @Composable RowScope.() -> Unit,
- trailingContent: @Composable RowScope.() -> Unit,
- checked: Boolean,
- modifier: Modifier = Modifier,
- enabled: Boolean = true,
- innerCornerSize: CornerSize = SplitButtonDefaults.InnerCornerSize,
- spacing: Dp = SplitButtonDefaults.Spacing
-) {
- SplitButton(
- modifier = modifier,
- spacing = spacing,
- leadingButton = {
- SplitButtonDefaults.LeadingButton(
- onClick = onLeadingButtonClick,
- enabled = enabled,
- shapes = SplitButtonDefaults.leadingButtonShapes(innerCornerSize),
- content = leadingContent
- )
- },
- trailingButton = {
- SplitButtonDefaults.TrailingButton(
- onClick = onTrailingButtonClick,
- modifier = Modifier,
- enabled = enabled,
- checked = checked,
- shapes =
- SplitButtonDefaults.trailingButtonShapes(startCornerSize = innerCornerSize),
- content = trailingContent,
- )
- },
- )
-}
-
-/**
- * A [SplitButton] let user define a button group consisting of 2 buttons. The leading button
- * performs a primary action, and the trailing button performs a secondary action that is
- * contextually related to the primary action.
- *
- * Tonal split button is the medium-emphasis version of split buttons. It's a middle ground between
- * [FilledSplitButton] and [OutlinedSplitButton]
- *
- * @sample androidx.compose.material3.samples.TonalSplitButtonSample
- *
- * Choose the best split button for an action based on the amount of emphasis it needs. The more
- * important an action is, the higher emphasis its button should be.
- *
- * @param onLeadingButtonClick called when the leading button is clicked
- * @param onTrailingButtonClick called when the trailing button is clicked
- * @param leadingContent the content to be placed inside the leading button. A container will be
- * provided internally to offer the standard design and style for a [TonalSplitButton].
- * @param trailingContent the content to be placed inside the trailing button. A container is
- * provided internally to ensure the standard design and style of a [TonalSplitButton]. The
- * container corner radius morphs to full when the [checked] state changes to `true`.
- * @param checked indicates if the trailing button is toggled. This can be used to indicate a new
- * state that's a result of [onTrailingButtonClick]. For example, a drop down menu or pop up.
- * @param modifier the [Modifier] to be applied to this split button.
- * @param enabled controls the enabled state of the split button. When `false`, this component will
- * not respond to user input, and it will appear visually disabled and disabled to accessibility
- * services.
- * @param innerCornerSize The size for leading button's end corners and trailing button's start
- * corners
- * @param spacing The spacing between the leading and trailing buttons
- * @see FilledSplitButton for a high-emphasis split button without a shadow.
- * @see OutlinedSplitButton for a medium-emphasis split button with a border.
- * @see ElevatedSplitButton for an [TonalSplitButton] with a shadow.
- *
- * The default text style for internal [Text] components will be set to [Typography.labelLarge].
- */
-@ExperimentalMaterial3ExpressiveApi
-@Composable
-fun TonalSplitButton(
- onLeadingButtonClick: () -> Unit,
- onTrailingButtonClick: () -> Unit,
- leadingContent: @Composable RowScope.() -> Unit,
- trailingContent: @Composable RowScope.() -> Unit,
- checked: Boolean,
- modifier: Modifier = Modifier,
- enabled: Boolean = true,
- innerCornerSize: CornerSize = SplitButtonDefaults.InnerCornerSize,
- spacing: Dp = SplitButtonDefaults.Spacing
-) {
- SplitButton(
- leadingButton = {
- TonalLeadingButton(
- onClick = onLeadingButtonClick,
- modifier = Modifier,
- enabled = enabled,
- shapes = SplitButtonDefaults.leadingButtonShapes(endCornerSize = innerCornerSize),
- content = leadingContent,
- )
- },
- trailingButton = {
- TonalTrailingButton(
- onClick = onTrailingButtonClick,
- modifier = Modifier,
- enabled = enabled,
- checked = checked,
- shapes = SplitButtonDefaults.trailingButtonShapes(innerCornerSize),
- content = trailingContent,
- )
- },
- modifier = modifier,
- spacing = spacing
- )
-}
-
-/**
- * A [SplitButton] let user define a button group consisting of 2 buttons. The leading button
- * performs a primary action, and the trailing button performs a secondary action that is
- * contextually related to the primary action.
- *
- * Elevated split buttons are essentially [OutlinedSplitButton]s with a shadow. To prevent shadow
- * creep, only use them when absolutely necessary, such as when the button requires visual
- * separation from patterned container.
- *
- * @sample androidx.compose.material3.samples.ElevatedSplitButtonSample
- *
- * Choose the best split button for an action based on the amount of emphasis it needs. The more
- * important an action is, the higher emphasis its button should be.
- *
- * @param onLeadingButtonClick called when the leading button is clicked
- * @param onTrailingButtonClick called when the trailing button is clicked
- * @param leadingContent the content to be placed inside the leading button. A container will be
- * provided internally to offer the standard design and style for a [ElevatedSplitButton].
- * @param trailingContent the content to be placed inside the trailing button. A container is
- * provided internally to ensure the standard design and style of a [ElevatedSplitButton]. The
- * container corner radius morphs to full when the [checked] state changes to `true`.
- * @param checked indicates if the trailing button is toggled. This can be used to indicate a new
- * state that's a result of [onTrailingButtonClick]. For example, a drop down menu or pop up.
- * @param modifier the [Modifier] to be applied to this split button.
- * @param enabled controls the enabled state of the split button. When `false`, this component will
- * not respond to user input, and it will appear visually disabled and disabled to accessibility
- * services.
- * @param innerCornerSize The size for leading button's end corners and trailing button's start
- * corners
- * @param spacing The spacing between the leading and trailing buttons
- * @see FilledSplitButton for a high-emphasis split button without a shadow.
- * @see OutlinedSplitButton for a medium-emphasis split button with a border.
- * @see TonalSplitButton for a middle ground between [OutlinedSplitButton] and [FilledSplitButton].
- *
- * The default text style for internal [Text] components will be set to [Typography.labelLarge].
- */
-@ExperimentalMaterial3ExpressiveApi
-@Composable
-fun ElevatedSplitButton(
- onLeadingButtonClick: () -> Unit,
- onTrailingButtonClick: () -> Unit,
- leadingContent: @Composable RowScope.() -> Unit,
- trailingContent: @Composable RowScope.() -> Unit,
- checked: Boolean,
- modifier: Modifier = Modifier,
- enabled: Boolean = true,
- innerCornerSize: CornerSize = SplitButtonDefaults.InnerCornerSize,
- spacing: Dp = SplitButtonDefaults.Spacing
-) {
- SplitButton(
- leadingButton = {
- ElevatedLeadingButton(
- onClick = onLeadingButtonClick,
- modifier = Modifier,
- enabled = enabled,
- shapes = SplitButtonDefaults.leadingButtonShapes(endCornerSize = innerCornerSize),
- content = leadingContent,
- )
- },
- trailingButton = {
- ElevatedTrailingButton(
- onClick = onTrailingButtonClick,
- modifier = Modifier,
- enabled = enabled,
- checked = checked,
- shapes =
- SplitButtonDefaults.trailingButtonShapes(startCornerSize = innerCornerSize),
- content = trailingContent
- )
- },
- modifier = modifier,
- spacing = spacing
- )
-}
-
-/**
- * A [SplitButton] let user define a button group consisting of 2 buttons. The leading button
- * performs a primary action, and the trailing button performs a secondary action that is
- * contextually related to the primary action.
- *
- * Outlined split buttons are medium-emphasis split buttons that are essentially
- * [OutlinedSplitButton]s with a shadow. They contain actions that are important, but aren’t the
- * primary action in an app.
- *
- * @sample androidx.compose.material3.samples.OutlinedSplitButtonSample
- *
- * Choose the best split button for an action based on the amount of emphasis it needs. The more
- * important an action is, the higher emphasis its button should be.
- *
- * @param onLeadingButtonClick called when the leading button is clicked
- * @param onTrailingButtonClick called when the trailing button is clicked
- * @param leadingContent the content to be placed inside the leading button. A container will be
- * provided internally to offer the standard design and style for a [OutlinedSplitButton].
- * @param trailingContent the content to be placed inside the trailing button. A container is
- * provided internally to ensure the standard design and style of a [OutlinedSplitButton]. The
- * container corner radius morphs to full when the [checked] state changes to `true`.
- * @param checked indicates if the trailing button is toggled. This can be used to indicate a new
- * state that's a result of [onTrailingButtonClick]. For example, a drop down menu or pop up.
- * @param modifier the [Modifier] to be applied to this split button.
- * @param enabled controls the enabled state of the split button. When `false`, this component will
- * not respond to user input, and it will appear visually disabled and disabled to accessibility
- * services.
- * @param innerCornerSize The size for leading button's end corners and trailing button's start
- * corners
- * @param spacing The spacing between the leading and trailing buttons
- * @see FilledSplitButton for a high-emphasis split button without a shadow.
- * @see TonalSplitButton for a middle ground between [OutlinedSplitButton] and [FilledSplitButton].
- * @see ElevatedSplitButton for an [TonalSplitButton] with a shadow.
- *
- * The default text style for internal [Text] components will be set to [Typography.labelLarge].
- */
-@ExperimentalMaterial3ExpressiveApi
-@Composable
-fun OutlinedSplitButton(
- onLeadingButtonClick: () -> Unit,
- onTrailingButtonClick: () -> Unit,
- leadingContent: @Composable RowScope.() -> Unit,
- trailingContent: @Composable RowScope.() -> Unit,
- checked: Boolean,
- modifier: Modifier = Modifier,
- enabled: Boolean = true,
- innerCornerSize: CornerSize = SplitButtonDefaults.InnerCornerSize,
- spacing: Dp = SplitButtonDefaults.Spacing
-) {
- SplitButton(
- leadingButton = {
- OutlinedLeadingButton(
- onClick = onLeadingButtonClick,
- modifier = Modifier,
- enabled = enabled,
- shapes = SplitButtonDefaults.leadingButtonShapes(innerCornerSize),
- content = leadingContent,
- )
- },
- trailingButton = {
- OutlinedTrailingButton(
- onClick = onTrailingButtonClick,
- modifier = Modifier,
- enabled = enabled,
- shapes = SplitButtonDefaults.trailingButtonShapes(innerCornerSize),
- checked = checked,
- content = trailingContent
- )
- },
- modifier = modifier,
- spacing = spacing
- )
-}
-
-@Composable
-private fun SplitButtonLayout(
- leadingButton: @Composable () -> Unit,
- trailingButton: @Composable () -> Unit,
- spacing: Dp,
- modifier: Modifier = Modifier,
-) {
Layout(
{
// Override min component size enforcement to avoid create extra padding internally
@@ -420,7 +128,7 @@
)
}
},
- modifier,
+ modifier.minimumInteractiveComponentSize(),
measurePolicy = { measurables, constraints ->
val looseConstraints = constraints.copy(minWidth = 0, minHeight = 0)
@@ -462,7 +170,7 @@
)
}
-/** Contains default values used by [SplitButton] and its style variants. */
+/** Contains default values used by [SplitButtonLayout] and its style variants. */
@ExperimentalMaterial3ExpressiveApi
object SplitButtonDefaults {
/** Default icon size for the leading button */
@@ -641,9 +349,7 @@
}
/**
- * Creates a `trailing` button that has the same visual as a Filled[Button]. When [checked] is
- * updated from `false` to `true`, the buttons corners will morph to `full` by default. Pressed
- * shape and checked shape can be customized via [shapes] param.
+ * Creates a `trailing` button that has the same visual as a [Button].
*
* To create a `tonal`, `outlined`, or `elevated` version, the default value of [Button] params
* can be passed in. For example, [ElevatedButton].
@@ -651,8 +357,6 @@
* The default text style for internal [Text] components will be set to [Typography.labelLarge].
*
* @param onClick called when the button is clicked
- * @param checked indicates whether the button is toggled to a `checked` state. This will
- * trigger the corner morphing animation to reflect the updated state.
* @param modifier the [Modifier] to be applied to this button.
* @param enabled controls the enabled state of the split button. When `false`, this component
* will not respond to user input, and it will appear visually disabled and disabled to
@@ -678,7 +382,6 @@
@ExperimentalMaterial3ExpressiveApi
fun TrailingButton(
onClick: () -> Unit,
- checked: Boolean,
modifier: Modifier = Modifier,
enabled: Boolean = true,
shapes: SplitButtonShapes = trailingButtonShapes(),
@@ -696,24 +399,11 @@
val defaultAnimationSpec = MotionSchemeKeyTokens.DefaultEffects.value<Float>()
val pressed by interactionSource.collectIsPressedAsState()
- val density = LocalDensity.current
- val shape = shapeByInteraction(shapes, pressed, checked, defaultAnimationSpec)
+ val shape = shapeByInteraction(shapes, pressed, false, defaultAnimationSpec)
Surface(
onClick = onClick,
- modifier =
- modifier
- .drawWithContent {
- drawContent()
- if (checked) {
- drawOutline(
- outline = shape.createOutline(size, layoutDirection, density),
- color = colors.contentColor,
- alpha = TrailingButtonStateLayerAlpha
- )
- }
- }
- .semantics { role = Role.Button },
+ modifier = modifier.semantics { role = Role.Button },
enabled = enabled,
shape = shape,
color = colors.containerColor,
@@ -757,138 +447,488 @@
}
}
}
-}
-@OptIn(ExperimentalMaterial3ExpressiveApi::class)
-@Composable
-private fun TonalLeadingButton(
- onClick: () -> Unit,
- modifier: Modifier,
- enabled: Boolean,
- shapes: SplitButtonShapes,
- content: @Composable RowScope.() -> Unit
-) {
- SplitButtonDefaults.LeadingButton(
- modifier = modifier,
- onClick = onClick,
- enabled = enabled,
- shapes = shapes,
- colors = ButtonDefaults.filledTonalButtonColors(),
- elevation = ButtonDefaults.filledTonalButtonElevation(),
- border = null,
- content = content,
- )
-}
+ /**
+ * Creates a `trailing` button that has the same visual as a [Button]. When [checked] is updated
+ * from `false` to `true`, the buttons corners will morph to `full` by default. Pressed shape
+ * and checked shape can be customized via [shapes] param.
+ *
+ * To create a `tonal`, `outlined`, or `elevated` version, the default value of [Button] params
+ * can be passed in. For example, [ElevatedButton].
+ *
+ * The default text style for internal [Text] components will be set to [Typography.labelLarge].
+ *
+ * @param checked indicates whether the button is toggled to a `checked` state. This will
+ * trigger the corner morphing animation to reflect the updated state.
+ * @param onCheckedChange called when the button is clicked
+ * @param modifier the [Modifier] to be applied to this button.
+ * @param enabled controls the enabled state of the split button. When `false`, this component
+ * will not respond to user input, and it will appear visually disabled and disabled to
+ * accessibility services.
+ * @param shapes the [SplitButtonShapes] that the trailing button will morph between depending
+ * on the user's interaction with the button.
+ * @param colors [ButtonColors] that will be used to resolve the colors for this button in
+ * different states. See [ButtonDefaults.buttonColors].
+ * @param elevation [ButtonElevation] used to resolve the elevation for this button in different
+ * states. This controls the size of the shadow below the button. See
+ * [ButtonElevation.shadowElevation].
+ * @param border the border to draw around the container of this button contentPadding the
+ * spacing values to apply internally between the container and the content
+ * @param contentPadding the spacing values to apply internally between the container and the
+ * content
+ * @param interactionSource an optional hoisted [MutableInteractionSource] for observing and
+ * emitting [Interaction]s for this button. You can use this to change the button's appearance
+ * or preview the button in different states. Note that if `null` is provided, interactions
+ * will still happen internally.
+ * @param content the content to be placed in the button
+ */
+ @Composable
+ @ExperimentalMaterial3ExpressiveApi
+ fun TrailingButton(
+ checked: Boolean,
+ onCheckedChange: (Boolean) -> Unit,
+ modifier: Modifier = Modifier,
+ enabled: Boolean = true,
+ shapes: SplitButtonShapes = trailingButtonShapes(),
+ colors: ButtonColors = ButtonDefaults.buttonColors(),
+ elevation: ButtonElevation? = ButtonDefaults.buttonElevation(),
+ border: BorderStroke? = null,
+ contentPadding: PaddingValues = TrailingButtonContentPadding,
+ interactionSource: MutableInteractionSource? = null,
+ content: @Composable RowScope.() -> Unit
+ ) {
+ @Suppress("NAME_SHADOWING")
+ val interactionSource = interactionSource ?: remember { MutableInteractionSource() }
-@OptIn(ExperimentalMaterial3ExpressiveApi::class)
-@Composable
-private fun TonalTrailingButton(
- onClick: () -> Unit,
- checked: Boolean,
- modifier: Modifier,
- enabled: Boolean,
- shapes: SplitButtonShapes,
- content: @Composable RowScope.() -> Unit
-) {
- SplitButtonDefaults.TrailingButton(
- modifier = modifier,
- onClick = onClick,
- enabled = enabled,
- shapes = shapes,
- checked = checked,
- colors = ButtonDefaults.filledTonalButtonColors(),
- elevation = ButtonDefaults.filledTonalButtonElevation(),
- border = null,
- content = content
- )
-}
+ // TODO Load the motionScheme tokens from the component tokens file
+ val defaultAnimationSpec = MotionSchemeKeyTokens.DefaultEffects.value<Float>()
+ val pressed by interactionSource.collectIsPressedAsState()
-@OptIn(ExperimentalMaterial3ExpressiveApi::class)
-@Composable
-private fun OutlinedLeadingButton(
- onClick: () -> Unit,
- modifier: Modifier,
- enabled: Boolean,
- shapes: SplitButtonShapes,
- content: @Composable RowScope.() -> Unit
-) {
- SplitButtonDefaults.LeadingButton(
- modifier = modifier,
- onClick = onClick,
- enabled = enabled,
- shapes = shapes,
- colors = ButtonDefaults.outlinedButtonColors(),
- elevation = null,
- border = ButtonDefaults.outlinedButtonBorder(enabled),
- content = content
- )
-}
+ val density = LocalDensity.current
+ val shape = shapeByInteraction(shapes, pressed, checked, defaultAnimationSpec)
-@OptIn(ExperimentalMaterial3ExpressiveApi::class)
-@Composable
-private fun OutlinedTrailingButton(
- onClick: () -> Unit,
- checked: Boolean,
- modifier: Modifier,
- enabled: Boolean,
- shapes: SplitButtonShapes,
- content: @Composable RowScope.() -> Unit
-) {
- SplitButtonDefaults.TrailingButton(
- modifier = modifier,
- onClick = onClick,
- enabled = enabled,
- shapes = shapes,
- checked = checked,
- colors = ButtonDefaults.outlinedButtonColors(),
- elevation = null,
- border = ButtonDefaults.outlinedButtonBorder(enabled),
- content = content
- )
-}
+ Surface(
+ checked = checked,
+ onCheckedChange = onCheckedChange,
+ modifier =
+ modifier
+ .drawWithContent {
+ drawContent()
+ if (checked) {
+ drawOutline(
+ outline = shape.createOutline(size, layoutDirection, density),
+ color = colors.contentColor,
+ alpha = TrailingButtonStateLayerAlpha
+ )
+ }
+ }
+ .semantics { role = Role.Checkbox },
+ enabled = enabled,
+ shape = shape,
+ color = colors.containerColor,
+ contentColor = colors.contentColor,
+ shadowElevation = elevation?.shadowElevation(enabled, interactionSource)?.value ?: 0.dp,
+ border = border,
+ interactionSource = interactionSource
+ ) {
+ ProvideContentColorTextStyle(
+ contentColor = colors.contentColor,
+ textStyle = MaterialTheme.typography.labelLarge
+ ) {
+ Row(
+ Modifier.defaultMinSize(
+ minWidth = TrailingButtonMinWidth,
+ minHeight = MinHeight
+ )
+ .then(
+ when (shape) {
+ is ShapeWithOpticalCentering -> {
+ Modifier.opticalCentering(
+ shape = shape,
+ basePadding = contentPadding
+ )
+ }
+ is CornerBasedShape -> {
+ Modifier.opticalCentering(
+ shape = shape,
+ basePadding = contentPadding
+ )
+ }
+ else -> {
+ Modifier.padding(contentPadding)
+ }
+ }
+ ),
+ horizontalArrangement = Arrangement.Center,
+ verticalAlignment = Alignment.CenterVertically,
+ content = content
+ )
+ }
+ }
+ }
-@OptIn(ExperimentalMaterial3ExpressiveApi::class)
-@Composable
-private fun ElevatedLeadingButton(
- onClick: () -> Unit,
- modifier: Modifier,
- enabled: Boolean,
- shapes: SplitButtonShapes,
- content: @Composable RowScope.() -> Unit
-) {
- SplitButtonDefaults.LeadingButton(
- modifier = modifier,
- onClick = onClick,
- enabled = enabled,
- shapes = shapes,
- colors = ButtonDefaults.elevatedButtonColors(),
- elevation = ButtonDefaults.elevatedButtonElevation(),
- border = null,
- content = content
- )
-}
+ /**
+ * Create a tonal `leading` button that has the same visual as a Tonal[Button]. To create a
+ * `filled`, `outlined`, or `elevated` version, the default value of [Button] params can be
+ * passed in. For example, [ElevatedButton].
+ *
+ * The default text style for internal [Text] components will be set to [Typography.labelLarge].
+ *
+ * @param onClick called when the button is clicked
+ * @param modifier the [Modifier] to be applied to this button.
+ * @param enabled controls the enabled state of the split button. When `false`, this component
+ * will not respond to user input, and it will appear visually disabled and disabled to
+ * accessibility services.
+ * @param shapes the [SplitButtonShapes] that the trailing button will morph between depending
+ * on the user's interaction with the button.
+ * @param colors [ButtonColors] that will be used to resolve the colors for this button in
+ * different states. See [ButtonDefaults.buttonColors].
+ * @param elevation [ButtonElevation] used to resolve the elevation for this button in different
+ * states. This controls the size of the shadow below the button. See
+ * [ButtonElevation.shadowElevation].
+ * @param border the border to draw around the container of this button contentPadding the
+ * spacing values to apply internally between the container and the content
+ * @param contentPadding the spacing values to apply internally between the container and the
+ * content
+ * @param interactionSource an optional hoisted [MutableInteractionSource] for observing and
+ * emitting [Interaction]s for this button. You can use this to change the button's appearance
+ * or preview the button in different states. Note that if `null` is provided, interactions
+ * will still happen internally.
+ * @param content the content for the button.
+ */
+ @ExperimentalMaterial3ExpressiveApi
+ @Composable
+ fun TonalLeadingButton(
+ onClick: () -> Unit,
+ modifier: Modifier = Modifier,
+ enabled: Boolean = true,
+ shapes: SplitButtonShapes = leadingButtonShapes(),
+ colors: ButtonColors = ButtonDefaults.filledTonalButtonColors(),
+ elevation: ButtonElevation? = ButtonDefaults.filledTonalButtonElevation(),
+ border: BorderStroke? = null,
+ contentPadding: PaddingValues = LeadingButtonContentPadding,
+ interactionSource: MutableInteractionSource? = null,
+ content: @Composable RowScope.() -> Unit
+ ) {
+ LeadingButton(
+ modifier = modifier,
+ onClick = onClick,
+ enabled = enabled,
+ shapes = shapes,
+ colors = colors,
+ elevation = elevation,
+ border = border,
+ contentPadding = contentPadding,
+ interactionSource = interactionSource,
+ content = content,
+ )
+ }
-@OptIn(ExperimentalMaterial3ExpressiveApi::class)
-@Composable
-private fun ElevatedTrailingButton(
- onClick: () -> Unit,
- checked: Boolean,
- modifier: Modifier,
- enabled: Boolean,
- shapes: SplitButtonShapes,
- content: @Composable RowScope.() -> Unit
-) {
- SplitButtonDefaults.TrailingButton(
- modifier = modifier,
- onClick = onClick,
- enabled = enabled,
- shapes = shapes,
- checked = checked,
- colors = ButtonDefaults.elevatedButtonColors(),
- elevation = ButtonDefaults.elevatedButtonElevation(),
- border = null,
- content = content
- )
+ /**
+ * Creates a tonal `trailing` button that has the same visual as a [FilledTonalButton]. When
+ * [checked] is updated from `false` to `true`, the buttons corners will morph to `full` by
+ * default. Pressed shape and checked shape can be customized via [shapes] param.
+ *
+ * To create a `tonal`, `outlined`, or `elevated` version, the default value of [Button] params
+ * can be passed in. For example, [ElevatedButton].
+ *
+ * The default text style for internal [Text] components will be set to [Typography.labelLarge].
+ *
+ * @param checked indicates whether the button is toggled to a `checked` state. This will
+ * trigger the corner morphing animation to reflect the updated state.
+ * @param onCheckedChange called when the button is clicked
+ * @param modifier the [Modifier] to be applied to this button.
+ * @param enabled controls the enabled state of the split button. When `false`, this component
+ * will not respond to user input, and it will appear visually disabled and disabled to
+ * accessibility services.
+ * @param shapes the [SplitButtonShapes] that the trailing button will morph between depending
+ * on the user's interaction with the button.
+ * @param colors [ButtonColors] that will be used to resolve the colors for this button in
+ * different states. See [ButtonDefaults.buttonColors].
+ * @param elevation [ButtonElevation] used to resolve the elevation for this button in different
+ * states. This controls the size of the shadow below the button. See
+ * [ButtonElevation.shadowElevation].
+ * @param border the border to draw around the container of this button contentPadding the
+ * spacing values to apply internally between the container and the content
+ * @param contentPadding the spacing values to apply internally between the container and the
+ * content
+ * @param interactionSource an optional hoisted [MutableInteractionSource] for observing and
+ * emitting [Interaction]s for this button. You can use this to change the button's appearance
+ * or preview the button in different states. Note that if `null` is provided, interactions
+ * will still happen internally.
+ * @param content the content to be placed in the button
+ */
+ @ExperimentalMaterial3ExpressiveApi
+ @Composable
+ fun TonalTrailingButton(
+ checked: Boolean,
+ onCheckedChange: (Boolean) -> Unit,
+ modifier: Modifier = Modifier,
+ enabled: Boolean = true,
+ shapes: SplitButtonShapes = trailingButtonShapes(),
+ colors: ButtonColors = ButtonDefaults.filledTonalButtonColors(),
+ elevation: ButtonElevation? = ButtonDefaults.filledTonalButtonElevation(),
+ border: BorderStroke? = null,
+ contentPadding: PaddingValues = TrailingButtonContentPadding,
+ interactionSource: MutableInteractionSource? = null,
+ content: @Composable RowScope.() -> Unit
+ ) {
+ TrailingButton(
+ checked = checked,
+ onCheckedChange = onCheckedChange,
+ modifier = modifier,
+ enabled = enabled,
+ shapes = shapes,
+ colors = colors,
+ elevation = elevation,
+ border = border,
+ contentPadding = contentPadding,
+ interactionSource = interactionSource,
+ content = content
+ )
+ }
+
+ /**
+ * Create a elevated `leading` button that has the same visual as a [ElevatedButton]. To create
+ * a `filled`, `outlined`, or `elevated` version, the default value of [Button] params can be
+ * passed in. For example, [ElevatedButton].
+ *
+ * The default text style for internal [Text] components will be set to [Typography.labelLarge].
+ *
+ * @param onClick called when the button is clicked
+ * @param modifier the [Modifier] to be applied to this button.
+ * @param enabled controls the enabled state of the split button. When `false`, this component
+ * will not respond to user input, and it will appear visually disabled and disabled to
+ * accessibility services.
+ * @param shapes the [SplitButtonShapes] that the trailing button will morph between depending
+ * on the user's interaction with the button.
+ * @param colors [ButtonColors] that will be used to resolve the colors for this button in
+ * different states. See [ButtonDefaults.buttonColors].
+ * @param elevation [ButtonElevation] used to resolve the elevation for this button in different
+ * states. This controls the size of the shadow below the button. See
+ * [ButtonElevation.shadowElevation].
+ * @param border the border to draw around the container of this button contentPadding the
+ * spacing values to apply internally between the container and the content
+ * @param contentPadding the spacing values to apply internally between the container and the
+ * content
+ * @param interactionSource an optional hoisted [MutableInteractionSource] for observing and
+ * emitting [Interaction]s for this button. You can use this to change the button's appearance
+ * or preview the button in different states. Note that if `null` is provided, interactions
+ * will still happen internally.
+ * @param content the content for the button.
+ */
+ @ExperimentalMaterial3ExpressiveApi
+ @Composable
+ fun OutlinedLeadingButton(
+ onClick: () -> Unit,
+ modifier: Modifier = Modifier,
+ enabled: Boolean = true,
+ shapes: SplitButtonShapes = leadingButtonShapes(),
+ colors: ButtonColors = ButtonDefaults.outlinedButtonColors(),
+ elevation: ButtonElevation? = null,
+ border: BorderStroke? = ButtonDefaults.outlinedButtonBorder(enabled),
+ contentPadding: PaddingValues = LeadingButtonContentPadding,
+ interactionSource: MutableInteractionSource? = null,
+ content: @Composable RowScope.() -> Unit
+ ) {
+ LeadingButton(
+ modifier = modifier,
+ onClick = onClick,
+ enabled = enabled,
+ shapes = shapes,
+ colors = colors,
+ elevation = elevation,
+ border = border,
+ contentPadding = contentPadding,
+ interactionSource = interactionSource,
+ content = content,
+ )
+ }
+
+ /**
+ * Creates a outlined `trailing` button that has the same visual as a [OutlinedButton]. When
+ * [checked] is updated from `false` to `true`, the buttons corners will morph to `full` by
+ * default. Pressed shape and checked shape can be customized via [shapes] param.
+ *
+ * To create a `tonal`, `outlined`, or `elevated` version, the default value of [Button] params
+ * can be passed in. For example, [ElevatedButton].
+ *
+ * The default text style for internal [Text] components will be set to [Typography.labelLarge].
+ *
+ * @param checked indicates whether the button is toggled to a `checked` state. This will
+ * trigger the corner morphing animation to reflect the updated state.
+ * @param onCheckedChange called when the button is clicked
+ * @param modifier the [Modifier] to be applied to this button.
+ * @param enabled controls the enabled state of the split button. When `false`, this component
+ * will not respond to user input, and it will appear visually disabled and disabled to
+ * accessibility services.
+ * @param shapes the [SplitButtonShapes] that the trailing button will morph between depending
+ * on the user's interaction with the button.
+ * @param colors [ButtonColors] that will be used to resolve the colors for this button in
+ * different states. See [ButtonDefaults.buttonColors].
+ * @param elevation [ButtonElevation] used to resolve the elevation for this button in different
+ * states. This controls the size of the shadow below the button. See
+ * [ButtonElevation.shadowElevation].
+ * @param border the border to draw around the container of this button contentPadding the
+ * spacing values to apply internally between the container and the content
+ * @param contentPadding the spacing values to apply internally between the container and the
+ * content
+ * @param interactionSource an optional hoisted [MutableInteractionSource] for observing and
+ * emitting [Interaction]s for this button. You can use this to change the button's appearance
+ * or preview the button in different states. Note that if `null` is provided, interactions
+ * will still happen internally.
+ * @param content the content to be placed in the button
+ */
+ @ExperimentalMaterial3ExpressiveApi
+ @Composable
+ fun OutlinedTrailingButton(
+ checked: Boolean,
+ onCheckedChange: (Boolean) -> Unit,
+ modifier: Modifier = Modifier,
+ enabled: Boolean = true,
+ shapes: SplitButtonShapes = trailingButtonShapes(),
+ colors: ButtonColors = ButtonDefaults.outlinedButtonColors(),
+ elevation: ButtonElevation? = null,
+ border: BorderStroke? = ButtonDefaults.outlinedButtonBorder(enabled),
+ contentPadding: PaddingValues = TrailingButtonContentPadding,
+ interactionSource: MutableInteractionSource? = null,
+ content: @Composable RowScope.() -> Unit
+ ) {
+ TrailingButton(
+ checked = checked,
+ onCheckedChange = onCheckedChange,
+ modifier = modifier,
+ enabled = enabled,
+ shapes = shapes,
+ colors = colors,
+ elevation = elevation,
+ border = border,
+ contentPadding = contentPadding,
+ interactionSource = interactionSource,
+ content = content
+ )
+ }
+
+ /**
+ * Create a elevated `leading` button that has the same visual as a [ElevatedButton]. To create
+ * a `filled`, `outlined`, or `elevated` version, the default value of [Button] params can be
+ * passed in. For example, [ElevatedButton].
+ *
+ * The default text style for internal [Text] components will be set to [Typography.labelLarge].
+ *
+ * @param onClick called when the button is clicked
+ * @param modifier the [Modifier] to be applied to this button.
+ * @param enabled controls the enabled state of the split button. When `false`, this component
+ * will not respond to user input, and it will appear visually disabled and disabled to
+ * accessibility services.
+ * @param shapes the [SplitButtonShapes] that the trailing button will morph between depending
+ * on the user's interaction with the button.
+ * @param colors [ButtonColors] that will be used to resolve the colors for this button in
+ * different states. See [ButtonDefaults.buttonColors].
+ * @param elevation [ButtonElevation] used to resolve the elevation for this button in different
+ * states. This controls the size of the shadow below the button. See
+ * [ButtonElevation.shadowElevation].
+ * @param border the border to draw around the container of this button contentPadding the
+ * spacing values to apply internally between the container and the content
+ * @param contentPadding the spacing values to apply internally between the container and the
+ * content
+ * @param interactionSource an optional hoisted [MutableInteractionSource] for observing and
+ * emitting [Interaction]s for this button. You can use this to change the button's appearance
+ * or preview the button in different states. Note that if `null` is provided, interactions
+ * will still happen internally.
+ * @param content the content for the button.
+ */
+ @ExperimentalMaterial3ExpressiveApi
+ @Composable
+ fun ElevatedLeadingButton(
+ onClick: () -> Unit,
+ modifier: Modifier = Modifier,
+ enabled: Boolean = true,
+ shapes: SplitButtonShapes = leadingButtonShapes(),
+ colors: ButtonColors = ButtonDefaults.elevatedButtonColors(),
+ elevation: ButtonElevation? = ButtonDefaults.elevatedButtonElevation(),
+ border: BorderStroke? = null,
+ contentPadding: PaddingValues = LeadingButtonContentPadding,
+ interactionSource: MutableInteractionSource? = null,
+ content: @Composable RowScope.() -> Unit
+ ) {
+ LeadingButton(
+ modifier = modifier,
+ onClick = onClick,
+ enabled = enabled,
+ shapes = shapes,
+ colors = colors,
+ elevation = elevation,
+ border = border,
+ contentPadding = contentPadding,
+ interactionSource = interactionSource,
+ content = content,
+ )
+ }
+
+ /**
+ * Creates a elevated `trailing` button that has the same visual as a [ElevatedButton]. When
+ * [checked] is updated from `false` to `true`, the buttons corners will morph to `full` by
+ * default. Pressed shape and checked shape can be customized via [shapes] param.
+ *
+ * To create a `tonal`, `outlined`, or `elevated` version, the default value of [Button] params
+ * can be passed in. For example, [ElevatedButton].
+ *
+ * The default text style for internal [Text] components will be set to [Typography.labelLarge].
+ *
+ * @param checked indicates whether the button is toggled to a `checked` state. This will
+ * trigger the corner morphing animation to reflect the updated state.
+ * @param onCheckedChange called when the button is clicked
+ * @param modifier the [Modifier] to be applied to this button.
+ * @param enabled controls the enabled state of the split button. When `false`, this component
+ * will not respond to user input, and it will appear visually disabled and disabled to
+ * accessibility services.
+ * @param shapes the [SplitButtonShapes] that the trailing button will morph between depending
+ * on the user's interaction with the button.
+ * @param colors [ButtonColors] that will be used to resolve the colors for this button in
+ * different states. See [ButtonDefaults.buttonColors].
+ * @param elevation [ButtonElevation] used to resolve the elevation for this button in different
+ * states. This controls the size of the shadow below the button. See
+ * [ButtonElevation.shadowElevation].
+ * @param border the border to draw around the container of this button contentPadding the
+ * spacing values to apply internally between the container and the content
+ * @param contentPadding the spacing values to apply internally between the container and the
+ * content
+ * @param interactionSource an optional hoisted [MutableInteractionSource] for observing and
+ * emitting [Interaction]s for this button. You can use this to change the button's appearance
+ * or preview the button in different states. Note that if `null` is provided, interactions
+ * will still happen internally.
+ * @param content the content to be placed in the button
+ */
+ @ExperimentalMaterial3ExpressiveApi
+ @Composable
+ fun ElevatedTrailingButton(
+ checked: Boolean,
+ onCheckedChange: (Boolean) -> Unit,
+ modifier: Modifier = Modifier,
+ enabled: Boolean = true,
+ shapes: SplitButtonShapes = trailingButtonShapes(),
+ colors: ButtonColors = ButtonDefaults.elevatedButtonColors(),
+ elevation: ButtonElevation? = ButtonDefaults.elevatedButtonElevation(),
+ border: BorderStroke? = null,
+ contentPadding: PaddingValues = TrailingButtonContentPadding,
+ interactionSource: MutableInteractionSource? = null,
+ content: @Composable RowScope.() -> Unit
+ ) {
+ TrailingButton(
+ checked = checked,
+ onCheckedChange = onCheckedChange,
+ modifier = modifier,
+ enabled = enabled,
+ shapes = shapes,
+ colors = colors,
+ elevation = elevation,
+ border = border,
+ contentPadding = contentPadding,
+ interactionSource = interactionSource,
+ content = content
+ )
+ }
}
@Composable
@@ -912,7 +952,7 @@
}
/**
- * The shapes that will be used in [SplitButton]. Split button will morph between these shapes
+ * The shapes that will be used in [SplitButtonLayout]. Split button will morph between these shapes
* depending on the interaction of the buttons, assuming all of the shapes are [CornerBasedShape]s.
*
* @property shape is the default shape.
diff --git a/compose/runtime/runtime/proguard-rules.pro b/compose/runtime/runtime/proguard-rules.pro
index f32c782..a0d0c23 100644
--- a/compose/runtime/runtime/proguard-rules.pro
+++ b/compose/runtime/runtime/proguard-rules.pro
@@ -20,7 +20,9 @@
-keep,allowshrinking,allowobfuscation class androidx.compose.runtime.** {
# java.lang.Void == methods that return Nothing
static void throw*Exception(...);
+ static void throw*ExceptionForNullCheck(...);
static java.lang.Void throw*Exception(...);
+ static java.lang.Void throw*ExceptionForNullCheck(...);
static void compose*RuntimeError(...);
static java.lang.Void compose*RuntimeError(...);
diff --git a/compose/ui/ui-graphics/build.gradle b/compose/ui/ui-graphics/build.gradle
index 75bba20..842022a 100644
--- a/compose/ui/ui-graphics/build.gradle
+++ b/compose/ui/ui-graphics/build.gradle
@@ -129,4 +129,7 @@
android {
compileSdk 35
namespace "androidx.compose.ui.graphics"
+ buildTypes.configureEach {
+ consumerProguardFiles("proguard-rules.pro")
+ }
}
diff --git a/compose/ui/ui-graphics/proguard-rules.pro b/compose/ui/ui-graphics/proguard-rules.pro
new file mode 100644
index 0000000..67d118b
--- /dev/null
+++ b/compose/ui/ui-graphics/proguard-rules.pro
@@ -0,0 +1,24 @@
+# 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.
+# 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.
+
+# Keep all the functions created to throw an exception. We don't want these functions to be
+# inlined in any way, which R8 will do by default. The whole point of these functions is to
+# reduce the amount of code generated at the call site.
+-keep,allowshrinking,allowobfuscation class androidx.compose.**.* {
+ static void throw*Exception(...);
+ static void throw*ExceptionForNullCheck(...);
+ # For methods returning Nothing
+ static java.lang.Void throw*Exception(...);
+ static java.lang.Void throw*ExceptionForNullCheck(...);
+}
diff --git a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/Bezier.kt b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/Bezier.kt
index 15437fd..fe448fb 100644
--- a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/Bezier.kt
+++ b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/Bezier.kt
@@ -40,7 +40,7 @@
// and because we use a fast approximation of cbrt(). The epsilon we use here is
// slightly larger than the max error of fastCbrt() in the -1f..1f range
// (8.3446500e-7f) but smaller than 1.0f.ulp * 10.
-private const val FloatEpsilon = 1e-6f
+private const val FloatEpsilon = 1.05e-6f
/**
* Evaluate the specified [segment] at position [t] and returns the X coordinate of the segment's
diff --git a/compose/ui/ui-test/samples/src/main/java/androidx/compose/ui/test/samples/DeviceConfigurationOverrideSamples.kt b/compose/ui/ui-test/samples/src/main/java/androidx/compose/ui/test/samples/DeviceConfigurationOverrideSamples.kt
index 084fbb4..d345fcb 100644
--- a/compose/ui/ui-test/samples/src/main/java/androidx/compose/ui/test/samples/DeviceConfigurationOverrideSamples.kt
+++ b/compose/ui/ui-test/samples/src/main/java/androidx/compose/ui/test/samples/DeviceConfigurationOverrideSamples.kt
@@ -20,13 +20,13 @@
import androidx.compose.foundation.background
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.roundToAndroidXInsets
import androidx.compose.foundation.layout.safeDrawingPadding
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalConfiguration
+import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.test.DarkMode
import androidx.compose.ui.test.DeviceConfigurationOverride
import androidx.compose.ui.test.FontScale
@@ -40,8 +40,10 @@
import androidx.compose.ui.text.intl.LocaleList
import androidx.compose.ui.unit.DpRect
import androidx.compose.ui.unit.DpSize
+import androidx.compose.ui.unit.IntRect
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.roundToIntRect
import androidx.core.view.WindowInsetsCompat
@Sampled
@@ -115,16 +117,22 @@
@Sampled
@Composable
fun DeviceConfigurationOverrideWindowInsetsSample() {
+ fun IntRect.toAndroidXInsets() = androidx.core.graphics.Insets.of(left, top, right, bottom)
+
DeviceConfigurationOverride(
DeviceConfigurationOverride.WindowInsets(
WindowInsetsCompat.Builder()
.setInsets(
WindowInsetsCompat.Type.captionBar(),
- DpRect(0.dp, 64.dp, 0.dp, 0.dp).roundToAndroidXInsets(),
+ with(LocalDensity.current) { DpRect(0.dp, 64.dp, 0.dp, 0.dp).toRect() }
+ .roundToIntRect()
+ .toAndroidXInsets()
)
.setInsets(
WindowInsetsCompat.Type.navigationBars(),
- DpRect(24.dp, 0.dp, 48.dp, 24.dp).roundToAndroidXInsets(),
+ with(LocalDensity.current) { DpRect(24.dp, 0.dp, 48.dp, 24.dp).toRect() }
+ .roundToIntRect()
+ .toAndroidXInsets()
)
.build()
)
diff --git a/compose/ui/ui-tooling-data/src/androidInstrumentedTest/kotlin/androidx/compose/ui/tooling/data/OffsetInformationTest.kt b/compose/ui/ui-tooling-data/src/androidInstrumentedTest/kotlin/androidx/compose/ui/tooling/data/OffsetInformationTest.kt
index 3350a5f1..ebb0263 100644
--- a/compose/ui/ui-tooling-data/src/androidInstrumentedTest/kotlin/androidx/compose/ui/tooling/data/OffsetInformationTest.kt
+++ b/compose/ui/ui-tooling-data/src/androidInstrumentedTest/kotlin/androidx/compose/ui/tooling/data/OffsetInformationTest.kt
@@ -50,11 +50,9 @@
"Text" to 1680,
"Greeting" to 1845,
"Text" to 2509,
- "<get-shapes>" to 1927,
"Surface" to 1877,
"Button" to 1959,
"Text" to 1982,
- "<get-shapes>" to 2070,
"Surface" to 2021,
"TextButton" to 2102,
"Row" to 2185
@@ -87,11 +85,9 @@
"Text" to false,
"Greeting" to false,
"Text" to false,
- "<get-shapes>" to false,
"Surface" to false,
"Button" to false,
"Text" to false,
- "<get-shapes>" to false,
"Surface" to false,
"TextButton" to false,
"Row" to true
diff --git a/compose/ui/ui-unit/build.gradle b/compose/ui/ui-unit/build.gradle
index 91140c3..9cd6331 100644
--- a/compose/ui/ui-unit/build.gradle
+++ b/compose/ui/ui-unit/build.gradle
@@ -118,4 +118,7 @@
android {
namespace "androidx.compose.ui.unit"
+ buildTypes.configureEach {
+ consumerProguardFiles("proguard-rules.pro")
+ }
}
diff --git a/compose/ui/ui-unit/proguard-rules.pro b/compose/ui/ui-unit/proguard-rules.pro
new file mode 100644
index 0000000..67d118b
--- /dev/null
+++ b/compose/ui/ui-unit/proguard-rules.pro
@@ -0,0 +1,24 @@
+# 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.
+# 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.
+
+# Keep all the functions created to throw an exception. We don't want these functions to be
+# inlined in any way, which R8 will do by default. The whole point of these functions is to
+# reduce the amount of code generated at the call site.
+-keep,allowshrinking,allowobfuscation class androidx.compose.**.* {
+ static void throw*Exception(...);
+ static void throw*ExceptionForNullCheck(...);
+ # For methods returning Nothing
+ static java.lang.Void throw*Exception(...);
+ static java.lang.Void throw*ExceptionForNullCheck(...);
+}
diff --git a/compose/ui/ui-util/build.gradle b/compose/ui/ui-util/build.gradle
index 2ce5e6f..b1788829 100644
--- a/compose/ui/ui-util/build.gradle
+++ b/compose/ui/ui-util/build.gradle
@@ -107,4 +107,7 @@
android {
namespace "androidx.compose.ui.util"
+ buildTypes.configureEach {
+ consumerProguardFiles("proguard-rules.pro")
+ }
}
diff --git a/compose/ui/ui-util/proguard-rules.pro b/compose/ui/ui-util/proguard-rules.pro
new file mode 100644
index 0000000..67d118b
--- /dev/null
+++ b/compose/ui/ui-util/proguard-rules.pro
@@ -0,0 +1,24 @@
+# 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.
+# 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.
+
+# Keep all the functions created to throw an exception. We don't want these functions to be
+# inlined in any way, which R8 will do by default. The whole point of these functions is to
+# reduce the amount of code generated at the call site.
+-keep,allowshrinking,allowobfuscation class androidx.compose.**.* {
+ static void throw*Exception(...);
+ static void throw*ExceptionForNullCheck(...);
+ # For methods returning Nothing
+ static java.lang.Void throw*Exception(...);
+ static java.lang.Void throw*ExceptionForNullCheck(...);
+}
diff --git a/compose/ui/ui/proguard-rules.pro b/compose/ui/ui/proguard-rules.pro
index 29f2984..f5603a7 100644
--- a/compose/ui/ui/proguard-rules.pro
+++ b/compose/ui/ui/proguard-rules.pro
@@ -37,8 +37,10 @@
# reduce the amount of code generated at the call site.
-keep,allowshrinking,allowobfuscation class androidx.compose.**.* {
static void throw*Exception(...);
+ static void throw*ExceptionForNullCheck(...);
# For methods returning Nothing
static java.lang.Void throw*Exception(...);
+ static java.lang.Void throw*ExceptionForNullCheck(...);
}
# When pointer input modifier nodes are added dynamically and have the same keys (common when
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/nestedscroll/NestedScrollModifierTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/nestedscroll/NestedScrollModifierTest.kt
index b208f50..bfeca00 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/nestedscroll/NestedScrollModifierTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/nestedscroll/NestedScrollModifierTest.kt
@@ -24,7 +24,6 @@
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.requiredSize
-import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.text.BasicText
import androidx.compose.runtime.Composable
@@ -1549,52 +1548,6 @@
assertThat(postFlingCount).isGreaterThan(0)
}
}
-
- @Test
- fun modifierIsRemoved_shouldKeepInfoAboutPreviousParent() {
- val innerDispatcher = NestedScrollDispatcher()
- val outerDispatcher = NestedScrollDispatcher()
- var keepAround by mutableStateOf(true)
-
- rule.setContent {
- Column(
- modifier =
- Modifier.nestedScroll(
- dispatcher = outerDispatcher,
- connection = object : NestedScrollConnection {}
- )
- ) {
- Box(
- Modifier.size(400.dp)
- .then(
- if (keepAround)
- Modifier.nestedScroll(
- dispatcher = innerDispatcher,
- connection = object : NestedScrollConnection {}
- )
- else Modifier
- )
- )
- }
- }
-
- rule.runOnIdle {
- assertThat(innerDispatcher.lastKnownValidParentNode).isNull()
- assertThat(innerDispatcher.nestedScrollNode?.parentNestedScrollNode)
- .isEqualTo(outerDispatcher.nestedScrollNode)
- }
-
- rule.runOnIdle {
- keepAround = false // remove inner node
- }
-
- rule.runOnIdle {
- // the inner node's parent is the outer node
- assertThat(innerDispatcher.lastKnownValidParentNode)
- .isEqualTo(outerDispatcher.nestedScrollNode)
- assertThat(innerDispatcher.nestedScrollNode?.parentNestedScrollNode).isNull()
- }
- }
}
private fun Offset.customEquals(other: Offset): Boolean {
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/nestedscroll/NestedScrollModifier.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/nestedscroll/NestedScrollModifier.kt
index 5e82355..b8d1e64 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/nestedscroll/NestedScrollModifier.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/nestedscroll/NestedScrollModifier.kt
@@ -106,9 +106,6 @@
internal var nestedScrollNode: NestedScrollNode? = null
- // caches last known parent for fling clean up use.
- internal var lastKnownValidParentNode: NestedScrollNode? = null
-
// lambda to calculate the most outer nested scroll scope for this dispatcher on demand
internal var calculateNestedScrollScope: () -> CoroutineScope? = { scope }
@@ -145,9 +142,7 @@
/**
* Parent to be set when attached to nested scrolling chain. `null` is valid and means there no
- * nested scrolling parent above. The last known attached parent might be used in case this
- * dispatcher is not attached to any node, that is [nestedScrollNode?.parentNestedScrollNode] is
- * null.
+ * nested scrolling parent above
*/
internal val parent: NestedScrollConnection?
get() = nestedScrollNode?.parentNestedScrollNode
@@ -209,17 +204,7 @@
* @return velocity that has been consumed by all the ancestors
*/
suspend fun dispatchPostFling(consumed: Velocity, available: Velocity): Velocity {
- // lastKnownValidParentNode can be used to send clean up signals.
- // If this dispatcher's regular parent is not present it means either it never attached or
- // it was detached. If it was detached we have information about its last known parent so
- // we use it to send the post fling signal. We don't need to do the same for the other
- // methods because the problem with parity in this API comes from a node that detaches
- // during a fling.
- return if (parent == null) {
- lastKnownValidParentNode?.onPostFling(consumed, available) ?: Velocity.Zero
- } else {
- parent?.onPostFling(consumed, available) ?: Velocity.Zero
- }
+ return parent?.onPostFling(consumed, available) ?: Velocity.Zero
}
}
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/nestedscroll/NestedScrollNode.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/nestedscroll/NestedScrollNode.kt
index 680033b..432daec 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/nestedscroll/NestedScrollNode.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/nestedscroll/NestedScrollNode.kt
@@ -21,7 +21,6 @@
import androidx.compose.ui.node.DelegatableNode
import androidx.compose.ui.node.TraversableNode
import androidx.compose.ui.node.findNearestAncestor
-import androidx.compose.ui.node.traverseAncestors
import androidx.compose.ui.unit.Velocity
import kotlinx.coroutines.CoroutineScope
@@ -50,8 +49,6 @@
resolvedDispatcher = dispatcher ?: NestedScrollDispatcher() // Resolve null dispatcher
}
- internal var lastKnownValidParentNode: NestedScrollNode? = null
-
internal val parentNestedScrollNode: NestedScrollNode?
get() = if (isAttached) findNearestAncestor() else null
@@ -97,12 +94,11 @@
}
override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity {
+
val selfConsumed = connection.onPostFling(consumed, available)
- // if we receive an onPostFling after detaching this node, use the last known parent
- // if this parent is also detached it will send the signal through the detached parents
- val parent = if (isAttached) parentConnection else lastKnownValidParentNode
val parentConsumed =
- parent?.onPostFling(consumed + selfConsumed, available - selfConsumed) ?: Velocity.Zero
+ parentConnection?.onPostFling(consumed + selfConsumed, available - selfConsumed)
+ ?: Velocity.Zero
return selfConsumed + parentConsumed
}
@@ -132,9 +128,6 @@
}
override fun onDetach() {
- // cache parent for detached clean up access in the dispatcher and in this node.
- lastKnownValidParentNode = findNearestAttachedAncestor()
- resolvedDispatcher.lastKnownValidParentNode = lastKnownValidParentNode
resetDispatcherFields()
}
@@ -144,9 +137,6 @@
*/
private fun updateDispatcherFields() {
resolvedDispatcher.nestedScrollNode = this
- // reset lastKnownValidParentNodes
- resolvedDispatcher.lastKnownValidParentNode = null
- lastKnownValidParentNode = null
resolvedDispatcher.calculateNestedScrollScope = { nestedCoroutineScope }
resolvedDispatcher.scope = coroutineScope
}
@@ -165,16 +155,3 @@
updateDispatcher(dispatcher)
}
}
-
-private fun <T : TraversableNode> T.findNearestAttachedAncestor(): T? {
- var node: T? = null
- traverseAncestors {
- if (it.node.isAttached) {
- node = it
- false
- } else {
- true
- }
- }
- return node
-}
diff --git a/core/core/integration-tests/publishing/src/test/kotlin/androidx/build/ConstraintTest.kt b/core/core/integration-tests/publishing/src/test/kotlin/androidx/build/ConstraintTest.kt
index c96cd6d..545a3d6 100644
--- a/core/core/integration-tests/publishing/src/test/kotlin/androidx/build/ConstraintTest.kt
+++ b/core/core/integration-tests/publishing/src/test/kotlin/androidx/build/ConstraintTest.kt
@@ -63,32 +63,15 @@
}
}
],
- variants: [
+ "dependencyConstraints": [
{
- "name": "releaseVariantReleaseApiPublication",
- "dependencyConstraints": [
- {
- "group": "org.jetbrains.kotlin",
- "module": "kotlin-stdlib",
- "version": {
- "requires": "1.8.22"
- }
- }
- ],
- },
- {
- "name": "releaseVariantReleaseRuntimePublication",
- "dependencyConstraints": [
- {
- "group": "androidx.preference",
- "module": "preference-ktx",
- "version": {
- "requires": "1.3.0-alpha01"
- }
- }
- ],
- }
- ]
+ "group": "androidx.preference",
+ "module": "preference-ktx",
+ "version": {
+ "requires": "1.3.0-alpha01"
+ }
+ }
+ ],
"files": [
{
"name": "preference-1.3.0-alpha01.aar",
@@ -102,7 +85,7 @@
}
private fun getConstraintVersion(metadata: String, groupId: String, artifact: String): String? =
- getDependencyConstraints(metadata).let {
+ getDependencyConstraints(metadata)?.let {
Regex(
"\"group\": \"$groupId\",\\s+\"module\": " +
"\"$artifact\",\\s+\"version\": \\{\\s+\"requires\": \"(.+?)\""
@@ -114,8 +97,8 @@
}
private fun getDependencyConstraints(moduleJson: String) =
- Regex("(?s)\"dependencyConstraints\": \\[(.+?)]").findAll(moduleJson).joinToString("\n") {
- it.groups.get(1)?.value.orEmpty()
+ moduleJson.let {
+ Regex("(?s)\"dependencyConstraints\": \\[(.+?)]").find(it)?.groups?.get(1)?.value
}
// Yes, I know https://stackoverflow.com/a/1732454/258688, but it's just a test...
diff --git a/datastore/datastore-core-okio/build.gradle b/datastore/datastore-core-okio/build.gradle
index 6fae6c4..76f36b5 100644
--- a/datastore/datastore-core-okio/build.gradle
+++ b/datastore/datastore-core-okio/build.gradle
@@ -22,8 +22,6 @@
* modifying its settings.
*/
-
-import androidx.build.KotlinTarget
import androidx.build.LibraryType
import androidx.build.PlatformIdentifier
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
@@ -103,6 +101,5 @@
type = LibraryType.PUBLISHED_LIBRARY
inceptionYear = "2020"
description = "Android DataStore Core Okio- contains APIs to use datastore-core in multiplatform via okio"
- kotlinTarget = KotlinTarget.KOTLIN_1_9
metalavaK2UastEnabled = false
}
diff --git a/datastore/datastore-guava/build.gradle b/datastore/datastore-guava/build.gradle
index 9b5e7d5..ed7a9bf 100644
--- a/datastore/datastore-guava/build.gradle
+++ b/datastore/datastore-guava/build.gradle
@@ -21,8 +21,6 @@
* Please use that script when creating a new project, rather than copying an existing project and
* modifying its settings.
*/
-
-import androidx.build.KotlinTarget
import androidx.build.LibraryType
plugins {
@@ -62,6 +60,5 @@
type = LibraryType.PUBLISHED_LIBRARY
inceptionYear = "2024"
description = "Android DataStore Guava - contains wrappers for using DataStore using ListenableFuture"
- kotlinTarget = KotlinTarget.KOTLIN_1_9
metalavaK2UastEnabled = true
}
diff --git a/datastore/datastore-rxjava2/build.gradle b/datastore/datastore-rxjava2/build.gradle
index 2403a7c..db861b7 100644
--- a/datastore/datastore-rxjava2/build.gradle
+++ b/datastore/datastore-rxjava2/build.gradle
@@ -21,8 +21,6 @@
* Please use that script when creating a new project, rather than copying an existing project and
* modifying its settings.
*/
-
-import androidx.build.KotlinTarget
import androidx.build.LibraryType
plugins {
@@ -65,6 +63,5 @@
type = LibraryType.PUBLISHED_LIBRARY
inceptionYear = "2020"
description = "Android DataStore Core - contains wrappers for using DataStore using RxJava2"
- kotlinTarget = KotlinTarget.KOTLIN_1_9
legacyDisableKotlinStrictApiMode = true
}
diff --git a/datastore/datastore-rxjava3/build.gradle b/datastore/datastore-rxjava3/build.gradle
index 9d2e9cc..58fe0d7 100644
--- a/datastore/datastore-rxjava3/build.gradle
+++ b/datastore/datastore-rxjava3/build.gradle
@@ -21,8 +21,6 @@
* Please use that script when creating a new project, rather than copying an existing project and
* modifying its settings.
*/
-
-import androidx.build.KotlinTarget
import androidx.build.LibraryType
plugins {
@@ -65,6 +63,5 @@
type = LibraryType.PUBLISHED_LIBRARY
inceptionYear = "2020"
description = "Android DataStore Core - contains wrappers for using DataStore using RxJava2"
- kotlinTarget = KotlinTarget.KOTLIN_1_9
legacyDisableKotlinStrictApiMode = true
}
diff --git a/datastore/datastore/build.gradle b/datastore/datastore/build.gradle
index 8113d77..6bdb7be 100644
--- a/datastore/datastore/build.gradle
+++ b/datastore/datastore/build.gradle
@@ -21,8 +21,6 @@
* Please use that script when creating a new project, rather than copying an existing project and
* modifying its settings.
*/
-
-import androidx.build.KotlinTarget
import androidx.build.LibraryType
import androidx.build.PlatformIdentifier
@@ -114,6 +112,5 @@
inceptionYear = "2020"
description = "Android DataStore - contains the underlying store used by each serialization " +
"method along with components that require an Android dependency"
- kotlinTarget = KotlinTarget.KOTLIN_1_9
legacyDisableKotlinStrictApiMode = true
}
diff --git a/development/importMaven/src/main/kotlin/androidx/build/importMaven/ArtifactResolver.kt b/development/importMaven/src/main/kotlin/androidx/build/importMaven/ArtifactResolver.kt
index cccd79d..185d6ac 100644
--- a/development/importMaven/src/main/kotlin/androidx/build/importMaven/ArtifactResolver.kt
+++ b/development/importMaven/src/main/kotlin/androidx/build/importMaven/ArtifactResolver.kt
@@ -40,6 +40,7 @@
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinUsages
+import org.jetbrains.kotlin.gradle.targets.js.KotlinJsCompilerAttribute
import org.jetbrains.kotlin.gradle.targets.js.KotlinWasmTargetAttribute
import org.jetbrains.kotlin.konan.target.KonanTarget
@@ -428,6 +429,25 @@
}
}
+ val js =
+ KOTlIN_USAGES.map { kotlinUsage ->
+ createConfiguration(*dependencies) {
+ attributes.apply {
+ attribute(Category.CATEGORY_ATTRIBUTE, Category.LIBRARY)
+ attribute(
+ TargetJvmEnvironment.TARGET_JVM_ENVIRONMENT_ATTRIBUTE,
+ "non-jvm"
+ )
+ attribute(Usage.USAGE_ATTRIBUTE, kotlinUsage)
+ attribute(
+ KotlinJsCompilerAttribute.jsCompilerAttribute,
+ KotlinJsCompilerAttribute.ir
+ )
+ attribute(KotlinPlatformType.attribute, KotlinPlatformType.js)
+ }
+ }
+ }
+
val commonArtifacts = KOTlIN_USAGES.map { kotlinUsage ->
createConfiguration(*dependencies) {
attributes.apply {
@@ -437,7 +457,7 @@
}
}
}
- return jvmAndAndroid + wasmJs + konanTargetConfigurations + commonArtifacts
+ return jvmAndAndroid + wasmJs + js + konanTargetConfigurations + commonArtifacts
}
private fun createKonanTargetConfiguration(
diff --git a/development/update_kotlin.sh b/development/update_kotlin.sh
index eff00fd..b6f492a 100755
--- a/development/update_kotlin.sh
+++ b/development/update_kotlin.sh
@@ -2,12 +2,14 @@
set -e
KOTLIN_VERSION="$1"
-KSP_VERSION="$2"
-if [[ $# -eq 0 ]] ; then
- echo "Usage ./development/update_kotlin.sh <kotlin_version> [<ksp_version>]"
- exit 1
-fi
+ALLOW_JETBRAINS_DEV=""
+for arg in "$@"
+do
+ if [ "$arg" == "--allow-jetbrains-dev" ]; then
+ ALLOW_JETBRAINS_DEV="--allow-jetbrains-dev"
+ fi
+done
# Download maven artifacts
ARTIFACTS_TO_DOWNLOAD="org.jetbrains.kotlin:kotlin-gradle-plugin:$KOTLIN_VERSION,"
@@ -36,39 +38,7 @@
ARTIFACTS_TO_DOWNLOAD+="org.jetbrains.kotlin:kotlin-native-prebuilt:$KOTLIN_VERSION:[email protected],"
ARTIFACTS_TO_DOWNLOAD+="org.jetbrains.kotlin:kotlin-native-prebuilt:$KOTLIN_VERSION:[email protected],"
-if [ "$KSP_VERSION" ]; then
- ARTIFACTS_TO_DOWNLOAD+="com.google.devtools.ksp:symbol-processing:$KSP_VERSION,"
- ARTIFACTS_TO_DOWNLOAD+="com.google.devtools.ksp:symbol-processing-api:$KSP_VERSION,"
- ARTIFACTS_TO_DOWNLOAD+="com.google.devtools.ksp:symbol-processing-cmdline:$KSP_VERSION,"
- ARTIFACTS_TO_DOWNLOAD+="com.google.devtools.ksp:symbol-processing-gradle-plugin:$KSP_VERSION,"
- ARTIFACTS_TO_DOWNLOAD+="com.google.devtools.ksp:symbol-processing-aa-embeddable:$KSP_VERSION,"
-fi
+./development/importMaven/importMaven.sh "$ALLOW_JETBRAINS_DEV" "$ARTIFACTS_TO_DOWNLOAD"
-./development/importMaven/importMaven.sh "$ARTIFACTS_TO_DOWNLOAD"
+ ./development/importMaven/importMaven.sh import-konan-binaries --konan-compiler-version "$KOTLIN_VERSION"
-# symlink native compiler prebuilt archives from prebuilts/androidx/external to prebuilts/androidx/konan
-# to make KonanPrebuiltsSetup.kt work.
-rm -fr "../../prebuilts/androidx/konan/nativeCompilerPrebuilts/releases"
-
-REAL_NATIVE_PREBUILT_DIR="../../../../../external/org/jetbrains/kotlin/kotlin-native-prebuilt/$KOTLIN_VERSION/"
-
-LINUX_DIR="../../prebuilts/androidx/konan/nativeCompilerPrebuilts/releases/$KOTLIN_VERSION/linux-x86_64"
-mkdir -p "$LINUX_DIR"
-ln -s -f "$REAL_NATIVE_PREBUILT_DIR/kotlin-native-prebuilt-$KOTLIN_VERSION-linux-x86_64.tar.gz" \
- "$LINUX_DIR/kotlin-native-prebuilt-linux-x86_64-$KOTLIN_VERSION.tar.gz"
-ln -s -f "$REAL_NATIVE_PREBUILT_DIR/kotlin-native-prebuilt-$KOTLIN_VERSION-linux-x86_64.tar.gz.asc" \
- "$LINUX_DIR/kotlin-native-prebuilt-linux-x86_64-$KOTLIN_VERSION.tar.gz.asc"
-
-MAC_ARM_DIR="../../prebuilts/androidx/konan/nativeCompilerPrebuilts/releases/$KOTLIN_VERSION/macos-aarch64"
-mkdir -p "$MAC_ARM_DIR"
-ln -s -f "$REAL_NATIVE_PREBUILT_DIR/kotlin-native-prebuilt-$KOTLIN_VERSION-macos-aarch64.tar.gz" \
- "$MAC_ARM_DIR/kotlin-native-prebuilt-macos-aarch64-$KOTLIN_VERSION.tar.gz"
-ln -s -f "$REAL_NATIVE_PREBUILT_DIR/kotlin-native-prebuilt-$KOTLIN_VERSION-macos-aarch64.tar.gz.asc" \
- "$MAC_ARM_DIR/kotlin-native-prebuilt-macos-aarch64-$KOTLIN_VERSION.tar.gz.asc"
-
-MAC_X86_DIR="../../prebuilts/androidx/konan/nativeCompilerPrebuilts/releases/$KOTLIN_VERSION/macos-x86_64"
-mkdir -p "$MAC_X86_DIR"
-ln -s -f "$REAL_NATIVE_PREBUILT_DIR/kotlin-native-prebuilt-$KOTLIN_VERSION-macos-x86_64.tar.gz" \
- "$MAC_X86_DIR/kotlin-native-prebuilt-macos-x86_64-$KOTLIN_VERSION.tar.gz"
-ln -s -f "$REAL_NATIVE_PREBUILT_DIR/kotlin-native-prebuilt-$KOTLIN_VERSION-macos-x86_64.tar.gz.asc" \
- "$MAC_X86_DIR/kotlin-native-prebuilt-macos-x86_64-$KOTLIN_VERSION.tar.gz.asc"
diff --git a/docs-tip-of-tree/build.gradle b/docs-tip-of-tree/build.gradle
index c082e75..822623e 100644
--- a/docs-tip-of-tree/build.gradle
+++ b/docs-tip-of-tree/build.gradle
@@ -366,6 +366,7 @@
docs(project(":wear:protolayout:protolayout-material"))
docs(project(":wear:protolayout:protolayout-material-core"))
docs(project(":wear:protolayout:protolayout-material3"))
+ samples(project(":wear:protolayout:protolayout-material3-samples"))
docs(project(":wear:protolayout:protolayout-renderer"))
docs(project(":wear:protolayout:protolayout-testing"))
docs(project(":wear:tiles:tiles"))
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 3a9fe44..66db4f6 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -45,7 +45,7 @@
kotlin17 = "1.7.10"
kotlin18 = "1.8.22"
kotlin19 = "1.9.24"
-kotlin = "2.0.21-RC"
+kotlin = "2.0.10"
kotlinBenchmark = "0.4.11"
kotlinGradlePluginAnnotations = "1.9.24"
kotlinGradlePluginApi = "1.9.24"
@@ -54,7 +54,7 @@
kotlinNativeUtils = "1.9.24"
kotlinSerialization = "1.6.3"
kotlinToolingCore = "1.9.24"
-ksp = "2.0.20-1.0.25"
+ksp = "2.0.10-1.0.24"
ktfmt = "0.50"
leakcanary = "2.13"
media3 = "1.4.1"
@@ -62,7 +62,7 @@
mockito = "2.25.0"
moshi = "1.13.0"
node = "16.20.2"
-protobuf = "3.22.3"
+protobuf = "4.28.2"
skiko = "0.7.7"
spdxGradlePlugin = "0.6.0"
sqldelight = "1.3.0"
@@ -276,7 +276,6 @@
protobufCompiler = { module = "com.google.protobuf:protoc", version.ref = "protobuf" }
protobufGradlePlugin = { module = "com.google.protobuf:protobuf-gradle-plugin", version = "0.9.4" }
protobufLite = { module = "com.google.protobuf:protobuf-javalite", version.ref = "protobuf" }
-protobufKotlin = { module = "com.google.protobuf:protobuf-kotlin", version.ref = "protobuf" }
reactiveStreams = { module = "org.reactivestreams:reactive-streams", version = "1.0.0" }
retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" }
retrofitConverterWire = { module = "com.squareup.retrofit2:converter-wire", version.ref = "retrofit" }
diff --git a/health/connect/connect-testing/src/main/java/androidx/health/connect/client/testing/RecordTestUtils.kt b/health/connect/connect-testing/src/main/java/androidx/health/connect/client/testing/RecordTestUtils.kt
index 3c3dd99..74f741d 100644
--- a/health/connect/connect-testing/src/main/java/androidx/health/connect/client/testing/RecordTestUtils.kt
+++ b/health/connect/connect-testing/src/main/java/androidx/health/connect/client/testing/RecordTestUtils.kt
@@ -37,22 +37,22 @@
if (proto.hasInstantTimeMillis()) {
val time =
LocalDateTime.ofInstant(proto.time, proto.zoneOffset ?: ZoneId.systemDefault())
- return !time.isBefore(timeRangeFilter.localStartTime) &&
+ return !time.isBefore(timeRangeFilter.localStartTime!!) &&
timeRangeFilter.localEndTime!!.isAfter(time)
}
val startTime =
LocalDateTime.ofInstant(proto.startTime, proto.zoneOffset ?: ZoneId.systemDefault())
- return !startTime.isBefore(timeRangeFilter.localStartTime) &&
+ return !startTime.isBefore(timeRangeFilter.localStartTime!!) &&
timeRangeFilter.localEndTime!!.isAfter(startTime)
}
if (proto.hasInstantTimeMillis()) {
- return proto.time >= timeRangeFilter.startTime && // Inclusive
- proto.time.isBefore(timeRangeFilter.endTime) // Exclusive
+ return proto.time >= timeRangeFilter.startTime!! && // Inclusive
+ proto.time.isBefore(timeRangeFilter.endTime!!) // Exclusive
}
- return proto.startTime >= timeRangeFilter.startTime && // Inclusive
- proto.endTime.isBefore(timeRangeFilter.endTime) // Exclusive
+ return proto.startTime >= timeRangeFilter.startTime!! && // Inclusive
+ proto.endTime.isBefore(timeRangeFilter.endTime!!) // Exclusive
}
private fun TimeRangeFilter.sanitize(clock: Clock): TimeRangeFilter {
diff --git a/libraryversions.toml b/libraryversions.toml
index 9da553b..8a6f498 100644
--- a/libraryversions.toml
+++ b/libraryversions.toml
@@ -1,5 +1,5 @@
[versions]
-ACTIVITY = "1.10.0-alpha02"
+ACTIVITY = "1.10.0-alpha03"
ANNOTATION = "1.9.0-rc01"
ANNOTATION_EXPERIMENTAL = "1.5.0-alpha01"
APPCOMPAT = "1.8.0-alpha01"
@@ -7,7 +7,7 @@
ARCH_CORE = "2.3.0-alpha01"
ASYNCLAYOUTINFLATER = "1.1.0-alpha02"
AUTOFILL = "1.3.0-beta01"
-BENCHMARK = "1.4.0-alpha02"
+BENCHMARK = "1.4.0-alpha03"
BIOMETRIC = "1.4.0-alpha02"
BLUETOOTH = "1.0.0-alpha02"
BROWSER = "1.9.0-alpha01"
@@ -19,12 +19,12 @@
CAMERA_VIEWFINDER = "1.4.0-alpha09"
CARDVIEW = "1.1.0-alpha01"
CAR_APP = "1.7.0-beta02"
-COLLECTION = "1.5.0-alpha03"
-COMPOSE = "1.8.0-alpha03"
+COLLECTION = "1.5.0-alpha04"
+COMPOSE = "1.8.0-alpha04"
COMPOSE_MATERIAL3 = "1.4.0-alpha01"
COMPOSE_MATERIAL3_ADAPTIVE = "1.1.0-alpha04"
COMPOSE_MATERIAL3_COMMON = "1.0.0-alpha01"
-COMPOSE_RUNTIME = "1.8.0-alpha03"
+COMPOSE_RUNTIME = "1.8.0-alpha04"
CONSTRAINTLAYOUT = "2.2.0-beta01"
CONSTRAINTLAYOUT_COMPOSE = "1.1.0-beta01"
CONSTRAINTLAYOUT_CORE = "1.1.0-beta01"
@@ -91,7 +91,7 @@
LEANBACK_TAB = "1.1.0-beta01"
LEGACY = "1.1.0-alpha01"
LIBYUV = "0.1.0-dev01"
-LIFECYCLE = "2.9.0-alpha04"
+LIFECYCLE = "2.9.0-alpha05"
LIFECYCLE_EXTENSIONS = "2.2.0"
LINT = "1.0.0-alpha02"
LOADER = "1.2.0-alpha01"
@@ -117,9 +117,9 @@
RECYCLERVIEW_SELECTION = "1.2.0-alpha02"
REMOTECALLBACK = "1.0.0-alpha02"
RESOURCEINSPECTION = "1.1.0-alpha01"
-ROOM = "2.7.0-alpha09"
+ROOM = "2.7.0-alpha10"
SAFEPARCEL = "1.0.0-alpha01"
-SAVEDSTATE = "1.3.0-alpha02"
+SAVEDSTATE = "1.3.0-alpha03"
SECURITY = "1.1.0-alpha07"
SECURITY_APP_AUTHENTICATOR = "1.0.0-rc01"
SECURITY_APP_AUTHENTICATOR_TESTING = "1.0.0-rc01"
@@ -133,7 +133,7 @@
SLICE_BUILDERS_KTX = "1.0.0-alpha09"
SLICE_REMOTECALLBACK = "1.0.0-alpha01"
SLIDINGPANELAYOUT = "1.3.0-alpha01"
-SQLITE = "2.5.0-alpha09"
+SQLITE = "2.5.0-alpha10"
SQLITE_INSPECTOR = "2.1.0-alpha01"
STABLE_AIDL = "1.0.0-alpha01"
STARTUP = "1.2.0-rc01"
@@ -174,7 +174,7 @@
WINDOW_EXTENSIONS = "1.4.0-beta01"
WINDOW_EXTENSIONS_CORE = "1.1.0-alpha01"
WINDOW_SIDECAR = "1.0.0-rc01"
-WORK = "2.10.0-beta01"
+WORK = "2.10.0-rc01"
XR = "1.0.0-alpha01"
[groups]
diff --git a/navigation/navigation-runtime-lint/build.gradle b/navigation/navigation-runtime-lint/build.gradle
index 8baa413..575793e 100644
--- a/navigation/navigation-runtime-lint/build.gradle
+++ b/navigation/navigation-runtime-lint/build.gradle
@@ -38,7 +38,6 @@
compileOnly(libs.androidToolsCommon)
compileOnly(libs.intellijCore)
compileOnly(libs.uast)
- bundleInside(project(":navigation:navigation-common-lint"))
bundleInside(project(":navigation:navigation-lint-common"))
testImplementation(libs.kotlinStdlib)
diff --git a/paging/paging-common/bcv/native/current.txt b/paging/paging-common/bcv/native/current.txt
index 61b670d..64890c9 100644
--- a/paging/paging-common/bcv/native/current.txt
+++ b/paging/paging-common/bcv/native/current.txt
@@ -70,6 +70,8 @@
final fun unregisterInvalidatedCallback(kotlin/Function0<kotlin/Unit>) // androidx.paging/PagingSource.unregisterInvalidatedCallback|unregisterInvalidatedCallback(kotlin.Function0<kotlin.Unit>){}[0]
sealed class <#A1: kotlin/Any, #B1: kotlin/Any> LoadResult { // androidx.paging/PagingSource.LoadResult|null[0]
+ constructor <init>() // androidx.paging/PagingSource.LoadResult.<init>|<init>(){}[0]
+
final class <#A2: kotlin/Any, #B2: kotlin/Any> Error : androidx.paging/PagingSource.LoadResult<#A2, #B2> { // androidx.paging/PagingSource.LoadResult.Error|null[0]
constructor <init>(kotlin/Throwable) // androidx.paging/PagingSource.LoadResult.Error.<init>|<init>(kotlin.Throwable){}[0]
@@ -123,6 +125,8 @@
}
sealed class <#A1: kotlin/Any> LoadParams { // androidx.paging/PagingSource.LoadParams|null[0]
+ constructor <init>(kotlin/Int, kotlin/Boolean) // androidx.paging/PagingSource.LoadParams.<init>|<init>(kotlin.Int;kotlin.Boolean){}[0]
+
abstract val key // androidx.paging/PagingSource.LoadParams.key|{}key[0]
abstract fun <get-key>(): #A1? // androidx.paging/PagingSource.LoadParams.key.<get-key>|<get-key>(){}[0]
final val loadSize // androidx.paging/PagingSource.LoadParams.loadSize|{}loadSize[0]
@@ -168,6 +172,8 @@
}
sealed class MediatorResult { // androidx.paging/RemoteMediator.MediatorResult|null[0]
+ constructor <init>() // androidx.paging/RemoteMediator.MediatorResult.<init>|<init>(){}[0]
+
final class Error : androidx.paging/RemoteMediator.MediatorResult { // androidx.paging/RemoteMediator.MediatorResult.Error|null[0]
constructor <init>(kotlin/Throwable) // androidx.paging/RemoteMediator.MediatorResult.Error.<init>|<init>(kotlin.Throwable){}[0]
@@ -336,6 +342,8 @@
}
sealed class <#A: kotlin/Any> androidx.paging/PagingDataEvent { // androidx.paging/PagingDataEvent|null[0]
+ constructor <init>() // androidx.paging/PagingDataEvent.<init>|<init>(){}[0]
+
final class <#A1: kotlin/Any> Append : androidx.paging/PagingDataEvent<#A1> { // androidx.paging/PagingDataEvent.Append|null[0]
constructor <init>(kotlin/Int, kotlin.collections/List<#A1>, kotlin/Int, kotlin/Int) // androidx.paging/PagingDataEvent.Append.<init>|<init>(kotlin.Int;kotlin.collections.List<1:0>;kotlin.Int;kotlin.Int){}[0]
@@ -415,6 +423,8 @@
}
sealed class androidx.paging/LoadState { // androidx.paging/LoadState|null[0]
+ constructor <init>(kotlin/Boolean) // androidx.paging/LoadState.<init>|<init>(kotlin.Boolean){}[0]
+
final val endOfPaginationReached // androidx.paging/LoadState.endOfPaginationReached|{}endOfPaginationReached[0]
final fun <get-endOfPaginationReached>(): kotlin/Boolean // androidx.paging/LoadState.endOfPaginationReached.<get-endOfPaginationReached>|<get-endOfPaginationReached>(){}[0]
diff --git a/pdf/pdf-viewer-fragment/src/main/java/androidx/pdf/viewer/fragment/PdfViewerFragment.kt b/pdf/pdf-viewer-fragment/src/main/java/androidx/pdf/viewer/fragment/PdfViewerFragment.kt
index ab10603..ac0ae4c 100644
--- a/pdf/pdf-viewer-fragment/src/main/java/androidx/pdf/viewer/fragment/PdfViewerFragment.kt
+++ b/pdf/pdf-viewer-fragment/src/main/java/androidx/pdf/viewer/fragment/PdfViewerFragment.kt
@@ -262,11 +262,6 @@
): View? {
super.onCreateView(inflater, container, savedInstanceState)
this.container = container
- if (!hasContents && delayedContentsAvailable == null) {
- if (savedInstanceState != null) {
- restoreContents(savedInstanceState)
- }
- }
pdfViewer = inflater.inflate(R.layout.pdf_viewer_container, container, false) as FrameLayout
pdfViewer?.isScrollContainer = true
@@ -313,7 +308,9 @@
// and no means to load it. The best way is to just kill the service which
// will restart on the next onStart.
pdfLoader?.disconnect()
+ return@PdfLoaderCallbacksImpl true
}
+ return@PdfLoaderCallbacksImpl false
},
onDocumentLoaded = {
documentLoaded = true
@@ -354,6 +351,12 @@
}
}
+ if (!hasContents && delayedContentsAvailable == null) {
+ if (savedInstanceState != null) {
+ restoreContents(savedInstanceState)
+ }
+ }
+
return pdfViewer
}
@@ -402,7 +405,6 @@
if (onScreen) {
onExit()
}
- onScreen = false
started = false
super.onStop()
}
@@ -688,6 +690,7 @@
fileData?.let {
localUri = it.uri
postContentsAvailable(it)
+ postEnter()
}
} catch (e: Exception) {
// This can happen if the data is an instance of StreamOpenable, and the client
@@ -735,6 +738,7 @@
pdfLoaderCallbacks?.searchModel = null
+ pdfLoader?.disconnect()
pdfLoader = null
documentLoaded = false
}
diff --git a/pdf/pdf-viewer/src/main/java/androidx/pdf/viewer/PageMosaicView.java b/pdf/pdf-viewer/src/main/java/androidx/pdf/viewer/PageMosaicView.java
index 3a8b773..7b18834 100644
--- a/pdf/pdf-viewer/src/main/java/androidx/pdf/viewer/PageMosaicView.java
+++ b/pdf/pdf-viewer/src/main/java/androidx/pdf/viewer/PageMosaicView.java
@@ -109,10 +109,13 @@
@NonNull
protected String buildContentDescription(@Nullable String pageText, int pageNum) {
- return (pageText != null)
- ? pageText
- : getContext()
- .getString(androidx.pdf.R.string.desc_page, (mPageNum + 1));
+ if (pageText != null) {
+ if (pageText.trim().isEmpty()) {
+ return getContext().getString(androidx.pdf.R.string.desc_empty_page);
+ }
+ return pageText;
+ }
+ return getContext().getString(androidx.pdf.R.string.desc_page, (mPageNum + 1));
}
/** Returns true if we have data about any links on the page. */
diff --git a/pdf/pdf-viewer/src/main/java/androidx/pdf/viewer/PdfSelectionHandles.java b/pdf/pdf-viewer/src/main/java/androidx/pdf/viewer/PdfSelectionHandles.java
index d91d660..99ad13f 100644
--- a/pdf/pdf-viewer/src/main/java/androidx/pdf/viewer/PdfSelectionHandles.java
+++ b/pdf/pdf-viewer/src/main/java/androidx/pdf/viewer/PdfSelectionHandles.java
@@ -28,6 +28,7 @@
import androidx.pdf.models.SelectionBoundary;
import androidx.pdf.select.SelectionActionMode;
import androidx.pdf.select.SelectionModel;
+import androidx.pdf.util.Accessibility;
import androidx.pdf.util.Preconditions;
import androidx.pdf.widget.ZoomView;
import androidx.pdf.widget.ZoomableSelectionHandles;
@@ -45,6 +46,7 @@
private SelectionBoundary mDragging;
private SelectionActionMode mSelectionActionMode;
+ private Boolean mIsSelectionHandlesVisible;
public PdfSelectionHandles(
@NonNull PdfSelectionModel selectionModel, @NonNull ZoomView zoomView,
@@ -62,10 +64,17 @@
protected void updateHandles() {
if (mSelection == null || mPdfView.getViewAt(mSelection.getPage()) == null) {
hideHandles();
+ mIsSelectionHandlesVisible = false;
} else {
View pageView = mPdfView.getViewAt(mSelection.getPage()).asView();
showHandle(mStartHandle, pageView, mSelection.getStart(), false);
showHandle(mStopHandle, pageView, mSelection.getStop(), true);
+
+ if (!mIsSelectionHandlesVisible) {
+ Accessibility.get().announce(mZoomView.getContext(), mZoomView,
+ mSelection.getText());
+ mIsSelectionHandlesVisible = true;
+ }
}
}
@@ -96,6 +105,8 @@
protected void onDragHandleUp() {
mSelectionActionMode.resume();
mPdfView.performHapticFeedback(HapticFeedbackConstants.TEXT_HANDLE_MOVE);
+ Accessibility.get().announce(mZoomView.getContext(), mZoomView,
+ mSelection.getText());
}
@NonNull
diff --git a/pdf/pdf-viewer/src/main/java/androidx/pdf/viewer/loader/PdfConnection.java b/pdf/pdf-viewer/src/main/java/androidx/pdf/viewer/loader/PdfConnection.java
index df72681..a86c12b 100644
--- a/pdf/pdf-viewer/src/main/java/androidx/pdf/viewer/loader/PdfConnection.java
+++ b/pdf/pdf-viewer/src/main/java/androidx/pdf/viewer/loader/PdfConnection.java
@@ -74,6 +74,11 @@
this.mOnConnectFailure = onConnectFailure;
}
+ /** Checks if Connection to PdfDocumentService is established */
+ public boolean isConnected() {
+ return mConnected;
+ }
+
/**
* Returns a {@link PdfDocumentRemote} if the service is bound. It could be still initializing
* (see {@link #setDocumentLoaded}).
diff --git a/pdf/pdf-viewer/src/main/java/androidx/pdf/viewer/loader/PdfLoader.java b/pdf/pdf-viewer/src/main/java/androidx/pdf/viewer/loader/PdfLoader.java
index cf49ad7..4506163 100644
--- a/pdf/pdf-viewer/src/main/java/androidx/pdf/viewer/loader/PdfLoader.java
+++ b/pdf/pdf-viewer/src/main/java/androidx/pdf/viewer/loader/PdfLoader.java
@@ -139,7 +139,26 @@
/** Schedule task to load a PdfDocument. */
public void reloadDocument() {
- mExecutor.schedule(new LoadDocumentTask(mLoadedPassword));
+ if (isConnected()) {
+ mExecutor.schedule(new LoadDocumentTask(mLoadedPassword));
+ } else {
+ /*
+ * For password protected files we kill the service if the app goes into
+ * background before the document is loaded hence here we just register a
+ * task which will be executed once the service is reconnected onStart
+ */
+ mConnection.setOnConnectInitializer(
+ () -> mExecutor.schedule(new LoadDocumentTask(mLoadedPassword)));
+ mConnection.setConnectionFailureHandler(
+ () -> mCallbacks.documentNotLoaded(PdfStatus.NONE));
+ }
+ }
+
+ /**
+ * Check if PdfLoader is connected to PdfDocumentService
+ */
+ public boolean isConnected() {
+ return mConnection.isConnected();
}
/**
diff --git a/pdf/pdf-viewer/src/main/java/androidx/pdf/viewer/loader/PdfLoaderCallbacksImpl.kt b/pdf/pdf-viewer/src/main/java/androidx/pdf/viewer/loader/PdfLoaderCallbacksImpl.kt
index 7b2d1b0..2f5210b 100644
--- a/pdf/pdf-viewer/src/main/java/androidx/pdf/viewer/loader/PdfLoaderCallbacksImpl.kt
+++ b/pdf/pdf-viewer/src/main/java/androidx/pdf/viewer/loader/PdfLoaderCallbacksImpl.kt
@@ -67,7 +67,7 @@
private var isTextSearchActive: Boolean,
private var viewState: ExposedValue<ViewState>,
private val fragmentContainerView: View?,
- private val onRequestPassword: (Boolean) -> Unit,
+ private val onRequestPassword: (Boolean) -> Boolean,
private val onDocumentLoaded: () -> Unit,
private val onDocumentLoadFailure: (Throwable) -> Unit,
private var eventCallback: EventCallback?,
@@ -148,39 +148,39 @@
override fun requestPassword(incorrect: Boolean) {
eventCallback?.onViewerReset()
- onRequestPassword(onScreen)
+ if (onRequestPassword(onScreen)) return
if (viewState.get() != ViewState.NO_VIEW) {
var passwordDialog = currentPasswordDialog(fragmentManager)
if (passwordDialog == null) {
passwordDialog = PdfPasswordDialog()
- passwordDialog.setListener(
- object : PdfPasswordDialog.PasswordDialogEventsListener {
- override fun onPasswordTextChange(password: String) {
- pdfLoader?.applyPassword(password)
- }
-
- override fun onDialogCancelled() {
- val retryCallback = Runnable { requestPassword(false) }
- val snackbar =
- fragmentContainerView?.let {
- Snackbar.make(
- it,
- R.string.password_not_entered,
- Snackbar.LENGTH_INDEFINITE
- )
- }
- val mResolveClickListener =
- View.OnClickListener { _: View? -> retryCallback.run() }
- snackbar?.setAction(R.string.retry_button_text, mResolveClickListener)
- snackbar?.show()
- }
- }
- )
-
passwordDialog.show(fragmentManager, PASSWORD_DIALOG_TAG)
}
+ passwordDialog.setListener(
+ object : PdfPasswordDialog.PasswordDialogEventsListener {
+ override fun onPasswordTextChange(password: String) {
+ pdfLoader?.applyPassword(password)
+ }
+
+ override fun onDialogCancelled() {
+ val retryCallback = Runnable { requestPassword(false) }
+ val snackbar =
+ fragmentContainerView?.let {
+ Snackbar.make(
+ it,
+ R.string.password_not_entered,
+ Snackbar.LENGTH_INDEFINITE
+ )
+ }
+ val mResolveClickListener =
+ View.OnClickListener { _: View? -> retryCallback.run() }
+ snackbar?.setAction(R.string.retry_button_text, mResolveClickListener)
+ snackbar?.show()
+ }
+ }
+ )
+
if (incorrect) {
passwordDialog.retry()
}
diff --git a/pdf/pdf-viewer/src/main/java/androidx/pdf/viewer/password/PasswordDialog.java b/pdf/pdf-viewer/src/main/java/androidx/pdf/viewer/password/PasswordDialog.java
index a994a5d..d887f00 100644
--- a/pdf/pdf-viewer/src/main/java/androidx/pdf/viewer/password/PasswordDialog.java
+++ b/pdf/pdf-viewer/src/main/java/androidx/pdf/viewer/password/PasswordDialog.java
@@ -63,6 +63,7 @@
private int mBlueColor;
private int mTextErrorColor;
private AlertDialog mPasswordDialog;
+ private static final String PASSWORD_INPUT = "password_input";
private boolean mIncorrect;
private boolean mFinishOnCancel;
@@ -92,6 +93,11 @@
final EditText passwordField = (EditText) view.findViewById(R.id.password);
setupPasswordField(passwordField);
+ if (savedInstanceState != null) {
+ String savedPassword = savedInstanceState.getString(PASSWORD_INPUT, "");
+ passwordField.setText(savedPassword);
+ }
+
// Hijack the positive button to NOT dismiss the dialog immediately.
dialog.setOnShowListener(
new OnShowListener() {
@@ -146,6 +152,17 @@
return dialog;
}
+ @Override
+ public void onSaveInstanceState(@NonNull Bundle outState) {
+ super.onSaveInstanceState(outState);
+ // Find the EditText by its ID
+ EditText editTextPassword = (EditText) mPasswordDialog.findViewById(R.id.password);
+ // Get the text from the EditText and store it in passwordInput
+ String passwordInput = editTextPassword.getText().toString();
+ // Save the input to the outState bundle
+ outState.putString(PASSWORD_INPUT, passwordInput);
+ }
+
private void setupPasswordField(final EditText passwordField) {
passwordField.setFocusable(true);
passwordField.requestFocus();
diff --git a/pdf/pdf-viewer/src/main/res/layout/find_in_file.xml b/pdf/pdf-viewer/src/main/res/layout/find_in_file.xml
index d58540a..0e33f06 100644
--- a/pdf/pdf-viewer/src/main/res/layout/find_in_file.xml
+++ b/pdf/pdf-viewer/src/main/res/layout/find_in_file.xml
@@ -57,41 +57,37 @@
<ImageButton
android:id="@+id/find_prev_btn"
- android:layout_width="34dp"
- android:layout_height="34dp"
+ android:layout_width="@dimen/find_in_file_button_size"
+ android:layout_height="@dimen/find_in_file_button_size"
android:background="@drawable/shape_oval"
android:src="@drawable/keyboard_up"
app:tint="?attr/colorOnSurfaceVariant"
android:cropToPadding="true"
android:padding="3dp"
android:scaleType="centerInside"
- android:layout_margin="5dp"
android:contentDescription = "@string/previous_button_description"/>
<ImageButton
android:id="@+id/find_next_btn"
- android:layout_width="34dp"
- android:layout_height="34dp"
+ android:layout_width="@dimen/find_in_file_button_size"
+ android:layout_height="@dimen/find_in_file_button_size"
android:background="@drawable/shape_oval"
android:src="@drawable/keyboard_down"
app:tint="?attr/colorOnSurfaceVariant"
android:cropToPadding="true"
android:padding="3dp"
android:scaleType="centerInside"
- android:layout_margin="5dp"
android:contentDescription = "@string/next_button_description"/>
<ImageButton
android:id="@+id/close_btn"
- android:layout_width="34dp"
- android:layout_height="34dp"
+ android:layout_width="@dimen/find_in_file_button_size"
+ android:layout_height="@dimen/find_in_file_button_size"
android:background="@drawable/shape_oval"
android:src="@drawable/close_button"
app:tint="?attr/colorOnSurfaceVariant"
android:cropToPadding="true"
android:padding="5dp"
android:scaleType="centerInside"
- android:layout_marginVertical="5dp"
- android:layout_marginLeft="5dp"
android:layout_marginRight="10dp"
android:contentDescription = "@string/close_button_description"/>
diff --git a/pdf/pdf-viewer/src/main/res/menu/context_menu.xml b/pdf/pdf-viewer/src/main/res/menu/context_menu.xml
index 9557c52..156ad91 100644
--- a/pdf/pdf-viewer/src/main/res/menu/context_menu.xml
+++ b/pdf/pdf-viewer/src/main/res/menu/context_menu.xml
@@ -21,10 +21,12 @@
android:id="@+id/action_copy"
android:icon="?android:attr/actionModeCopyDrawable"
android:title="@android:string/copy"
- android:alphabeticShortcut="c" />
+ android:alphabeticShortcut="c"
+ android:contentDescription="@android:string/copy"/>
<item
android:id="@+id/action_selectAll"
android:icon="?android:attr/actionModeSelectAllDrawable"
android:title="@android:string/selectAll"
- android:alphabeticShortcut="a" />
+ android:alphabeticShortcut="a"
+ android:contentDescription="@android:string/selectAll"/>
</menu>
\ No newline at end of file
diff --git a/pdf/pdf-viewer/src/main/res/values/dimensions.xml b/pdf/pdf-viewer/src/main/res/values/dimensions.xml
index 584fda6..ab5c220 100644
--- a/pdf/pdf-viewer/src/main/res/values/dimensions.xml
+++ b/pdf/pdf-viewer/src/main/res/values/dimensions.xml
@@ -23,4 +23,7 @@
<dimen name="viewer_edit_fab_margin_bottom">16dp</dimen>
<dimen name="viewer_edit_fab_margin_right">16dp</dimen>
+ <!--Find in file button size -->
+ <dimen name="find_in_file_button_size">48dp</dimen>
+
</resources>
diff --git a/pdf/pdf-viewer/src/main/res/values/strings.xml b/pdf/pdf-viewer/src/main/res/values/strings.xml
index c6ad40f..20aa27e 100644
--- a/pdf/pdf-viewer/src/main/res/values/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values/strings.xml
@@ -57,6 +57,9 @@
<!-- Content description for a page of a paginated document, eg "page 3". [CHAR LIMIT=50] -->
<string name="desc_page">page <xliff:g example="3" id="page">%1$d</xliff:g></string>
+ <!-- Content description for an empty page of a paginated document -->
+ <string name="desc_empty_page">Empty page</string>
+
<!-- Error message when file format isn't valid PDF. [CHAR LIMIT=60] -->
<string name="error_file_format_pdf">Cannot display PDF ("<xliff:g example="Treasure Island" id="title">%1$s</xliff:g>" is of invalid format)</string>
diff --git a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/KotlinMetadataTest.kt b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/KotlinMetadataTest.kt
index 6f711e5..68add33 100644
--- a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/KotlinMetadataTest.kt
+++ b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/KotlinMetadataTest.kt
@@ -24,7 +24,6 @@
import androidx.room.compiler.processing.util.getParameter
import androidx.room.compiler.processing.util.runKaptTest
import androidx.room.compiler.processing.util.runProcessorTest
-import org.junit.Ignore
import org.junit.Test
class KotlinMetadataTest {
@@ -49,7 +48,6 @@
}
}
- @Ignore("b/360398921")
@Test
fun inlineReifiedFunctionAndKAPT4() {
val source =
diff --git a/room/room-migration/bcv/native/current.txt b/room/room-migration/bcv/native/current.txt
index 9b3bd15..0b1314c 100644
--- a/room/room-migration/bcv/native/current.txt
+++ b/room/room-migration/bcv/native/current.txt
@@ -337,6 +337,9 @@
}
sealed class androidx.room.migration.bundle/BaseEntityBundle { // androidx.room.migration.bundle/BaseEntityBundle|null[0]
+ constructor <init>() // androidx.room.migration.bundle/BaseEntityBundle.<init>|<init>(){}[0]
+ constructor <init>(kotlin/Int, kotlinx.serialization.internal/SerializationConstructorMarker?) // androidx.room.migration.bundle/BaseEntityBundle.<init>|<init>(kotlin.Int;kotlinx.serialization.internal.SerializationConstructorMarker?){}[0]
+
abstract val createSql // androidx.room.migration.bundle/BaseEntityBundle.createSql|{}createSql[0]
abstract fun <get-createSql>(): kotlin/String // androidx.room.migration.bundle/BaseEntityBundle.createSql.<get-createSql>|<get-createSql>(){}[0]
abstract val fields // androidx.room.migration.bundle/BaseEntityBundle.fields|{}fields[0]
diff --git a/settings.gradle b/settings.gradle
index 867951c..e9a417f 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1011,6 +1011,7 @@
includeProject(":wear:protolayout:protolayout-material", [BuildType.MAIN, BuildType.WEAR])
includeProject(":wear:protolayout:protolayout-material-core", [BuildType.MAIN, BuildType.WEAR])
includeProject(":wear:protolayout:protolayout-material3", [BuildType.MAIN, BuildType.WEAR])
+includeProject(":wear:protolayout:protolayout-material3-samples", "wear/protolayout/protolayout-material3/samples", [BuildType.MAIN, BuildType.WEAR])
includeProject(":wear:protolayout:protolayout-proto", [BuildType.MAIN, BuildType.WEAR])
includeProject(":wear:protolayout:protolayout-renderer", [BuildType.MAIN, BuildType.WEAR])
includeProject(":wear:protolayout:protolayout-lint", [BuildType.MAIN, BuildType.WEAR])
diff --git a/wear/compose/compose-foundation/api/current.txt b/wear/compose/compose-foundation/api/current.txt
index 42ea898..5cc082e 100644
--- a/wear/compose/compose-foundation/api/current.txt
+++ b/wear/compose/compose-foundation/api/current.txt
@@ -326,6 +326,7 @@
method public static androidx.wear.compose.foundation.ScrollInfoProvider ScrollInfoProvider(androidx.compose.foundation.ScrollState state);
method public static androidx.wear.compose.foundation.ScrollInfoProvider ScrollInfoProvider(androidx.wear.compose.foundation.lazy.LazyColumnState state);
method public static androidx.wear.compose.foundation.ScrollInfoProvider ScrollInfoProvider(androidx.wear.compose.foundation.lazy.ScalingLazyListState state);
+ method public static androidx.wear.compose.foundation.ScrollInfoProvider ScrollInfoProvider(androidx.wear.compose.foundation.pager.PagerState state, androidx.compose.foundation.gestures.Orientation orientation);
}
@kotlin.jvm.JvmInline public final value class SwipeDirection {
@@ -397,11 +398,12 @@
method public androidx.compose.ui.Modifier transformedHeight(androidx.compose.ui.Modifier, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super androidx.wear.compose.foundation.lazy.LazyColumnItemScrollProgress,java.lang.Integer> heightProvider);
}
- public sealed interface LazyColumnItemScrollProgress {
+ @kotlin.jvm.JvmInline public final value class LazyColumnItemScrollProgress {
+ ctor public LazyColumnItemScrollProgress(float topOffsetFraction, float bottomOffsetFraction);
method public float getBottomOffsetFraction();
method public float getTopOffsetFraction();
- property public abstract float bottomOffsetFraction;
- property public abstract float topOffsetFraction;
+ property public final float bottomOffsetFraction;
+ property public final float topOffsetFraction;
}
public final class LazyColumnKt {
@@ -448,13 +450,13 @@
method public int getIndex();
method public Object getKey();
method public int getOffset();
- method public androidx.wear.compose.foundation.lazy.LazyColumnItemScrollProgress getScrollProgress();
+ method public long getScrollProgress();
property public abstract Object? contentType;
property public abstract int height;
property public abstract int index;
property public abstract Object key;
property public abstract int offset;
- property public abstract androidx.wear.compose.foundation.lazy.LazyColumnItemScrollProgress scrollProgress;
+ property public abstract long scrollProgress;
}
public final class ScalingLazyColumnDefaults {
@@ -595,14 +597,15 @@
package androidx.wear.compose.foundation.pager {
public final class PagerDefaults {
- method @androidx.compose.runtime.Composable public androidx.compose.foundation.gestures.TargetedFlingBehavior flingBehavior(androidx.wear.compose.foundation.pager.PagerState state);
+ method @androidx.compose.runtime.Composable public androidx.compose.foundation.gestures.TargetedFlingBehavior snapFlingBehavior(androidx.wear.compose.foundation.pager.PagerState state, optional androidx.compose.foundation.pager.PagerSnapDistance pagerSnapDistance, optional androidx.compose.animation.core.DecayAnimationSpec<java.lang.Float> decayAnimationSpec, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float> snapAnimationSpec, optional @FloatRange(from=0.0, to=1.0) float snapPositionalThreshold);
+ field public static final int BeyondViewportPageCount = 0; // 0x0
field public static final androidx.wear.compose.foundation.pager.PagerDefaults INSTANCE;
field public static final float SwipeToDismissEdgeZoneFraction = 0.15f;
}
public final class PagerKt {
- method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.wear.compose.foundation.ExperimentalWearFoundationApi public static void HorizontalPager(androidx.wear.compose.foundation.pager.PagerState state, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional int beyondViewportPageCount, optional androidx.compose.foundation.gestures.TargetedFlingBehavior flingBehavior, optional boolean userScrollEnabled, optional boolean reverseLayout, optional kotlin.jvm.functions.Function1<? super java.lang.Integer,?>? key, optional @FloatRange(from=0.0, to=1.0) float swipeToDismissEdgeZoneFraction, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.pager.PagerScope,? super java.lang.Integer,kotlin.Unit> content);
- method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.wear.compose.foundation.ExperimentalWearFoundationApi public static void VerticalPager(androidx.wear.compose.foundation.pager.PagerState state, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional int beyondViewportPageCount, optional androidx.compose.foundation.gestures.TargetedFlingBehavior flingBehavior, optional boolean userScrollEnabled, optional boolean reverseLayout, optional kotlin.jvm.functions.Function1<? super java.lang.Integer,?>? key, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.pager.PagerScope,? super java.lang.Integer,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void HorizontalPager(androidx.wear.compose.foundation.pager.PagerState state, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional int beyondViewportPageCount, optional androidx.compose.foundation.gestures.TargetedFlingBehavior flingBehavior, optional boolean userScrollEnabled, optional boolean reverseLayout, optional kotlin.jvm.functions.Function1<? super java.lang.Integer,?>? key, optional @FloatRange(from=0.0, to=1.0) float swipeToDismissEdgeZoneFraction, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.pager.PagerScope,? super java.lang.Integer,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void VerticalPager(androidx.wear.compose.foundation.pager.PagerState state, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional int beyondViewportPageCount, optional androidx.compose.foundation.gestures.TargetedFlingBehavior flingBehavior, optional boolean userScrollEnabled, optional boolean reverseLayout, optional kotlin.jvm.functions.Function1<? super java.lang.Integer,?>? key, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.pager.PagerScope,? super java.lang.Integer,kotlin.Unit> content);
}
public abstract class PagerState extends androidx.compose.foundation.pager.PagerState {
diff --git a/wear/compose/compose-foundation/api/restricted_current.txt b/wear/compose/compose-foundation/api/restricted_current.txt
index 42ea898..5cc082e 100644
--- a/wear/compose/compose-foundation/api/restricted_current.txt
+++ b/wear/compose/compose-foundation/api/restricted_current.txt
@@ -326,6 +326,7 @@
method public static androidx.wear.compose.foundation.ScrollInfoProvider ScrollInfoProvider(androidx.compose.foundation.ScrollState state);
method public static androidx.wear.compose.foundation.ScrollInfoProvider ScrollInfoProvider(androidx.wear.compose.foundation.lazy.LazyColumnState state);
method public static androidx.wear.compose.foundation.ScrollInfoProvider ScrollInfoProvider(androidx.wear.compose.foundation.lazy.ScalingLazyListState state);
+ method public static androidx.wear.compose.foundation.ScrollInfoProvider ScrollInfoProvider(androidx.wear.compose.foundation.pager.PagerState state, androidx.compose.foundation.gestures.Orientation orientation);
}
@kotlin.jvm.JvmInline public final value class SwipeDirection {
@@ -397,11 +398,12 @@
method public androidx.compose.ui.Modifier transformedHeight(androidx.compose.ui.Modifier, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super androidx.wear.compose.foundation.lazy.LazyColumnItemScrollProgress,java.lang.Integer> heightProvider);
}
- public sealed interface LazyColumnItemScrollProgress {
+ @kotlin.jvm.JvmInline public final value class LazyColumnItemScrollProgress {
+ ctor public LazyColumnItemScrollProgress(float topOffsetFraction, float bottomOffsetFraction);
method public float getBottomOffsetFraction();
method public float getTopOffsetFraction();
- property public abstract float bottomOffsetFraction;
- property public abstract float topOffsetFraction;
+ property public final float bottomOffsetFraction;
+ property public final float topOffsetFraction;
}
public final class LazyColumnKt {
@@ -448,13 +450,13 @@
method public int getIndex();
method public Object getKey();
method public int getOffset();
- method public androidx.wear.compose.foundation.lazy.LazyColumnItemScrollProgress getScrollProgress();
+ method public long getScrollProgress();
property public abstract Object? contentType;
property public abstract int height;
property public abstract int index;
property public abstract Object key;
property public abstract int offset;
- property public abstract androidx.wear.compose.foundation.lazy.LazyColumnItemScrollProgress scrollProgress;
+ property public abstract long scrollProgress;
}
public final class ScalingLazyColumnDefaults {
@@ -595,14 +597,15 @@
package androidx.wear.compose.foundation.pager {
public final class PagerDefaults {
- method @androidx.compose.runtime.Composable public androidx.compose.foundation.gestures.TargetedFlingBehavior flingBehavior(androidx.wear.compose.foundation.pager.PagerState state);
+ method @androidx.compose.runtime.Composable public androidx.compose.foundation.gestures.TargetedFlingBehavior snapFlingBehavior(androidx.wear.compose.foundation.pager.PagerState state, optional androidx.compose.foundation.pager.PagerSnapDistance pagerSnapDistance, optional androidx.compose.animation.core.DecayAnimationSpec<java.lang.Float> decayAnimationSpec, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float> snapAnimationSpec, optional @FloatRange(from=0.0, to=1.0) float snapPositionalThreshold);
+ field public static final int BeyondViewportPageCount = 0; // 0x0
field public static final androidx.wear.compose.foundation.pager.PagerDefaults INSTANCE;
field public static final float SwipeToDismissEdgeZoneFraction = 0.15f;
}
public final class PagerKt {
- method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.wear.compose.foundation.ExperimentalWearFoundationApi public static void HorizontalPager(androidx.wear.compose.foundation.pager.PagerState state, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional int beyondViewportPageCount, optional androidx.compose.foundation.gestures.TargetedFlingBehavior flingBehavior, optional boolean userScrollEnabled, optional boolean reverseLayout, optional kotlin.jvm.functions.Function1<? super java.lang.Integer,?>? key, optional @FloatRange(from=0.0, to=1.0) float swipeToDismissEdgeZoneFraction, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.pager.PagerScope,? super java.lang.Integer,kotlin.Unit> content);
- method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.wear.compose.foundation.ExperimentalWearFoundationApi public static void VerticalPager(androidx.wear.compose.foundation.pager.PagerState state, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional int beyondViewportPageCount, optional androidx.compose.foundation.gestures.TargetedFlingBehavior flingBehavior, optional boolean userScrollEnabled, optional boolean reverseLayout, optional kotlin.jvm.functions.Function1<? super java.lang.Integer,?>? key, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.pager.PagerScope,? super java.lang.Integer,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void HorizontalPager(androidx.wear.compose.foundation.pager.PagerState state, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional int beyondViewportPageCount, optional androidx.compose.foundation.gestures.TargetedFlingBehavior flingBehavior, optional boolean userScrollEnabled, optional boolean reverseLayout, optional kotlin.jvm.functions.Function1<? super java.lang.Integer,?>? key, optional @FloatRange(from=0.0, to=1.0) float swipeToDismissEdgeZoneFraction, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.pager.PagerScope,? super java.lang.Integer,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void VerticalPager(androidx.wear.compose.foundation.pager.PagerState state, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional int beyondViewportPageCount, optional androidx.compose.foundation.gestures.TargetedFlingBehavior flingBehavior, optional boolean userScrollEnabled, optional boolean reverseLayout, optional kotlin.jvm.functions.Function1<? super java.lang.Integer,?>? key, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.pager.PagerScope,? super java.lang.Integer,kotlin.Unit> content);
}
public abstract class PagerState extends androidx.compose.foundation.pager.PagerState {
diff --git a/wear/compose/compose-foundation/samples/src/main/java/androidx/wear/compose/foundation/samples/PagerSamples.kt b/wear/compose/compose-foundation/samples/src/main/java/androidx/wear/compose/foundation/samples/PagerSamples.kt
index 074cfe6..aa2d1cf 100644
--- a/wear/compose/compose-foundation/samples/src/main/java/androidx/wear/compose/foundation/samples/PagerSamples.kt
+++ b/wear/compose/compose-foundation/samples/src/main/java/androidx/wear/compose/foundation/samples/PagerSamples.kt
@@ -25,12 +25,10 @@
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle
-import androidx.wear.compose.foundation.ExperimentalWearFoundationApi
import androidx.wear.compose.foundation.pager.HorizontalPager
import androidx.wear.compose.foundation.pager.VerticalPager
import androidx.wear.compose.foundation.pager.rememberPagerState
-@OptIn(ExperimentalWearFoundationApi::class)
@Sampled
@Composable
fun SimpleHorizontalPagerSample() {
@@ -45,7 +43,6 @@
}
}
-@OptIn(ExperimentalWearFoundationApi::class)
@Sampled
@Composable
fun SimpleVerticalPagerSample() {
diff --git a/wear/compose/compose-foundation/src/androidTest/kotlin/androidx/wear/compose/foundation/lazy/LazyColumnItemScrollProgressTest.kt b/wear/compose/compose-foundation/src/androidTest/kotlin/androidx/wear/compose/foundation/lazy/LazyColumnItemScrollProgressTest.kt
new file mode 100644
index 0000000..54511d3
--- /dev/null
+++ b/wear/compose/compose-foundation/src/androidTest/kotlin/androidx/wear/compose/foundation/lazy/LazyColumnItemScrollProgressTest.kt
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.wear.compose.foundation.lazy
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import org.junit.Assert.assertEquals
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class LazyColumnScrollProgressTest {
+ @Test
+ fun negativeValuesPackedCorrectly() {
+ val progress =
+ LazyColumnItemScrollProgress(topOffsetFraction = -0.5f, bottomOffsetFraction = 0.2f)
+ assertEquals(progress.topOffsetFraction, -0.5f, 1e-2f)
+ assertEquals(progress.bottomOffsetFraction, 0.2f, 1e-2f)
+ }
+
+ @Test
+ fun zeroValuesPackedCorrectly() {
+ val progress =
+ LazyColumnItemScrollProgress(topOffsetFraction = 0f, bottomOffsetFraction = 0f)
+ assertEquals(progress.topOffsetFraction, 0f, 1e-2f)
+ assertEquals(progress.bottomOffsetFraction, 0f, 1e-2f)
+ }
+
+ @Test
+ fun normalValuesPackedCorrectly() {
+ val progress =
+ LazyColumnItemScrollProgress(topOffsetFraction = 0.3f, bottomOffsetFraction = 0.7f)
+ assertEquals(progress.topOffsetFraction, 0.3f, 1e-2f)
+ assertEquals(progress.bottomOffsetFraction, 0.7f, 1e-2f)
+ }
+
+ @Test
+ fun nanValuesPackedCorrectly() {
+ val progress =
+ LazyColumnItemScrollProgress(
+ topOffsetFraction = Float.NaN,
+ bottomOffsetFraction = Float.NaN
+ )
+ assertEquals(progress.topOffsetFraction, Float.NaN)
+ assertEquals(progress.bottomOffsetFraction, Float.NaN)
+ }
+
+ @Test
+ fun infValuesPackedCorrectly() {
+ val progress =
+ LazyColumnItemScrollProgress(
+ topOffsetFraction = Float.NEGATIVE_INFINITY,
+ bottomOffsetFraction = Float.POSITIVE_INFINITY
+ )
+ assertEquals(progress.topOffsetFraction, Float.NEGATIVE_INFINITY)
+ assertEquals(progress.bottomOffsetFraction, Float.POSITIVE_INFINITY)
+ }
+}
diff --git a/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/ScrollInfoProvider.kt b/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/ScrollInfoProvider.kt
index 2fe51fe..8b16a45 100644
--- a/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/ScrollInfoProvider.kt
+++ b/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/ScrollInfoProvider.kt
@@ -17,6 +17,7 @@
package androidx.wear.compose.foundation
import androidx.compose.foundation.ScrollState
+import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListState
@@ -26,6 +27,10 @@
import androidx.wear.compose.foundation.lazy.ScalingLazyListAnchorType
import androidx.wear.compose.foundation.lazy.ScalingLazyListState
import androidx.wear.compose.foundation.lazy.startOffset
+import androidx.wear.compose.foundation.pager.HorizontalPager
+import androidx.wear.compose.foundation.pager.PagerState
+import androidx.wear.compose.foundation.pager.VerticalPager
+import kotlin.math.absoluteValue
/**
* An interface for providing scroll information for different scrollable containers, such lists.
@@ -103,6 +108,24 @@
fun ScrollInfoProvider(state: ScrollState): ScrollInfoProvider =
ScrollStateScrollInfoProvider(state)
+/**
+ * Function for creating a [ScrollInfoProvider] from a [PagerState], for use with [HorizontalPager]
+ * and [VerticalPager]
+ * - used to coordinate when to fade out the PageIndicator and [TimeText]. The PageIndicator fades
+ * out when when scrolling is finished and the screen is in an idle state. For [VerticalPager] the
+ * [TimeText] is scrolled away as you page, for [HorizontalPager] the [TimeText] remains present
+ * as you page.
+ *
+ * @param state the [PagerState] to use as the base for creating the [ScrollInfoProvider]
+ * @param orientation a parameter used to specify whether the Pager is Horizontal or Vertical
+ */
+fun ScrollInfoProvider(state: PagerState, orientation: Orientation): ScrollInfoProvider =
+ if (orientation == Orientation.Horizontal) {
+ HorizontalPagerStateScrollInfoProvider(state)
+ } else {
+ VerticalPagerStateScrollInfoProvider(state)
+ }
+
// Implementation of [ScrollInfoProvider] for [ScalingLazyColumn].
// Being in Foundation, this implementation has access to the ScalingLazyListState
// auto-centering params, which are internal.
@@ -270,3 +293,47 @@
"lastItemOffset=$lastItemOffset)"
}
}
+
+// Implementation of [ScrollInfoProvider] for [HorizontalPager].
+private class HorizontalPagerStateScrollInfoProvider(val state: PagerState) : ScrollInfoProvider {
+ override val isScrollAwayValid: Boolean
+ get() = false
+
+ override val isScrollable: Boolean
+ get() = state.canScrollBackward || state.canScrollForward
+
+ override val isScrollInProgress: Boolean
+ get() = state.isScrollInProgress
+
+ override val anchorItemOffset: Float
+ get() = Float.NaN
+
+ override val lastItemOffset: Float
+ get() = 0f
+}
+
+// Implementation of [ScrollInfoProvider] for [VerticalPager].
+private class VerticalPagerStateScrollInfoProvider(val state: PagerState) : ScrollInfoProvider {
+ override val isScrollAwayValid: Boolean
+ get() = state.pageCount > 1
+
+ override val isScrollable: Boolean
+ get() = state.canScrollBackward || state.canScrollForward
+
+ override val isScrollInProgress: Boolean
+ get() = state.isScrollInProgress
+
+ override val anchorItemOffset: Float
+ get() {
+ val offset =
+ when (state.currentPage) {
+ 0 -> state.currentPageOffsetFraction.absoluteValue
+ 1 -> 1 - state.currentPageOffsetFraction.absoluteValue
+ else -> Float.NaN
+ }
+ return offset * state.layoutInfo.pageSize
+ }
+
+ override val lastItemOffset: Float
+ get() = 0f
+}
diff --git a/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/lazy/LazyColumnLayoutInfo.kt b/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/lazy/LazyColumnLayoutInfo.kt
index cf4df5a..573aa798 100644
--- a/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/lazy/LazyColumnLayoutInfo.kt
+++ b/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/lazy/LazyColumnLayoutInfo.kt
@@ -17,29 +17,72 @@
package androidx.wear.compose.foundation.lazy
import androidx.compose.ui.unit.IntSize
+import androidx.compose.ui.util.packFloats
+import androidx.compose.ui.util.unpackFloat1
+import androidx.compose.ui.util.unpackFloat2
/**
* Scroll progress of an item in a [LazyColumn] before any modifications to the item's height are
* applied (using [LazyColumnItemScope.transformedHeight] modifier).
*/
-sealed interface LazyColumnItemScrollProgress {
+@JvmInline
+value class LazyColumnItemScrollProgress internal constructor(private val packedValue: Long) {
/**
- * The offset as a fraction of the top of the item relative to the list container. Is within
- * (0, 1) when item is inside the screen and could be negative if the top of the item is off the
- * screen. Value is calculated from the top of the container. This value is calculated before
- * any height modifications are applied (using [LazyColumnItemScope.transformedHeight]
- * modifier).
+ * The top offset (between the top of the list container and the top of the item) as a fraction
+ * of the height of the list container. Is within (0, 1) when item is inside the screen and
+ * could be negative if the top of the item is off the screen. Value is calculated from the top
+ * of the container. This value is calculated before any height modifications are applied (using
+ * [LazyColumnItemScope.transformedHeight] modifier).
*/
val topOffsetFraction: Float
+ get() = unpackFloat1(packedValue)
/**
- * The offset as a fraction of the bottom of the item relative to the list container. Is within
- * (0, 1) when item is inside the screen and could exceed 1 when the bottom of item is off the
- * screen. Value is calculated from the top of the container. This value is calculated before
- * any height modifications are applied (using [LazyColumnItemScope.transformedHeight]
- * modifier).
+ * The bottom offset (between the top of the list container and the bottom of the item) as a
+ * fraction of the height of the list container. Is within (0, 1) when item is inside the screen
+ * and could exceed 1 when the bottom of item is off the screen. Value is calculated from the
+ * top of the container. This value is calculated before any height modifications are applied
+ * (using [LazyColumnItemScope.transformedHeight] modifier).
*/
val bottomOffsetFraction: Float
+ get() = unpackFloat2(packedValue)
+
+ /**
+ * Constructs a [LazyColumnItemScrollProgress] with two offset fraction [Float] values.
+ *
+ * @param topOffsetFraction The top offset (between the top of the list container and the top of
+ * the item) as a fraction of the height of the list container.
+ * @param bottomOffsetFraction The bottom offset (between the top of the list container and the
+ * bottom of the item) as a fraction of the height of the list container.
+ */
+ constructor(
+ topOffsetFraction: Float,
+ bottomOffsetFraction: Float
+ ) : this(packFloats(topOffsetFraction, bottomOffsetFraction))
+
+ internal companion object {
+ internal val Zero = LazyColumnItemScrollProgress(0f, 0f)
+
+ internal fun bottomItemScrollProgress(
+ offset: Int,
+ height: Int,
+ containerHeight: Int
+ ): LazyColumnItemScrollProgress =
+ LazyColumnItemScrollProgress(
+ topOffsetFraction = offset.toFloat() / containerHeight.toFloat(),
+ bottomOffsetFraction = (offset + height).toFloat() / containerHeight.toFloat(),
+ )
+
+ internal fun topItemScrollProgress(
+ offset: Int,
+ height: Int,
+ containerHeight: Int
+ ): LazyColumnItemScrollProgress =
+ LazyColumnItemScrollProgress(
+ topOffsetFraction = (offset - height).toFloat() / containerHeight.toFloat(),
+ bottomOffsetFraction = offset / containerHeight.toFloat(),
+ )
+ }
}
/** Represents an item that is visible in the [LazyColumn] component. */
diff --git a/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/lazy/LazyColumnMeasuredItem.kt b/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/lazy/LazyColumnMeasuredItem.kt
index f783788..47014ab 100644
--- a/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/lazy/LazyColumnMeasuredItem.kt
+++ b/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/lazy/LazyColumnMeasuredItem.kt
@@ -20,6 +20,7 @@
import androidx.compose.ui.layout.Placeable
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.LayoutDirection
+import androidx.wear.compose.foundation.lazy.LazyColumnItemScrollProgress.Companion.topItemScrollProgress
/** Represents a placeable item in the [LazyColumn] layout. */
internal data class LazyColumnMeasuredItem(
@@ -32,7 +33,7 @@
/** The vertical offset of the item from the top of the list after transformations applied. */
override var offset: Int,
/** Scroll progress of the item used to calculate transformations applied. */
- override val scrollProgress: LazyColumnItemScrollProgress,
+ override var scrollProgress: LazyColumnItemScrollProgress,
/** The horizontal alignment to apply during placement. */
val horizontalAlignment: Alignment.Horizontal,
/** The [LayoutDirection] of the `Layout`. */
@@ -40,11 +41,27 @@
override val key: Any,
override val contentType: Any?,
) : LazyColumnVisibleItemInfo {
+ private var lastMeasuredHeight = Int.MIN_VALUE
+ private var lastMeasuredOffset = Int.MIN_VALUE
+ private var lastMeasuredScrollProgress = LazyColumnItemScrollProgress.Zero
+
/** The height of the item after transformations applied. */
- override val height =
- (placeable.parentData as? HeightProviderParentData)?.let {
- it.heightProvider(placeable.height, scrollProgress)
- } ?: placeable.height
+ override val height: Int
+ get() {
+ if (
+ lastMeasuredHeight == Int.MIN_VALUE ||
+ lastMeasuredOffset != offset ||
+ lastMeasuredScrollProgress != scrollProgress
+ ) {
+ lastMeasuredHeight =
+ (placeable.parentData as? HeightProviderParentData)?.let {
+ it.heightProvider(placeable.height, scrollProgress)
+ } ?: placeable.height
+ lastMeasuredOffset = offset
+ lastMeasuredScrollProgress = scrollProgress
+ }
+ return lastMeasuredHeight
+ }
fun place(scope: Placeable.PlacementScope) =
with(scope) {
@@ -57,4 +74,14 @@
offset
)
}
+
+ fun pinToCenter() {
+ scrollProgress =
+ topItemScrollProgress(
+ containerConstraints.maxHeight / 2 - height / 2,
+ placeable.height,
+ containerConstraints.maxHeight
+ )
+ offset = containerConstraints.maxHeight / 2 - height / 2
+ }
}
diff --git a/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/lazy/LazyColumnMeasurement.kt b/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/lazy/LazyColumnMeasurement.kt
index c3c64f1..e5fff610 100644
--- a/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/lazy/LazyColumnMeasurement.kt
+++ b/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/lazy/LazyColumnMeasurement.kt
@@ -29,6 +29,8 @@
import androidx.compose.ui.unit.constrainHeight
import androidx.compose.ui.unit.constrainWidth
import androidx.compose.ui.util.fastForEach
+import androidx.wear.compose.foundation.lazy.LazyColumnItemScrollProgress.Companion.bottomItemScrollProgress
+import androidx.wear.compose.foundation.lazy.LazyColumnItemScrollProgress.Companion.topItemScrollProgress
import kotlin.math.abs
import kotlin.math.roundToInt
@@ -111,14 +113,14 @@
centerItem.offset + centerItem.height / 2 >= containerConstraints.maxHeight / 2
) {
canScrollBackward = false
- centerItem.offset = containerConstraints.maxHeight / 2 - centerItem.height / 2
+ centerItem.pinToCenter()
}
if (
centerItem.index == itemsCount - 1 &&
centerItem.offset + centerItem.height / 2 <= containerConstraints.maxHeight / 2
) {
canScrollForward = false
- centerItem.offset = containerConstraints.maxHeight / 2 - centerItem.height / 2
+ centerItem.pinToCenter()
}
visibleItems.add(centerItem)
@@ -177,31 +179,6 @@
)
}
-private fun bottomItemScrollProgress(
- offset: Int,
- height: Int,
- containerHeight: Int
-): LazyColumnItemScrollProgress =
- LazyColumnItemScrollProgressImpl(
- topOffsetFraction = offset.toFloat() / containerHeight.toFloat(),
- bottomOffsetFraction = (offset + height).toFloat() / containerHeight.toFloat(),
- )
-
-private fun topItemScrollProgress(
- offset: Int,
- height: Int,
- containerHeight: Int
-): LazyColumnItemScrollProgress =
- LazyColumnItemScrollProgressImpl(
- topOffsetFraction = (offset - height).toFloat() / containerHeight.toFloat(),
- bottomOffsetFraction = offset / containerHeight.toFloat(),
- )
-
-internal data class LazyColumnItemScrollProgressImpl(
- override val topOffsetFraction: Float,
- override val bottomOffsetFraction: Float
-) : LazyColumnItemScrollProgress
-
@Composable
@OptIn(ExperimentalFoundationApi::class)
internal fun rememberLazyColumnMeasurePolicy(
diff --git a/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/pager/Pager.kt b/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/pager/Pager.kt
index 019f683..680f343 100644
--- a/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/pager/Pager.kt
+++ b/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/pager/Pager.kt
@@ -17,8 +17,10 @@
package androidx.wear.compose.foundation.pager
import androidx.annotation.FloatRange
+import androidx.compose.animation.core.AnimationSpec
+import androidx.compose.animation.core.DecayAnimationSpec
import androidx.compose.animation.core.tween
-import androidx.compose.foundation.gestures.Orientation
+import androidx.compose.animation.rememberSplineBasedDecay
import androidx.compose.foundation.gestures.TargetedFlingBehavior
import androidx.compose.foundation.gestures.awaitEachGesture
import androidx.compose.foundation.gestures.awaitFirstDown
@@ -49,7 +51,6 @@
import androidx.compose.ui.semantics.horizontalScrollAxisRange
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.unit.dp
-import androidx.wear.compose.foundation.ExperimentalWearFoundationApi
import androidx.wear.compose.foundation.HierarchicalFocusCoordinator
import kotlinx.coroutines.coroutineScope
@@ -90,14 +91,13 @@
* @param content A composable function that defines the content of each page displayed by the
* Pager. This is where the UI elements that should appear within each page should be placed.
*/
-@ExperimentalWearFoundationApi
@Composable
fun HorizontalPager(
state: PagerState,
modifier: Modifier = Modifier,
contentPadding: PaddingValues = PaddingValues(0.dp),
- beyondViewportPageCount: Int = ComposePagerDefaults.BeyondViewportPageCount,
- flingBehavior: TargetedFlingBehavior = PagerDefaults.flingBehavior(state = state),
+ beyondViewportPageCount: Int = PagerDefaults.BeyondViewportPageCount,
+ flingBehavior: TargetedFlingBehavior = PagerDefaults.snapFlingBehavior(state = state),
userScrollEnabled: Boolean = true,
reverseLayout: Boolean = false,
key: ((index: Int) -> Any)? = null,
@@ -153,8 +153,6 @@
userScrollEnabled = userScrollEnabled && allowPaging,
reverseLayout = reverseLayout,
key = key,
- pageNestedScrollConnection =
- ComposePagerDefaults.pageNestedScrollConnection(state, Orientation.Horizontal),
snapPosition = SnapPosition.Start,
) { page ->
CustomTouchSlopProvider(newTouchSlop = originalTouchSlop) {
@@ -195,14 +193,13 @@
* @param content A composable function that defines the content of each page displayed by the
* Pager. This is where the UI elements that should appear within each page should be placed.
*/
-@ExperimentalWearFoundationApi
@Composable
fun VerticalPager(
state: PagerState,
modifier: Modifier = Modifier,
contentPadding: PaddingValues = PaddingValues(0.dp),
- beyondViewportPageCount: Int = ComposePagerDefaults.BeyondViewportPageCount,
- flingBehavior: TargetedFlingBehavior = PagerDefaults.flingBehavior(state = state),
+ beyondViewportPageCount: Int = PagerDefaults.BeyondViewportPageCount,
+ flingBehavior: TargetedFlingBehavior = PagerDefaults.snapFlingBehavior(state = state),
userScrollEnabled: Boolean = true,
reverseLayout: Boolean = false,
key: ((index: Int) -> Any)? = null,
@@ -220,29 +217,68 @@
userScrollEnabled = userScrollEnabled,
reverseLayout = reverseLayout,
key = key,
- pageNestedScrollConnection =
- ComposePagerDefaults.pageNestedScrollConnection(state, Orientation.Vertical),
snapPosition = SnapPosition.Start,
) { page ->
FocusedPageContent(page = page, pagerState = state, content = { content(page) })
}
}
-/** Convenience fling behavior optimised for Wear. */
+/** Contains the default values used by [Pager]. These are optimised for Wear. */
object PagerDefaults {
+ /**
+ * Default fling behavior for pagers on Wear, snaps at most one page at a time.
+ *
+ * @param state The [PagerState] that controls the [Pager] to which this FlingBehavior will be
+ * applied to.
+ * @param pagerSnapDistance A way to control the snapping destination for this [Pager]. Use
+ * [PagerSnapDistance.atMost] to define a maximum number of pages this [Pager] is allowed to
+ * fling after scrolling is finished and fling has started.
+ * @param decayAnimationSpec The animation spec used to approach the target offset. When the
+ * fling velocity is large enough. Large enough means large enough to naturally decay. For
+ * single page snapping this usually never happens since there won't be enough space to run a
+ * decay animation.
+ * @param snapAnimationSpec The animation spec used to finally snap to the position. This
+ * animation will be often used in 2 cases: 1) There was enough space to an approach
+ * animation, the Pager will use [snapAnimationSpec] in the last step of the animation to
+ * settle the page into position. 2) There was not enough space to run the approach animation.
+ * @param snapPositionalThreshold If the fling has a low velocity (e.g. slow scroll), this fling
+ * behavior will use this snap threshold in order to determine if the pager should snap back
+ * or move forward. Use a number between 0 and 1 as a fraction of the page size that needs to
+ * be scrolled before the Pager considers it should move to the next page. For instance, if
+ * snapPositionalThreshold = 0.35, it means if this pager is scrolled with a slow velocity and
+ * the Pager scrolls more than 35% of the page size, then will jump to the next page, if not
+ * it scrolls back. Note that any fling that has high enough velocity will *always* move to
+ * the next page in the direction of the fling.
+ */
@Composable
- fun flingBehavior(
+ fun snapFlingBehavior(
state: PagerState,
+ pagerSnapDistance: PagerSnapDistance = PagerSnapDistance.atMost(1),
+ decayAnimationSpec: DecayAnimationSpec<Float> = rememberSplineBasedDecay(),
+ snapAnimationSpec: AnimationSpec<Float> = tween(150, 0),
+ @FloatRange(from = 0.0, to = 1.0) snapPositionalThreshold: Float = 0.5f
): TargetedFlingBehavior {
return ComposePagerDefaults.flingBehavior(
state = state,
- pagerSnapDistance = PagerSnapDistance.atMost(1),
- snapAnimationSpec = tween(150, 0),
+ pagerSnapDistance = pagerSnapDistance,
+ decayAnimationSpec = decayAnimationSpec,
+ snapAnimationSpec = snapAnimationSpec,
+ snapPositionalThreshold = snapPositionalThreshold,
)
}
- /** Configure Swipe To Dismiss behaviour, only applies to [HorizontalPager]. */
+ /**
+ * The default value of swipeToDismissEdgeZoneFraction used to configure the size of the edge
+ * zone in a [HorizontalPager].
+ */
const val SwipeToDismissEdgeZoneFraction: Float = 0.15f
+
+ /**
+ * The default value of beyondViewportPageCount used to specify the number of pages to compose
+ * and layout before and after the visible pages. It does not include the pages automatically
+ * composed and laid out by the pre-fetcher in the direction of the scroll during scroll events.
+ */
+ const val BeyondViewportPageCount = 0
}
@Composable
diff --git a/wear/compose/compose-material3/api/current.txt b/wear/compose/compose-material3/api/current.txt
index 3a4d82c..17e1f37 100644
--- a/wear/compose/compose-material3/api/current.txt
+++ b/wear/compose/compose-material3/api/current.txt
@@ -628,16 +628,20 @@
}
public final class ListHeaderDefaults {
- method public androidx.compose.foundation.layout.PaddingValues getHeaderContentPadding();
- method public androidx.compose.foundation.layout.PaddingValues getSubheaderContentPadding();
- property public final androidx.compose.foundation.layout.PaddingValues HeaderContentPadding;
- property public final androidx.compose.foundation.layout.PaddingValues SubheaderContentPadding;
+ method @androidx.compose.runtime.Composable public long getContentColor();
+ method public androidx.compose.foundation.layout.PaddingValues getContentPadding();
+ method @androidx.compose.runtime.Composable public long getSubHeaderContentColor();
+ method public androidx.compose.foundation.layout.PaddingValues getSubHeaderContentPadding();
+ property @androidx.compose.runtime.Composable public final long ContentColor;
+ property public final androidx.compose.foundation.layout.PaddingValues ContentPadding;
+ property public final androidx.compose.foundation.layout.PaddingValues SubHeaderContentPadding;
+ property @androidx.compose.runtime.Composable public final long subHeaderContentColor;
field public static final androidx.wear.compose.material3.ListHeaderDefaults INSTANCE;
}
public final class ListHeaderKt {
method @androidx.compose.runtime.Composable public static void ListHeader(optional androidx.compose.ui.Modifier modifier, optional long backgroundColor, optional long contentColor, optional androidx.compose.foundation.layout.PaddingValues contentPadding, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
- method @androidx.compose.runtime.Composable public static void ListSubheader(optional androidx.compose.ui.Modifier modifier, optional long backgroundColor, optional long contentColor, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? icon, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> label);
+ method @androidx.compose.runtime.Composable public static void ListSubHeader(optional androidx.compose.ui.Modifier modifier, optional long backgroundColor, optional long contentColor, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? icon, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> label);
}
public final class MaterialTheme {
@@ -663,17 +667,12 @@
method public <T> androidx.compose.animation.core.FiniteAnimationSpec<T> fastSpatialSpec();
method public <T> androidx.compose.animation.core.FiniteAnimationSpec<T> slowEffectsSpec();
method public <T> androidx.compose.animation.core.FiniteAnimationSpec<T> slowSpatialSpec();
+ field public static final androidx.wear.compose.material3.MotionScheme.Companion Companion;
}
- public final class MotionSchemeKt {
- method public static androidx.wear.compose.material3.MotionScheme expressiveMotionScheme();
- method @androidx.compose.runtime.Composable public static inline <reified T> androidx.compose.animation.core.FiniteAnimationSpec<T> rememberDefaultEffectsSpec(androidx.wear.compose.material3.MotionScheme);
- method @androidx.compose.runtime.Composable public static inline <reified T> androidx.compose.animation.core.FiniteAnimationSpec<T> rememberDefaultSpatialSpec(androidx.wear.compose.material3.MotionScheme);
- method @androidx.compose.runtime.Composable public static inline <reified T> androidx.compose.animation.core.FiniteAnimationSpec<T> rememberFastEffectsSpec(androidx.wear.compose.material3.MotionScheme);
- method @androidx.compose.runtime.Composable public static inline <reified T> androidx.compose.animation.core.FiniteAnimationSpec<T> rememberFastSpatialSpec(androidx.wear.compose.material3.MotionScheme);
- method @androidx.compose.runtime.Composable public static inline <reified T> androidx.compose.animation.core.FiniteAnimationSpec<T> rememberSlowEffectsSpec(androidx.wear.compose.material3.MotionScheme);
- method @androidx.compose.runtime.Composable public static inline <reified T> androidx.compose.animation.core.FiniteAnimationSpec<T> rememberSlowSpatialSpec(androidx.wear.compose.material3.MotionScheme);
- method public static androidx.wear.compose.material3.MotionScheme standardMotionScheme();
+ public static final class MotionScheme.Companion {
+ method public androidx.wear.compose.material3.MotionScheme expressive();
+ method public androidx.wear.compose.material3.MotionScheme standard();
}
public final class OpenOnPhoneDialogColors {
@@ -719,6 +718,17 @@
method @androidx.compose.runtime.Composable public static void VerticalPageIndicator(androidx.wear.compose.foundation.pager.PagerState pagerState, optional androidx.compose.ui.Modifier modifier, optional long selectedColor, optional long unselectedColor, optional long backgroundColor);
}
+ public final class PagerScaffoldDefaults {
+ method public androidx.compose.animation.core.AnimationSpec<java.lang.Float> getFadeOutAnimation();
+ property public final androidx.compose.animation.core.AnimationSpec<java.lang.Float> FadeOutAnimation;
+ field public static final androidx.wear.compose.material3.PagerScaffoldDefaults INSTANCE;
+ }
+
+ public final class PagerScaffoldKt {
+ method @androidx.compose.runtime.Composable public static void HorizontalPagerScaffold(androidx.wear.compose.foundation.pager.PagerState pagerState, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? pageIndicator, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float>? pageIndicatorAnimationSpec, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.pager.PagerScope,? super java.lang.Integer,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void VerticalPagerScaffold(androidx.wear.compose.foundation.pager.PagerState pagerState, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? pageIndicator, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float>? pageIndicatorAnimationSpec, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.pager.PagerScope,? super java.lang.Integer,kotlin.Unit> content);
+ }
+
public final class PickerDefaults {
method public float getGradientRatio();
method @androidx.compose.runtime.Composable public androidx.wear.compose.foundation.rotary.RotaryScrollableBehavior rotarySnapBehavior(androidx.wear.compose.material3.PickerState state);
diff --git a/wear/compose/compose-material3/api/restricted_current.txt b/wear/compose/compose-material3/api/restricted_current.txt
index 3a4d82c..17e1f37 100644
--- a/wear/compose/compose-material3/api/restricted_current.txt
+++ b/wear/compose/compose-material3/api/restricted_current.txt
@@ -628,16 +628,20 @@
}
public final class ListHeaderDefaults {
- method public androidx.compose.foundation.layout.PaddingValues getHeaderContentPadding();
- method public androidx.compose.foundation.layout.PaddingValues getSubheaderContentPadding();
- property public final androidx.compose.foundation.layout.PaddingValues HeaderContentPadding;
- property public final androidx.compose.foundation.layout.PaddingValues SubheaderContentPadding;
+ method @androidx.compose.runtime.Composable public long getContentColor();
+ method public androidx.compose.foundation.layout.PaddingValues getContentPadding();
+ method @androidx.compose.runtime.Composable public long getSubHeaderContentColor();
+ method public androidx.compose.foundation.layout.PaddingValues getSubHeaderContentPadding();
+ property @androidx.compose.runtime.Composable public final long ContentColor;
+ property public final androidx.compose.foundation.layout.PaddingValues ContentPadding;
+ property public final androidx.compose.foundation.layout.PaddingValues SubHeaderContentPadding;
+ property @androidx.compose.runtime.Composable public final long subHeaderContentColor;
field public static final androidx.wear.compose.material3.ListHeaderDefaults INSTANCE;
}
public final class ListHeaderKt {
method @androidx.compose.runtime.Composable public static void ListHeader(optional androidx.compose.ui.Modifier modifier, optional long backgroundColor, optional long contentColor, optional androidx.compose.foundation.layout.PaddingValues contentPadding, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
- method @androidx.compose.runtime.Composable public static void ListSubheader(optional androidx.compose.ui.Modifier modifier, optional long backgroundColor, optional long contentColor, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? icon, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> label);
+ method @androidx.compose.runtime.Composable public static void ListSubHeader(optional androidx.compose.ui.Modifier modifier, optional long backgroundColor, optional long contentColor, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? icon, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> label);
}
public final class MaterialTheme {
@@ -663,17 +667,12 @@
method public <T> androidx.compose.animation.core.FiniteAnimationSpec<T> fastSpatialSpec();
method public <T> androidx.compose.animation.core.FiniteAnimationSpec<T> slowEffectsSpec();
method public <T> androidx.compose.animation.core.FiniteAnimationSpec<T> slowSpatialSpec();
+ field public static final androidx.wear.compose.material3.MotionScheme.Companion Companion;
}
- public final class MotionSchemeKt {
- method public static androidx.wear.compose.material3.MotionScheme expressiveMotionScheme();
- method @androidx.compose.runtime.Composable public static inline <reified T> androidx.compose.animation.core.FiniteAnimationSpec<T> rememberDefaultEffectsSpec(androidx.wear.compose.material3.MotionScheme);
- method @androidx.compose.runtime.Composable public static inline <reified T> androidx.compose.animation.core.FiniteAnimationSpec<T> rememberDefaultSpatialSpec(androidx.wear.compose.material3.MotionScheme);
- method @androidx.compose.runtime.Composable public static inline <reified T> androidx.compose.animation.core.FiniteAnimationSpec<T> rememberFastEffectsSpec(androidx.wear.compose.material3.MotionScheme);
- method @androidx.compose.runtime.Composable public static inline <reified T> androidx.compose.animation.core.FiniteAnimationSpec<T> rememberFastSpatialSpec(androidx.wear.compose.material3.MotionScheme);
- method @androidx.compose.runtime.Composable public static inline <reified T> androidx.compose.animation.core.FiniteAnimationSpec<T> rememberSlowEffectsSpec(androidx.wear.compose.material3.MotionScheme);
- method @androidx.compose.runtime.Composable public static inline <reified T> androidx.compose.animation.core.FiniteAnimationSpec<T> rememberSlowSpatialSpec(androidx.wear.compose.material3.MotionScheme);
- method public static androidx.wear.compose.material3.MotionScheme standardMotionScheme();
+ public static final class MotionScheme.Companion {
+ method public androidx.wear.compose.material3.MotionScheme expressive();
+ method public androidx.wear.compose.material3.MotionScheme standard();
}
public final class OpenOnPhoneDialogColors {
@@ -719,6 +718,17 @@
method @androidx.compose.runtime.Composable public static void VerticalPageIndicator(androidx.wear.compose.foundation.pager.PagerState pagerState, optional androidx.compose.ui.Modifier modifier, optional long selectedColor, optional long unselectedColor, optional long backgroundColor);
}
+ public final class PagerScaffoldDefaults {
+ method public androidx.compose.animation.core.AnimationSpec<java.lang.Float> getFadeOutAnimation();
+ property public final androidx.compose.animation.core.AnimationSpec<java.lang.Float> FadeOutAnimation;
+ field public static final androidx.wear.compose.material3.PagerScaffoldDefaults INSTANCE;
+ }
+
+ public final class PagerScaffoldKt {
+ method @androidx.compose.runtime.Composable public static void HorizontalPagerScaffold(androidx.wear.compose.foundation.pager.PagerState pagerState, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? pageIndicator, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float>? pageIndicatorAnimationSpec, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.pager.PagerScope,? super java.lang.Integer,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void VerticalPagerScaffold(androidx.wear.compose.foundation.pager.PagerState pagerState, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? pageIndicator, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float>? pageIndicatorAnimationSpec, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.pager.PagerScope,? super java.lang.Integer,kotlin.Unit> content);
+ }
+
public final class PickerDefaults {
method public float getGradientRatio();
method @androidx.compose.runtime.Composable public androidx.wear.compose.foundation.rotary.RotaryScrollableBehavior rotarySnapBehavior(androidx.wear.compose.material3.PickerState state);
diff --git a/wear/compose/compose-material3/benchmark/src/androidTest/java/androidx/wear/compose/material3/benchmark/ListHeaderBenchmark.kt b/wear/compose/compose-material3/benchmark/src/androidTest/java/androidx/wear/compose/material3/benchmark/ListHeaderBenchmark.kt
index c0795a3..43bb317 100644
--- a/wear/compose/compose-material3/benchmark/src/androidTest/java/androidx/wear/compose/material3/benchmark/ListHeaderBenchmark.kt
+++ b/wear/compose/compose-material3/benchmark/src/androidTest/java/androidx/wear/compose/material3/benchmark/ListHeaderBenchmark.kt
@@ -22,7 +22,7 @@
import androidx.compose.testutils.benchmark.benchmarkToFirstPixel
import androidx.test.filters.LargeTest
import androidx.wear.compose.material3.ListHeader
-import androidx.wear.compose.material3.ListSubheader
+import androidx.wear.compose.material3.ListSubHeader
import androidx.wear.compose.material3.MaterialTheme
import androidx.wear.compose.material3.Text
import org.junit.Rule
@@ -55,7 +55,7 @@
override fun MeasuredContent() {
when (type) {
ListHeaderType.ListHeader -> ListHeader { Text("Header") }
- ListHeaderType.ListSubheader -> ListSubheader { Text("Subheader") }
+ ListHeaderType.ListSubheader -> ListSubHeader { Text("SubHeader") }
}
}
diff --git a/wear/compose/compose-material3/integration-tests/src/main/java/androidx/wear/compose/material3/demos/ButtonDemo.kt b/wear/compose/compose-material3/integration-tests/src/main/java/androidx/wear/compose/material3/demos/ButtonDemo.kt
index e5e8942..fb76b908 100644
--- a/wear/compose/compose-material3/integration-tests/src/main/java/androidx/wear/compose/material3/demos/ButtonDemo.kt
+++ b/wear/compose/compose-material3/integration-tests/src/main/java/androidx/wear/compose/material3/demos/ButtonDemo.kt
@@ -35,7 +35,7 @@
import androidx.wear.compose.material3.CompactButton
import androidx.wear.compose.material3.FilledTonalButton
import androidx.wear.compose.material3.ListHeader
-import androidx.wear.compose.material3.ListSubheader
+import androidx.wear.compose.material3.ListSubHeader
import androidx.wear.compose.material3.OutlinedButton
import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.samples.ButtonExtraLargeIconSample
@@ -62,9 +62,9 @@
// to the content slot.
ScalingLazyDemo {
item { ListHeader { Text("Base Button") } }
- item { ListSubheader { Text("Default alignment") } }
+ item { ListSubHeader { Text("Default alignment") } }
item { Button(onClick = {}, modifier = Modifier.fillMaxWidth()) { Text("Base Button") } }
- item { ListSubheader { Text("Top Alignment") } }
+ item { ListSubHeader { Text("Top Alignment") } }
item {
Button(onClick = {}, modifier = Modifier.fillMaxWidth()) {
Text("Base Button", modifier = Modifier.align(Alignment.Top))
diff --git a/wear/compose/compose-material3/integration-tests/src/main/java/androidx/wear/compose/material3/demos/ListHeaderDemo.kt b/wear/compose/compose-material3/integration-tests/src/main/java/androidx/wear/compose/material3/demos/ListHeaderDemo.kt
index 6cdcf30..4134ebb 100644
--- a/wear/compose/compose-material3/integration-tests/src/main/java/androidx/wear/compose/material3/demos/ListHeaderDemo.kt
+++ b/wear/compose/compose-material3/integration-tests/src/main/java/androidx/wear/compose/material3/demos/ListHeaderDemo.kt
@@ -18,14 +18,14 @@
import androidx.compose.runtime.Composable
import androidx.wear.compose.material3.samples.ListHeaderSample
-import androidx.wear.compose.material3.samples.ListSubheaderSample
-import androidx.wear.compose.material3.samples.ListSubheaderWithIconSample
+import androidx.wear.compose.material3.samples.ListSubHeaderSample
+import androidx.wear.compose.material3.samples.ListSubHeaderWithIconSample
@Composable
fun ListHeaderDemo() {
ScalingLazyDemo {
item { ListHeaderSample() }
- item { ListSubheaderSample() }
- item { ListSubheaderWithIconSample() }
+ item { ListSubHeaderSample() }
+ item { ListSubHeaderWithIconSample() }
}
}
diff --git a/wear/compose/compose-material3/integration-tests/src/main/java/androidx/wear/compose/material3/demos/RobotoFlexTypography.kt b/wear/compose/compose-material3/integration-tests/src/main/java/androidx/wear/compose/material3/demos/RobotoFlexTypography.kt
new file mode 100644
index 0000000..a79a509
--- /dev/null
+++ b/wear/compose/compose-material3/integration-tests/src/main/java/androidx/wear/compose/material3/demos/RobotoFlexTypography.kt
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
+
+package androidx.wear.compose.material3.demos
+
+import androidx.compose.ui.text.ExperimentalTextApi
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.font.Font
+import androidx.compose.ui.text.font.FontVariation
+import androidx.compose.ui.text.font.toFontFamily
+import androidx.wear.compose.material3.Typography
+import androidx.wear.compose.material3.tokens.TypographyVariableFontsTokens
+
+@OptIn(ExperimentalTextApi::class)
+fun createRobotoFlexTextStyle(variationSettings: FontVariation.Settings) =
+ TextStyle(
+ fontFamily =
+ Font(R.font.robotoflex_variable, variationSettings = variationSettings).toFontFamily()
+ )
+
+val RobotoFlexTypography =
+ Typography(
+ arcLarge =
+ createRobotoFlexTextStyle(TypographyVariableFontsTokens.ArcLargeVariationSettings),
+ arcMedium =
+ createRobotoFlexTextStyle(TypographyVariableFontsTokens.ArcMediumVariationSettings),
+ arcSmall =
+ createRobotoFlexTextStyle(TypographyVariableFontsTokens.ArcSmallVariationSettings),
+ bodyExtraSmall =
+ createRobotoFlexTextStyle(
+ TypographyVariableFontsTokens.BodyExtraSmallVariationSettings
+ ),
+ bodySmall =
+ createRobotoFlexTextStyle(TypographyVariableFontsTokens.BodySmallVariationSettings),
+ bodyMedium =
+ createRobotoFlexTextStyle(TypographyVariableFontsTokens.BodyMediumVariationSettings),
+ bodyLarge =
+ createRobotoFlexTextStyle(TypographyVariableFontsTokens.BodyLargeVariationSettings),
+ displaySmall =
+ createRobotoFlexTextStyle(TypographyVariableFontsTokens.DisplaySmallVariationSettings),
+ displayMedium =
+ createRobotoFlexTextStyle(TypographyVariableFontsTokens.DisplayMediumVariationSettings),
+ displayLarge =
+ createRobotoFlexTextStyle(TypographyVariableFontsTokens.DisplayLargeVariationSettings),
+ labelSmall =
+ createRobotoFlexTextStyle(TypographyVariableFontsTokens.LabelSmallVariationSettings),
+ labelMedium =
+ createRobotoFlexTextStyle(TypographyVariableFontsTokens.LabelMediumVariationSettings),
+ labelLarge =
+ createRobotoFlexTextStyle(TypographyVariableFontsTokens.LabelLargeVariationSettings),
+ titleSmall =
+ createRobotoFlexTextStyle(TypographyVariableFontsTokens.TitleSmallVariationSettings),
+ titleMedium =
+ createRobotoFlexTextStyle(TypographyVariableFontsTokens.TitleMediumVariationSettings),
+ titleLarge =
+ createRobotoFlexTextStyle(TypographyVariableFontsTokens.TitleLargeVariationSettings),
+ numeralExtraSmall =
+ createRobotoFlexTextStyle(
+ TypographyVariableFontsTokens.NumeralExtraSmallVariationSettings
+ ),
+ numeralSmall =
+ createRobotoFlexTextStyle(TypographyVariableFontsTokens.NumeralSmallVariationSettings),
+ numeralMedium =
+ createRobotoFlexTextStyle(TypographyVariableFontsTokens.NumeralMediumVariationSettings),
+ numeralLarge =
+ createRobotoFlexTextStyle(TypographyVariableFontsTokens.NumeralLargeVariationSettings),
+ numeralExtraLarge =
+ createRobotoFlexTextStyle(
+ TypographyVariableFontsTokens.NumeralExtraLargeVariationSettings
+ ),
+ )
diff --git a/wear/compose/compose-material3/integration-tests/src/main/java/androidx/wear/compose/material3/demos/ScaffoldDemos.kt b/wear/compose/compose-material3/integration-tests/src/main/java/androidx/wear/compose/material3/demos/ScaffoldDemos.kt
new file mode 100644
index 0000000..1aec2b4
--- /dev/null
+++ b/wear/compose/compose-material3/integration-tests/src/main/java/androidx/wear/compose/material3/demos/ScaffoldDemos.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.wear.compose.material3.demos
+
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.wear.compose.foundation.pager.rememberPagerState
+import androidx.wear.compose.material3.AppScaffold
+import androidx.wear.compose.material3.HorizontalPagerScaffold
+import androidx.wear.compose.material3.PagerScaffoldDefaults
+import androidx.wear.compose.material3.ScreenScaffold
+import androidx.wear.compose.material3.Text
+import androidx.wear.compose.material3.VerticalPagerScaffold
+
+@Composable
+fun HorizontalPagerScaffoldFadeOutIndicatorDemo() {
+ AppScaffold {
+ val pagerState = rememberPagerState(pageCount = { 10 })
+
+ HorizontalPagerScaffold(
+ pagerState = pagerState,
+ pageIndicatorAnimationSpec = PagerScaffoldDefaults.FadeOutAnimation
+ ) { page ->
+ ScreenScaffold {
+ Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
+ Text("Page $page")
+ }
+ }
+ }
+ }
+}
+
+@Composable
+fun VerticalPagerScaffoldFadeOutIndicatorDemo() {
+ AppScaffold {
+ val pagerState = rememberPagerState(pageCount = { 10 })
+
+ VerticalPagerScaffold(
+ pagerState = pagerState,
+ pageIndicatorAnimationSpec = PagerScaffoldDefaults.FadeOutAnimation
+ ) { page ->
+ ScreenScaffold {
+ Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
+ Text("Page $page")
+ }
+ }
+ }
+ }
+}
diff --git a/wear/compose/compose-material3/integration-tests/src/main/java/androidx/wear/compose/material3/demos/WearMaterial3Demos.kt b/wear/compose/compose-material3/integration-tests/src/main/java/androidx/wear/compose/material3/demos/WearMaterial3Demos.kt
index 395cf6e..f0baac8 100644
--- a/wear/compose/compose-material3/integration-tests/src/main/java/androidx/wear/compose/material3/demos/WearMaterial3Demos.kt
+++ b/wear/compose/compose-material3/integration-tests/src/main/java/androidx/wear/compose/material3/demos/WearMaterial3Demos.kt
@@ -31,6 +31,7 @@
import androidx.wear.compose.material3.samples.EdgeSwipeForSwipeToDismiss
import androidx.wear.compose.material3.samples.FixedFontSize
import androidx.wear.compose.material3.samples.HorizontalPageIndicatorWithPagerSample
+import androidx.wear.compose.material3.samples.HorizontalPagerScaffoldSample
import androidx.wear.compose.material3.samples.LazyColumnScalingMorphingEffectSample
import androidx.wear.compose.material3.samples.LazyColumnTargetMorphingHeightSample
import androidx.wear.compose.material3.samples.ScaffoldSample
@@ -40,159 +41,180 @@
import androidx.wear.compose.material3.samples.SwipeToRevealSample
import androidx.wear.compose.material3.samples.SwipeToRevealSingleActionCardSample
import androidx.wear.compose.material3.samples.VerticalPageIndicatorWithPagerSample
+import androidx.wear.compose.material3.samples.VerticalPagerScaffoldSample
val WearMaterial3Demos =
Material3DemoCategory(
"Material 3",
listOf(
- ComposableDemo("Haptics") { Centralize { HapticsDemos() } },
- Material3DemoCategory(title = "Typography", TypographyDemos),
- Material3DemoCategory(
- "Button",
- listOf(
- ComposableDemo("Base Button") { BaseButtonDemo() },
- ComposableDemo("Filled Button") { ButtonDemo() },
- ComposableDemo("Filled Tonal Button") { FilledTonalButtonDemo() },
- ComposableDemo("Filled Variant Button") { FilledVariantButtonDemo() },
- ComposableDemo("Outlined Button") { OutlinedButtonDemo() },
- ComposableDemo("Child Button") { ChildButtonDemo() },
- ComposableDemo("Multiline Button") { MultilineButtonDemo() },
- ComposableDemo("App Button") { AppButtonDemo() },
- ComposableDemo("Avatar Button") { AvatarButtonDemo() },
- ComposableDemo("Button (Image Background)") { ButtonBackgroundImageDemo() },
- )
- ),
- ComposableDemo("Color Scheme") { ColorSchemeDemos() },
- ComposableDemo("Dynamic Color Scheme") { DynamicColorSchemeDemos() },
- Material3DemoCategory("Curved Text", CurvedTextDemos),
- Material3DemoCategory("Alert Dialog", AlertDialogs),
- Material3DemoCategory("Confirmation", Comfirmations),
- Material3DemoCategory("Open on phone Dialog", OpenOnPhoneDialogDemos),
- ComposableDemo("Scaffold") { ScaffoldSample() },
- Material3DemoCategory("ScrollAway", ScrollAwayDemos),
- ComposableDemo("Compact Button") { CompactButtonDemo() },
- ComposableDemo("Icon Button") { IconButtonDemo() },
- ComposableDemo("Image Button") { ImageButtonDemo() },
- ComposableDemo("Text Button") { TextButtonDemo() },
- Material3DemoCategory(
- "Edge Button",
- listOf(
- ComposableDemo("Simple Edge Button") { EdgeButtonSample() },
- ComposableDemo("Sizes and Colors") { EdgeButtonMultiDemo() },
- ComposableDemo("Configurable") { EdgeButtonConfigurableDemo() },
- ComposableDemo("Simple Edge Button below SLC") { EdgeButtonListSample() },
- ComposableDemo("Edge Button Below LC") { EdgeButtonBelowLazyColumnDemo() },
- ComposableDemo("Edge Button Below SLC") {
- EdgeButtonBelowScalingLazyColumnDemo()
- },
- )
- ),
- Material3DemoCategory(
- "Button Group",
- listOf(
- ComposableDemo("Two buttons") { ButtonGroupSample() },
- ComposableDemo("Three buttons") { ButtonGroupDemo() },
- )
- ),
- ComposableDemo("List Header") { Centralize { ListHeaderDemo() } },
- Material3DemoCategory("Time Text", TimeTextDemos),
- ComposableDemo("Card") { CardDemo() },
- ComposableDemo("Animated Shape Buttons") { AnimatedShapeButtonDemo() },
- ComposableDemo("Animated Shape Toggle Buttons") { AnimatedShapeToggleButtonDemo() },
- ComposableDemo("Text Toggle Button") { TextToggleButtonDemo() },
- ComposableDemo("Icon Toggle Button") { IconToggleButtonDemo() },
- ComposableDemo("Checkbox Button") { CheckboxButtonDemo() },
- ComposableDemo("Split Checkbox Button") { SplitCheckboxButtonDemo() },
- ComposableDemo("Radio Button") { RadioButtonDemo() },
- ComposableDemo("Split Radio Button") { SplitRadioButtonDemo() },
- ComposableDemo("Switch Button") { SwitchButtonDemo() },
- ComposableDemo("Split Switch Button") { SplitSwitchButtonDemo() },
- Material3DemoCategory("Stepper", StepperDemos),
- Material3DemoCategory("Slider", SliderDemos),
- Material3DemoCategory("Picker", PickerDemos),
- // Requires API level 26 or higher due to java.time dependency.
- *(if (Build.VERSION.SDK_INT >= 26)
- arrayOf(
- Material3DemoCategory("TimePicker", TimePickerDemos),
- Material3DemoCategory("DatePicker", DatePickerDemos)
- )
- else emptyArray<Material3DemoCategory>()),
- Material3DemoCategory("Progress Indicator", ProgressIndicatorDemos),
- Material3DemoCategory("Scroll Indicator", ScrollIndicatorDemos),
- Material3DemoCategory("Placeholder", PlaceholderDemos),
- ComposableDemo(title = "Fixed Font Size") { Centralize { FixedFontSize() } },
- Material3DemoCategory(
- title = "Swipe To Dismiss",
- listOf(
- ComposableDemo("Simple") { SimpleSwipeToDismissBox(it.navigateBack) },
- ComposableDemo("Stateful") { StatefulSwipeToDismissBox() },
- ComposableDemo("Edge swipe") { EdgeSwipeForSwipeToDismiss(it.navigateBack) },
- )
- ),
- Material3DemoCategory(
- title = "Page Indicator",
- listOf(
- ComposableDemo("HorizontalPageIndicator") {
- HorizontalPageIndicatorWithPagerSample()
- },
- ComposableDemo("VerticalPageIndicator") {
- VerticalPageIndicatorWithPagerSample()
- },
- )
- ),
- Material3DemoCategory(
- title = "Swipe to Reveal",
- listOf(
- ComposableDemo("Bi-directional / Non-anchoring") {
- Centralize { SwipeToRevealBothDirectionsNonAnchoring() }
- },
- ComposableDemo("Bi-directional Two Actions") {
- Centralize { SwipeToRevealBothDirections() }
- },
- ComposableDemo("Two Actions") { Centralize { SwipeToRevealSample() } },
- ComposableDemo("Two Undo Actions") {
- Centralize { SwipeToRevealTwoActionsWithUndo() }
- },
- ComposableDemo("Single action with Card") {
- Centralize { SwipeToRevealSingleActionCardSample() }
- },
- ComposableDemo("In a list") { Centralize { SwipeToRevealInList() } },
- ComposableDemo("Non-anchoring") {
- Centralize { SwipeToRevealNonAnchoredSample() }
- }
- )
- ),
- Material3DemoCategory(title = "Typography", TypographyDemos),
- Material3DemoCategory(
- "Animated Text",
- if (Build.VERSION.SDK_INT > 31) {
+ ComposableDemo("Haptics") { Centralize { HapticsDemos() } },
+ Material3DemoCategory(title = "Typography", TypographyDemos),
+ Material3DemoCategory(
+ "Button",
listOf(
- ComposableDemo("Simple animation") { Centralize { AnimatedTextSample() } },
- ComposableDemo("Animation with button click") {
- Centralize { AnimatedTextSampleButtonResponse() }
+ ComposableDemo("Base Button") { BaseButtonDemo() },
+ ComposableDemo("Filled Button") { ButtonDemo() },
+ ComposableDemo("Filled Tonal Button") { FilledTonalButtonDemo() },
+ ComposableDemo("Filled Variant Button") { FilledVariantButtonDemo() },
+ ComposableDemo("Outlined Button") { OutlinedButtonDemo() },
+ ComposableDemo("Child Button") { ChildButtonDemo() },
+ ComposableDemo("Multiline Button") { MultilineButtonDemo() },
+ ComposableDemo("App Button") { AppButtonDemo() },
+ ComposableDemo("Avatar Button") { AvatarButtonDemo() },
+ ComposableDemo("Button (Image Background)") { ButtonBackgroundImageDemo() },
+ )
+ ),
+ ComposableDemo("Color Scheme") { ColorSchemeDemos() },
+ ComposableDemo("Dynamic Color Scheme") { DynamicColorSchemeDemos() },
+ Material3DemoCategory("Curved Text", CurvedTextDemos),
+ Material3DemoCategory("Alert Dialog", AlertDialogs),
+ Material3DemoCategory("Confirmation", Comfirmations),
+ Material3DemoCategory("Open on phone Dialog", OpenOnPhoneDialogDemos),
+ Material3DemoCategory(
+ "Scaffold",
+ listOf(
+ ComposableDemo("Screen Scaffold") { ScaffoldSample() },
+ ComposableDemo("Horizontal Pager Scaffold") {
+ HorizontalPagerScaffoldSample()
},
- ComposableDemo("Shared Font Registry") {
- Centralize { AnimatedTextSampleSharedFontRegistry() }
+ ComposableDemo("Horizontal Pager Scaffold (Fade Out Indicator)") {
+ HorizontalPagerScaffoldFadeOutIndicatorDemo()
+ },
+ ComposableDemo("Vertical Pager Scaffold") { VerticalPagerScaffoldSample() },
+ ComposableDemo("Vertical Pager Scaffold (Fade Out Indicator)") {
+ VerticalPagerScaffoldFadeOutIndicatorDemo()
},
)
- } else {
- emptyList()
- }
- ),
- ComposableDemo("Settings Demo") { SettingsDemo() },
- Material3DemoCategory(
- title = "LazyColumn",
- listOf(
- ComposableDemo("Notifications") { LazyColumnNotificationsDemo() },
- ComposableDemo("Scaling Morphing Effect Sample") {
- LazyColumnScalingMorphingEffectSample()
- },
- ComposableDemo("Target Morphing Height Sample") {
- LazyColumnTargetMorphingHeightSample()
+ ),
+ Material3DemoCategory("ScrollAway", ScrollAwayDemos),
+ ComposableDemo("Compact Button") { CompactButtonDemo() },
+ ComposableDemo("Icon Button") { IconButtonDemo() },
+ ComposableDemo("Image Button") { ImageButtonDemo() },
+ ComposableDemo("Text Button") { TextButtonDemo() },
+ Material3DemoCategory(
+ "Edge Button",
+ listOf(
+ ComposableDemo("Simple Edge Button") { EdgeButtonSample() },
+ ComposableDemo("Sizes and Colors") { EdgeButtonMultiDemo() },
+ ComposableDemo("Configurable") { EdgeButtonConfigurableDemo() },
+ ComposableDemo("Simple Edge Button below SLC") { EdgeButtonListSample() },
+ ComposableDemo("Edge Button Below LC") { EdgeButtonBelowLazyColumnDemo() },
+ ComposableDemo("Edge Button Below SLC") {
+ EdgeButtonBelowScalingLazyColumnDemo()
+ },
+ )
+ ),
+ Material3DemoCategory(
+ "Button Group",
+ listOf(
+ ComposableDemo("Two buttons") { ButtonGroupSample() },
+ ComposableDemo("Three buttons") { ButtonGroupDemo() },
+ )
+ ),
+ ComposableDemo("List Header") { Centralize { ListHeaderDemo() } },
+ Material3DemoCategory("Time Text", TimeTextDemos),
+ ComposableDemo("Card") { CardDemo() },
+ ComposableDemo("Animated Shape Buttons") { AnimatedShapeButtonDemo() },
+ ComposableDemo("Animated Shape Toggle Buttons") { AnimatedShapeToggleButtonDemo() },
+ ComposableDemo("Text Toggle Button") { TextToggleButtonDemo() },
+ ComposableDemo("Icon Toggle Button") { IconToggleButtonDemo() },
+ ComposableDemo("Checkbox Button") { CheckboxButtonDemo() },
+ ComposableDemo("Split Checkbox Button") { SplitCheckboxButtonDemo() },
+ ComposableDemo("Radio Button") { RadioButtonDemo() },
+ ComposableDemo("Split Radio Button") { SplitRadioButtonDemo() },
+ ComposableDemo("Switch Button") { SwitchButtonDemo() },
+ ComposableDemo("Split Switch Button") { SplitSwitchButtonDemo() },
+ Material3DemoCategory("Stepper", StepperDemos),
+ Material3DemoCategory("Slider", SliderDemos),
+ Material3DemoCategory("Picker", PickerDemos),
+ // Requires API level 26 or higher due to java.time dependency.
+ *(if (Build.VERSION.SDK_INT >= 26)
+ arrayOf(
+ Material3DemoCategory("TimePicker", TimePickerDemos),
+ Material3DemoCategory("DatePicker", DatePickerDemos)
+ )
+ else emptyArray<Material3DemoCategory>()),
+ Material3DemoCategory("Progress Indicator", ProgressIndicatorDemos),
+ Material3DemoCategory("Scroll Indicator", ScrollIndicatorDemos),
+ Material3DemoCategory("Placeholder", PlaceholderDemos),
+ ComposableDemo(title = "Fixed Font Size") { Centralize { FixedFontSize() } },
+ Material3DemoCategory(
+ title = "Swipe To Dismiss",
+ listOf(
+ ComposableDemo("Simple") { SimpleSwipeToDismissBox(it.navigateBack) },
+ ComposableDemo("Stateful") { StatefulSwipeToDismissBox() },
+ ComposableDemo("Edge swipe") {
+ EdgeSwipeForSwipeToDismiss(it.navigateBack)
+ },
+ )
+ ),
+ Material3DemoCategory(
+ title = "Page Indicator",
+ listOf(
+ ComposableDemo("HorizontalPageIndicator") {
+ HorizontalPageIndicatorWithPagerSample()
+ },
+ ComposableDemo("VerticalPageIndicator") {
+ VerticalPageIndicatorWithPagerSample()
+ },
+ )
+ ),
+ Material3DemoCategory(
+ title = "Swipe to Reveal",
+ listOf(
+ ComposableDemo("Bi-directional / Non-anchoring") {
+ Centralize { SwipeToRevealBothDirectionsNonAnchoring() }
+ },
+ ComposableDemo("Bi-directional Two Actions") {
+ Centralize { SwipeToRevealBothDirections() }
+ },
+ ComposableDemo("Two Actions") { Centralize { SwipeToRevealSample() } },
+ ComposableDemo("Two Undo Actions") {
+ Centralize { SwipeToRevealTwoActionsWithUndo() }
+ },
+ ComposableDemo("Single action with Card") {
+ Centralize { SwipeToRevealSingleActionCardSample() }
+ },
+ ComposableDemo("In a list") { Centralize { SwipeToRevealInList() } },
+ ComposableDemo("Non-anchoring") {
+ Centralize { SwipeToRevealNonAnchoredSample() }
+ }
+ )
+ ),
+ Material3DemoCategory(title = "Typography", TypographyDemos),
+ Material3DemoCategory(
+ "Animated Text",
+ if (Build.VERSION.SDK_INT > 31) {
+ listOf(
+ ComposableDemo("Simple animation") {
+ Centralize { AnimatedTextSample() }
+ },
+ ComposableDemo("Animation with button click") {
+ Centralize { AnimatedTextSampleButtonResponse() }
+ },
+ ComposableDemo("Shared Font Registry") {
+ Centralize { AnimatedTextSampleSharedFontRegistry() }
+ },
+ )
+ } else {
+ emptyList()
}
+ ),
+ ComposableDemo("Settings Demo") { SettingsDemo() },
+ Material3DemoCategory(
+ title = "LazyColumn",
+ listOf(
+ ComposableDemo("Notifications") { LazyColumnNotificationsDemo() },
+ ComposableDemo("Scaling Morphing Effect Sample") {
+ LazyColumnScalingMorphingEffectSample()
+ },
+ ComposableDemo("Target Morphing Height Sample") {
+ LazyColumnTargetMorphingHeightSample()
+ }
+ )
)
)
- )
+ .sortedBy { it.title }
)
internal fun showOnClickToast(context: Context) {
diff --git a/wear/compose/compose-material3/integration-tests/src/main/res/font/robotoflex_variable.ttf b/wear/compose/compose-material3/integration-tests/src/main/res/font/robotoflex_variable.ttf
new file mode 100644
index 0000000..c39aafb
--- /dev/null
+++ b/wear/compose/compose-material3/integration-tests/src/main/res/font/robotoflex_variable.ttf
Binary files differ
diff --git a/wear/compose/compose-material3/samples/src/main/java/androidx/wear/compose/material3/samples/ListHeaderSample.kt b/wear/compose/compose-material3/samples/src/main/java/androidx/wear/compose/material3/samples/ListHeaderSample.kt
index abb6f9f..baf20de 100644
--- a/wear/compose/compose-material3/samples/src/main/java/androidx/wear/compose/material3/samples/ListHeaderSample.kt
+++ b/wear/compose/compose-material3/samples/src/main/java/androidx/wear/compose/material3/samples/ListHeaderSample.kt
@@ -22,7 +22,7 @@
import androidx.compose.runtime.Composable
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.ListHeader
-import androidx.wear.compose.material3.ListSubheader
+import androidx.wear.compose.material3.ListSubHeader
import androidx.wear.compose.material3.Text
@Sampled
@@ -33,15 +33,15 @@
@Sampled
@Composable
-fun ListSubheaderSample() {
- ListSubheader { Text("Subheader") }
+fun ListSubHeaderSample() {
+ ListSubHeader { Text("SubHeader") }
}
@Sampled
@Composable
-fun ListSubheaderWithIconSample() {
- ListSubheader(
- label = { Text(text = "Subheader") },
+fun ListSubHeaderWithIconSample() {
+ ListSubHeader(
+ label = { Text(text = "SubHeader") },
icon = { Icon(imageVector = Icons.Outlined.Home, "home") }
)
}
diff --git a/wear/compose/compose-material3/samples/src/main/java/androidx/wear/compose/material3/samples/PagerScaffoldSample.kt b/wear/compose/compose-material3/samples/src/main/java/androidx/wear/compose/material3/samples/PagerScaffoldSample.kt
new file mode 100644
index 0000000..08c15c9
--- /dev/null
+++ b/wear/compose/compose-material3/samples/src/main/java/androidx/wear/compose/material3/samples/PagerScaffoldSample.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.wear.compose.material3.samples
+
+import androidx.annotation.Sampled
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.wear.compose.foundation.pager.rememberPagerState
+import androidx.wear.compose.material3.AppScaffold
+import androidx.wear.compose.material3.HorizontalPagerScaffold
+import androidx.wear.compose.material3.ScreenScaffold
+import androidx.wear.compose.material3.Text
+import androidx.wear.compose.material3.VerticalPagerScaffold
+
+@Sampled
+@Composable
+fun HorizontalPagerScaffoldSample() {
+ AppScaffold {
+ val pagerState = rememberPagerState(pageCount = { 10 })
+
+ HorizontalPagerScaffold(pagerState = pagerState) { page ->
+ ScreenScaffold {
+ Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
+ Text("Page $page")
+ }
+ }
+ }
+ }
+}
+
+@Sampled
+@Composable
+fun VerticalPagerScaffoldSample() {
+ AppScaffold {
+ val pagerState = rememberPagerState(pageCount = { 10 })
+
+ VerticalPagerScaffold(pagerState = pagerState) { page ->
+ ScreenScaffold {
+ Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
+ Text("Page $page")
+ }
+ }
+ }
+ }
+}
diff --git a/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/ListHeaderScreenshotTest.kt b/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/ListHeaderScreenshotTest.kt
index 1f3ba09..6209574 100644
--- a/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/ListHeaderScreenshotTest.kt
+++ b/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/ListHeaderScreenshotTest.kt
@@ -54,7 +54,7 @@
methodName = testName.methodName,
screenshotRule = screenshotRule,
) {
- ListSubheader(modifier = Modifier.testTag(TEST_TAG)) { Text("Subheader") }
+ ListSubHeader(modifier = Modifier.testTag(TEST_TAG)) { Text("Subheader") }
}
@Test
@@ -64,7 +64,7 @@
screenshotRule = screenshotRule,
layoutDirection = LayoutDirection.Rtl,
) {
- ListSubheader(modifier = Modifier.testTag(TEST_TAG)) { Text("Subheader") }
+ ListSubHeader(modifier = Modifier.testTag(TEST_TAG)) { Text("Subheader") }
}
@Test
@@ -74,7 +74,7 @@
screenshotRule = screenshotRule,
layoutDirection = LayoutDirection.Ltr,
) {
- ListSubheader(
+ ListSubHeader(
modifier = Modifier.testTag(TEST_TAG),
label = { Text(text = "Subheader") },
icon = { Icon(imageVector = Icons.Outlined.Home, "home") }
@@ -88,7 +88,7 @@
screenshotRule = screenshotRule,
layoutDirection = LayoutDirection.Rtl
) {
- ListSubheader(
+ ListSubHeader(
modifier = Modifier.testTag(TEST_TAG),
label = { Text(text = "Subheader") },
icon = { Icon(imageVector = Icons.Outlined.Home, "home") }
diff --git a/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/ListHeaderTest.kt b/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/ListHeaderTest.kt
index 167473c..3a34438 100644
--- a/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/ListHeaderTest.kt
+++ b/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/ListHeaderTest.kt
@@ -62,7 +62,7 @@
@Test
fun listSubheader_has_semantic_heading_property() {
rule.setContentWithTheme {
- ListSubheader(modifier = Modifier.testTag(TEST_TAG)) { Text("Subheader") }
+ ListSubHeader(modifier = Modifier.testTag(TEST_TAG)) { Text("Subheader") }
}
rule.assertNodeIsHeading(TEST_TAG)
@@ -103,7 +103,7 @@
rule
.setContentWithThemeForSizeAssertions {
- ListSubheader(modifier = Modifier.testTag(TEST_TAG)) {
+ ListSubHeader(modifier = Modifier.testTag(TEST_TAG)) {
Text(
"Header with multiple lines of text to exceed" +
" the minimum height, should adjust"
@@ -120,7 +120,7 @@
rule.setContentWithTheme {
expectedTextStyle = MaterialTheme.typography.titleMedium
- ListSubheader { actualTextStyle = LocalTextStyle.current }
+ ListSubHeader { actualTextStyle = LocalTextStyle.current }
}
Assert.assertEquals(expectedTextStyle, actualTextStyle)
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/DatePicker.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/DatePicker.kt
index b5e9a6c..bcfac15 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/DatePicker.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/DatePicker.kt
@@ -142,15 +142,15 @@
val isLargeScreen = LocalConfiguration.current.screenWidthDp > 225
val labelTextStyle =
if (isLargeScreen) {
- DatePickerTokens.PickerLabelLargeTypography.value
+ DatePickerTokens.LabelLargeTypography.value
} else {
- DatePickerTokens.PickerLabelTypography.value
+ DatePickerTokens.LabelTypography.value
}
val optionTextStyle =
if (isLargeScreen) {
- DatePickerTokens.PickerContentLargeTypography.value
+ DatePickerTokens.ContentLargeTypography.value
} else {
- DatePickerTokens.PickerContentTypography.value
+ DatePickerTokens.ContentTypography.value
}
val optionHeight = if (isLargeScreen) 48.dp else 36.dp
@@ -528,10 +528,10 @@
return defaultDatePickerColorsCached
?: DatePickerColors(
selectedPickerContentColor =
- fromToken(DatePickerTokens.SelectedPickerContentColor),
+ fromToken(DatePickerTokens.SelectedContentColor),
unselectedPickerContentColor =
- fromToken(DatePickerTokens.UnselectedPickerContentColor),
- pickerLabelColor = fromToken(DatePickerTokens.PickerLabelColor),
+ fromToken(DatePickerTokens.UnselectedContentColor),
+ pickerLabelColor = fromToken(DatePickerTokens.LabelColor),
nextButtonContentColor = fromToken(DatePickerTokens.NextButtonContentColor),
nextButtonContainerColor =
fromToken(DatePickerTokens.NextButtonContainerColor),
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/IconToggleButton.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/IconToggleButton.kt
index 39f2537..8fb2afe 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/IconToggleButton.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/IconToggleButton.kt
@@ -229,7 +229,7 @@
checkedCornerSize: CornerSize = CheckedCornerSize,
pressedCornerSize: CornerSize = PressedCornerSize,
onPressAnimationSpec: FiniteAnimationSpec<Float> =
- MaterialTheme.motionScheme.rememberFastSpatialSpec(),
+ MaterialTheme.motionScheme.fastSpatialSpec(),
onReleaseAnimationSpec: FiniteAnimationSpec<Float> =
MaterialTheme.motionScheme.slowSpatialSpec(),
): Shape {
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/ListHeader.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/ListHeader.kt
index 2e63601..db65f78 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/ListHeader.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/ListHeader.kt
@@ -55,15 +55,13 @@
* @param contentPadding The spacing values to apply internally between the container and the
* content.
* @param content Slot for [ListHeader] content, expected to be a single line of text.
- *
- * TODO(b/261838497) Add Material3 UX guidance links
*/
@Composable
fun ListHeader(
modifier: Modifier = Modifier,
backgroundColor: Color = Color.Transparent,
- contentColor: Color = ListHeaderTokens.ContentColor.value,
- contentPadding: PaddingValues = ListHeaderDefaults.HeaderContentPadding,
+ contentColor: Color = ListHeaderDefaults.ContentColor,
+ contentPadding: PaddingValues = ListHeaderDefaults.ContentPadding,
content: @Composable RowScope.() -> Unit
) {
Row(
@@ -87,32 +85,30 @@
}
/**
- * A two slot based composable for creating a list subheader item. [ListSubheader]s offer slots for
+ * A two slot based composable for creating a list sub-header item. [ListSubHeader]s offer slots for
* an icon and for a text label. The contents will be start and end padded.
*
- * Example of a [ListSubheader]:
+ * Example of a [ListSubHeader]:
*
- * @sample androidx.wear.compose.material3.samples.ListSubheaderSample
+ * @sample androidx.wear.compose.material3.samples.ListSubHeaderSample
*
- * Example of a [ListSubheader] with an icon:
+ * Example of a [ListSubHeader] with an icon:
*
- * @sample androidx.wear.compose.material3.samples.ListSubheaderWithIconSample
- * @param modifier The modifier for the [ListSubheader].
+ * @sample androidx.wear.compose.material3.samples.ListSubHeaderWithIconSample
+ * @param modifier The modifier for the [ListSubHeader].
* @param backgroundColor The background color to apply - typically Color.Transparent
* @param contentColor The color to apply to content.
* @param contentPadding The spacing values to apply internally between the container and the
* content.
- * @param icon A slot for providing icon to the [ListSubheader].
- * @param label A slot for providing label to the [ListSubheader].
- *
- * TODO(b/261838497) Add Material3 UX guidance links
+ * @param icon A slot for providing icon to the [ListSubHeader].
+ * @param label A slot for providing label to the [ListSubHeader].
*/
@Composable
-fun ListSubheader(
+fun ListSubHeader(
modifier: Modifier = Modifier,
backgroundColor: Color = Color.Transparent,
- contentColor: Color = ListSubHeaderTokens.ContentColor.value,
- contentPadding: PaddingValues = ListHeaderDefaults.SubheaderContentPadding,
+ contentColor: Color = ListHeaderDefaults.subHeaderContentColor,
+ contentPadding: PaddingValues = ListHeaderDefaults.SubHeaderContentPadding,
icon: (@Composable BoxScope.() -> Unit)? = null,
label: @Composable RowScope.() -> Unit,
) {
@@ -147,12 +143,23 @@
object ListHeaderDefaults {
private val TopPadding = 16.dp
- private val SubheaderBottomPadding = 8.dp
+ private val SubHeaderBottomPadding = 8.dp
private val HeaderBottomPadding = 12.dp
private val HorizontalPadding = 14.dp
- val HeaderContentPadding =
+ /** The default content padding for ListHeader */
+ val ContentPadding =
PaddingValues(HorizontalPadding, TopPadding, HorizontalPadding, HeaderBottomPadding)
- val SubheaderContentPadding =
- PaddingValues(HorizontalPadding, TopPadding, HorizontalPadding, SubheaderBottomPadding)
+
+ /** The default content padding for ListSubHeader */
+ val SubHeaderContentPadding =
+ PaddingValues(HorizontalPadding, TopPadding, HorizontalPadding, SubHeaderBottomPadding)
+
+ /** The default color for ListHeader */
+ val ContentColor: Color
+ @Composable get() = ListHeaderTokens.ContentColor.value
+
+ /** The default color for ListSubHeader */
+ val subHeaderContentColor: Color
+ @Composable get() = ListSubHeaderTokens.ContentColor.value
}
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/MotionScheme.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/MotionScheme.kt
index d3d3e89..25711f6 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/MotionScheme.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/MotionScheme.kt
@@ -20,9 +20,7 @@
import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.TwoWayConverter
import androidx.compose.animation.core.spring
-import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
-import androidx.compose.runtime.remember
import androidx.compose.runtime.staticCompositionLocalOf
/**
@@ -30,8 +28,8 @@
*
* Motion schemes are designed to create a harmonious motion for components in the app.
*
- * There are two built-in schemes, a [standardMotionScheme] and an [expressiveMotionScheme], that
- * can be used as-is or customized.
+ * There are two built-in schemes, a [standard] and an [expressive], that can be used as-is or
+ * customized.
*/
@Immutable
interface MotionScheme {
@@ -44,9 +42,6 @@
*
* [T] is the generic data type that will be animated by the system, as long as the appropriate
* [TwoWayConverter] for converting the data to and from an [AnimationVector] is supplied.
- *
- * When called from a Composable, use [rememberDefaultSpatialSpec] extension to ensure that the
- * returned animation spec is remembered across compositions.
*/
fun <T> defaultSpatialSpec(): FiniteAnimationSpec<T>
@@ -59,9 +54,6 @@
*
* [T] is the generic data type that will be animated by the system, as long as the appropriate
* [TwoWayConverter] for converting the data to and from an [AnimationVector] is supplied.
- *
- * When called from a Composable, use [rememberFastSpatialSpec] extension to ensure that the
- * returned animation spec is remembered across compositions.
*/
fun <T> fastSpatialSpec(): FiniteAnimationSpec<T>
@@ -74,9 +66,6 @@
*
* [T] is the generic data type that will be animated by the system, as long as the appropriate
* [TwoWayConverter] for converting the data to and from an [AnimationVector] is supplied.
- *
- * When called from a Composable, use [rememberSlowSpatialSpec] extension to ensure that the
- * returned animation spec is remembered across compositions.
*/
fun <T> slowSpatialSpec(): FiniteAnimationSpec<T>
@@ -88,9 +77,6 @@
*
* [T] is the generic data type that will be animated by the system, as long as the appropriate
* [TwoWayConverter] for converting the data to and from an [AnimationVector] is supplied.
- *
- * When called from a Composable, use [rememberDefaultEffectsSpec] extension to ensure that the
- * returned animation spec is remembered across compositions.
*/
fun <T> defaultEffectsSpec(): FiniteAnimationSpec<T>
@@ -102,9 +88,6 @@
*
* [T] is the generic data type that will be animated by the system, as long as the appropriate
* [TwoWayConverter] for converting the data to and from an [AnimationVector] is supplied.
- *
- * When called from a Composable, use [rememberFastEffectsSpec] extension to ensure that the
- * returned animation spec is remembered across compositions.
*/
fun <T> fastEffectsSpec(): FiniteAnimationSpec<T>
@@ -116,174 +99,160 @@
*
* [T] is the generic data type that will be animated by the system, as long as the appropriate
* [TwoWayConverter] for converting the data to and from an [AnimationVector] is supplied.
- *
- * When called from a Composable, use [rememberSlowEffectsSpec] extension to ensure that the
- * returned animation spec is remembered across compositions.
*/
fun <T> slowEffectsSpec(): FiniteAnimationSpec<T>
+
+ companion object {
+ /**
+ * Returns a standard Material motion scheme.
+ *
+ * The standard scheme is Material's basic motion scheme for utilitarian UI elements and
+ * recurring interactions. It provides a linear motion feel.
+ */
+ @Suppress("UNCHECKED_CAST")
+ fun standard(): MotionScheme =
+ object : MotionScheme {
+ private val defaultSpatialSpec =
+ spring<Any>(
+ dampingRatio = StandardSpatialDampingRatio,
+ stiffness = StandardDefaultStiffness
+ )
+
+ private val fastSpatialSpec =
+ spring<Any>(
+ dampingRatio = StandardSpatialDampingRatio,
+ stiffness = StandardFastStiffness
+ )
+
+ private val slowSpatialSpec =
+ spring<Any>(
+ dampingRatio = StandardSpatialDampingRatio,
+ stiffness = StandardSlowStiffness
+ )
+
+ private val defaultEffectsSpec =
+ spring<Any>(
+ dampingRatio = EffectsDampingRatio,
+ stiffness = EffectsDefaultStiffness
+ )
+
+ private val fastEffectsSpec =
+ spring<Any>(
+ dampingRatio = EffectsDampingRatio,
+ stiffness = EffectsFastStiffness
+ )
+
+ private val slowEffectsSpec =
+ spring<Any>(
+ dampingRatio = EffectsDampingRatio,
+ stiffness = EffectsSlowStiffness
+ )
+
+ override fun <T> defaultSpatialSpec(): FiniteAnimationSpec<T> {
+ return defaultSpatialSpec as FiniteAnimationSpec<T>
+ }
+
+ override fun <T> fastSpatialSpec(): FiniteAnimationSpec<T> {
+ return fastSpatialSpec as FiniteAnimationSpec<T>
+ }
+
+ override fun <T> slowSpatialSpec(): FiniteAnimationSpec<T> {
+ return slowSpatialSpec as FiniteAnimationSpec<T>
+ }
+
+ override fun <T> defaultEffectsSpec(): FiniteAnimationSpec<T> {
+ return defaultEffectsSpec as FiniteAnimationSpec<T>
+ }
+
+ override fun <T> fastEffectsSpec(): FiniteAnimationSpec<T> {
+ return fastEffectsSpec as FiniteAnimationSpec<T>
+ }
+
+ override fun <T> slowEffectsSpec(): FiniteAnimationSpec<T> {
+ return slowEffectsSpec as FiniteAnimationSpec<T>
+ }
+ }
+
+ /**
+ * Returns an expressive Material motion scheme.
+ *
+ * The expressive scheme is Material's recommended motion scheme for prominent UI elements
+ * and hero interactions. It provides a visually engaging motion feel.
+ */
+ @Suppress("UNCHECKED_CAST")
+ fun expressive(): MotionScheme =
+ object : MotionScheme {
+ private val defaultSpatialSpec =
+ spring<Any>(
+ dampingRatio = ExpressiveDefaultDamping,
+ stiffness = ExpressiveDefaultStiffness
+ )
+
+ private val fastSpatialSpec =
+ spring<Any>(
+ dampingRatio = ExpressiveFastDamping,
+ stiffness = ExpressiveFastStiffness
+ )
+
+ private val slowSpatialSpec =
+ spring<Any>(
+ dampingRatio = ExpressiveSlowDamping,
+ stiffness = ExpressiveSlowStiffness
+ )
+
+ private val defaultEffectsSpec =
+ spring<Any>(
+ dampingRatio = EffectsDampingRatio,
+ stiffness = EffectsDefaultStiffness
+ )
+
+ private val fastEffectsSpec =
+ spring<Any>(
+ dampingRatio = EffectsDampingRatio,
+ stiffness = EffectsFastStiffness
+ )
+
+ private val slowEffectsSpec =
+ spring<Any>(
+ dampingRatio = EffectsDampingRatio,
+ stiffness = EffectsSlowStiffness
+ )
+
+ override fun <T> defaultSpatialSpec(): FiniteAnimationSpec<T> {
+ return defaultSpatialSpec as FiniteAnimationSpec<T>
+ }
+
+ override fun <T> fastSpatialSpec(): FiniteAnimationSpec<T> {
+ return fastSpatialSpec as FiniteAnimationSpec<T>
+ }
+
+ override fun <T> slowSpatialSpec(): FiniteAnimationSpec<T> {
+ return slowSpatialSpec as FiniteAnimationSpec<T>
+ }
+
+ override fun <T> defaultEffectsSpec(): FiniteAnimationSpec<T> {
+ return defaultEffectsSpec as FiniteAnimationSpec<T>
+ }
+
+ override fun <T> fastEffectsSpec(): FiniteAnimationSpec<T> {
+ return fastEffectsSpec as FiniteAnimationSpec<T>
+ }
+
+ override fun <T> slowEffectsSpec(): FiniteAnimationSpec<T> {
+ return slowEffectsSpec as FiniteAnimationSpec<T>
+ }
+ }
+ }
}
/**
- * A default spatial motion [FiniteAnimationSpec] that is remembered across compositions.
- *
- * [T] is the generic data type that will be animated by the system, as long as the appropriate
- * [TwoWayConverter] for converting the data to and from an [AnimationVector] is supplied.
- *
- * @see [MotionScheme.defaultSpatialSpec]
- */
-@Composable
-inline fun <reified T> MotionScheme.rememberDefaultSpatialSpec() =
- remember(this, T::class) {
- val spec: FiniteAnimationSpec<T> = defaultSpatialSpec()
- spec
- }
-
-/**
- * A fast spatial motion [FiniteAnimationSpec] that is remembered across compositions.
- *
- * [T] is the generic data type that will be animated by the system.
- *
- * @see [MotionScheme.fastSpatialSpec]
- */
-@Composable
-inline fun <reified T> MotionScheme.rememberFastSpatialSpec() =
- remember(this, T::class) {
- val spec: FiniteAnimationSpec<T> = fastSpatialSpec()
- spec
- }
-
-/**
- * A slow spatial motion [FiniteAnimationSpec] that is remembered across compositions.
- *
- * [T] is the generic data type that will be animated by the system.
- *
- * @see [MotionScheme.slowSpatialSpec]
- */
-@Composable
-inline fun <reified T> MotionScheme.rememberSlowSpatialSpec() =
- remember(this, T::class) {
- val spec: FiniteAnimationSpec<T> = slowSpatialSpec()
- spec
- }
-
-/**
- * A default effects motion [FiniteAnimationSpec] that is remembered across compositions.
- *
- * [T] is the generic data type that will be animated by the system.
- *
- * @see [MotionScheme.defaultEffectsSpec]
- */
-@Composable
-inline fun <reified T> MotionScheme.rememberDefaultEffectsSpec() =
- remember(this, T::class) {
- val spec: FiniteAnimationSpec<T> = defaultEffectsSpec()
- spec
- }
-
-/**
- * A fast effects motion [FiniteAnimationSpec] that is remembered across compositions.
- *
- * [T] is the generic data type that will be animated by the system.
- *
- * @see [MotionScheme.fastEffectsSpec]
- */
-@Composable
-inline fun <reified T> MotionScheme.rememberFastEffectsSpec() =
- remember(this, T::class) {
- val spec: FiniteAnimationSpec<T> = fastEffectsSpec()
- spec
- }
-
-/**
- * A slow effects motion [FiniteAnimationSpec] that is remembered across compositions.
- *
- * [T] is the generic data type that will be animated by the system.
- *
- * @see [MotionScheme.slowEffectsSpec]
- */
-@Composable
-inline fun <reified T> MotionScheme.rememberSlowEffectsSpec() =
- remember(this, T::class) {
- val spec: FiniteAnimationSpec<T> = slowEffectsSpec()
- spec
- }
-
-/** Returns a standard Material motion scheme. */
-fun standardMotionScheme(): MotionScheme =
- object : MotionScheme {
- override fun <T> defaultSpatialSpec(): FiniteAnimationSpec<T> {
- return spring(
- dampingRatio = StandardSpatialDampingRatio,
- stiffness = StandardDefaultStiffness
- )
- }
-
- override fun <T> fastSpatialSpec(): FiniteAnimationSpec<T> {
- return spring(
- dampingRatio = StandardSpatialDampingRatio,
- stiffness = StandardFastStiffness
- )
- }
-
- override fun <T> slowSpatialSpec(): FiniteAnimationSpec<T> {
- return spring(
- dampingRatio = StandardSpatialDampingRatio,
- stiffness = StandardSlowStiffness
- )
- }
-
- override fun <T> defaultEffectsSpec(): FiniteAnimationSpec<T> {
- return spring(dampingRatio = EffectsDampingRatio, stiffness = EffectsDefaultStiffness)
- }
-
- override fun <T> fastEffectsSpec(): FiniteAnimationSpec<T> {
- return spring(dampingRatio = EffectsDampingRatio, stiffness = EffectsFastStiffness)
- }
-
- override fun <T> slowEffectsSpec(): FiniteAnimationSpec<T> {
- return spring(dampingRatio = EffectsDampingRatio, stiffness = EffectsSlowStiffness)
- }
- }
-
-/** Returns an expressive Material motion scheme. */
-fun expressiveMotionScheme(): MotionScheme =
- object : MotionScheme {
- override fun <T> defaultSpatialSpec(): FiniteAnimationSpec<T> {
- return spring(
- dampingRatio = ExpressiveDefaultDamping,
- stiffness = ExpressiveDefaultStiffness
- )
- }
-
- override fun <T> fastSpatialSpec(): FiniteAnimationSpec<T> {
- return spring(dampingRatio = ExpressiveFastDamping, stiffness = ExpressiveFastStiffness)
- }
-
- override fun <T> slowSpatialSpec(): FiniteAnimationSpec<T> {
- return spring(dampingRatio = ExpressiveSlowDamping, stiffness = ExpressiveSlowStiffness)
- }
-
- override fun <T> defaultEffectsSpec(): FiniteAnimationSpec<T> {
- return spring(dampingRatio = EffectsDampingRatio, stiffness = EffectsDefaultStiffness)
- }
-
- override fun <T> fastEffectsSpec(): FiniteAnimationSpec<T> {
- return spring(dampingRatio = EffectsDampingRatio, stiffness = EffectsFastStiffness)
- }
-
- override fun <T> slowEffectsSpec(): FiniteAnimationSpec<T> {
- return spring(dampingRatio = EffectsDampingRatio, stiffness = EffectsSlowStiffness)
- }
- }
-
-/**
* CompositionLocal used to pass [MotionScheme] down the tree.
*
* Setting the value here is typically done as part of [MaterialTheme]. To retrieve the current
* value of this CompositionLocal, use [MaterialTheme.motionScheme].
*/
@Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
-internal val LocalMotionScheme = staticCompositionLocalOf { standardMotionScheme() }
+internal val LocalMotionScheme = staticCompositionLocalOf { MotionScheme.standard() }
// TODO - These values should come from Tokens.
private const val StandardSpatialDampingRatio = 0.9f
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/PageIndicator.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/PageIndicator.kt
index 77f72e3..c57cae9 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/PageIndicator.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/PageIndicator.kt
@@ -58,12 +58,12 @@
import androidx.wear.compose.foundation.curvedBox
import androidx.wear.compose.foundation.curvedRow
import androidx.wear.compose.foundation.padding
+import androidx.wear.compose.foundation.pager.HorizontalPager
import androidx.wear.compose.foundation.pager.PagerState
+import androidx.wear.compose.foundation.pager.VerticalPager
import androidx.wear.compose.foundation.radialSize
import androidx.wear.compose.foundation.size
import androidx.wear.compose.foundation.weight
-import androidx.wear.compose.material3.pager.HorizontalPager
-import androidx.wear.compose.material3.pager.VerticalPager
import androidx.wear.compose.material3.tokens.ColorSchemeKeyTokens
import androidx.wear.compose.materialcore.BoundsLimiter
import androidx.wear.compose.materialcore.isLayoutDirectionRtl
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/pager/Pager.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/PagerScaffold.kt
similarity index 61%
rename from wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/pager/Pager.kt
rename to wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/PagerScaffold.kt
index 3075495..2676d72 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/pager/Pager.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/PagerScaffold.kt
@@ -14,23 +14,27 @@
* limitations under the License.
*/
-package androidx.wear.compose.material3.pager
+package androidx.wear.compose.material3
import androidx.annotation.FloatRange
+import androidx.compose.animation.core.AnimationSpec
+import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.spring
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.gestures.TargetedFlingBehavior
import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.pager.PagerDefaults as ComposePagerDefaults
import androidx.compose.foundation.pager.PagerScope
import androidx.compose.foundation.pager.PagerSnapDistance
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
+import androidx.compose.runtime.key
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
@@ -42,15 +46,147 @@
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
import androidx.compose.ui.util.lerp
-import androidx.wear.compose.foundation.ExperimentalWearFoundationApi
+import androidx.wear.compose.foundation.ActiveFocusListener
+import androidx.wear.compose.foundation.ScrollInfoProvider
import androidx.wear.compose.foundation.pager.HorizontalPager
+import androidx.wear.compose.foundation.pager.PagerDefaults
import androidx.wear.compose.foundation.pager.PagerState
import androidx.wear.compose.foundation.pager.VerticalPager
-import androidx.wear.compose.material3.DefaultTouchExplorationStateProvider
-import androidx.wear.compose.material3.MaterialTheme
import kotlin.math.absoluteValue
/**
+ * [HorizontalPagerScaffold] is one of the Wear Material3 scaffold components.
+ *
+ * The scaffold components [AppScaffold] and [HorizontalPagerScaffold] lay out the structure of a
+ * Pager and coordinate transitions of the [HorizontalPageIndicator] and [TimeText] components.
+ *
+ * [HorizontalPagerScaffold] displays the [HorizontalPageIndicator] at the center-end of the screen
+ * by default and coordinates showing/hiding [TimeText] and [HorizontalPageIndicator] according to
+ * whether the Pager is being paged, this is determined by the [PagerState].
+ *
+ * Example of using [AppScaffold] and [HorizontalPagerScaffold]:
+ *
+ * @sample androidx.wear.compose.material3.samples.HorizontalPagerScaffoldSample
+ * @param pagerState The state of the pager controlling the page content.
+ * @param modifier The modifier to be applied to the scaffold.
+ * @param pageIndicator A composable function that defines the page indicator to be displayed. By
+ * default, it uses a [HorizontalPageIndicator].
+ * @param pageIndicatorAnimationSpec - An optional parameter to set whether the page indicator
+ * should fade out when paging has finished. This is useful for when the underlying page content
+ * conflicts with the page indicator. By default this is null, so the page indicator will be
+ * visible at all times, setting this to [PagerScaffoldDefaults.FadeOutAnimation] ensures the
+ * indicator only shows during paging, and fades out when the Pager is idle.
+ * @param content A composable function that takes the current page index as a parameter and defines
+ * the content to be displayed on that page.
+ */
+@Composable
+fun HorizontalPagerScaffold(
+ pagerState: PagerState,
+ modifier: Modifier = Modifier,
+ pageIndicator: (@Composable BoxScope.() -> Unit)? = { HorizontalPageIndicator(pagerState) },
+ pageIndicatorAnimationSpec: AnimationSpec<Float>? = null,
+ content: @Composable PagerScope.(page: Int) -> Unit,
+) =
+ PagerScaffoldImpl(
+ scrollInfoProvider = ScrollInfoProvider(pagerState, orientation = Orientation.Horizontal),
+ pagerContent = { AnimatedHorizontalPager(pagerState, content = content) },
+ modifier = modifier,
+ pagerState = pagerState,
+ pageIndicator = pageIndicator,
+ pageIndicatorAnimationSpec = pageIndicatorAnimationSpec,
+ )
+
+/**
+ * [VerticalPagerScaffold] is one of the Wear Material3 scaffold components.
+ *
+ * The scaffold components [AppScaffold] and [VerticalPagerScaffold] lay out the structure of a
+ * Pager and coordinate transitions of the [VerticalPageIndicator] and [TimeText] components.
+ *
+ * [VerticalPagerScaffold] displays the [VerticalPageIndicator] at the center-end of the screen by
+ * default and coordinates showing/hiding [TimeText] and [VerticalPageIndicator] according to
+ * whether the Pager is being paged, this is determined by the [PagerState].
+ *
+ * Example of using [AppScaffold] and [VerticalPagerScaffold]:
+ *
+ * @sample androidx.wear.compose.material3.samples.VerticalPagerScaffoldSample
+ * @param pagerState The state of the pager controlling the page content.
+ * @param modifier The modifier to be applied to the scaffold.
+ * @param pageIndicator A composable function that defines the page indicator to be displayed. By
+ * default, it uses a [VerticalPageIndicator].
+ * @param pageIndicatorAnimationSpec - An optional parameter to set whether the page indicator
+ * should fade out when paging has finished. This is useful for when the underlying page content
+ * conflicts with the page indicator. By default this is null, so the page indicator will be
+ * visible at all times, setting this to [PagerScaffoldDefaults.FadeOutAnimation] ensures the
+ * indicator only shows during paging, and fades out when the Pager is idle.
+ * @param content A composable function that takes the current page index as a parameter and defines
+ * the content to be displayed on that page.
+ */
+@Composable
+fun VerticalPagerScaffold(
+ pagerState: PagerState,
+ modifier: Modifier = Modifier,
+ pageIndicator: (@Composable BoxScope.() -> Unit)? = { VerticalPageIndicator(pagerState) },
+ pageIndicatorAnimationSpec: AnimationSpec<Float>? = null,
+ content: @Composable PagerScope.(page: Int) -> Unit,
+) =
+ PagerScaffoldImpl(
+ scrollInfoProvider = ScrollInfoProvider(pagerState, orientation = Orientation.Vertical),
+ pagerContent = { AnimatedVerticalPager(pagerState, content = content) },
+ modifier = modifier,
+ pagerState = pagerState,
+ pageIndicator = pageIndicator,
+ pageIndicatorAnimationSpec = pageIndicatorAnimationSpec,
+ )
+
+/** Contains default values used for [HorizontalPagerScaffold] and [VerticalPagerScaffold]. */
+object PagerScaffoldDefaults {
+ /**
+ * The default value for the indicator fade out animation spec. Use this to fade out the page
+ * indicator when paging has stopped.
+ */
+ val FadeOutAnimation: AnimationSpec<Float> = spring(stiffness = Spring.StiffnessMediumLow)
+}
+
+@Composable
+private fun PagerScaffoldImpl(
+ scrollInfoProvider: ScrollInfoProvider,
+ pagerContent: @Composable () -> Unit,
+ pagerState: PagerState,
+ modifier: Modifier,
+ pageIndicator: (@Composable BoxScope.() -> Unit)?,
+ pageIndicatorAnimationSpec: AnimationSpec<Float>?,
+) {
+ val scaffoldState = LocalScaffoldState.current
+ val key = remember { Any() }
+
+ key(scrollInfoProvider) {
+ DisposableEffect(key) { onDispose { scaffoldState.removeScreen(key) } }
+
+ ActiveFocusListener { focused ->
+ if (focused) {
+ scaffoldState.addScreen(key, null, scrollInfoProvider)
+ } else {
+ scaffoldState.removeScreen(key)
+ }
+ }
+ }
+
+ scaffoldState.UpdateIdlingDetectorIfNeeded()
+
+ Box(modifier = modifier.fillMaxSize()) {
+ pagerContent()
+
+ AnimatedIndicator(
+ isVisible = {
+ scaffoldState.screenStage.value != ScreenStage.Idle || pagerState.isScrollInProgress
+ },
+ animationSpec = pageIndicatorAnimationSpec,
+ content = pageIndicator,
+ )
+ }
+}
+
+/**
* A full-screen horizontally scrolling Pager optimized for Wear OS devices. This component wraps
* the Wear Compose Foundation [HorizontalPager] and provides Material3 animations. Note: If
* accessibility is enabled the Wear system swipe to dismiss gesture will be disabled, in this case
@@ -87,21 +223,19 @@
* @param content A composable function that defines the content of each page displayed by the
* Pager. This is where the UI elements that should appear within each page should be placed.
*/
-@ExperimentalWearFoundationApi
@Composable
-internal fun HorizontalPager(
+internal fun AnimatedHorizontalPager(
state: PagerState,
modifier: Modifier = Modifier,
contentPadding: PaddingValues = PaddingValues(0.dp),
contentScrimColor: Color = MaterialTheme.colorScheme.background,
- beyondViewportPageCount: Int = ComposePagerDefaults.BeyondViewportPageCount,
- flingBehavior: TargetedFlingBehavior = PagerDefaults.flingBehavior(state = state),
+ beyondViewportPageCount: Int = PagerDefaults.BeyondViewportPageCount,
+ flingBehavior: TargetedFlingBehavior = snapWithSpringBehavior(state = state),
userScrollEnabled: Boolean = true,
reverseLayout: Boolean = false,
key: ((index: Int) -> Any)? = null,
@FloatRange(from = 0.0, to = 1.0)
- swipeToDismissEdgeZoneFraction: Float =
- androidx.wear.compose.foundation.pager.PagerDefaults.SwipeToDismissEdgeZoneFraction,
+ swipeToDismissEdgeZoneFraction: Float = PagerDefaults.SwipeToDismissEdgeZoneFraction,
content: @Composable PagerScope.(page: Int) -> Unit
) {
val touchExplorationStateProvider = remember { DefaultTouchExplorationStateProvider() }
@@ -158,15 +292,14 @@
* @param content A composable function that defines the content of each page displayed by the
* Pager. This is where the UI elements that should appear within each page should be placed.
*/
-@ExperimentalWearFoundationApi
@Composable
-internal fun VerticalPager(
+internal fun AnimatedVerticalPager(
state: PagerState,
modifier: Modifier = Modifier,
contentPadding: PaddingValues = PaddingValues(0.dp),
contentScrimColor: Color = MaterialTheme.colorScheme.background,
- beyondViewportPageCount: Int = ComposePagerDefaults.BeyondViewportPageCount,
- flingBehavior: TargetedFlingBehavior = PagerDefaults.flingBehavior(state = state),
+ beyondViewportPageCount: Int = PagerDefaults.BeyondViewportPageCount,
+ flingBehavior: TargetedFlingBehavior = snapWithSpringBehavior(state = state),
userScrollEnabled: Boolean = true,
reverseLayout: Boolean = false,
key: ((index: Int) -> Any)? = null,
@@ -192,22 +325,20 @@
}
}
-internal object PagerDefaults {
- @Composable
- fun flingBehavior(
- state: PagerState,
- ): TargetedFlingBehavior {
- return ComposePagerDefaults.flingBehavior(
- state = state,
- pagerSnapDistance = PagerSnapDistance.atMost(1),
- snapAnimationSpec = spring(dampingRatio = 1f, stiffness = 200f),
- snapPositionalThreshold = 0.35f,
- )
- }
+@Composable
+internal fun snapWithSpringBehavior(
+ state: PagerState,
+): TargetedFlingBehavior {
+ return PagerDefaults.snapFlingBehavior(
+ state = state,
+ pagerSnapDistance = PagerSnapDistance.atMost(1),
+ snapAnimationSpec = spring(dampingRatio = 1f, stiffness = 200f),
+ snapPositionalThreshold = 0.35f,
+ )
}
@Composable
-internal fun AnimatedPageContent(
+private fun AnimatedPageContent(
orientation: Orientation,
page: Int,
pagerState: PagerState,
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/RoundButton.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/RoundButton.kt
index 7c1d103..767891d 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/RoundButton.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/RoundButton.kt
@@ -98,10 +98,9 @@
interactionSource: InteractionSource,
shape: CornerBasedShape,
pressedShape: CornerBasedShape,
- onPressAnimationSpec: FiniteAnimationSpec<Float> =
- MaterialTheme.motionScheme.rememberFastEffectsSpec(),
+ onPressAnimationSpec: FiniteAnimationSpec<Float> = MaterialTheme.motionScheme.fastEffectsSpec(),
onReleaseAnimationSpec: FiniteAnimationSpec<Float> =
- MaterialTheme.motionScheme.rememberDefaultSpatialSpec(),
+ MaterialTheme.motionScheme.defaultSpatialSpec(),
): Shape {
val pressed = interactionSource.collectIsPressedAsState()
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/Scaffold.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/Scaffold.kt
index 4f722495..e2eba10 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/Scaffold.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/Scaffold.kt
@@ -16,18 +16,30 @@
package androidx.wear.compose.material3
+import androidx.compose.animation.core.AnimationSpec
+import androidx.compose.animation.core.Spring
+import androidx.compose.animation.core.animate
+import androidx.compose.animation.core.spring
import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.compositionLocalOf
+import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.util.fastForEach
import androidx.wear.compose.foundation.ScrollInfoProvider
import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.collectLatest
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.launch
internal class ScaffoldState(private val appTimeText: (@Composable (() -> Unit))? = null) {
fun removeScreen(key: Any) {
@@ -96,6 +108,43 @@
private val screenContent = mutableStateListOf<ScreenContent>()
}
+@Composable
+internal fun AnimatedIndicator(
+ isVisible: () -> Boolean,
+ animationSpec: AnimationSpec<Float>? = spring(stiffness = Spring.StiffnessMediumLow),
+ content: @Composable (BoxScope.() -> Unit)? = null
+) {
+ // Skip if no indicator provided
+ content?.let { pageIndicator ->
+ if (animationSpec == null) {
+ // if no animationSpec is provided then indicator will always be visible
+ Box(modifier = Modifier.fillMaxSize(), content = pageIndicator)
+ } else {
+ // if animationSpec is provided this will be used to fade out indicator
+ val alphaValue = remember { mutableFloatStateOf(0f) }
+ LaunchedEffect(isVisible) {
+ launch {
+ snapshotFlow { if (isVisible()) 1f else 0f }
+ .distinctUntilChanged()
+ .collectLatest { targetValue ->
+ animate(
+ alphaValue.floatValue,
+ targetValue,
+ animationSpec = animationSpec
+ ) { value, _ ->
+ alphaValue.floatValue = value
+ }
+ }
+ }
+ }
+ Box(
+ modifier = Modifier.fillMaxSize().graphicsLayer { alpha = alphaValue.floatValue },
+ content = pageIndicator
+ )
+ }
+ }
+}
+
internal val LocalScaffoldState = compositionLocalOf { ScaffoldState() }
private const val IDLE_DELAY = 2500L
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/ScreenScaffold.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/ScreenScaffold.kt
index 3af611e..50260db 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/ScreenScaffold.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/ScreenScaffold.kt
@@ -16,10 +16,6 @@
package androidx.wear.compose.material3
-import androidx.compose.animation.core.AnimationSpec
-import androidx.compose.animation.core.Spring
-import androidx.compose.animation.core.animate
-import androidx.compose.animation.core.spring
import androidx.compose.foundation.ScrollState
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
@@ -27,14 +23,10 @@
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
-import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.key
-import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.remember
-import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.layout.Measurable
import androidx.compose.ui.layout.MeasureResult
import androidx.compose.ui.layout.MeasureScope
@@ -49,9 +41,6 @@
import androidx.wear.compose.foundation.lazy.ScalingLazyColumn
import androidx.wear.compose.foundation.lazy.ScalingLazyListState
import kotlin.math.roundToInt
-import kotlinx.coroutines.flow.collectLatest
-import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.launch
/**
* [ScreenScaffold] is one of the Wear Material3 scaffold components.
@@ -376,50 +365,17 @@
Box(modifier = modifier.fillMaxSize()) {
content()
scrollInfoProvider?.let {
- AnimatedScrollIndicator(
- scrollInfoProvider = scrollInfoProvider,
+ AnimatedIndicator(
+ isVisible = {
+ scaffoldState.screenStage.value != ScreenStage.Idle &&
+ scrollInfoProvider.isScrollable
+ },
content = scrollIndicator,
- stage = { scaffoldState.screenStage.value }
)
} ?: scrollIndicator?.let { it() }
}
}
-@Composable
-private fun AnimatedScrollIndicator(
- scrollInfoProvider: ScrollInfoProvider,
- stage: () -> ScreenStage,
- content: @Composable (BoxScope.() -> Unit)? = null
-) {
- // Skip if no scroll indicator provided
- content?.let { scrollIndicator ->
- val alphaValue = remember { mutableFloatStateOf(0f) }
- val animationSpec: AnimationSpec<Float> = spring(stiffness = Spring.StiffnessMediumLow)
- LaunchedEffect(scrollInfoProvider, scrollIndicator) {
- launch {
- snapshotFlow {
- if (stage() != ScreenStage.Idle && scrollInfoProvider.isScrollable) 1f
- else 0f
- }
- .distinctUntilChanged()
- .collectLatest { targetValue ->
- animate(
- alphaValue.floatValue,
- targetValue,
- animationSpec = animationSpec
- ) { value, _ ->
- alphaValue.floatValue = value
- }
- }
- }
- }
- Box(
- modifier = Modifier.fillMaxSize().graphicsLayer { alpha = alphaValue.floatValue },
- content = scrollIndicator
- )
- }
-}
-
// Sets the height that will be used down the line, using a state as parameter, to avoid
// recompositions when the height changes.
internal fun Modifier.dynamicHeight(heightState: () -> Float) =
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/TextToggleButton.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/TextToggleButton.kt
index 6de3ad5..a7ee821 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/TextToggleButton.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/TextToggleButton.kt
@@ -209,7 +209,7 @@
checkedCornerSize: CornerSize = CheckedCornerSize,
pressedCornerSize: CornerSize = PressedCornerSize,
onPressAnimationSpec: FiniteAnimationSpec<Float> =
- MaterialTheme.motionScheme.rememberFastSpatialSpec(),
+ MaterialTheme.motionScheme.fastSpatialSpec(),
onReleaseAnimationSpec: FiniteAnimationSpec<Float> =
MaterialTheme.motionScheme.slowSpatialSpec(),
): Shape {
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/TimePicker.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/TimePicker.kt
index cb1daac..bcab35d 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/TimePicker.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/TimePicker.kt
@@ -424,11 +424,11 @@
return defaultTimePickerColorsCached
?: TimePickerColors(
selectedPickerContentColor =
- fromToken(TimePickerTokens.SelectedPickerContentColor),
+ fromToken(TimePickerTokens.SelectedContentColor),
unselectedPickerContentColor =
- fromToken(TimePickerTokens.UnselectedPickerContentColor),
+ fromToken(TimePickerTokens.UnselectedContentColor),
separatorColor = fromToken(TimePickerTokens.SeparatorColor),
- pickerLabelColor = fromToken(TimePickerTokens.PickerLabelColor),
+ pickerLabelColor = fromToken(TimePickerTokens.LabelColor),
confirmButtonContentColor =
fromToken(TimePickerTokens.ConfirmButtonContentColor),
confirmButtonContainerColor =
@@ -512,17 +512,17 @@
val isLargeScreen = LocalConfiguration.current.screenWidthDp > 225
val labelTextStyle =
if (isLargeScreen) {
- TimePickerTokens.PickerLabelLargeTypography
+ TimePickerTokens.LabelLargeTypography
} else {
- TimePickerTokens.PickerLabelTypography
+ TimePickerTokens.LabelTypography
}
.value
val optionTextStyle =
if (isLargeScreen || timePickerType == TimePickerType.HoursMinutes24H) {
- TimePickerTokens.PickerContentLargeTypography
+ TimePickerTokens.ContentLargeTypography
} else {
- TimePickerTokens.PickerContentTypography
+ TimePickerTokens.ContentTypography
}
.value
.copy(textAlign = TextAlign.Center)
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/CardTokens.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/CardTokens.kt
index cd03fe5..d8e3459 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/CardTokens.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/CardTokens.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 The Android Open Source Project
+ * Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-// VERSION: v0_65
+// VERSION: v0_87
// GENERATED CODE - DO NOT MODIFY BY HAND
package androidx.wear.compose.material3.tokens
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/CheckboxButtonTokens.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/CheckboxButtonTokens.kt
index 25c6f47..a905591 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/CheckboxButtonTokens.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/CheckboxButtonTokens.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 The Android Open Source Project
+ * Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-// VERSION: v0_65
+// VERSION: v0_87
// GENERATED CODE - DO NOT MODIFY BY HAND
package androidx.wear.compose.material3.tokens
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/ChildButtonTokens.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/ChildButtonTokens.kt
index 3b050ce..539470c 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/ChildButtonTokens.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/ChildButtonTokens.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 The Android Open Source Project
+ * Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-// VERSION: v0_65
+// VERSION: v0_87
// GENERATED CODE - DO NOT MODIFY BY HAND
package androidx.wear.compose.material3.tokens
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/ColorSchemeKeyTokens.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/ColorSchemeKeyTokens.kt
index bdafd77..8ab38e0 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/ColorSchemeKeyTokens.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/ColorSchemeKeyTokens.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 The Android Open Source Project
+ * Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-// VERSION: v0_65
+// VERSION: v0_87
// GENERATED CODE - DO NOT MODIFY BY HAND
package androidx.wear.compose.material3.tokens
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/ColorTokens.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/ColorTokens.kt
index a2e2591..1da7bb3 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/ColorTokens.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/ColorTokens.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 The Android Open Source Project
+ * Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-// VERSION: v0_65
+// VERSION: v0_87
// GENERATED CODE - DO NOT MODIFY BY HAND
package androidx.wear.compose.material3.tokens
@@ -27,13 +27,13 @@
val OnError = PaletteTokens.Error20
val OnErrorContainer = PaletteTokens.Error10
val OnPrimary = PaletteTokens.Primary10
- val OnPrimaryContainer = PaletteTokens.Primary90
+ val OnPrimaryContainer = PaletteTokens.Primary95
val OnSecondary = PaletteTokens.Secondary10
- val OnSecondaryContainer = PaletteTokens.Secondary90
+ val OnSecondaryContainer = PaletteTokens.Secondary95
val OnSurface = PaletteTokens.Neutral95
val OnSurfaceVariant = PaletteTokens.NeutralVariant80
val OnTertiary = PaletteTokens.Tertiary10
- val OnTertiaryContainer = PaletteTokens.Tertiary90
+ val OnTertiaryContainer = PaletteTokens.Tertiary95
val Outline = PaletteTokens.NeutralVariant60
val OutlineVariant = PaletteTokens.NeutralVariant40
val Primary = PaletteTokens.Primary90
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/CompactButtonTokens.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/CompactButtonTokens.kt
index 97b5c3f..e3fcd94e 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/CompactButtonTokens.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/CompactButtonTokens.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 The Android Open Source Project
+ * Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-// VERSION: v0_65
+// VERSION: v0_87
// GENERATED CODE - DO NOT MODIFY BY HAND
package androidx.wear.compose.material3.tokens
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/DatePickerTokens.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/DatePickerTokens.kt
index 9c53ae8..41e7411 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/DatePickerTokens.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/DatePickerTokens.kt
@@ -14,19 +14,20 @@
* limitations under the License.
*/
+// VERSION: v0_87
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
package androidx.wear.compose.material3.tokens
-
internal object DatePickerTokens {
- val SelectedPickerContentColor = ColorSchemeKeyTokens.OnBackground
- val UnselectedPickerContentColor = ColorSchemeKeyTokens.SecondaryDim
- val PickerLabelColor = ColorSchemeKeyTokens.Primary
- val NextButtonContentColor = ColorSchemeKeyTokens.Primary
- val NextButtonContainerColor = ColorSchemeKeyTokens.SurfaceContainer
- val ConfirmButtonContentColor = ColorSchemeKeyTokens.OnPrimary
val ConfirmButtonContainerColor = ColorSchemeKeyTokens.PrimaryDim
-
- val PickerLabelLargeTypography = TypographyKeyTokens.TitleLarge
- val PickerLabelTypography = TypographyKeyTokens.TitleMedium
- val PickerContentLargeTypography = TypographyKeyTokens.NumeralMedium
- val PickerContentTypography = TypographyKeyTokens.NumeralSmall
+ val ConfirmButtonContentColor = ColorSchemeKeyTokens.OnPrimary
+ val NextButtonContainerColor = ColorSchemeKeyTokens.SurfaceContainer
+ val NextButtonContentColor = ColorSchemeKeyTokens.Primary
+ val ContentLargeTypography = TypographyKeyTokens.NumeralMedium
+ val ContentTypography = TypographyKeyTokens.NumeralSmall
+ val LabelColor = ColorSchemeKeyTokens.Primary
+ val LabelLargeTypography = TypographyKeyTokens.TitleLarge
+ val LabelTypography = TypographyKeyTokens.TitleMedium
+ val SelectedContentColor = ColorSchemeKeyTokens.OnBackground
+ val UnselectedContentColor = ColorSchemeKeyTokens.SecondaryDim
}
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/FilledButtonTokens.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/FilledButtonTokens.kt
index f2501f5..fc611f1 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/FilledButtonTokens.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/FilledButtonTokens.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 The Android Open Source Project
+ * Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-// VERSION: v0_73
+// VERSION: v0_87
// GENERATED CODE - DO NOT MODIFY BY HAND
package androidx.wear.compose.material3.tokens
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/FilledIconButtonTokens.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/FilledIconButtonTokens.kt
index d68f8cc..5ea9650 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/FilledIconButtonTokens.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/FilledIconButtonTokens.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 The Android Open Source Project
+ * Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-// VERSION: v0_67
+// VERSION: v0_87
// GENERATED CODE - DO NOT MODIFY BY HAND
package androidx.wear.compose.material3.tokens
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/FilledTextButtonTokens.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/FilledTextButtonTokens.kt
index 92f987b..37b7212 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/FilledTextButtonTokens.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/FilledTextButtonTokens.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 The Android Open Source Project
+ * Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-// VERSION: v0_67
+// VERSION: v0_87
// GENERATED CODE - DO NOT MODIFY BY HAND
package androidx.wear.compose.material3.tokens
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/FilledTonalButtonTokens.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/FilledTonalButtonTokens.kt
index 1ad42ba..e9ec515 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/FilledTonalButtonTokens.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/FilledTonalButtonTokens.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 The Android Open Source Project
+ * Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-// VERSION: v0_65
+// VERSION: v0_87
// GENERATED CODE - DO NOT MODIFY BY HAND
package androidx.wear.compose.material3.tokens
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/FilledTonalIconButtonTokens.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/FilledTonalIconButtonTokens.kt
index 681e78f..4ad4143 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/FilledTonalIconButtonTokens.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/FilledTonalIconButtonTokens.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 The Android Open Source Project
+ * Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-// VERSION: v0_65
+// VERSION: v0_87
// GENERATED CODE - DO NOT MODIFY BY HAND
package androidx.wear.compose.material3.tokens
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/FilledTonalTextButtonTokens.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/FilledTonalTextButtonTokens.kt
index a220a6a..5588557e 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/FilledTonalTextButtonTokens.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/FilledTonalTextButtonTokens.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 The Android Open Source Project
+ * Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-// VERSION: v0_65
+// VERSION: v0_87
// GENERATED CODE - DO NOT MODIFY BY HAND
package androidx.wear.compose.material3.tokens
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/IconButtonTokens.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/IconButtonTokens.kt
index c54e56e..49a07de 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/IconButtonTokens.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/IconButtonTokens.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 The Android Open Source Project
+ * Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-// VERSION: v0_65
+// VERSION: v0_87
// GENERATED CODE - DO NOT MODIFY BY HAND
package androidx.wear.compose.material3.tokens
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/IconToggleButtonTokens.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/IconToggleButtonTokens.kt
index eaaddff..501a593 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/IconToggleButtonTokens.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/IconToggleButtonTokens.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 The Android Open Source Project
+ * Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-// VERSION: v0_65
+// VERSION: v0_87
// GENERATED CODE - DO NOT MODIFY BY HAND
package androidx.wear.compose.material3.tokens
@@ -24,6 +24,10 @@
internal object IconToggleButtonTokens {
val CheckedContainerColor = ColorSchemeKeyTokens.Primary
val CheckedContentColor = ColorSchemeKeyTokens.OnPrimary
+ val ContainerDefaultSize = 52.0.dp
+ val ContainerExtraLargeSize = 72.0.dp
+ val ContainerLargeSize = 60.0.dp
+ val ContainerSmallSize = 48.0.dp
val DisabledCheckedContainerColor = ColorSchemeKeyTokens.OnSurface
val DisabledCheckedContainerOpacity = 0.12f
val DisabledCheckedContentColor = ColorSchemeKeyTokens.OnSurface
@@ -32,16 +36,11 @@
val DisabledUncheckedContainerOpacity = 0.12f
val DisabledUncheckedContentColor = ColorSchemeKeyTokens.OnSurface
val DisabledUncheckedContentOpacity = 0.38f
+ val IconDefaultSize = 26.0.dp
+ val IconExtraLargeSize = 36.0.dp
+ val IconLargeSize = 32.0.dp
+ val IconSmallSize = 24.0.dp
val IconDisabledCheckedContainerShape = ShapeKeyTokens.CornerExtraLarge
val UncheckedContainerColor = ColorSchemeKeyTokens.SurfaceContainer
val UncheckedContentColor = ColorSchemeKeyTokens.OnSurfaceVariant
-
- val ContainerSmallSize = 48.0.dp
- val ContainerDefaultSize = 52.0.dp
- val ContainerLargeSize = 60.0.dp
- val ContainerExtraLargeSize = 72.0.dp
- val IconSmallSize = 24.0.dp
- val IconDefaultSize = 26.0.dp
- val IconLargeSize = 32.0.dp
- val IconExtraLargeSize = 36.0.dp
}
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/ImageButtonTokens.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/ImageButtonTokens.kt
index a95e41f..c47a1ed 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/ImageButtonTokens.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/ImageButtonTokens.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 The Android Open Source Project
+ * Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-// VERSION: 0_72
+// VERSION: v0_87
// GENERATED CODE - DO NOT MODIFY BY HAND
package androidx.wear.compose.material3.tokens
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/ImageCardTokens.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/ImageCardTokens.kt
index a6fe8bd..260535f9 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/ImageCardTokens.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/ImageCardTokens.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 The Android Open Source Project
+ * Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-// VERSION: v0_65
+// VERSION: v0_87
// GENERATED CODE - DO NOT MODIFY BY HAND
package androidx.wear.compose.material3.tokens
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/ListHeaderTokens.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/ListHeaderTokens.kt
index fc38bc0..ebdaca2 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/ListHeaderTokens.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/ListHeaderTokens.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 The Android Open Source Project
+ * Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-// VERSION: v0_65
+// VERSION: v0_87
// GENERATED CODE - DO NOT MODIFY BY HAND
package androidx.wear.compose.material3.tokens
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/ListSubHeaderTokens.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/ListSubHeaderTokens.kt
index a31f870..36c8dd6 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/ListSubHeaderTokens.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/ListSubHeaderTokens.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 The Android Open Source Project
+ * Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-// VERSION: v0_65
+// VERSION: v0_87
// GENERATED CODE - DO NOT MODIFY BY HAND
package androidx.wear.compose.material3.tokens
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/MotionTokens.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/MotionTokens.kt
index a5a96a11..a2e37ff 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/MotionTokens.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/MotionTokens.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-// VERSION: v0_65
+// VERSION: v0_87
// GENERATED CODE - DO NOT MODIFY BY HAND
package androidx.wear.compose.material3.tokens
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/OutlinedButtonTokens.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/OutlinedButtonTokens.kt
index 62eb568..3e60b0c 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/OutlinedButtonTokens.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/OutlinedButtonTokens.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 The Android Open Source Project
+ * Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-// VERSION: v0_65
+// VERSION: v0_87
// GENERATED CODE - DO NOT MODIFY BY HAND
package androidx.wear.compose.material3.tokens
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/OutlinedCardTokens.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/OutlinedCardTokens.kt
index 8c17f20..2ecdd18 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/OutlinedCardTokens.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/OutlinedCardTokens.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 The Android Open Source Project
+ * Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-// VERSION: v0_65
+// VERSION: v0_87
// GENERATED CODE - DO NOT MODIFY BY HAND
package androidx.wear.compose.material3.tokens
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/OutlinedIconButtonTokens.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/OutlinedIconButtonTokens.kt
index 02f0728..cdcb50b 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/OutlinedIconButtonTokens.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/OutlinedIconButtonTokens.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 The Android Open Source Project
+ * Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-// VERSION: v0_65
+// VERSION: v0_87
// GENERATED CODE - DO NOT MODIFY BY HAND
package androidx.wear.compose.material3.tokens
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/OutlinedTextButtonTokens.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/OutlinedTextButtonTokens.kt
index de29596..5bc3a3d 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/OutlinedTextButtonTokens.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/OutlinedTextButtonTokens.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 The Android Open Source Project
+ * Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-// VERSION: v0_65
+// VERSION: v0_87
// GENERATED CODE - DO NOT MODIFY BY HAND
package androidx.wear.compose.material3.tokens
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/PaletteTokens.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/PaletteTokens.kt
index 608479b..d2b7737 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/PaletteTokens.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/PaletteTokens.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 The Android Open Source Project
+ * Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-// VERSION: v0_65
+// VERSION: v0_87
// GENERATED CODE - DO NOT MODIFY BY HAND
package androidx.wear.compose.material3.tokens
@@ -38,7 +38,6 @@
val Error90 = Color(red = 249, green = 222, blue = 220)
val Error95 = Color(red = 252, green = 238, blue = 238)
val Neutral0 = Color(red = 0, green = 0, blue = 0)
- val Neutral10 = Color(red = 29, green = 26, blue = 38)
val Neutral100 = Color(red = 255, green = 255, blue = 255)
val Neutral15 = Color(red = 39, green = 36, blue = 48)
val Neutral20 = Color(red = 51, green = 46, blue = 60)
@@ -75,17 +74,17 @@
val Primary90 = Color(red = 233, green = 221, blue = 255)
val Primary95 = Color(red = 246, green = 237, blue = 255)
val Secondary0 = Color(red = 0, green = 0, blue = 0)
- val Secondary10 = Color(red = 30, green = 24, blue = 46)
+ val Secondary10 = Color(red = 12, green = 22, blue = 73)
val Secondary100 = Color(red = 255, green = 255, blue = 255)
- val Secondary20 = Color(red = 51, green = 45, blue = 68)
- val Secondary30 = Color(red = 74, green = 67, blue = 91)
- val Secondary40 = Color(red = 98, green = 90, blue = 116)
- val Secondary50 = Color(red = 123, green = 115, blue = 141)
- val Secondary60 = Color(red = 150, green = 140, blue = 168)
- val Secondary70 = Color(red = 177, green = 167, blue = 195)
- val Secondary80 = Color(red = 204, green = 194, blue = 223)
- val Secondary90 = Color(red = 233, green = 222, blue = 252)
- val Secondary95 = Color(red = 246, green = 237, blue = 255)
+ val Secondary20 = Color(red = 35, green = 44, blue = 94)
+ val Secondary30 = Color(red = 58, green = 67, blue = 118)
+ val Secondary40 = Color(red = 82, green = 91, blue = 144)
+ val Secondary50 = Color(red = 106, green = 116, blue = 170)
+ val Secondary60 = Color(red = 132, green = 141, blue = 198)
+ val Secondary70 = Color(red = 159, green = 168, blue = 226)
+ val Secondary80 = Color(red = 186, green = 195, blue = 255)
+ val Secondary90 = Color(red = 222, green = 224, blue = 255)
+ val Secondary95 = Color(red = 240, green = 239, blue = 255)
val Tertiary0 = Color(red = 0, green = 0, blue = 0)
val Tertiary10 = Color(red = 46, green = 21, blue = 0)
val Tertiary100 = Color(red = 255, green = 255, blue = 255)
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/RadioButtonTokens.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/RadioButtonTokens.kt
index 12ed324..6e5c957 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/RadioButtonTokens.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/RadioButtonTokens.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 The Android Open Source Project
+ * Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-// VERSION: v0_65
+// VERSION: v0_87
// GENERATED CODE - DO NOT MODIFY BY HAND
package androidx.wear.compose.material3.tokens
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/ShapeKeyTokens.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/ShapeKeyTokens.kt
index 653efce..7654116 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/ShapeKeyTokens.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/ShapeKeyTokens.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 The Android Open Source Project
+ * Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-// VERSION: v0_65
+// VERSION: v0_87
// GENERATED CODE - DO NOT MODIFY BY HAND
package androidx.wear.compose.material3.tokens
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/ShapeTokens.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/ShapeTokens.kt
index a220415..781e3d8 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/ShapeTokens.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/ShapeTokens.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 The Android Open Source Project
+ * Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-// VERSION: v0_65
+// VERSION: v0_87
// GENERATED CODE - DO NOT MODIFY BY HAND
package androidx.wear.compose.material3.tokens
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/SliderTokens.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/SliderTokens.kt
index ad0ea71..1157ecc 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/SliderTokens.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/SliderTokens.kt
@@ -14,27 +14,27 @@
* limitations under the License.
*/
+// VERSION: v0_87
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
package androidx.wear.compose.material3.tokens
-
internal object SliderTokens {
- val ContainerColor = ColorSchemeKeyTokens.SurfaceContainer
val ButtonIconColor = ColorSchemeKeyTokens.OnSurface
- val SelectedBarColor = ColorSchemeKeyTokens.Primary
- val UnselectedBarSeparatorColor = ColorSchemeKeyTokens.Primary
- val VariantSelectedBarColor = ColorSchemeKeyTokens.PrimaryDim
- val VariantUnselectedBarSeparatorColor = ColorSchemeKeyTokens.PrimaryDim
- val UnselectedBarSeparatorOpacity = 0.5f
- val UnselectedBarColor = ColorSchemeKeyTokens.Background
- val SelectedBarSeparatorColor = ColorSchemeKeyTokens.PrimaryContainer
-
- val DisabledContainerColor = ColorSchemeKeyTokens.OnSurface
- val DisabledContainerOpacity = 0.12f
+ val ContainerColor = ColorSchemeKeyTokens.SurfaceContainer
+ val ContainerShape = ShapeKeyTokens.CornerLarge
val DisabledButtonIconColor = ColorSchemeKeyTokens.OnSurface
val DisabledButtonIconOpacity = 0.38f
+ val DisabledContainerColor = ColorSchemeKeyTokens.OnSurface
+ val DisabledContainerOpacity = 0.12f
val DisabledSelectedBarColor = ColorSchemeKeyTokens.OutlineVariant
- val DisabledUnselectedBarColor = ColorSchemeKeyTokens.Background
val DisabledSelectedBarSeparatorColor = ColorSchemeKeyTokens.SurfaceContainer
+ val DisabledUnselectedBarColor = ColorSchemeKeyTokens.Background
val DisabledUnselectedBarSeparatorColor = ColorSchemeKeyTokens.OutlineVariant
-
- val ContainerShape = ShapeKeyTokens.CornerLarge
+ val SelectedBarColor = ColorSchemeKeyTokens.Primary
+ val SelectedBarSeparatorColor = ColorSchemeKeyTokens.PrimaryContainer
+ val UnselectedBarColor = ColorSchemeKeyTokens.Background
+ val UnselectedBarSeparatorColor = ColorSchemeKeyTokens.Primary
+ val UnselectedBarSeparatorOpacity = 0.5f
+ val VariantSelectedBarColor = ColorSchemeKeyTokens.PrimaryDim
+ val VariantUnselectedBarSeparatorColor = ColorSchemeKeyTokens.PrimaryDim
}
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/SplitCheckboxButtonTokens.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/SplitCheckboxButtonTokens.kt
index 0c24b09..5a7f25a 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/SplitCheckboxButtonTokens.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/SplitCheckboxButtonTokens.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 The Android Open Source Project
+ * Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-// VERSION: v0_65
+// VERSION: v0_87
// GENERATED CODE - DO NOT MODIFY BY HAND
package androidx.wear.compose.material3.tokens
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/SplitRadioButtonTokens.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/SplitRadioButtonTokens.kt
index acee450..8fef64d1 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/SplitRadioButtonTokens.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/SplitRadioButtonTokens.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 The Android Open Source Project
+ * Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-// VERSION: v0_65
+// VERSION: v0_87
// GENERATED CODE - DO NOT MODIFY BY HAND
package androidx.wear.compose.material3.tokens
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/SplitSwitchButtonTokens.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/SplitSwitchButtonTokens.kt
index 1142bf0..b6ed908 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/SplitSwitchButtonTokens.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/SplitSwitchButtonTokens.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 The Android Open Source Project
+ * Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-// VERSION: v0_65
+// VERSION: v0_87
// GENERATED CODE - DO NOT MODIFY BY HAND
package androidx.wear.compose.material3.tokens
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/SwipeToRevealTokens.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/SwipeToRevealTokens.kt
index a82d210..0d7f3ed 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/SwipeToRevealTokens.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/SwipeToRevealTokens.kt
@@ -14,8 +14,10 @@
* limitations under the License.
*/
-package androidx.wear.compose.material3.tokens
+// VERSION: v0_87
+// GENERATED CODE - DO NOT MODIFY BY HAND
+package androidx.wear.compose.material3.tokens
internal object SwipeToRevealTokens {
val PrimaryActionContainerColor = ColorSchemeKeyTokens.Error
val PrimaryActionContentColor = ColorSchemeKeyTokens.OnError
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/SwitchButtonTokens.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/SwitchButtonTokens.kt
index 657e8cc..77f4fb2 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/SwitchButtonTokens.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/SwitchButtonTokens.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 The Android Open Source Project
+ * Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-// VERSION: v0_65
+// VERSION: v0_87
// GENERATED CODE - DO NOT MODIFY BY HAND
package androidx.wear.compose.material3.tokens
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TextButtonTokens.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TextButtonTokens.kt
index 67ae831..1412af9 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TextButtonTokens.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TextButtonTokens.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 The Android Open Source Project
+ * Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-// VERSION: v0_65
+// VERSION: v0_87
// GENERATED CODE - DO NOT MODIFY BY HAND
package androidx.wear.compose.material3.tokens
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TextToggleButtonTokens.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TextToggleButtonTokens.kt
index f89f0b7..a80bbd4 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TextToggleButtonTokens.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TextToggleButtonTokens.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 The Android Open Source Project
+ * Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-// VERSION: v0_65
+// VERSION: v0_87
// GENERATED CODE - DO NOT MODIFY BY HAND
package androidx.wear.compose.material3.tokens
@@ -24,6 +24,13 @@
internal object TextToggleButtonTokens {
val CheckedContainerColor = ColorSchemeKeyTokens.Primary
val CheckedContentColor = ColorSchemeKeyTokens.OnPrimary
+ val ContainerDefaultSize = 52.0.dp
+ val ContainerExtraLargeSize = 72.0.dp
+ val ContainerLargeSize = 60.0.dp
+ val ContainerShape = ShapeKeyTokens.CornerFull
+ val ContentDefaultFont = TypographyKeyTokens.LabelMedium
+ val ContentExtraLargeFont = TypographyKeyTokens.LabelLarge
+ val ContentLargeFont = TypographyKeyTokens.LabelMedium
val DisabledCheckedContainerColor = ColorSchemeKeyTokens.OnSurface
val DisabledCheckedContainerOpacity = 0.12f
val DisabledCheckedContentColor = ColorSchemeKeyTokens.OnSurface
@@ -34,11 +41,4 @@
val DisabledUncheckedContentOpacity = 0.38f
val UncheckedContainerColor = ColorSchemeKeyTokens.SurfaceContainer
val UncheckedContentColor = ColorSchemeKeyTokens.OnSurfaceVariant
-
- val ContentDefaultFont = TypographyKeyTokens.LabelMedium
- val ContentLargeFont = TypographyKeyTokens.LabelMedium
- val ContentExtraLargeFont = TypographyKeyTokens.LabelLarge
- val ContainerDefaultSize = 52.0.dp
- val ContainerLargeSize = 60.0.dp
- val ContainerExtraLargeSize = 72.0.dp
}
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TimePickerTokens.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TimePickerTokens.kt
index 8700fc6..2597355 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TimePickerTokens.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TimePickerTokens.kt
@@ -14,18 +14,19 @@
* limitations under the License.
*/
+// VERSION: v0_87
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
package androidx.wear.compose.material3.tokens
-
internal object TimePickerTokens {
- val SelectedPickerContentColor = ColorSchemeKeyTokens.OnBackground
- val UnselectedPickerContentColor = ColorSchemeKeyTokens.SecondaryDim
- val SeparatorColor = ColorSchemeKeyTokens.OnSurfaceVariant
- val PickerLabelColor = ColorSchemeKeyTokens.Primary
- val ConfirmButtonContentColor = ColorSchemeKeyTokens.OnPrimary
val ConfirmButtonContainerColor = ColorSchemeKeyTokens.PrimaryDim
-
- val PickerLabelLargeTypography = TypographyKeyTokens.TitleLarge
- val PickerLabelTypography = TypographyKeyTokens.TitleMedium
- val PickerContentLargeTypography = TypographyKeyTokens.NumeralMedium
- val PickerContentTypography = TypographyKeyTokens.NumeralSmall
+ val ConfirmButtonContentColor = ColorSchemeKeyTokens.OnPrimary
+ val ContentLargeTypography = TypographyKeyTokens.NumeralMedium
+ val ContentTypography = TypographyKeyTokens.NumeralSmall
+ val LabelColor = ColorSchemeKeyTokens.Primary
+ val LabelLargeTypography = TypographyKeyTokens.TitleLarge
+ val LabelTypography = TypographyKeyTokens.TitleMedium
+ val SelectedContentColor = ColorSchemeKeyTokens.OnBackground
+ val SeparatorColor = ColorSchemeKeyTokens.OnSurfaceVariant
+ val UnselectedContentColor = ColorSchemeKeyTokens.SecondaryDim
}
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TypeScaleTokens.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TypeScaleTokens.kt
index be763e7..1c6878e 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TypeScaleTokens.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TypeScaleTokens.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-// VERSION: v0_71
+// VERSION: v0_87
// GENERATED CODE - DO NOT MODIFY BY HAND
package androidx.wear.compose.material3.tokens
@@ -25,19 +25,22 @@
val ArcLargeFont = TypefaceTokens.Brand
val ArcLargeLineHeight = 22.0.sp
val ArcLargeSize = 20.sp
- val ArcLargeTracking = 0.4.sp
+ val ArcLargeTrackingBottom = 1.8.sp
+ val ArcLargeTrackingTop = 0.4.sp
val ArcLargeWeight = 600.0f
val ArcLargeWidth = 100.0f
val ArcMediumFont = TypefaceTokens.Brand
val ArcMediumLineHeight = 18.0.sp
val ArcMediumSize = 15.sp
- val ArcMediumTracking = 0.6.sp
+ val ArcMediumTrackingBottom = 1.4.sp
+ val ArcMediumTrackingTop = 0.6.sp
val ArcMediumWeight = 600.0f
val ArcMediumWidth = 100.0f
val ArcSmallFont = TypefaceTokens.Brand
val ArcSmallLineHeight = 16.0.sp
val ArcSmallSize = 14.sp
- val ArcSmallTracking = 0.6.sp
+ val ArcSmallTrackingBottom = 1.6.sp
+ val ArcSmallTrackingTop = 0.6.sp
val ArcSmallWeight = 560.0f
val ArcSmallWidth = 100.0f
val BodyExtraSmallFont = TypefaceTokens.Brand
@@ -69,13 +72,13 @@
val BodySmallWeightProminent = 700.0f
val BodySmallWidth = 110.0f
val DisplayLargeFont = TypefaceTokens.Brand
- val DisplayLargeLineHeight = 46.0.sp
+ val DisplayLargeLineHeight = 44.0.sp
val DisplayLargeSize = 40.sp
val DisplayLargeTracking = 0.2.sp
val DisplayLargeWeight = 500.0f
val DisplayLargeWidth = 110.0f
val DisplayMediumFont = TypefaceTokens.Brand
- val DisplayMediumLineHeight = 36.0.sp
+ val DisplayMediumLineHeight = 34.0.sp
val DisplayMediumSize = 30.sp
val DisplayMediumTracking = 0.2.sp
val DisplayMediumWeight = 520.0f
@@ -93,7 +96,7 @@
val LabelLargeWeight = 500.0f
val LabelLargeWidth = 110.0f
val LabelMediumFont = TypefaceTokens.Brand
- val LabelMediumLineHeight = 16.0.sp
+ val LabelMediumLineHeight = 18.0.sp
val LabelMediumSize = 15.sp
val LabelMediumTracking = 0.4.sp
val LabelMediumWeight = 500.0f
@@ -121,7 +124,7 @@
val NumeralLargeFont = TypefaceTokens.Brand
val NumeralLargeLineHeight = 50.0.sp
val NumeralLargeSize = 50.sp
- val NumeralLargeTracking = 1.0.sp
+ val NumeralLargeTracking = 0.0.sp
val NumeralLargeWeight = 580.0f
val NumeralLargeWeightProminent = 780.0f
val NumeralLargeWidth = 110.0f
@@ -135,7 +138,7 @@
val NumeralSmallFont = TypefaceTokens.Brand
val NumeralSmallLineHeight = 30.0.sp
val NumeralSmallSize = 30.sp
- val NumeralSmallTracking = 1.0.sp
+ val NumeralSmallTracking = 0.0.sp
val NumeralSmallWeight = 550.0f
val NumeralSmallWeightProminent = 750.0f
val NumeralSmallWidth = 100.0f
@@ -149,12 +152,12 @@
val TitleMediumLineHeight = 18.0.sp
val TitleMediumSize = 16.sp
val TitleMediumTracking = 0.4.sp
- val TitleMediumWeight = 500.0f
+ val TitleMediumWeight = 550.0f
val TitleMediumWidth = 110.0f
val TitleSmallFont = TypefaceTokens.Brand
val TitleSmallLineHeight = 16.0.sp
val TitleSmallSize = 14.sp
val TitleSmallTracking = 0.4.sp
- val TitleSmallWeight = 500.0f
+ val TitleSmallWeight = 550.0f
val TitleSmallWidth = 110.0f
}
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TypefaceTokens.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TypefaceTokens.kt
index 0779680..75614cf 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TypefaceTokens.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TypefaceTokens.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-// VERSION: v0_71
+// VERSION: v0_87
// GENERATED CODE - DO NOT MODIFY BY HAND
package androidx.wear.compose.material3.tokens
@@ -26,5 +26,6 @@
val Brand = FontFamily.SansSerif
val Plain = FontFamily.SansSerif
val WeightBold = FontWeight.Bold
+ val WeightMedium = FontWeight.Medium
val WeightRegular = FontWeight.Normal
}
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TypographyKeyTokens.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TypographyKeyTokens.kt
index ea1dec4..04482df 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TypographyKeyTokens.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TypographyKeyTokens.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-// VERSION: v0_71
+// VERSION: v0_87
// GENERATED CODE - DO NOT MODIFY BY HAND
package androidx.wear.compose.material3.tokens
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TypographyTokens.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TypographyTokens.kt
index 9165f0d..f65d23f 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TypographyTokens.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TypographyTokens.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-// VERSION: v0_71
+// VERSION: v0_87
// GENERATED CODE - DO NOT MODIFY BY HAND
package androidx.wear.compose.material3.tokens
@@ -38,7 +38,7 @@
fontWeight = FontWeight(TypeScaleTokens.ArcLargeWeight.toInt()),
fontSize = TypeScaleTokens.ArcLargeSize,
lineHeight = TypeScaleTokens.ArcLargeLineHeight,
- letterSpacing = TypeScaleTokens.ArcLargeTracking,
+ letterSpacing = TypeScaleTokens.ArcLargeTrackingTop,
)
val ArcMedium =
DefaultTextStyle.copy(
@@ -53,7 +53,7 @@
fontWeight = FontWeight(TypeScaleTokens.ArcMediumWeight.toInt()),
fontSize = TypeScaleTokens.ArcMediumSize,
lineHeight = TypeScaleTokens.ArcMediumLineHeight,
- letterSpacing = TypeScaleTokens.ArcMediumTracking,
+ letterSpacing = TypeScaleTokens.ArcMediumTrackingTop,
)
val ArcSmall =
DefaultTextStyle.copy(
@@ -67,7 +67,7 @@
fontWeight = FontWeight(TypeScaleTokens.ArcSmallWeight.toInt()),
fontSize = TypeScaleTokens.ArcSmallSize,
lineHeight = TypeScaleTokens.ArcSmallLineHeight,
- letterSpacing = TypeScaleTokens.ArcSmallTracking,
+ letterSpacing = TypeScaleTokens.ArcSmallTrackingTop,
)
val BodyExtraSmall =
DefaultTextStyle.copy(
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TypographyVariableFontsTokens.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TypographyVariableFontsTokens.kt
index 6169c9f..89874b0 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TypographyVariableFontsTokens.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TypographyVariableFontsTokens.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-// VERSION: v0_71
+// VERSION: v0_87
// GENERATED CODE - DO NOT MODIFY BY HAND
package androidx.wear.compose.material3.tokens
@@ -24,13 +24,13 @@
internal object TypographyVariableFontsTokens {
val ArcLargeVariationSettings =
FontVariation.Settings(
- FontVariation.Setting("wght", TypeScaleTokens.ArcLargeWeight),
FontVariation.Setting("wdth", TypeScaleTokens.ArcLargeWidth),
+ FontVariation.Setting("wght", TypeScaleTokens.ArcLargeWeight),
)
val ArcMediumVariationSettings =
FontVariation.Settings(
- FontVariation.Setting("wght", TypeScaleTokens.ArcMediumWeight),
FontVariation.Setting("wdth", TypeScaleTokens.ArcMediumWidth),
+ FontVariation.Setting("wght", TypeScaleTokens.ArcMediumWeight),
)
val ArcSmallVariationSettings =
FontVariation.Settings(
@@ -39,8 +39,8 @@
)
val BodyExtraSmallVariationSettings =
FontVariation.Settings(
- FontVariation.Setting("wdth", TypeScaleTokens.BodyExtraSmallWidth),
FontVariation.Setting("wght", TypeScaleTokens.BodyExtraSmallWeight),
+ FontVariation.Setting("wdth", TypeScaleTokens.BodyExtraSmallWidth),
)
val BodyLargeVariationSettings =
FontVariation.Settings(
@@ -49,8 +49,8 @@
)
val BodyMediumVariationSettings =
FontVariation.Settings(
- FontVariation.Setting("wdth", TypeScaleTokens.BodyMediumWidth),
FontVariation.Setting("wght", TypeScaleTokens.BodyMediumWeight),
+ FontVariation.Setting("wdth", TypeScaleTokens.BodyMediumWidth),
)
val BodySmallVariationSettings =
FontVariation.Settings(
@@ -59,18 +59,18 @@
)
val DisplayLargeVariationSettings =
FontVariation.Settings(
- FontVariation.Setting("wght", TypeScaleTokens.DisplayLargeWeight),
FontVariation.Setting("wdth", TypeScaleTokens.DisplayLargeWidth),
+ FontVariation.Setting("wght", TypeScaleTokens.DisplayLargeWeight),
)
val DisplayMediumVariationSettings =
FontVariation.Settings(
- FontVariation.Setting("wdth", TypeScaleTokens.DisplayMediumWidth),
FontVariation.Setting("wght", TypeScaleTokens.DisplayMediumWeight),
+ FontVariation.Setting("wdth", TypeScaleTokens.DisplayMediumWidth),
)
val DisplaySmallVariationSettings =
FontVariation.Settings(
- FontVariation.Setting("wght", TypeScaleTokens.DisplaySmallWeight),
FontVariation.Setting("wdth", TypeScaleTokens.DisplaySmallWidth),
+ FontVariation.Setting("wght", TypeScaleTokens.DisplaySmallWeight),
)
val LabelLargeVariationSettings =
FontVariation.Settings(
@@ -79,8 +79,8 @@
)
val LabelMediumVariationSettings =
FontVariation.Settings(
- FontVariation.Setting("wght", TypeScaleTokens.LabelMediumWeight),
FontVariation.Setting("wdth", TypeScaleTokens.LabelMediumWidth),
+ FontVariation.Setting("wght", TypeScaleTokens.LabelMediumWeight),
)
val LabelSmallVariationSettings =
FontVariation.Settings(
@@ -89,8 +89,8 @@
)
val NumeralExtraLargeVariationSettings =
FontVariation.Settings(
- FontVariation.Setting("wdth", TypeScaleTokens.NumeralExtraLargeWidth),
FontVariation.Setting("wght", TypeScaleTokens.NumeralExtraLargeWeight),
+ FontVariation.Setting("wdth", TypeScaleTokens.NumeralExtraLargeWidth),
)
val NumeralExtraSmallVariationSettings =
FontVariation.Settings(
@@ -104,27 +104,27 @@
)
val NumeralMediumVariationSettings =
FontVariation.Settings(
- FontVariation.Setting("wght", TypeScaleTokens.NumeralMediumWeight),
FontVariation.Setting("wdth", TypeScaleTokens.NumeralMediumWidth),
+ FontVariation.Setting("wght", TypeScaleTokens.NumeralMediumWeight),
)
val NumeralSmallVariationSettings =
FontVariation.Settings(
- FontVariation.Setting("wght", TypeScaleTokens.NumeralSmallWeight),
FontVariation.Setting("wdth", TypeScaleTokens.NumeralSmallWidth),
+ FontVariation.Setting("wght", TypeScaleTokens.NumeralSmallWeight),
)
val TitleLargeVariationSettings =
FontVariation.Settings(
- FontVariation.Setting("wght", TypeScaleTokens.TitleLargeWeight),
FontVariation.Setting("wdth", TypeScaleTokens.TitleLargeWidth),
+ FontVariation.Setting("wght", TypeScaleTokens.TitleLargeWeight),
)
val TitleMediumVariationSettings =
FontVariation.Settings(
- FontVariation.Setting("wdth", TypeScaleTokens.TitleMediumWidth),
FontVariation.Setting("wght", TypeScaleTokens.TitleMediumWeight),
+ FontVariation.Setting("wdth", TypeScaleTokens.TitleMediumWidth),
)
val TitleSmallVariationSettings =
FontVariation.Settings(
- FontVariation.Setting("wdth", TypeScaleTokens.TitleSmallWidth),
FontVariation.Setting("wght", TypeScaleTokens.TitleSmallWeight),
+ FontVariation.Setting("wdth", TypeScaleTokens.TitleSmallWidth),
)
}
diff --git a/wear/compose/compose-material3/src/test/kotlin/androidx/wear/compose/material3/AnimationSpecUtilsTest.kt b/wear/compose/compose-material3/src/test/kotlin/androidx/wear/compose/material3/AnimationSpecUtilsTest.kt
index 7888df6..130f0d8 100644
--- a/wear/compose/compose-material3/src/test/kotlin/androidx/wear/compose/material3/AnimationSpecUtilsTest.kt
+++ b/wear/compose/compose-material3/src/test/kotlin/androidx/wear/compose/material3/AnimationSpecUtilsTest.kt
@@ -92,7 +92,7 @@
val actual = wrappedSpec.speedAt((duration / speedupFactor * i / 100).toLong())
// The unit is pixels per second, so this is really small.
- assertEquals(expected, actual, 0.005f)
+ assertEquals(expected, actual, 0.006f)
}
}
}
diff --git a/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/DemoApp.kt b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/DemoApp.kt
index a674c88..89744df 100644
--- a/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/DemoApp.kt
+++ b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/DemoApp.kt
@@ -49,6 +49,7 @@
import androidx.wear.compose.material.MaterialTheme
import androidx.wear.compose.material.SwipeToDismissBox
import androidx.wear.compose.material.Text
+import androidx.wear.compose.material3.demos.RobotoFlexTypography
@Composable
fun DemoApp(
@@ -109,12 +110,15 @@
@Composable { it: @Composable () -> Unit ->
// Only material3 demos benefit from the Material3 ScreenScaffold
if (category.materialVersion == 3) {
- val timeText = @Composable { androidx.wear.compose.material3.TimeText { time() } }
- androidx.wear.compose.material3.ScreenScaffold(
- scrollState = state,
- timeText = remember { timeText },
- ) {
- it()
+ androidx.wear.compose.material3.MaterialTheme(typography = RobotoFlexTypography) {
+ val timeText =
+ @Composable { androidx.wear.compose.material3.TimeText { time() } }
+ androidx.wear.compose.material3.ScreenScaffold(
+ scrollState = state,
+ timeText = remember { timeText },
+ ) {
+ it()
+ }
}
} else {
it()
diff --git a/wear/protolayout/protolayout-material3/api/current.txt b/wear/protolayout/protolayout-material3/api/current.txt
index 582409a..f083fc52 100644
--- a/wear/protolayout/protolayout-material3/api/current.txt
+++ b/wear/protolayout/protolayout-material3/api/current.txt
@@ -47,6 +47,39 @@
field public static final int TERTIARY_DIM = 27; // 0x1b
}
+ public final class EdgeButtonColors {
+ ctor public EdgeButtonColors(androidx.wear.protolayout.ColorBuilders.ColorProp container, androidx.wear.protolayout.ColorBuilders.ColorProp content);
+ method public androidx.wear.protolayout.ColorBuilders.ColorProp getContainer();
+ method public androidx.wear.protolayout.ColorBuilders.ColorProp getContent();
+ property public final androidx.wear.protolayout.ColorBuilders.ColorProp container;
+ property public final androidx.wear.protolayout.ColorBuilders.ColorProp content;
+ }
+
+ public final class EdgeButtonDefaults {
+ method public androidx.wear.protolayout.material3.EdgeButtonColors filled(androidx.wear.protolayout.material3.MaterialScope);
+ method public androidx.wear.protolayout.material3.EdgeButtonColors filledTonal(androidx.wear.protolayout.material3.MaterialScope);
+ method public androidx.wear.protolayout.material3.EdgeButtonColors filledVariant(androidx.wear.protolayout.material3.MaterialScope);
+ field public static final androidx.wear.protolayout.material3.EdgeButtonDefaults INSTANCE;
+ }
+
+ public final class EdgeButtonKt {
+ method public static androidx.wear.protolayout.LayoutElementBuilders.LayoutElement iconEdgeButton(androidx.wear.protolayout.material3.MaterialScope, androidx.wear.protolayout.ModifiersBuilders.Clickable onClick, androidx.wear.protolayout.TypeBuilders.StringProp contentDescription, optional androidx.wear.protolayout.material3.EdgeButtonColors colors, kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement> iconContent);
+ method public static androidx.wear.protolayout.LayoutElementBuilders.LayoutElement textEdgeButton(androidx.wear.protolayout.material3.MaterialScope, androidx.wear.protolayout.ModifiersBuilders.Clickable onClick, androidx.wear.protolayout.TypeBuilders.StringProp contentDescription, optional androidx.wear.protolayout.material3.EdgeButtonColors colors, kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement> labelContent);
+ }
+
+ public final class EdgeButtonStyle {
+ field public static final androidx.wear.protolayout.material3.EdgeButtonStyle.Companion Companion;
+ field public static final androidx.wear.protolayout.material3.EdgeButtonStyle DEFAULT;
+ field public static final androidx.wear.protolayout.material3.EdgeButtonStyle TOP_ALIGN;
+ }
+
+ public static final class EdgeButtonStyle.Companion {
+ }
+
+ public final class IconKt {
+ method public static androidx.wear.protolayout.LayoutElementBuilders.LayoutElement icon(androidx.wear.protolayout.material3.MaterialScope, String protoLayoutResourceId, optional androidx.wear.protolayout.DimensionBuilders.ImageDimension size, optional androidx.wear.protolayout.ColorBuilders.ColorProp tintColor);
+ }
+
@androidx.wear.protolayout.material3.MaterialScopeMarker public class MaterialScope {
method public final androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters getDeviceConfiguration();
property public final androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters deviceConfiguration;
@@ -56,6 +89,8 @@
method public static androidx.wear.protolayout.ColorBuilders.ColorProp getColorProp(androidx.wear.protolayout.material3.MaterialScope, int colorToken);
method public static androidx.wear.protolayout.ModifiersBuilders.Corner getCorner(androidx.wear.protolayout.material3.MaterialScope, int shapeToken);
method public static boolean isDynamicThemeEnabled(android.content.Context);
+ method public static androidx.wear.protolayout.LayoutElementBuilders.LayoutElement materialScope(android.content.Context context, androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters deviceConfiguration, optional boolean allowDynamicTheme, kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement> layout);
+ method public static androidx.wear.protolayout.LayoutElementBuilders.LayoutElement materialScope(android.content.Context context, androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters deviceConfiguration, kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement> layout);
}
@kotlin.DslMarker public @interface MaterialScopeMarker {
@@ -72,6 +107,10 @@
field public static final androidx.wear.protolayout.material3.Shape INSTANCE;
}
+ public final class TextKt {
+ method public static androidx.wear.protolayout.LayoutElementBuilders.LayoutElement text(androidx.wear.protolayout.material3.MaterialScope, androidx.wear.protolayout.TypeBuilders.StringProp text, optional androidx.wear.protolayout.TypeBuilders.StringLayoutConstraint stringLayoutConstraint, optional int typography, optional androidx.wear.protolayout.ColorBuilders.ColorProp color, optional boolean italic, optional boolean underline, optional boolean scalable, optional int maxLines, optional int multilineAlignment, optional int overflow, optional androidx.wear.protolayout.ModifiersBuilders.Modifiers modifiers);
+ }
+
public final class Typography {
field public static final int ARC_MEDIUM = 0; // 0x0
field public static final int ARC_SMALL = 1; // 0x1
diff --git a/wear/protolayout/protolayout-material3/api/restricted_current.txt b/wear/protolayout/protolayout-material3/api/restricted_current.txt
index 582409a..f083fc52 100644
--- a/wear/protolayout/protolayout-material3/api/restricted_current.txt
+++ b/wear/protolayout/protolayout-material3/api/restricted_current.txt
@@ -47,6 +47,39 @@
field public static final int TERTIARY_DIM = 27; // 0x1b
}
+ public final class EdgeButtonColors {
+ ctor public EdgeButtonColors(androidx.wear.protolayout.ColorBuilders.ColorProp container, androidx.wear.protolayout.ColorBuilders.ColorProp content);
+ method public androidx.wear.protolayout.ColorBuilders.ColorProp getContainer();
+ method public androidx.wear.protolayout.ColorBuilders.ColorProp getContent();
+ property public final androidx.wear.protolayout.ColorBuilders.ColorProp container;
+ property public final androidx.wear.protolayout.ColorBuilders.ColorProp content;
+ }
+
+ public final class EdgeButtonDefaults {
+ method public androidx.wear.protolayout.material3.EdgeButtonColors filled(androidx.wear.protolayout.material3.MaterialScope);
+ method public androidx.wear.protolayout.material3.EdgeButtonColors filledTonal(androidx.wear.protolayout.material3.MaterialScope);
+ method public androidx.wear.protolayout.material3.EdgeButtonColors filledVariant(androidx.wear.protolayout.material3.MaterialScope);
+ field public static final androidx.wear.protolayout.material3.EdgeButtonDefaults INSTANCE;
+ }
+
+ public final class EdgeButtonKt {
+ method public static androidx.wear.protolayout.LayoutElementBuilders.LayoutElement iconEdgeButton(androidx.wear.protolayout.material3.MaterialScope, androidx.wear.protolayout.ModifiersBuilders.Clickable onClick, androidx.wear.protolayout.TypeBuilders.StringProp contentDescription, optional androidx.wear.protolayout.material3.EdgeButtonColors colors, kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement> iconContent);
+ method public static androidx.wear.protolayout.LayoutElementBuilders.LayoutElement textEdgeButton(androidx.wear.protolayout.material3.MaterialScope, androidx.wear.protolayout.ModifiersBuilders.Clickable onClick, androidx.wear.protolayout.TypeBuilders.StringProp contentDescription, optional androidx.wear.protolayout.material3.EdgeButtonColors colors, kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement> labelContent);
+ }
+
+ public final class EdgeButtonStyle {
+ field public static final androidx.wear.protolayout.material3.EdgeButtonStyle.Companion Companion;
+ field public static final androidx.wear.protolayout.material3.EdgeButtonStyle DEFAULT;
+ field public static final androidx.wear.protolayout.material3.EdgeButtonStyle TOP_ALIGN;
+ }
+
+ public static final class EdgeButtonStyle.Companion {
+ }
+
+ public final class IconKt {
+ method public static androidx.wear.protolayout.LayoutElementBuilders.LayoutElement icon(androidx.wear.protolayout.material3.MaterialScope, String protoLayoutResourceId, optional androidx.wear.protolayout.DimensionBuilders.ImageDimension size, optional androidx.wear.protolayout.ColorBuilders.ColorProp tintColor);
+ }
+
@androidx.wear.protolayout.material3.MaterialScopeMarker public class MaterialScope {
method public final androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters getDeviceConfiguration();
property public final androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters deviceConfiguration;
@@ -56,6 +89,8 @@
method public static androidx.wear.protolayout.ColorBuilders.ColorProp getColorProp(androidx.wear.protolayout.material3.MaterialScope, int colorToken);
method public static androidx.wear.protolayout.ModifiersBuilders.Corner getCorner(androidx.wear.protolayout.material3.MaterialScope, int shapeToken);
method public static boolean isDynamicThemeEnabled(android.content.Context);
+ method public static androidx.wear.protolayout.LayoutElementBuilders.LayoutElement materialScope(android.content.Context context, androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters deviceConfiguration, optional boolean allowDynamicTheme, kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement> layout);
+ method public static androidx.wear.protolayout.LayoutElementBuilders.LayoutElement materialScope(android.content.Context context, androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters deviceConfiguration, kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement> layout);
}
@kotlin.DslMarker public @interface MaterialScopeMarker {
@@ -72,6 +107,10 @@
field public static final androidx.wear.protolayout.material3.Shape INSTANCE;
}
+ public final class TextKt {
+ method public static androidx.wear.protolayout.LayoutElementBuilders.LayoutElement text(androidx.wear.protolayout.material3.MaterialScope, androidx.wear.protolayout.TypeBuilders.StringProp text, optional androidx.wear.protolayout.TypeBuilders.StringLayoutConstraint stringLayoutConstraint, optional int typography, optional androidx.wear.protolayout.ColorBuilders.ColorProp color, optional boolean italic, optional boolean underline, optional boolean scalable, optional int maxLines, optional int multilineAlignment, optional int overflow, optional androidx.wear.protolayout.ModifiersBuilders.Modifiers modifiers);
+ }
+
public final class Typography {
field public static final int ARC_MEDIUM = 0; // 0x0
field public static final int ARC_SMALL = 1; // 0x1
diff --git a/wear/protolayout/protolayout-material3/build.gradle b/wear/protolayout/protolayout-material3/build.gradle
index 94f203d..0931f6f 100644
--- a/wear/protolayout/protolayout-material3/build.gradle
+++ b/wear/protolayout/protolayout-material3/build.gradle
@@ -33,8 +33,10 @@
annotationProcessor(libs.nullaway)
api(project(":wear:protolayout:protolayout"))
api(libs.kotlinStdlib)
+ implementation(project(":wear:protolayout:protolayout-material-core"))
lintChecks(project(":wear:protolayout:protolayout-lint"))
lintPublish(project(":wear:protolayout:protolayout-lint"))
+ compileOnly(project(":annotation:annotation-sampled"))
testImplementation(libs.junit)
testImplementation(libs.mockitoCore4)
@@ -65,4 +67,5 @@
mavenVersion = LibraryVersions.WEAR_PROTOLAYOUT_MATERIAL3
inceptionYear = "2024"
description = "Material3 components library for ProtoLayout."
+ samples(project(":wear:protolayout:protolayout-material3-samples"))
}
diff --git a/wear/protolayout/protolayout-material3/samples/build.gradle b/wear/protolayout/protolayout-material3/samples/build.gradle
new file mode 100644
index 0000000..1c680ec
--- /dev/null
+++ b/wear/protolayout/protolayout-material3/samples/build.gradle
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import androidx.build.LibraryType
+
+plugins {
+ id("AndroidXPlugin")
+ id("com.android.library")
+ id("org.jetbrains.kotlin.android")
+}
+
+dependencies {
+ api(project(":wear:protolayout:protolayout-material3"))
+
+ compileOnly(project(":annotation:annotation-sampled"))
+}
+
+android {
+ defaultConfig {
+ minSdkVersion 26
+ }
+
+ namespace "androidx.wear.protolayout.material3.samples"
+}
+
+androidx {
+ name = "androidx.wear.protolayout:protolayout-material3-samples"
+ type = LibraryType.SAMPLES
+ inceptionYear = "2024"
+ description = "Contains the sample code for Material3 components library for ProtoLayout."
+}
diff --git a/wear/protolayout/protolayout-material3/samples/src/main/java/androidx/wear/protolayout/material3/samples/Material3ComponentsSample.kt b/wear/protolayout/protolayout-material3/samples/src/main/java/androidx/wear/protolayout/material3/samples/Material3ComponentsSample.kt
new file mode 100644
index 0000000..1103e2c
--- /dev/null
+++ b/wear/protolayout/protolayout-material3/samples/src/main/java/androidx/wear/protolayout/material3/samples/Material3ComponentsSample.kt
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.wear.protolayout.material3.samples
+
+import android.content.Context
+import androidx.annotation.Sampled
+import androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters
+import androidx.wear.protolayout.LayoutElementBuilders.LayoutElement
+import androidx.wear.protolayout.ModifiersBuilders.Clickable
+import androidx.wear.protolayout.TypeBuilders.StringLayoutConstraint
+import androidx.wear.protolayout.TypeBuilders.StringProp
+import androidx.wear.protolayout.expression.DynamicBuilders.DynamicString
+import androidx.wear.protolayout.material3.ColorTokens
+import androidx.wear.protolayout.material3.Typography
+import androidx.wear.protolayout.material3.getColorProp
+import androidx.wear.protolayout.material3.icon
+import androidx.wear.protolayout.material3.iconEdgeButton
+import androidx.wear.protolayout.material3.materialScope
+import androidx.wear.protolayout.material3.text
+import androidx.wear.protolayout.material3.textEdgeButton
+
+/** Builds Material3 text element with default options. */
+@Sampled
+fun helloWorldTextDefault(context: Context, deviceConfiguration: DeviceParameters): LayoutElement =
+ materialScope(context, deviceConfiguration) {
+ text(text = "Hello Material3".prop(), typography = Typography.DISPLAY_LARGE)
+ }
+
+/** Builds Material3 text element with some of the overridden defaults. */
+@Sampled
+fun helloWorldTextDynamicCustom(
+ context: Context,
+ deviceConfiguration: DeviceParameters
+): LayoutElement =
+ materialScope(context, deviceConfiguration) {
+ text(
+ text =
+ StringProp.Builder("Static")
+ .setDynamicValue(DynamicString.constant("Dynamic"))
+ .build(),
+ stringLayoutConstraint = StringLayoutConstraint.Builder("Constraint").build(),
+ typography = Typography.DISPLAY_LARGE,
+ color = getColorProp(ColorTokens.TERTIARY),
+ underline = true,
+ maxLines = 5
+ )
+ }
+
+@Sampled
+fun edgeButtonSampleIcon(
+ context: Context,
+ deviceConfiguration: DeviceParameters,
+ clickable: Clickable
+): LayoutElement =
+ materialScope(context, deviceConfiguration) {
+ iconEdgeButton(onClick = clickable, contentDescription = "Description of a button".prop()) {
+ icon("id")
+ }
+ }
+
+@Sampled
+fun edgeButtonSampleText(
+ context: Context,
+ deviceConfiguration: DeviceParameters,
+ clickable: Clickable
+): LayoutElement =
+ materialScope(context, deviceConfiguration) {
+ textEdgeButton(onClick = clickable, contentDescription = "Description of a button".prop()) {
+ text("Hello".prop())
+ }
+ }
+
+fun String.prop() = StringProp.Builder(this).build()
diff --git a/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/EdgeButton.kt b/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/EdgeButton.kt
new file mode 100644
index 0000000..c34e8ca
--- /dev/null
+++ b/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/EdgeButton.kt
@@ -0,0 +1,293 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.wear.protolayout.material3
+
+import androidx.wear.protolayout.ColorBuilders.ColorProp
+import androidx.wear.protolayout.DimensionBuilders.DpProp
+import androidx.wear.protolayout.DimensionBuilders.dp
+import androidx.wear.protolayout.LayoutElementBuilders
+import androidx.wear.protolayout.LayoutElementBuilders.Box
+import androidx.wear.protolayout.LayoutElementBuilders.LayoutElement
+import androidx.wear.protolayout.LayoutElementBuilders.VERTICAL_ALIGN_CENTER
+import androidx.wear.protolayout.LayoutElementBuilders.VerticalAlignment
+import androidx.wear.protolayout.ModifiersBuilders.Background
+import androidx.wear.protolayout.ModifiersBuilders.Clickable
+import androidx.wear.protolayout.ModifiersBuilders.Corner
+import androidx.wear.protolayout.ModifiersBuilders.Modifiers
+import androidx.wear.protolayout.ModifiersBuilders.Padding
+import androidx.wear.protolayout.TypeBuilders.StringProp
+import androidx.wear.protolayout.material3.EdgeButtonDefaults.BOTTOM_MARGIN_DP
+import androidx.wear.protolayout.material3.EdgeButtonDefaults.EDGE_BUTTON_HEIGHT_DP
+import androidx.wear.protolayout.material3.EdgeButtonDefaults.HORIZONTAL_MARGIN_PERCENT
+import androidx.wear.protolayout.material3.EdgeButtonDefaults.ICON_SIZE_DP
+import androidx.wear.protolayout.material3.EdgeButtonDefaults.METADATA_TAG
+import androidx.wear.protolayout.material3.EdgeButtonDefaults.TEXT_SIDE_PADDING_DP
+import androidx.wear.protolayout.material3.EdgeButtonDefaults.TEXT_TOP_PADDING_DP
+import androidx.wear.protolayout.material3.EdgeButtonDefaults.TOP_CORNER_RADIUS
+import androidx.wear.protolayout.material3.EdgeButtonDefaults.filled
+import androidx.wear.protolayout.material3.EdgeButtonStyle.Companion.DEFAULT
+import androidx.wear.protolayout.material3.EdgeButtonStyle.Companion.TOP_ALIGN
+
+/**
+ * ProtoLayout Material3 component edge button that offers a single slot to take an icon or similar
+ * round, small content.
+ *
+ * The edge button is intended to be used at the bottom of a round screen. It has a special shape
+ * with its bottom almost follows the screen's curvature. It has fixed height, and takes 1 line of
+ * text or a single icon. This button represents the most important action on the screen, and it
+ * must occupy the whole horizontal space in its position as well as being anchored to the screen
+ * bottom.
+ *
+ * This component is not intended to be used with an image background.
+ *
+ * @param onClick Associated [Clickable] for click events. When the button is clicked it will fire
+ * the associated action.
+ * @param contentDescription The content description to be read by Talkback.
+ * @param colors The colors used for this button. If not set, [EdgeButtonDefaults.filled] will be
+ * used as high emphasis button. Other recommended colors are [EdgeButtonDefaults.filledTonal] and
+ * [EdgeButtonDefaults.filledVariant]. If using custom colors, it is important to choose a color
+ * pair from same role to ensure accessibility with sufficient color contrast.
+ * @param iconContent The icon slot for content displayed in this button. It is recommended to use
+ * default styling that is automatically provided by only calling [icon] with the resource ID.
+ * @sample androidx.wear.protolayout.material3.samples.edgeButtonSampleIcon
+ */
+// TODO(b/346958146): link EdgeButton visuals in DAC
+public fun MaterialScope.iconEdgeButton(
+ onClick: Clickable,
+ contentDescription: StringProp,
+ colors: EdgeButtonColors = filled(),
+ iconContent: (MaterialScope.() -> LayoutElement)
+): LayoutElement =
+ edgeButton(
+ onClick = onClick,
+ contentDescription = contentDescription,
+ colors = colors,
+ style = DEFAULT
+ ) {
+ withStyle(
+ defaultIconStyle = IconStyle(size = ICON_SIZE_DP.toDp(), tintColor = colors.content)
+ )
+ .iconContent()
+ }
+
+/**
+ * ProtoLayout Material3 component edge button that offers a single slot to take a text or similar
+ * long and wide content.
+ *
+ * The edge button is intended to be used at the bottom of a round screen. It has a special shape
+ * with its bottom almost follows the screen's curvature. It has fixed height, and takes 1 line of
+ * text or a single icon. This button represents the most important action on the screen, and it
+ * must occupy the whole horizontal space in its position as well as being anchored to the screen
+ * bottom.
+ *
+ * This component is not intended to be used with an image background.
+ *
+ * @param onClick Associated [Clickable] for click events. When the button is clicked it will fire
+ * the associated action.
+ * @param contentDescription The content description to be read by Talkback.
+ * @param colors The colors used for this button. If not set, [EdgeButtonDefaults.filled] will be
+ * used as high emphasis button. Other recommended colors are [EdgeButtonDefaults.filledTonal] and
+ * [EdgeButtonDefaults.filledVariant]. If using custom colors, it is important to choose a color
+ * pair from same role to ensure accessibility with sufficient color contrast.
+ * @param labelContent The label slot for content displayed in this button. It is recommended to use
+ * default styling that is automatically provided by only calling [text] with the content.
+ * @sample androidx.wear.protolayout.material3.samples.edgeButtonSampleText
+ */
+// TODO(b/346958146): link EdgeButton visuals in DAC
+public fun MaterialScope.textEdgeButton(
+ onClick: Clickable,
+ contentDescription: StringProp,
+ colors: EdgeButtonColors = filled(),
+ labelContent: (MaterialScope.() -> LayoutElement)
+): LayoutElement =
+ edgeButton(
+ onClick = onClick,
+ contentDescription = contentDescription,
+ colors = colors,
+ style = TOP_ALIGN
+ ) {
+ withStyle(
+ defaultTextElementStyle =
+ TextElementStyle(
+ typography = Typography.LABEL_MEDIUM,
+ color = colors.content,
+ scalable = false
+ )
+ )
+ .labelContent()
+ }
+
+/**
+ * ProtoLayout Material3 component edge button that offers a single slot to take any content.
+ *
+ * The edge button is intended to be used at the bottom of a round screen. It has a special shape
+ * with its bottom almost follows the screen's curvature. It has fixed height, and takes 1 line of
+ * text or a single icon. This button represents the most important action on the screen, and it
+ * must occupy the whole horizontal space in its position as well as being anchored to the screen
+ * bottom.
+ *
+ * This component is not intended to be used with an image background.
+ *
+ * @param onClick Associated [Clickable] for click events. When the button is clicked it will fire
+ * the associated action.
+ * @param contentDescription The content description to be read by Talkback.
+ * @param colors The colors used for this button. If not set, [EdgeButtonDefaults.filled] will be
+ * used as high emphasis button. Other recommended colors are [EdgeButtonDefaults.filledTonal] and
+ * [EdgeButtonDefaults.filledVariant]. If using custom colors, it is important to choose a color
+ * pair from same role to ensure accessibility with sufficient color contrast.
+ * @param style The style used for the inner content, specifying how the content should be aligned.
+ * It is recommended to use [EdgeButtonStyle.TOP_ALIGN] for long, wide content. If not set,
+ * defaults to [EdgeButtonStyle.DEFAULT] which center-aligns the content.
+ * @param content The inner content to be put inside of this edge button.
+ * @sample androidx.wear.protolayout.material3.samples.edgeButtonSampleIcon
+ */
+// TODO(b/346958146): link EdgeButton visuals in DAC
+internal fun MaterialScope.edgeButton(
+ onClick: Clickable,
+ contentDescription: StringProp,
+ colors: EdgeButtonColors,
+ style: EdgeButtonStyle = DEFAULT,
+ content: MaterialScope.() -> LayoutElement
+): LayoutElement {
+ val containerWidth = deviceConfiguration.screenWidthDp.toDp()
+ val edgeButtonWidth: Float =
+ (100f - 2f * HORIZONTAL_MARGIN_PERCENT) * deviceConfiguration.screenWidthDp / 100f
+ val bottomCornerRadiusX = dp(edgeButtonWidth / 2f)
+ val bottomCornerRadiusY = dp(EDGE_BUTTON_HEIGHT_DP - TOP_CORNER_RADIUS.value)
+
+ val modifiers: Modifiers.Builder =
+ Modifiers.Builder()
+ .setClickable(onClick)
+ .setSemantics(contentDescription.buttonRoleSemantics())
+ .setBackground(
+ Background.Builder()
+ .setColor(colors.container)
+ .setCorner(
+ Corner.Builder()
+ .setRadius(TOP_CORNER_RADIUS)
+ .setBottomLeftRadius(bottomCornerRadiusX, bottomCornerRadiusY)
+ .setBottomRightRadius(bottomCornerRadiusX, bottomCornerRadiusY)
+ .build()
+ )
+ .build()
+ )
+
+ val button = Box.Builder().setHeight(EDGE_BUTTON_HEIGHT_DP.toDp()).setWidth(dp(edgeButtonWidth))
+ button
+ .setVerticalAlignment(style.verticalAlignment)
+ .setHorizontalAlignment(LayoutElementBuilders.HORIZONTAL_ALIGN_CENTER)
+ .addContent(content())
+
+ style.padding?.let { modifiers.setPadding(it) }
+
+ return Box.Builder()
+ .setHeight((EDGE_BUTTON_HEIGHT_DP + BOTTOM_MARGIN_DP).toDp())
+ .setWidth(containerWidth)
+ .setVerticalAlignment(LayoutElementBuilders.VERTICAL_ALIGN_TOP)
+ .setHorizontalAlignment(LayoutElementBuilders.HORIZONTAL_ALIGN_CENTER)
+ .addContent(button.setModifiers(modifiers.build()).build())
+ .setModifiers(Modifiers.Builder().setMetadata(METADATA_TAG.toElementMetadata()).build())
+ .build()
+}
+
+/** Provides style values for edge button component. */
+public class EdgeButtonStyle
+private constructor(
+ @VerticalAlignment internal val verticalAlignment: Int = VERTICAL_ALIGN_CENTER,
+ internal val padding: Padding? = null
+) {
+ public companion object {
+ /**
+ * Style variation for having content of the edge button anchored to the top.
+ *
+ * This should be used for text-like content, or the content that is wide, to accommodate
+ * for more space.
+ */
+ @JvmField
+ public val TOP_ALIGN: EdgeButtonStyle =
+ EdgeButtonStyle(
+ verticalAlignment = LayoutElementBuilders.VERTICAL_ALIGN_TOP,
+ padding =
+ Padding.Builder()
+ .setTop(TEXT_TOP_PADDING_DP.toDp())
+ .setStart(TEXT_SIDE_PADDING_DP.toDp())
+ .setEnd(TEXT_SIDE_PADDING_DP.toDp())
+ .build()
+ )
+
+ /**
+ * Default style variation for having content of the edge button center aligned.
+ *
+ * This should be used for icon-like or small, round content that doesn't occupy a lot of
+ * space.
+ */
+ @JvmField public val DEFAULT: EdgeButtonStyle = EdgeButtonStyle()
+ }
+}
+
+public object EdgeButtonDefaults {
+ /**
+ * [EdgeButtonColors] for the high-emphasis button representing the primary, most important or
+ * most common action on a screen.
+ *
+ * These colors are using [ColorTokens.PRIMARY] for background color and
+ * [ColorTokens.ON_PRIMARY] for content color.
+ */
+ public fun MaterialScope.filled(): EdgeButtonColors =
+ EdgeButtonColors(getColorProp(ColorTokens.PRIMARY), getColorProp(ColorTokens.ON_PRIMARY))
+
+ /**
+ * [EdgeButtonColors] for the medium-emphasis button.
+ *
+ * These colors are using [ColorTokens.SURFACE_CONTAINER] for background color and
+ * [ColorTokens.ON_SURFACE] for content color.
+ */
+ public fun MaterialScope.filledTonal(): EdgeButtonColors =
+ EdgeButtonColors(
+ getColorProp(ColorTokens.SURFACE_CONTAINER),
+ getColorProp(ColorTokens.ON_SURFACE)
+ )
+
+ /**
+ * Alternative [EdgeButtonColors] for the high-emphasis button.
+ *
+ * These colors are using [ColorTokens.PRIMARY_CONTAINER] for background color and
+ * [ColorTokens.ON_PRIMARY_CONTAINER] for content color.
+ */
+ public fun MaterialScope.filledVariant(): EdgeButtonColors =
+ EdgeButtonColors(
+ getColorProp(ColorTokens.PRIMARY_CONTAINER),
+ getColorProp(ColorTokens.ON_PRIMARY_CONTAINER)
+ )
+
+ @JvmField internal val TOP_CORNER_RADIUS: DpProp = dp(17f)
+ internal const val HORIZONTAL_MARGIN_PERCENT: Float = 24f
+ internal const val BOTTOM_MARGIN_DP: Int = 3
+ internal const val EDGE_BUTTON_HEIGHT_DP: Int = 46
+ internal const val METADATA_TAG: String = "EB"
+ internal const val ICON_SIZE_DP = 24
+ internal const val TEXT_TOP_PADDING_DP = 12
+ internal const val TEXT_SIDE_PADDING_DP = 8
+}
+
+/** Represents the container and content colors used in [textEdgeButton] or [iconEdgeButton]. */
+public class EdgeButtonColors(
+ /** The container color to be used for a button. */
+ public val container: ColorProp,
+ /** The color or icon tint color to be used for all content within a button. */
+ public val content: ColorProp
+)
diff --git a/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/Helpers.kt b/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/Helpers.kt
index d05e82f..9f088c4 100644
--- a/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/Helpers.kt
+++ b/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/Helpers.kt
@@ -16,6 +16,16 @@
package androidx.wear.protolayout.material3
+import android.os.Build.VERSION.SDK_INT
+import android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE
+import androidx.annotation.Dimension
+import androidx.annotation.Dimension.Companion.SP
+import androidx.wear.protolayout.DimensionBuilders.dp
+import androidx.wear.protolayout.ModifiersBuilders.ElementMetadata
+import androidx.wear.protolayout.ModifiersBuilders.SEMANTICS_ROLE_BUTTON
+import androidx.wear.protolayout.ModifiersBuilders.Semantics
+import androidx.wear.protolayout.TypeBuilders.StringProp
+import androidx.wear.protolayout.materialcore.fontscaling.FontScaleConverterFactory
import java.nio.charset.StandardCharsets
/** Returns byte array representation of tag from String. */
@@ -32,3 +42,20 @@
yield(element)
}
}
+
+@Dimension(unit = SP)
+internal fun Float.dpToSp(fontScale: Float): Float =
+ (if (SDK_INT >= UPSIDE_DOWN_CAKE) FontScaleConverterFactory.forScale(fontScale) else null)
+ ?.convertDpToSp(this) ?: dpToSpLinear(fontScale)
+
+@Dimension(unit = SP)
+private fun Float.dpToSpLinear(fontScale: Float): Float {
+ return this / fontScale
+}
+
+internal fun StringProp.buttonRoleSemantics() =
+ Semantics.Builder().setContentDescription(this).setRole(SEMANTICS_ROLE_BUTTON).build()
+
+internal fun Int.toDp() = dp(this.toFloat())
+
+internal fun String.toElementMetadata() = ElementMetadata.Builder().setTagData(toTagBytes()).build()
diff --git a/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/Icon.kt b/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/Icon.kt
new file mode 100644
index 0000000..fe1775c
--- /dev/null
+++ b/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/Icon.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.wear.protolayout.material3
+
+import androidx.wear.protolayout.ColorBuilders.ColorProp
+import androidx.wear.protolayout.DimensionBuilders.ImageDimension
+import androidx.wear.protolayout.LayoutElementBuilders.ColorFilter
+import androidx.wear.protolayout.LayoutElementBuilders.Image
+import androidx.wear.protolayout.LayoutElementBuilders.LayoutElement
+
+/**
+ * Returns the icon components with the defined style.
+ *
+ * Material components provide proper defaults for this icon. In order to take advantage of those,
+ * this should be used with the resource ID only: `icon("id")`.
+ *
+ * @param protoLayoutResourceId The protolayout resource id of the icon. Node that, this is not an
+ * Android resource id.
+ * @param size The side of an icon that will be used for width and height.
+ * @param tintColor The color used to tint the icon.
+ */
+public fun MaterialScope.icon(
+ protoLayoutResourceId: String,
+ size: ImageDimension = defaultIconStyle.size,
+ tintColor: ColorProp = defaultIconStyle.tintColor,
+): LayoutElement =
+ Image.Builder()
+ .setResourceId(protoLayoutResourceId)
+ .setWidth(size)
+ .setHeight(size)
+ .setColorFilter(ColorFilter.Builder().setTint(tintColor).build())
+ .build()
diff --git a/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/MaterialScope.kt b/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/MaterialScope.kt
index 6d6a3cb..bb84681 100644
--- a/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/MaterialScope.kt
+++ b/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/MaterialScope.kt
@@ -18,15 +18,20 @@
import android.content.Context
import android.provider.Settings
-import androidx.annotation.RestrictTo
-import androidx.annotation.RestrictTo.Scope
import androidx.annotation.VisibleForTesting
import androidx.wear.protolayout.ColorBuilders.ColorProp
import androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters
+import androidx.wear.protolayout.DimensionBuilders.ImageDimension
import androidx.wear.protolayout.LayoutElementBuilders.LayoutElement
+import androidx.wear.protolayout.LayoutElementBuilders.TEXT_ALIGN_CENTER
+import androidx.wear.protolayout.LayoutElementBuilders.TEXT_OVERFLOW_ELLIPSIZE
+import androidx.wear.protolayout.LayoutElementBuilders.TextAlignment
+import androidx.wear.protolayout.LayoutElementBuilders.TextOverflow
import androidx.wear.protolayout.ModifiersBuilders.Corner
import androidx.wear.protolayout.material3.ColorTokens.ColorToken
+import androidx.wear.protolayout.material3.ColorTokens.fromToken
import androidx.wear.protolayout.material3.Shape.ShapeToken
+import androidx.wear.protolayout.material3.Typography.TypographyToken
/**
* Receiver scope which is used by all ProtoLayout Material3 components and layout to support
@@ -52,14 +57,30 @@
* @param deviceConfiguration The device parameters for where the components will be rendered
* @param theme The theme to be used. If not set, default Material theme will be applied
* @param allowDynamicTheme If dynamic colors theme should be used on components, meaning that
+ * @param defaultTextElementStyle The opinionated text style that text component can use as defaults
*/
internal constructor(
internal val context: Context,
/** The device parameters for where the components will be rendered. */
public val deviceConfiguration: DeviceParameters,
internal val theme: MaterialTheme = DEFAULT_MATERIAL_THEME,
- internal val allowDynamicTheme: Boolean = true
-)
+ internal val allowDynamicTheme: Boolean = true,
+ internal val defaultTextElementStyle: TextElementStyle = TextElementStyle(),
+ internal val defaultIconStyle: IconStyle = IconStyle()
+) {
+ internal fun withStyle(
+ defaultTextElementStyle: TextElementStyle = this.defaultTextElementStyle,
+ defaultIconStyle: IconStyle = this.defaultIconStyle
+ ): MaterialScope =
+ MaterialScope(
+ context = context,
+ deviceConfiguration = deviceConfiguration,
+ theme = theme,
+ allowDynamicTheme = allowDynamicTheme,
+ defaultTextElementStyle = defaultTextElementStyle,
+ defaultIconStyle = defaultIconStyle
+ )
+}
/**
* Retrieves the [Corner] shape from the default Material theme with shape token name.
@@ -97,7 +118,7 @@
/**
* Creates a top-level receiver scope [MaterialScope] that calls the given [layout] to support for
- * opinionated defaults.
+ * opinionated defaults and building Material3 components and layout.
*
* @param context The Android Context for the Tile service
* @param deviceConfiguration The device parameters for where the components will be rendered
@@ -107,9 +128,10 @@
* @param layout Scoped slot for the content of layout to be displayed
*/
// TODO: b/369350414 - Allow for overriding colors theme.
+// TODO: b/370976767 - Specify in docs that MaterialTileService should be used instead of using this
+// directly.
@JvmOverloads
-@RestrictTo(Scope.LIBRARY_GROUP)
-public fun primaryScope(
+public fun materialScope(
context: Context,
deviceConfiguration: DeviceParameters,
allowDynamicTheme: Boolean = true,
@@ -128,3 +150,19 @@
@VisibleForTesting
internal const val THEME_CUSTOMIZATION_OVERLAY_PACKAGES: String =
"theme_customization_overlay_packages"
+
+internal class TextElementStyle(
+ @TypographyToken val typography: Int = Typography.BODY_MEDIUM,
+ val color: ColorProp = fromToken(ColorTokens.PRIMARY),
+ val italic: Boolean = false,
+ val underline: Boolean = false,
+ val scalable: Boolean = true,
+ val maxLines: Int = 1,
+ @TextAlignment val multilineAlignment: Int = TEXT_ALIGN_CENTER,
+ @TextOverflow val overflow: Int = TEXT_OVERFLOW_ELLIPSIZE,
+)
+
+internal class IconStyle(
+ val size: ImageDimension = 24.toDp(),
+ val tintColor: ColorProp = fromToken(ColorTokens.PRIMARY),
+)
diff --git a/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/MaterialTheme.kt b/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/MaterialTheme.kt
index 74c6ac0..11887c9 100644
--- a/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/MaterialTheme.kt
+++ b/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/MaterialTheme.kt
@@ -17,8 +17,10 @@
package androidx.wear.protolayout.material3
import android.annotation.SuppressLint
-import androidx.annotation.VisibleForTesting
import androidx.wear.protolayout.ColorBuilders.ColorProp
+import androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters
+import androidx.wear.protolayout.DimensionBuilders.SpProp
+import androidx.wear.protolayout.DimensionBuilders.sp
import androidx.wear.protolayout.LayoutElementBuilders.FontStyle
import androidx.wear.protolayout.ModifiersBuilders.Corner
import androidx.wear.protolayout.material3.ColorTokens.ColorToken
@@ -53,7 +55,7 @@
internal class MaterialTheme(private val customColorScheme: Map<Int, ColorProp> = emptyMap()) {
/** Retrieves the [FontStyle.Builder] with the typography name. */
internal fun getFontStyleBuilder(@TypographyToken typographyToken: Int) =
- createFontStyleBuilder(textStyle = Typography.fromToken(typographyToken))
+ createFontStyleBuilder(typographyToken)
/** Retrieves the line height with the typography name. */
internal fun getLineHeight(@TypographyToken typographyToken: Int) =
@@ -70,11 +72,22 @@
/** MaterialTheme that uses predefined default values without any customization. */
@JvmField internal val DEFAULT_MATERIAL_THEME: MaterialTheme = MaterialTheme(emptyMap())
-@VisibleForTesting
@SuppressLint("ResourceType")
-internal fun createFontStyleBuilder(textStyle: TextStyle): FontStyle.Builder {
+internal fun createFontStyleBuilder(
+ @TypographyToken typographyToken: Int,
+ deviceConfiguration: DeviceParameters? = null,
+ isScalable: Boolean = true
+): FontStyle.Builder {
+ val textStyle: TextStyle = Typography.fromToken(typographyToken)
+ val sizeSp: SpProp = textStyle.size
return FontStyle.Builder()
- .setSize(textStyle.size)
+ .setSize(
+ if (!isScalable && deviceConfiguration != null) {
+ sp(sizeSp.value.dpToSp(deviceConfiguration.fontScale))
+ } else {
+ sizeSp
+ }
+ )
.setLetterSpacing(textStyle.letterSpacing)
.setSettings(*textStyle.fontSettings.toTypedArray())
.setPreferredFontFamilies(textStyle.fontFamily)
diff --git a/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/Text.kt b/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/Text.kt
new file mode 100644
index 0000000..a42427f
--- /dev/null
+++ b/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/Text.kt
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.wear.protolayout.material3
+
+import androidx.wear.protolayout.ColorBuilders.ColorProp
+import androidx.wear.protolayout.LayoutElementBuilders.LayoutElement
+import androidx.wear.protolayout.LayoutElementBuilders.Text
+import androidx.wear.protolayout.LayoutElementBuilders.TextAlignment
+import androidx.wear.protolayout.LayoutElementBuilders.TextOverflow
+import androidx.wear.protolayout.ModifiersBuilders.Modifiers
+import androidx.wear.protolayout.TypeBuilders.StringLayoutConstraint
+import androidx.wear.protolayout.TypeBuilders.StringProp
+import androidx.wear.protolayout.material3.Typography.TypographyToken
+
+/**
+ * ProtoLayout component that represents text object holding any information.
+ *
+ * There are pre-defined typography styles that can be obtained from Materials token system in
+ * [Typography].
+ *
+ * @param text The text content for this component.
+ * @param stringLayoutConstraint The layout constraints used to correctly measure Text view size and
+ * align text when `text` has dynamic value.
+ * @param typography The typography from [Typography] to be applied to this text. This will have
+ * predefined default value specified by each components that uses this text, to achieve the
+ * recommended look.
+ * @param color The color to be applied to this text. It is recommended to use predefined default
+ * styles created by each component or `getColorProp(token)`.
+ * @param italic Whether text should be displayed as italic.
+ * @param underline Whether text should be displayed as underlined.
+ * @param scalable Whether text should scale with the user font size.
+ * @param maxLines The maximum number of lines that text can occupy.
+ * @param multilineAlignment The horizontal alignment of the multiple lines of text.
+ * @param overflow The overflow strategy when text doesn't have enough space to be shown.
+ * @param modifiers The additional [Modifiers] for this text.
+ * @sample androidx.wear.protolayout.material3.samples.helloWorldTextDefault
+ * @sample androidx.wear.protolayout.material3.samples.helloWorldTextDynamicCustom
+ */
+public fun MaterialScope.text(
+ text: StringProp,
+ stringLayoutConstraint: StringLayoutConstraint =
+ StringLayoutConstraint.Builder(text.value).build(),
+ @TypographyToken typography: Int = defaultTextElementStyle.typography,
+ color: ColorProp = defaultTextElementStyle.color,
+ italic: Boolean = defaultTextElementStyle.italic,
+ underline: Boolean = defaultTextElementStyle.underline,
+ scalable: Boolean = defaultTextElementStyle.scalable,
+ maxLines: Int = defaultTextElementStyle.maxLines,
+ @TextAlignment multilineAlignment: Int = defaultTextElementStyle.multilineAlignment,
+ @TextOverflow overflow: Int = defaultTextElementStyle.overflow,
+ modifiers: Modifiers = Modifiers.Builder().build()
+): LayoutElement =
+ Text.Builder()
+ .setText(text)
+ .setLayoutConstraintsForDynamicText(stringLayoutConstraint)
+ .setFontStyle(
+ createFontStyleBuilder(typographyToken = typography, deviceConfiguration, scalable)
+ .setColor(color)
+ .setItalic(italic)
+ .setUnderline(underline)
+ .build()
+ )
+ .setMaxLines(maxLines)
+ .setMultilineAlignment(multilineAlignment)
+ .setOverflow(overflow)
+ .setModifiers(modifiers)
+ .build()
diff --git a/wear/protolayout/protolayout-material3/src/test/java/androidx/wear/protolayout/material3/ButtonGroupTest.kt b/wear/protolayout/protolayout-material3/src/test/java/androidx/wear/protolayout/material3/ButtonGroupTest.kt
index 7c9300d..b991e06 100644
--- a/wear/protolayout/protolayout-material3/src/test/java/androidx/wear/protolayout/material3/ButtonGroupTest.kt
+++ b/wear/protolayout/protolayout-material3/src/test/java/androidx/wear/protolayout/material3/ButtonGroupTest.kt
@@ -36,7 +36,7 @@
val element2 = Box.Builder().setWidth(expand()).build()
val buttonGroup =
- primaryScope(
+ materialScope(
context = ApplicationProvider.getApplicationContext(),
deviceConfiguration = DEVICE_PARAMETERS
) {